summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--config/main.inc.php.dist14
-rw-r--r--index.php6
-rw-r--r--program/include/main.inc51
-rw-r--r--program/include/rcube_ldap.inc259
-rw-r--r--program/js/app.js163
-rw-r--r--program/localization/en/labels.inc9
-rw-r--r--program/localization/en/messages.inc9
-rw-r--r--program/steps/addressbook/func.inc3
-rw-r--r--program/steps/addressbook/ldapsearchform.inc264
-rw-r--r--program/steps/addressbook/save.inc162
-rw-r--r--skins/default/images/buttons/ldap_act.pngbin0 -> 335 bytes
-rw-r--r--skins/default/images/buttons/ldap_pas.pngbin0 -> 335 bytes
-rw-r--r--skins/default/includes/ldapscripts.html73
-rw-r--r--skins/default/ldapsearchform.css54
-rw-r--r--skins/default/templates/ldappublicsearch.html31
15 files changed, 1019 insertions, 79 deletions
diff --git a/config/main.inc.php.dist b/config/main.inc.php.dist
index 17beaf188..e7ccc913d 100644
--- a/config/main.inc.php.dist
+++ b/config/main.inc.php.dist
@@ -131,6 +131,20 @@ $rcmail_config['generic_message_footer'] = '';
// this string is used as a delimiter for message headers when sending
$rcmail_config['mail_header_delimiter'] = "\r\n";
+// public ldap servers to search for contacts
+$rcmail_config['ldap_public'] = false;
+
+/** example config for Verisign directory
+$rcmail_config['ldap_public']['Verisign'] = array('hosts' => array('directory.verisign.com'),
+ 'port' => 389,
+ 'base_dn' => '',
+ 'search_fields' => array('mail', 'cn'),
+ 'name_field' => 'cn',
+ 'mail_field' => 'mail',
+ 'scope' => 'sub',
+ 'fuzzy_search' => 0);
+**/
+
/***** these settings can be overwritten by user's preferences *****/
diff --git a/index.php b/index.php
index f864aca48..2490628af 100644
--- a/index.php
+++ b/index.php
@@ -1,5 +1,4 @@
<?php
-
/*
+-----------------------------------------------------------------------+
| RoundCube Webmail IMAP Client |
@@ -281,6 +280,9 @@ if ($_task=='addressbook')
if ($_action=='list' && $_GET['_remote'])
include('program/steps/addressbook/list.inc');
+
+ if ($_action=='ldappublicsearch')
+ include('program/steps/addressbook/ldapsearchform.inc');
}
@@ -325,4 +327,4 @@ raise_error(array('code' => 404,
'file' => __FILE__,
'message' => "Invalid request"), TRUE, TRUE);
-?> \ No newline at end of file
+?>
diff --git a/program/include/main.inc b/program/include/main.inc
index 24110d343..c64ac7d38 100644
--- a/program/include/main.inc
+++ b/program/include/main.inc
@@ -924,6 +924,8 @@ function rcube_xml_command($command, $str_attrib, $a_attrib=NULL)
'recordscountdisplay' => 'rcmail_rowcount_display',
'contactdetails' => 'rcmail_contact_details',
'contacteditform' => 'rcmail_contact_editform',
+ 'ldappublicsearch' => 'rcmail_ldap_public_search_form',
+ 'ldappublicaddresslist' => 'rcmail_ldap_public_list',
// USER SETTINGS
'userprefs' => 'rcmail_user_prefs_form',
@@ -1110,7 +1112,7 @@ function rcube_menu($attrib)
-function rcube_table_output($attrib, $sql_result, $a_show_cols, $id_col)
+function rcube_table_output($attrib, $table_data, $a_show_cols, $id_col)
{
global $DB;
@@ -1128,21 +1130,44 @@ function rcube_table_output($attrib, $sql_result, $a_show_cols, $id_col)
$table .= "</tr></thead>\n<tbody>\n";
$c = 0;
- while ($sql_result && ($sql_arr = $DB->fetch_assoc($sql_result)))
+
+ if (!is_array($table_data))
{
- $zebra_class = $c%2 ? 'even' : 'odd';
+ while ($table_data && ($sql_arr = $DB->fetch_assoc($table_data)))
+ {
+ $zebra_class = $c%2 ? 'even' : 'odd';
- $table .= sprintf('<tr id="rcmrow%d" class="contact '.$zebra_class.'">'."\n", $sql_arr[$id_col]);
+ $table .= sprintf('<tr id="rcmrow%d" class="contact '.$zebra_class.'">'."\n", $sql_arr[$id_col]);
- // format each col
- foreach ($a_show_cols as $col)
- {
- $cont = rep_specialchars_output($sql_arr[$col]);
- $table .= '<td class="'.$col.'">' . $cont . "</td>\n";
+ // format each col
+ foreach ($a_show_cols as $col)
+ {
+ $cont = rep_specialchars_output($sql_arr[$col]);
+ $table .= '<td class="'.$col.'">' . $cont . "</td>\n";
+ }
+
+ $table .= "</tr>\n";
+ $c++;
}
+ }
+ else
+ {
+ foreach ($table_data as $row_data)
+ {
+ $zebra_class = $c%2 ? 'even' : 'odd';
+
+ $table .= sprintf('<tr id="rcmrow%d" class="contact '.$zebra_class.'">'."\n", $row_data[$id_col]);
+
+ // format each col
+ foreach ($a_show_cols as $col)
+ {
+ $cont = rep_specialchars_output($row_data[$col]);
+ $table .= '<td class="'.$col.'">' . $cont . "</td>\n";
+ }
- $table .= "</tr>\n";
- $c++;
+ $table .= "</tr>\n";
+ $c++;
+ }
}
// complete message table
@@ -1420,7 +1445,6 @@ function rcmail_charset_selector($attrib)
}
-
function rcube_timer()
{
list($usec, $sec) = explode(" ", microtime());
@@ -1442,5 +1466,4 @@ function rcube_print_time($timer, $label='Timer')
console(sprintf("%s: %0.4f sec", $label, $diff));
}
-
-?> \ No newline at end of file
+?>
diff --git a/program/include/rcube_ldap.inc b/program/include/rcube_ldap.inc
new file mode 100644
index 000000000..7cb9dee53
--- /dev/null
+++ b/program/include/rcube_ldap.inc
@@ -0,0 +1,259 @@
+<?php
+
+/*
+ +-----------------------------------------------------------------------+
+ | program/include/rcube_ldap.inc |
+ | |
+ | This file is part of the RoundCube Webmail client |
+ | Copyright (C) 2005, RoundCube Dev. - Switzerland |
+ | Licensed under the GNU GPL |
+ | |
+ | PURPOSE: |
+ | Manage an LDAP connection |
+ | |
+ +-----------------------------------------------------------------------+
+ | Author: Jeremy Jongsma <jeremy@jongsma.org> |
+ +-----------------------------------------------------------------------+
+
+ $Id$
+
+*/
+
+require_once("bugs.inc");
+
+class rcube_ldap
+ {
+ var $conn;
+ var $host;
+ var $port;
+ var $protocol;
+ var $base_dn;
+ var $bind_dn;
+ var $bind_pass;
+
+ // PHP 5 constructor
+ function __construct()
+ {
+ }
+
+ // PHP 4 constructor
+ function rcube_ldap()
+ {
+ $this->__construct();
+ }
+
+ function connect($hosts, $port=389, $protocol=3)
+ {
+ if (!function_exists('ldap_connect'))
+ raise_error(array("type" => "ldap",
+ "message" => "No ldap support in this installation of php."),
+ TRUE);
+
+ if (is_resource($this->conn))
+ return TRUE;
+
+ if (!is_array($hosts))
+ $hosts = array($hosts);
+
+ foreach ($hosts as $host)
+ {
+ if ($lc = @ldap_connect($host, $port))
+ {
+ @ldap_set_option($lc, LDAP_OPT_PROTOCOL_VERSION, $protocol);
+ $this->host = $host;
+ $this->port = $port;
+ $this->protocol = $protocol;
+ $this->conn = $lc;
+ return TRUE;
+ }
+ }
+
+ if (!is_resource($this->conn))
+ raise_error(array("type" => "ldap",
+ "message" => "Could not connect to any LDAP server, tried $host:$port last"),
+ TRUE);
+ }
+
+ function close()
+ {
+ if ($this->conn)
+ {
+ if (@ldap_unbind($this->conn))
+ return TRUE;
+ else
+ raise_error(array("code" => ldap_errno($this->conn),
+ "type" => "ldap",
+ "message" => "Could not close connection to LDAP server: ".ldap_error($this->conn)),
+ TRUE);
+ }
+ return FALSE;
+ }
+
+ // Merge with connect()?
+ function bind($dn=null, $pass=null)
+ {
+ if ($this->conn)
+ {
+ if ($dn)
+ if (@ldap_bind($this->conn, $dn, $pass))
+ return TRUE;
+ else
+ raise_error(array("code" => ldap_errno($this->conn),
+ "type" => "ldap",
+ "message" => "Bind failed for dn=$dn: ".ldap_error($this->conn)),
+ TRUE);
+ else
+ if (@ldap_bind($this->conn))
+ return TRUE;
+ else
+ raise_error(array("code" => ldap_errno($this->conn),
+ "type" => "ldap",
+ "message" => "Anonymous bind failed: ".ldap_error($this->conn)),
+ TRUE);
+ }
+ else
+ raise_error(array("type" => "ldap",
+ "message" => "Attempted bind on nonexistent connection"), TRUE);
+ return FALSE;
+ }
+
+ function count($base, $filter=null, $attributes=null, $scope="sub")
+ {
+ if ($this->conn)
+ {
+ if ($scope === 'sub')
+ $sr = @ldap_search($this->conn, $base, $filter, $attributes, 0, $limit);
+ else if ($scope === 'one')
+ $sr = @ldap_list($this->conn, $base, $filter, $attributes, 0, $limit);
+ else if ($scope === 'base')
+ $sr = @ldap_read($this->conn, $base, $filter, $attributes, 0, $limit);
+ if ($sr)
+ return @ldap_count_entries($this->conn, $sr);
+ }
+ else
+ raise_error(array("type" => "ldap",
+ "message" => "Attempted count search on nonexistent connection"), TRUE);
+ return FALSE;
+ }
+
+ function search($base, $filter=null, $attributes=null, $scope='sub', $sort=null, $limit=0)
+ {
+ if ($this->conn)
+ {
+ if ($scope === 'sub')
+ $sr = @ldap_search($this->conn, $base, $filter, $attributes, 0, $limit);
+ else if ($scope === 'one')
+ $sr = @ldap_list($this->conn, $base, $filter, $attributes, 0, $limit);
+ else if ($scope === 'base')
+ $sr = @ldap_read($this->conn, $base, $filter, $attributes, 0, $limit);
+ if ($sr)
+ {
+ if ($sort && $scope !== "base")
+ {
+ if (is_array($sort))
+ {
+ // Start from the end so first sort field has highest priority
+ $sortfields = array_reverse($sort);
+ foreach ($sortfields as $sortfield)
+ @ldap_sort($this->conn, $sr, $sortfield);
+ }
+ else
+ @ldap_sort($this->conn, $sr, $sort);
+ }
+ return @ldap_get_entries($this->conn, $sr);
+ }
+ }
+ else
+ raise_error(array("type" => "ldap",
+ "message" => "Attempted search on nonexistent connection"), TRUE);
+ return FALSE;
+ }
+
+ function add($dn, $object)
+ {
+ if ($this->conn)
+ {
+ if (@ldap_add($this->conn, $dn, $object))
+ return TRUE;
+ else
+ raise_error(array("code" => ldap_errno($this->conn),
+ "type" => "ldap",
+ "message" => "Add object failed: ".ldap_error($this->conn)),
+ TRUE);
+ }
+ else
+ raise_error(array("type" => "ldap",
+ "message" => "Add object faile: no connection"),
+ TRUE);
+ return FALSE;
+ }
+
+ function modify($dn, $object)
+ {
+ if ($this->conn)
+ {
+ if (@ldap_modify($this->conn, $dn, $object))
+ return TRUE;
+ else
+ raise_error(array("code" => ldap_errno($this->conn),
+ "type" => "ldap",
+ "message" => "Modify object failed: ".ldap_error($this->conn)),
+ TRUE);
+ }
+ else
+ raise_error(array("type" => "ldap",
+ "message" => "Modify object failed: no connection"),
+ TRUE);
+ return FALSE;
+ }
+
+ function rename($dn, $newrdn, $parentdn)
+ {
+ if ($this->protocol < 3)
+ {
+ raise_error(array("type" => "ldap",
+ "message" => "rename() support requires LDAPv3 or above "),
+ TRUE);
+ return FALSE;
+ }
+
+ if ($this->conn)
+ {
+ if (@ldap_rename($this->conn, $dn, $newrdn, $parentdn, TRUE))
+ return TRUE;
+ else
+ raise_error(array("code" => ldap_errno($this->conn),
+ "type" => "ldap",
+ "message" => "Rename object failed: ".ldap_error($this->conn)),
+ TRUE);
+ }
+ else
+ raise_error(array("type" => "ldap",
+ "message" => "Rename object failed: no connection"),
+ TRUE);
+ return FALSE;
+ }
+
+ function delete($dn)
+ {
+ if ($this->conn)
+ {
+ if (@ldap_delete($this->conn, $dn))
+ return TRUE;
+ else
+ raise_error(array("code" => ldap_errno($this->conn),
+ "type" => "ldap",
+ "message" => "Delete object failed: ".ldap_error($this->conn)),
+ TRUE);
+ }
+ else
+ raise_error(array("type" => "ldap",
+ "message" => "Delete object failed: no connection"),
+ TRUE);
+ return FALSE;
+ }
+
+ }
+
+// vi: et ts=2 sw=2
+?>
diff --git a/program/js/app.js b/program/js/app.js
index dc0275c4b..6d76d04e2 100644
--- a/program/js/app.js
+++ b/program/js/app.js
@@ -160,10 +160,15 @@ function rcube_webmail()
case 'addressbook':
- var contacts_list = this.gui_objects.contactslist;
+ var contacts_list = this.gui_objects.contactslist;
+ var ldap_contacts_list = this.gui_objects.ldapcontactslist;
+
if (contacts_list)
this.init_contactslist(contacts_list);
+ if (ldap_contacts_list)
+ this.init_ldapsearchlist(ldap_contacts_list);
+
this.set_page_buttons();
if (this.env.cid)
@@ -172,7 +177,7 @@ function rcube_webmail()
if ((this.env.action=='add' || this.env.action=='edit') && this.gui_objects.editform)
this.enable_command('save', true);
- this.enable_command('list', 'add', true);
+ this.enable_command('list', 'add', 'ldappublicsearch', true);
break;
@@ -372,6 +377,26 @@ function rcube_webmail()
};
+ // get all contact rows from HTML table and init each row
+ this.init_ldapsearchlist = function(ldap_contacts_list)
+ {
+ if (ldap_contacts_list && ldap_contacts_list.tBodies[0])
+ {
+ this.ldap_contact_rows = new Array();
+
+ var row;
+ for(var r=0; r<ldap_contacts_list.tBodies[0].childNodes.length; r++)
+ {
+ row = ldap_contacts_list.tBodies[0].childNodes[r];
+ this.init_table_row(row, 'ldap_contact_rows');
+ }
+ }
+
+ // alias to common rows array
+ this.list_rows = this.ldap_contact_rows;
+ };
+
+
// make references in internal array and set event handlers
this.init_table_row = function(row, array_name)
{
@@ -548,7 +573,15 @@ function rcube_webmail()
case 'add':
if (this.task=='addressbook')
- this.load_contact(0, 'add');
+ if (!window.frames[this.env.contentframe].rcmail)
+ this.load_contact(0, 'add');
+ else
+ {
+ if (window.frames[this.env.contentframe].rcmail.selection.length)
+ this.add_ldap_contacts();
+ else
+ this.load_contact(0, 'add');
+ }
else if (this.task=='settings')
{
this.clear_selection();
@@ -682,7 +715,8 @@ function rcube_webmail()
this.show_message(this.env.prev_uid);
//location.href = this.env.comm_path+'&_action=show&_uid='+this.env.prev_uid+'&_mbox='+this.env.mailbox;
break;
-
+
+
case 'compose':
var url = this.env.comm_path+'&_action=compose';
@@ -699,21 +733,36 @@ function rcube_webmail()
// get selected contacts
else
{
- for (var n=0; n<this.selection.length; n++)
- a_cids[a_cids.length] = this.selection[n];
+ if (!window.frames[this.env.contentframe].rcmail.selection.length)
+ {
+ for (var n=0; n<this.selection.length; n++)
+ a_cids[a_cids.length] = this.selection[n];
+ }
+ else
+ {
+ var frameRcmail = window.frames[this.env.contentframe].rcmail;
+ // get the email address(es)
+ for (var n=0; n<frameRcmail.selection.length; n++)
+ a_cids[a_cids.length] = frameRcmail.ldap_contact_rows[frameRcmail.selection[n]].obj.cells[1].innerHTML;
+ }
}
-
if (a_cids.length)
url += '&_to='+a_cids.join(',');
else
break;
+
}
else if (props)
url += '&_to='+props;
+
+ // don't know if this is necessary...
+ url = url.replace(/&_framed=1/, "");
this.set_busy(true);
- location.href = url;
- break;
+
+ // need parent in case we are coming from the contact frame
+ parent.window.location.href = url;
+ break;
case 'send':
if (!this.gui_objects.messageform)
@@ -777,6 +826,15 @@ function rcube_webmail()
case 'add-contact':
this.add_contact(props);
break;
+
+
+ // ldap search
+ case 'ldappublicsearch':
+ if (this.gui_objects.ldappublicsearchform)
+ this.gui_objects.ldappublicsearchform.submit();
+ else
+ this.ldappublicsearch(command);
+ break;
// user settings commands
@@ -954,7 +1012,7 @@ function rcube_webmail()
// onmouseup-handler of message list row
this.click_row = function(e, id)
{
- var ctrl = this.check_ctrlkey(e);
+ var shift = this.check_shiftkey(e);
// don't do anything (another action processed before)
if (this.dont_select)
@@ -964,26 +1022,58 @@ function rcube_webmail()
}
if (!this.drag_active && this.in_selection_before==id)
- this.select(id, (ctrl && this.task!='settings'));
+ {
+ this.select(id, (shift && this.task!='settings'));
+ }
this.drag_start = false;
this.in_selection_before = false;
// row was double clicked
- if (this.task=='mail' && this.list_rows && this.list_rows[id].clicked && !ctrl)
+ if (this.task=='mail' && this.list_rows && this.list_rows[id].clicked && !shift)
{
this.show_message(id);
return false;
}
else if (this.task=='addressbook')
{
- if (this.selection.length==1 && this.env.contentframe)
+ if (this.contact_rows && this.selection.length==1)
+ {
this.load_contact(this.selection[0], 'show', true);
- else if (this.task=='addressbook' && this.list_rows && this.list_rows[id].clicked)
+ // change the text for the add contact button
+ var links = parent.document.getElementById('abooktoolbar').getElementsByTagName('A');
+ for (i = 0; i < links.length; i++)
+ {
+ var onclickstring = new String(links[i].onclick);
+ if (onclickstring.search('\"add\"') != -1)
+ links[i].title = this.env.newcontact;
+ }
+ }
+ else if (this.contact_rows && this.contact_rows[id].clicked)
{
this.load_contact(id, 'show');
return false;
}
+ else if (this.ldap_contact_rows && !this.ldap_contact_rows[id].clicked)
+ {
+ // clear selection
+ parent.rcmail.clear_selection();
+
+ // disable delete
+ parent.rcmail.set_button('delete', 'pas');
+
+ // change the text for the add contact button
+ var links = parent.document.getElementById('abooktoolbar').getElementsByTagName('A');
+ for (i = 0; i < links.length; i++)
+ {
+ var onclickstring = new String(links[i].onclick);
+ if (onclickstring.search('\"add\"') != -1)
+ links[i].title = this.env.addcontact;
+ }
+ }
+ // handle double click event
+ else if (this.ldap_contact_rows && this.selection.length==1 && this.ldap_contact_rows[id].clicked)
+ this.command('compose', this.ldap_contact_rows[id].obj.cells[1].innerHTML);
else if (this.env.contentframe)
{
var elm = document.getElementById(this.env.contentframe);
@@ -1004,7 +1094,6 @@ function rcube_webmail()
-
/*********************************************************/
/********* (message) list functionality *********/
/*********************************************************/
@@ -1919,6 +2008,50 @@ function rcube_webmail()
};
+
+ // load ldap search form
+ this.ldappublicsearch = function(action)
+ {
+ var add_url = '';
+ var target = window;
+ if (this.env.contentframe && window.frames && window.frames[this.env.contentframe])
+ {
+ add_url = '&_framed=1';
+ target = window.frames[this.env.contentframe];
+ document.getElementById(this.env.contentframe).style.visibility = 'inherit';
+ }
+ else
+ return false;
+
+
+ if (action == 'ldappublicsearch')
+ target.location.href = this.env.comm_path+'&_action='+action+add_url;
+ };
+
+ // add ldap contacts to address book
+ this.add_ldap_contacts = function()
+ {
+ if (window.frames[this.env.contentframe].rcmail)
+ {
+ var frame = window.frames[this.env.contentframe];
+
+ // build the url
+ var url = '&_framed=1';
+ var emails = '&_emails=';
+ var names = '&_names=';
+ var end = '';
+ for (var n=0; n<frame.rcmail.selection.length; n++)
+ {
+ end = n < frame.rcmail.selection.length - 1 ? ',' : '';
+ emails += frame.rcmail.ldap_contact_rows[frame.rcmail.selection[n]].obj.cells[1].innerHTML + end;
+ names += frame.rcmail.ldap_contact_rows[frame.rcmail.selection[n]].obj.cells[0].innerHTML + end;
+ }
+
+ frame.location.href = this.env.comm_path + '&_action=save&_framed=1' + emails + names;
+ }
+ return false;
+ }
+
/*********************************************************/
diff --git a/program/localization/en/labels.inc b/program/localization/en/labels.inc
index 086c3080f..1355c071d 100644
--- a/program/localization/en/labels.inc
+++ b/program/localization/en/labels.inc
@@ -143,12 +143,19 @@ $labels['save'] = 'Save';
$labels['delete'] = 'Delete';
$labels['newcontact'] = 'Create new contact card';
+$labels['addcontact'] = 'Add selected contact to your addressbook';
$labels['deletecontact'] = 'Delete selected contacts';
$labels['composeto'] = 'Compose mail to';
$labels['contactsfromto'] = 'Contacts $from to $to of $count';
$labels['print'] = 'Print';
$labels['export'] = 'Export';
+$labels['ldappublicsearchname'] = 'Contact name';
+$labels['ldappublicsearchtype'] = 'Exact match?';
+$labels['ldappublicserverselect'] = 'Select servers';
+$labels['ldappublicsearchfield'] = 'Search on';
+$labels['ldappublicsearchform'] = 'Look for a contact';
+$labels['ldappublicsearch'] = 'Search';
// settings
$labels['settingsfor'] = 'Settings for';
@@ -183,4 +190,4 @@ $labels['sortby'] = 'Sort by';
$labels['sortasc'] = 'Sort ascending';
$labels['sortdesc'] = 'Sort descending';
-?> \ No newline at end of file
+?>
diff --git a/program/localization/en/messages.inc b/program/localization/en/messages.inc
index c1520ecce..5a662d279 100644
--- a/program/localization/en/messages.inc
+++ b/program/localization/en/messages.inc
@@ -78,5 +78,12 @@ $messages['nobodywarning'] = 'Send this message without text?';
$messages['notsentwarning'] = 'Message has not been sent. Do you want to discard your message?';
+$messages['notsentwarning'] = 'Message has not been sent. Do you want to discard your message?';
+
+$messages['noldapserver'] = 'Please select an ldap server to search';
+
+$messages['nocontactsreturned'] = 'No contacts were found';
+
+$messages['nosearchname'] = 'Please enter a contact name or email address';
-?> \ No newline at end of file
+?>
diff --git a/program/steps/addressbook/func.inc b/program/steps/addressbook/func.inc
index 8065219b0..ee3b8804a 100644
--- a/program/steps/addressbook/func.inc
+++ b/program/steps/addressbook/func.inc
@@ -81,6 +81,7 @@ function rcmail_contacts_list($attrib)
$javascript = sprintf("%s.gui_object('contactslist', '%s');\n", $JS_OBJECT_NAME, $attrib['id']);
$javascript .= sprintf("%s.set_env('current_page', %d);\n", $JS_OBJECT_NAME, $CONTACTS_LIST['page']);
$javascript .= sprintf("%s.set_env('pagecount', %d);\n", $JS_OBJECT_NAME, ceil($rowcount/$CONFIG['pagesize']));
+ $javascript .= "rcmail.set_env('newcontact', '" . rcube_label('newcontact') . "');";
//$javascript .= sprintf("%s.set_env('contacts', %s);", $JS_OBJECT_NAME, array2js($a_js_message_arr));
$OUTPUT->add_script($javascript);
@@ -191,4 +192,4 @@ function rcmail_get_rowcount_text($max=NULL)
return $out;
}
-?> \ No newline at end of file
+?>
diff --git a/program/steps/addressbook/ldapsearchform.inc b/program/steps/addressbook/ldapsearchform.inc
new file mode 100644
index 000000000..f7d7cc9f5
--- /dev/null
+++ b/program/steps/addressbook/ldapsearchform.inc
@@ -0,0 +1,264 @@
+<?php
+
+/*
+ +-----------------------------------------------------------------------+
+ | program/steps/addressbook/ldapsearch.inc |
+ | |
+ | This file is part of the RoundCube Webmail client |
+ | Copyright (C) 2005, RoundCube Dev. - Switzerland |
+ | Licensed under the GNU GPL |
+ | |
+ | PURPOSE: |
+ | Show an ldap search form in the addressbook |
+ | |
+ +-----------------------------------------------------------------------+
+ | Author: Justin Randell <justin.randell@gmail.com> |
+ +-----------------------------------------------------------------------+
+
+ $Id$
+
+*/
+require_once 'include/rcube_ldap.inc';
+
+/**
+ * draw the ldap public search form
+ */
+function rcmail_ldap_public_search_form($attrib)
+ {
+ global $CONFIG, $JS_OBJECT_NAME, $OUTPUT;
+ if (!$CONFIG['ldap_public'])
+ {
+ // no ldap servers to search
+ show_message('noldapserver', 'warning');
+ rcmail_overwrite_action('add');
+ return false;
+ }
+ else
+ {
+ // store some information in the session
+ $_SESSION['ldap_public']['server_count'] = $server_count = count($CONFIG['ldap_public']);
+ $_SESSION['ldap_public']['server_names'] = $server_names = array_keys($CONFIG['ldap_public']);
+ }
+
+ list($form_start, $form_end) = get_form_tags($attrib);
+ $out = "$form_start<table id=\"ldap_public_search_table\">\n\n";
+
+ // search name field
+ $search_name = new textfield(array('name' => '_ldap_public_search_name',
+ 'id' => 'rcmfd_ldap_public_search_name'));
+ $out .= "<tr><td class=\"title\"><label for=\"rcmfd_ldap_public_search_name\">" .
+ rep_specialchars_output(rcube_label('ldappublicsearchname')) .
+ "</label></td><td>" . $search_name->show() . "</td></tr>\n";
+
+
+ // there's more than one server to search for, show a dropdown menu
+ if ($server_count > 1)
+ {
+ $select_server = new select(array('name' => '_ldap_public_servers',
+ 'id' => 'rcfmd_ldap_public_servers'));
+
+ $select_server->add($server_names, $server_names);
+
+ $out .= '<tr><td class="title"><label for="rcfmd_ldap_public_servers">' .
+ rep_specialchars_output(rcube_label('ldappublicserverselect')) .
+ "</label></td><td>" . $select_server->show() . "</td></tr>\n";
+ }
+
+ // foreach configured ldap server, set up the search fields
+ for ($i = 0; $i < $server_count; $i++)
+ {
+ $server = $CONFIG['ldap_public'][$server_names[$i]];
+
+ // only display one search fields select - js takes care of the rest
+ if (!$i)
+ {
+ $field_name = '_ldap_public_search_field';
+ $field_id = 'rcfmd_ldap_public_search_field';
+
+ $search_fields = new select(array('name' => $field_name,
+ 'id' => $field_id));
+
+ $search_fields->add($server['search_fields'], $server['search_fields']);
+ $out .= '<tr><td class="title"><label for="' . $field_id . '">' .
+ rep_specialchars_output(rcube_label('ldappublicsearchfield')) .
+ "</label></td><td>" . $search_fields->show() . "</td></tr>\n";
+
+ $search_type = new checkbox(array('name' => '_ldap_public_search_type',
+ 'id' => 'rcmfd_ldap_public_search_type', 'value' => 0));
+
+ $out .= '<tr id="ldap_fuzzy_search"><td class="title"><label for="rcmfd_ldap_public_search_type">' .
+ rep_specialchars_output(rcube_label('ldappublicsearchtype')) .
+ "</label></td><td>" . $search_type->show() . "</td></tr>\n";
+ }
+
+ // store the search fields in a js array for each server
+ $js = '';
+ foreach ($server['search_fields'] as $k => $search_field)
+ $js .= "'$search_field', ";
+
+ // store whether this server accepts fuzzy search as last item in array
+ $js .= $server['fuzzy_search'] ? "'fuzzy'" : "'exact'";
+ $OUTPUT->add_script("rcmail.set_env('{$server_names[$i]}_search_fields', new Array($js));");
+ }
+
+ // add contact button label text
+ $OUTPUT->add_script("rcmail.set_env('addcontact', '" . rcube_label('addcontact') . "');");
+
+ $out .= "\n</table>$form_end";
+ return $out;
+ }
+
+/**
+ * get search values and return ldap contacts
+ */
+function rcmail_ldap_public_list()
+ {
+ // just return if we are not being called from a search form
+ if (!isset($_POST['_action']))
+ return null;
+
+ global $CONFIG, $OUTPUT, $JS_OBJECT_NAME;
+
+ // show no search name warning and exit
+ if (empty($_POST['_ldap_public_search_name']) || trim($_POST['_ldap_public_search_name']) == '')
+ {
+ show_message('nosearchname', 'warning');
+ return false;
+ }
+
+ // set up ldap server(s) array or bail
+ if ($_SESSION['ldap_public']['server_count'] > 1)
+ // show no ldap server warning and exit
+ if (empty($_POST['_ldap_public_servers']))
+ {
+ show_message('noldappublicserver', 'warning');
+ return false;
+ }
+ else
+ $server_name = $_POST['_ldap_public_servers'];
+ else if ($_SESSION['ldap_public']['server_count'] == 1)
+ $server_name = $_SESSION['ldap_public']['server_names'][0];
+ else
+ return false;
+
+ // get search parameters
+ $search_value = $_POST['_ldap_public_search_name'];
+ $search_field = $_POST['_ldap_public_search_field'];
+
+ // only use the post var for search type if the ldap server allows 'like'
+ $exact = true;
+ if ($CONFIG['ldap_public'][$server_name]['fuzzy_search'])
+ $exact = isset($_POST['_ldap_public_search_type']) ? true : false;
+
+ // perform an ldap search
+ $contacts = rcmail_ldap_contact_search($search_value,
+ $search_field,
+ $CONFIG['ldap_public'][$server_name],
+ $exact);
+
+ // if no results, show a warning and return
+ if (!$contacts)
+ {
+ show_message('nocontactsreturned', 'warning');
+ return false;
+ }
+
+ // add id to message list table if not specified
+ if (!strlen($attrib['id']))
+ $attrib['id'] = 'ldapAddressList';
+
+ // define table class
+ $attrib['class'] = 'records-table';
+ $attrib['cellspacing'] = 0;
+
+ // define list of cols to be displayed
+ $a_show_cols = array('name', 'email');
+
+ // create XHTML table
+ $out = rcube_table_output($attrib, $contacts, $a_show_cols, 'row_id');
+
+ // set client env
+ $javascript = "$JS_OBJECT_NAME.gui_object('ldapcontactslist', '{$attrib['id']}');\n";
+ $OUTPUT->add_script($javascript);
+
+ return $out;
+ }
+
+/**
+ * perform search for contacts from given public ldap server
+ */
+function rcmail_ldap_contact_search($search_value, $search_field, $server, $exact=true)
+ {
+ global $CONFIG;
+
+ $attributes = array($server['name_field'], $server['mail_field']);
+
+ $LDAP = new rcube_ldap();
+ if ($LDAP->connect($server['hosts'], $server['port'], $server['protocol']))
+ {
+ $filter = "$search_field=" . ($exact ? $search_value : "*$search_value*");
+ $result = $LDAP->search($server['base_dn'],
+ $filter,
+ $attributes,
+ $server['scope'],
+ $sort=null);
+
+ // add any results to contact array
+ if ($result['count'])
+ {
+ for ($n = 0; $n < $result['count']; $n++)
+ {
+ $contacts[$n]['name'] = $result[$n][$server['name_field']][0];
+ $contacts[$n]['email'] = $result[$n][$server['mail_field']][0];
+ $contacts[$n]['row_id'] = $n + 1;
+ }
+ }
+ }
+ else
+ return false;
+
+ // cleanup
+ $LDAP->close();
+
+ if (!$result['count'])
+ return false;
+
+ // weed out duplicate emails
+ for ($n = 0; $n < $result['count']; $n++)
+ for ($i = 0; $i < $result['count']; $i++)
+ if ($contacts[$i]['email'] == $contacts[$n]['email'] && $i != $n)
+ unset($contacts[$n]);
+
+ return $contacts;
+ }
+
+function get_form_tags($attrib)
+ {
+ global $OUTPUT, $JS_OBJECT_NAME, $EDIT_FORM, $SESS_HIDDEN_FIELD;
+
+ $form_start = '';
+ if (!strlen($EDIT_FORM))
+ {
+ $hiddenfields = new hiddenfield(array('name' => '_task', 'value' => $GLOBALS['_task']));
+ $hiddenfields->add(array('name' => '_action', 'value' => 'ldappublicsearch'));
+
+ if ($_GET['_framed'] || $_POST['_framed'])
+ $hiddenfields->add(array('name' => '_framed', 'value' => 1));
+
+ $form_start .= !strlen($attrib['form']) ? '<form name="form" action="./" method="post">' : '';
+ $form_start .= "\n$SESS_HIDDEN_FIELD\n";
+ $form_start .= $hiddenfields->show();
+ }
+
+ $form_end = (strlen($EDIT_FORM) && !strlen($attrib['form'])) ? '</form>' : '';
+ $form_name = strlen($attrib['form']) ? $attrib['form'] : 'form';
+
+ $OUTPUT->add_script("$JS_OBJECT_NAME.gui_object('ldappublicsearchform', '$form_name');");
+
+ $EDIT_FORM = $form_name;
+
+ return array($form_start, $form_end);
+ }
+
+parse_template('ldappublicsearch');
+?>
diff --git a/program/steps/addressbook/save.inc b/program/steps/addressbook/save.inc
index f5ba139b9..24e375ef7 100644
--- a/program/steps/addressbook/save.inc
+++ b/program/steps/addressbook/save.inc
@@ -19,18 +19,17 @@
*/
-
-$a_save_cols = array('name', 'firstname', 'surname', 'email');
-
-
// check input
-if (empty($_POST['_name']) || empty($_POST['_email']))
+if ((empty($_POST['_name']) || empty($_POST['_email'])) && empty($_GET['_framed']))
{
show_message('formincomplete', 'warning');
rcmail_overwrite_action($_POST['_cid'] ? 'show' : 'add');
return;
}
+// setup some vars we need
+$a_save_cols = array('name', 'firstname', 'surname', 'email');
+$contacts_table = get_table_name('contacts');
// update an existing contact
if ($_POST['_cid'])
@@ -48,7 +47,7 @@ if ($_POST['_cid'])
if (sizeof($a_write_sql))
{
- $DB->query("UPDATE ".get_table_name('contacts')."
+ $DB->query("UPDATE $contacts_table
SET changed=now(), ".join(', ', $a_write_sql)."
WHERE contact_id=?
AND user_id=?
@@ -70,7 +69,7 @@ if ($_POST['_cid'])
$a_show_cols = array('name', 'email');
$a_js_cols = array();
- $sql_result = $DB->query("SELECT * FROM ".get_table_name('contacts')."
+ $sql_result = $DB->query("SELECT * FROM $contacts_table
WHERE contact_id=?
AND user_id=?
AND del<>1",
@@ -104,64 +103,137 @@ if ($_POST['_cid'])
else
{
$a_insert_cols = $a_insert_values = array();
-
+
// check for existing contacts
- $sql_result = $DB->query("SELECT 1 FROM ".get_table_name('contacts')."
- WHERE user_id=?
- AND email=?
- AND del<>1",
- $_SESSION['user_id'],
- $_POST['_email']);
+ $sql = "SELECT 1 FROM $contacts_table
+ WHERE user_id = {$_SESSION['user_id']}
+ AND del <> '1' ";
+
+ // get email and name, build sql for existing user check
+ if (isset($_GET['_emails']) && isset($_GET['_names']))
+ {
+ $sql .= "AND email IN (";
+ $emails = explode(',', $_GET['_emails']);
+ $names = explode(',', $_GET['_names']);
+ $count = count($emails);
+ $n = 0;
+ foreach ($emails as $email)
+ {
+ $end = (++$n == $count) ? '' : ',';
+ $sql .= $DB->quote(strip_tags($email)) . $end;
+ }
+ $sql .= ")";
+ $ldap_form = true;
+ }
+ else if (isset($_POST['_email']))
+ $sql .= "AND email = " . $DB->quote(strip_tags($_POST['_email']));
+
+ $sql_result = $DB->query($sql);
// show warning message
if ($DB->num_rows($sql_result))
{
show_message('contactexists', 'warning');
- $_action = 'add';
+
+ if ($ldap_form)
+ rcmail_overwrite_action('ldappublicsearch');
+ else
+ rcmail_overwrite_action('add');
+
return;
}
- foreach ($a_save_cols as $col)
+ if ($ldap_form)
{
- $fname = '_'.$col;
- if (!isset($_POST[$fname]))
- continue;
-
- $a_insert_cols[] = $col;
- $a_insert_values[] = $DB->quote(strip_tags($_POST[$fname]));
+ $n = 0;
+ foreach ($emails as $email)
+ {
+ $DB->query("INSERT INTO $contacts_table
+ (user_id, name, email)
+ VALUES ({$_SESSION['user_id']}," . $DB->quote(strip_tags($names[$n++])) . "," .
+ $DB->quote(strip_tags($email)) . ")");
+ $insert_id[] = $DB->insert_id();
+ }
}
-
- if (sizeof($a_insert_cols))
+ else
{
- $DB->query("INSERT INTO ".get_table_name('contacts')."
+ foreach ($a_save_cols as $col)
+ {
+ $fname = '_'.$col;
+ if (!isset($_POST[$fname]))
+ continue;
+
+ $a_insert_cols[] = $col;
+ $a_insert_values[] = $DB->quote(strip_tags($_POST[$fname]));
+ }
+
+ if (sizeof($a_insert_cols))
+ {
+ $DB->query("INSERT INTO $contacts_table
(user_id, changed, del, ".join(', ', $a_insert_cols).")
VALUES (?, now(), 0, ".join(', ', $a_insert_values).")",
$_SESSION['user_id']);
- $insert_id = $DB->insert_id(get_sequence_name('contacts'));
+ $insert_id = $DB->insert_id(get_sequence_name('contacts'));
+ }
}
if ($insert_id)
{
- $_action = 'show';
- $_GET['_cid'] = $insert_id;
+ if (!$ldap_form)
+ {
+ $_action = 'show';
+ $_GET['_cid'] = $insert_id;
- if ($_POST['_framed'])
+ if ($_POST['_framed'])
+ {
+ // add contact row or jump to the page where it should appear
+ $commands = sprintf("if(parent.%s)parent.", $JS_OBJECT_NAME);
+ $sql_result = $DB->query("SELECT * FROM $contacts_table
+ WHERE contact_id=?
+ AND user_id=?",
+ $insert_id,
+ $_SESSION['user_id']);
+ $commands .= rcmail_js_contacts_list($sql_result, $JS_OBJECT_NAME);
+
+ $commands .= sprintf("if(parent.%s)parent.%s.select('%d');\n",
+ $JS_OBJECT_NAME,
+ $JS_OBJECT_NAME,
+ $insert_id);
+
+ // update record count display
+ $commands .= sprintf("if(parent.%s)parent.%s.set_rowcount('%s');\n",
+ $JS_OBJECT_NAME,
+ $JS_OBJECT_NAME,
+ rcmail_get_rowcount_text());
+
+ $OUTPUT->add_script($commands);
+ }
+
+ // show confirmation
+ show_message('successfullysaved', 'confirmation');
+ }
+ else
{
// add contact row or jump to the page where it should appear
- $commands = sprintf("if(parent.%s)parent.", $JS_OBJECT_NAME);
- $sql_result = $DB->query("SELECT * FROM ".get_table_name('contacts')."
- WHERE contact_id=?
- AND user_id=?",
- $insert_id,
- $_SESSION['user_id']);
- $commands .= rcmail_js_contacts_list($sql_result, $JS_OBJECT_NAME);
+ $commands = '';
+ foreach ($insert_id as $id)
+ {
+ $sql_result = $DB->query("SELECT * FROM $contacts_table
+ WHERE contact_id = $id
+ AND user_id = {$_SESSION['user_id']}");
+
+ $commands .= sprintf("if(parent.%s)parent.", $JS_OBJECT_NAME);
+ $commands .= rcmail_js_contacts_list($sql_result, $JS_OBJECT_NAME);
+ $last_id = $id;
+ }
+ // display the last insert id
$commands .= sprintf("if(parent.%s)parent.%s.select('%d');\n",
- $JS_OBJECT_NAME,
- $JS_OBJECT_NAME,
- $insert_id);
-
+ $JS_OBJECT_NAME,
+ $JS_OBJECT_NAME,
+ $last_id);
+
// update record count display
$commands .= sprintf("if(parent.%s)parent.%s.set_rowcount('%s');\n",
$JS_OBJECT_NAME,
@@ -169,10 +241,11 @@ else
rcmail_get_rowcount_text());
$OUTPUT->add_script($commands);
-
- // show confirmation
- show_message('successfullysaved', 'confirmation');
+ rcmail_overwrite_action('ldappublicsearch');
}
+
+ // show confirmation
+ show_message('successfullysaved', 'confirmation');
}
else
{
@@ -182,5 +255,4 @@ else
}
}
-
-?> \ No newline at end of file
+?>
diff --git a/skins/default/images/buttons/ldap_act.png b/skins/default/images/buttons/ldap_act.png
new file mode 100644
index 000000000..b09f26707
--- /dev/null
+++ b/skins/default/images/buttons/ldap_act.png
Binary files differ
diff --git a/skins/default/images/buttons/ldap_pas.png b/skins/default/images/buttons/ldap_pas.png
new file mode 100644
index 000000000..b09f26707
--- /dev/null
+++ b/skins/default/images/buttons/ldap_pas.png
Binary files differ
diff --git a/skins/default/includes/ldapscripts.html b/skins/default/includes/ldapscripts.html
new file mode 100644
index 000000000..0dfda6cb7
--- /dev/null
+++ b/skins/default/includes/ldapscripts.html
@@ -0,0 +1,73 @@
+<script type="text/javascript">
+var ldap_server_select = document.getElementById('rcfmd_ldap_public_servers');
+if (ldap_server_select) {
+ // attach event to ldap server drop down
+ ldap_server_select.onchange = function() {
+ updateLdapSearchFields(this);
+ return false;
+ }
+}
+
+// update the fields on page load
+updateLdapSearchFields(ldap_server_select);
+
+/**
+ * function to change the attributes of the ldap server search fields select box
+ * this function is triggered by an onchange event in the server select box
+ */
+function updateLdapSearchFields(element) {
+
+ // get the search fields select element
+ var search_fields = document.getElementById('rcfmd_ldap_public_search_field');
+
+ // get rid of the current options for the select
+ for (i = search_fields.length - 1; i>=0; i--)
+ search_fields.remove(i);
+
+ // get the array containing this servers search fields
+ var server_fields = rcmail.env[element.value + '_search_fields'];
+
+ // add a new option for each of the possible search fields for the selected server
+ for (i = 0; i < server_fields.length; i++) {
+
+ // the last array value is for fuzzy search, so skip that one
+ if (i < (server_fields.length - 1)) {
+ var new_option = document.createElement('option');
+ new_option.text = server_fields[i];
+ new_option.value = server_fields[i];
+
+ // standards compliant browsers
+ try {
+ search_fields.add(new_option, null);
+ }
+ // for the standards challenged one...
+ catch(e) {
+ search_fields.add(new_option);
+ }
+ } else {
+ // ok, last member of array, so check the value of fuzzy_search
+ var fuzzy_search = server_fields[i];
+ var search_check_box = document.getElementById('rcmfd_ldap_public_search_type');
+
+ if (fuzzy_search == 'fuzzy') {
+ // we should enable the check box
+ if (search_check_box.disabled)
+ search_check_box.disabled = false;
+
+ // make sure the checkbox is unchecked
+ if (search_check_box.checked)
+ search_check_box.checked = false;
+
+ } else {
+ // we should disable the check box
+ if (!search_check_box.disabled)
+ search_check_box.disabled = true;
+
+ // check the checkbox (just a visual clue for the user)
+ if (!search_check_box.checked)
+ search_check_box.checked = true;
+ }
+ }
+ }
+}
+</script>
diff --git a/skins/default/ldapsearchform.css b/skins/default/ldapsearchform.css
new file mode 100644
index 000000000..9661442eb
--- /dev/null
+++ b/skins/default/ldapsearchform.css
@@ -0,0 +1,54 @@
+/***** RoundCube|Mail address book task styles *****/
+
+
+body.iframe,
+{
+ background-color: #F9F9F9;
+}
+
+#ldapsearch-title
+{
+ height: 12px !important;
+/* height: 20px; */
+ padding: 4px 20px 3px 20px;
+ border-bottom: 1px solid #999999;
+ color: #333333;
+ font-size: 11px;
+ font-weight: bold;
+ background-color: #EBEBEB;
+ background-image: url(images/listheader_aqua.gif);
+}
+
+#ldapsearch-details
+{
+ padding: 15px 20px 10px 20px;
+}
+
+#ldapsearch-details table td.title
+{
+ color: #666666;
+ font-weight: bold;
+ text-align: right;
+ padding-right: 10px;
+}
+
+#ldapAddressList
+{
+ width: 100%;
+ table-layout: fixed;
+ /* css hack for IE */
+ width: expression(document.getElementById('addresslist').clientWidth);
+}
+
+#ldapAddressList table
+{
+ border-top: 1px solid #999999;
+}
+
+#ldap-search-results div
+{
+ width: 100%;
+ color: red;
+ background-color: green;
+}
+
diff --git a/skins/default/templates/ldappublicsearch.html b/skins/default/templates/ldappublicsearch.html
new file mode 100644
index 000000000..70570c06f
--- /dev/null
+++ b/skins/default/templates/ldappublicsearch.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<title><roundcube:object name="pagetitle" /></title>
+<link rel="stylesheet" type="text/css" href="/common.css" />
+<link rel="stylesheet" type="text/css" href="/ldapsearchform.css" />
+</head>
+<body class="iframe">
+
+<div id="ldapsearch-title"><roundcube:label name="ldappublicsearchform" /></div>
+
+<div id="ldapsearch-details">
+<roundcube:object name="ldappublicsearch" size="40" />
+<p>
+<roundcube:button command="ldappublicsearch" type="input" class="button" label="ldappublicsearch" />
+<input type="button" value="<roundcube:label name="cancel" />" class="button" onclick="history.back()" />&nbsp;
+<br /></p>
+</div>
+
+
+<div id="ldapsearch-results">
+<roundcube:object name="ldappublicaddresslist"
+ id="ldappublicaddresslist"
+ cellspacing="0"
+ summary="Ldap email address list" />
+</div>
+
+<roundcube:include file="/includes/ldapscripts.html" />
+
+</body>
+</html>