Horde/Turba – allowing public LDAP addresses to be added to private addressbooks

30 Oct

Below is a description of what i had to do to Turba to allow it to save both local addresses and LDAP addresses to an SQL addressbook:

The diff command used (from the turba directory) was:
diff -burN –exclude=*.dist –exclude=config –exclude=*.back –exclude=*.modified –exclude=*.sql ~/turba-1.2/ ./ > ../turba.diff

——————————————————————————————————————–
Turba Patches
Turba 1.2

THIS PATCH IS FOR TURBA 1.2 STABLE

This patch allows for adding LDAP addresses to SQL addressbooks.

Both normal ‘Search’ and ‘Advanced Search’ results can be added to the addressbook.

It is backwards compatible to address entry entered before this patch.

Chuck told me that it would be better to patch against CVS HEAD,unfortunately my boss asked me to write it against 1.2 STABLE. So this patch is for 1.2 STABLE.

Basically:

I have changed the turba_member field in turba_objects.

Rather than just having a serialized array of object_id’s, i.e.:

a:3:{i:0;s:32:”876d1826fdb03265df3243272a5f4420″;i:1;s:32:”16469607fe47e22d129464135ee79160″;}

This is really just: array(XXX,YYY)

I now have serialized array of arrays, with each inner array containing the source where the entry is from, i.e:

a:2:{i:0;a:2:{i:0;s:8:”imvsldap”;i:1;s:47:”uid=iisjsoo,ou=Users,dc=imvs,dc=sa,dc=gov,dc=au”;}

i:1;a:2:{i:0;s:8:”localsql”;i:1;s:32:”4cf194f308531d497fc909be896e6f05″;}}

This is: array( array(localsql, XXX), array(localldap,YYY)

I had to change

* browse.php
* lib/AbstractObject.php
* lib/api.php
* lib/Group.php
* templates/browse/actions.inc
* templates/browse/contactrow.inc

Below are some notes, and things that NEED to be changed to make it work.

————————————————————————————————————–

NOTE:

In config/sources.php, you will need to add the following line to the bottom of the file, where ‘localsql’ is the name of your sql source.. (i.e. $cfgSources[‘localsql’] )

define(‘PERSONAL_ADDRESS_BOOK_SOURCE’, ‘localsql’);

Also, make sure that $cfgSources[‘localsql’] array has something that

looks like:

‘map’ => array(

‘__key’ => ‘object_id’,

‘__owner’ => ‘owner_id’,

‘__type’ => ‘object_type’,

‘__members’ => ‘object_members’,

Also,

In lib/api.php, i don’t check for ‘turba_lists’ as was in 1.2 STABLE, i couldn’t work out why this was needed, so i just assume it is a turba_list.

Diff’s follow:
################################################


diff -burN --exclude='*.dist' --exclude=config --exclude='*.back' --exclude='*.modified' --exclude='*.sql' /home/iisjsoo/turba-1.2/browse.php ./browse.php
--- /home/iisjsoo/turba-1.2/browse.php Wed Mar 5 02:33:34 2003
+++ ./browse.php Fri Aug 15 16:11:54 2003
@@ -69,13 +69,20 @@
/* Remove a contact from a list. */
$keys = Horde::getFormData('objectkeys');
if (is_array($keys)) {
-
$key = Horde::getFormData('key', false);
if ($key && $key != "**search") {
/* We are removing a contact from a list. */
$list = $driver->getObject($key);
foreach ($keys as $objectKey) {
- if (!$list->removeMember($driver->getObject($objectKey))) {
+/* iisjsoo
+ *
+ * This was changed so that it takes into account the source of the
+ * entry
+ *
+ */
+ list($objectKeySource, $objectKey) = splitSourceAndKey($objectKey);
+ $driver = &Turba_Source::singleton($objectKeySource, $cfgSources[$objectKeySource]);
+ if (!$list->removeMemberSource($driver->getObject($objectKey))) {
Horde::raiseMessage(_("There was an error removing this object."), HORDE_ERROR);
} else {
Horde::raiseMessage(_("Contact removed from list."), HORDE_SUCCESS);
@@ -84,6 +91,13 @@
} else {
/* We are deleting an object. */
foreach ($keys as $objectKey) {
+/* iisjsoo
+ *
+ * This was changed so that it takes into account the source of the
+ * entry
+ *
+ */
+ list($objectKeySource, $objectKey) = splitSourceAndKey($objectKey);
if (!$driver->removeObject($objectKey)) {
Horde::raiseMessage(_("There was an error deleting this object."), HORDE_ERROR);
}
@@ -110,15 +124,32 @@
break;
}

+/* iisjsoo
+ *
+ * I need to first get a driver for the PERSONAL_ADDRESS_BOOK_SOURCE and then get
+ * the object
+ *
+ */
+ list($targetKeySource, $newTargetKey) = splitSourceAndKey($targetKey);
if (!Horde::getFormData('targetNew')) {
- $target = $driver->getObject($targetKey);
+ $driver = &Turba_Source::singleton(PERSONAL_ADDRESS_BOOK_SOURCE, $cfgSources[PERSONAL_ADDRESS_BOOK_SOURCE]);
+ $target = $driver->getObject($newTargetKey);
}

+
if (!empty($target) && is_object($target) && $target->isGroup()) {
/* Adding contact to an existing list */
if (is_array($keys)) {
foreach ($keys as $objectKey) {
- $target->addMember($driver->getObject($objectKey));
+/* iisjsoo
+ *
+ * This was changed so that it takes into account the source of the
+ * entry
+ *
+ */
+ list($objectKeySource, $objectKey) = splitSourceAndKey($objectKey);
+ $driver = &Turba_Source::singleton($objectKeySource, $cfgSources[$objectKeySource]);
+ $target->addMemberSource($driver->getObject($objectKey),$objectKeySource);
}
$target->store();
}
@@ -135,7 +166,15 @@
if (!empty($target) && is_object($target) && $target->isGroup()) {
if (is_array($keys)) {
foreach ($keys as $objectKey) {
- $target->addMember($driver->getObject($objectKey));
+/* iisjsoo
+ *
+ * This was changed so that it takes into account the source of the
+ * entry
+ *
+ */
+ list($objectKeySource, $objectKey) = splitSourceAndKey($objectKey);
+ $driver = &Turba_Source::singleton($objectKeySource, $cfgSources[$objectKeySource]);
+ $target->addMemberSource($driver->getObject($objectKey),$objectKeySource);
}
$target->store();
}
@@ -165,13 +204,20 @@
!isset($columns[$prefs->getValue('sortby') - 1])) ?
'lastname' : $columns[$prefs->getValue('sortby') - 1];

- /* Create list of lists for Add to. */
+/* Create list of lists for Add to. */
+/* iisjsoo:
+ * this next block is new - it is used so that addresses can be added
+ * to any address books. (e.g. ldap addresses can be added to sql books)
+*/
$addToList = array();
- if (!empty($cfgSources[$source]['map']['__type'])) {
- $listList = $driver->search(array('__type' => 'Group'), null, null, 0);
+ foreach ($sources as $src=>$val) {
+ if (!empty($cfgSources[$src]['map']['__type'])) {
+ $tmp_driver = &Turba_Source::singleton($source, $cfgSources[$src]);
+ $listList = $tmp_driver->search(array('__type' => 'Group'), null, null, 0);
$listList->reset();
while ($listObject = $listList->next()) {
- $addToList[] = array('name' => $listObject->getValue('name'), 'key' => $listObject->getValue('__key'));
+ $addToList[] = array('name' => $listObject->getValue('name'), 'key' => $src."|".$listObject->getValue('__key'));
+ }
}
}

@@ -198,29 +244,44 @@

} else if (Horde::getFormData('key')) {
/* We are displaying the contents of a list */
+ $templates[] = '/browse/header.inc';
+
+ /* iisjsoo:
+ * First we will grab an array using the listMembersArray() function to
+ * give us all users in this list as well as the source they come from.
+ *
+ * Then we will go thru the list and extract the users from their sources
+ * into a Turba_List which will be passed on.
+ *
+ * Note: there could be a performance enhancement here - make only one driver
+ * for each source
+ */
+ require_once TURBA_BASE . '/lib/List.php';
+ $results = &new Turba_List();
+ $listType = 'list';
+
+ $driver = &Turba_Source::singleton(PERSONAL_ADDRESS_BOOK_SOURCE, $cfgSources[PERSONAL_ADDRESS_BOOK_SOURCE]);
$list = $driver->getObject(Horde::getFormData('key'));
- if (isset($list) && is_object($list) && $list->isGroup()) {
- $title = sprintf(_("Addresses in list: %s"), $list->getValue('name'));
- include TURBA_TEMPLATES . '/browse/header.inc';
- /* Show List Members */
- if (!is_object($results = $list->listMembers($sortcolumn, $prefs->getValue('sortdir')))) {
- Horde::raiseMessage(_("Failed to browse list"), HORDE_ERROR);
- include TURBA_BASE . '/status.php';
- } else {
- $listType = "list";
+ $results_array = $list->listMembersArray();
+ if (count($results_array) != 0) {
+ foreach ($results_array as $tmp=>$listMember) {
+ /* iisjsoo:
+ * The $results_array contains entries of the form:
+ * 'localsql'|'38183e5d7ace6910e33eb925f29181c6'
+ * 'localldap'|'uid=asddf,dn=adsf,dn=com'
+ */
+
+ $driver = &Turba_Source::singleton($listMember[0], $cfgSources[$listMember[0]]);
+ $tmp2= $driver->getObject($listMember[1]);
+ $results->insert($tmp2);
+ }
+ }
include TURBA_TEMPLATES . '/browse/actions.inc';
include TURBA_TEMPLATES . '/browse/column_headers.inc';
-
require_once TURBA_BASE . '/lib/ListView.php';
$display = &new Turba_ListView($results, TURBA_TEMPLATES . '/browse/contactrow.inc');
$numDisplayed = $display->display();
-
include TURBA_TEMPLATES . '/browse/column_footers.inc';
- }
- } else {
- Horde::raiseMessage(_("There was an error displaying the select List"), HORDE_ERROR);
- include TURBA_BASE . '/status.php';
- }
} else {
/* We are displaying the contents of the address book */
$title = sprintf(_("Contents of %s"), $cfgSources[$source]['title']);
@@ -256,3 +317,32 @@
require TURBA_TEMPLATES . '/browse/footer.inc';
$registry->shutdown();
require TURBA_TEMPLATES . '/common-footer.inc';
+
+
+/* iisjsoo
+ *
+ * Function written to take an $objectKey of form:
+ *
+ * 'localsql'|'38183e5d7ace6910e33eb925f29181c6'
+ * 'localldap'|'uid=asddf,dn=adsf,dn=com'
+ *
+ * and it returns an array of the two parts:
+ *
+ * Array([0]=>'localsql', [1]=>'38183e5d7ace6910e33eb925f29181c6')
+ * Array([0]=>'localldap', [1]=>'uid=asddf,dn=adsf,dn=com')
+ *
+ * You should probably call it like:
+ * list($objectKeySource, $objectKey) = splitSourceAndKey($objectKey);
+ */
+
+function splitSourceAndKey($objectKey) {
+ if (preg_match("/\|/", $objectKey)) {
+ $objectKeyArr = preg_split('/\|/', $objectKey);
+ $objectKeySource = $objectKeyArr[0];
+ $objectKeyKey = $objectKeyArr[1];
+ return array($objectKeySource, $objectKeyKey);
+ } else {
+ return -1;
+ }
+}
+
diff -burN --exclude='*.dist' --exclude=config --exclude='*.back' --exclude='*.modified' --exclude='*.sql' /home/iisjsoo/turba-1.2/lib/AbstractObject.php ./lib/AbstractObject.php
--- /home/iisjsoo/turba-1.2/lib/AbstractObject.php Sat Nov 2 03:42:00 2002
+++ ./lib/AbstractObject.php Thu Aug 14 16:35:05 2003
@@ -52,6 +52,14 @@
return $this->source->name;
}

+ /* iisjsoo
+ * return the type of source this is (e.g. ldap, sql)
+ */
+ function getSourceType()
+ {
+ return $this->source->driver->type;
+ }
+
/**
* Returns the value of the specified attribute.
*
diff -burN --exclude='*.dist' --exclude=config --exclude='*.back' --exclude='*.modified' --exclude='*.sql' /home/iisjsoo/turba-1.2/lib/Group.php ./lib/Group.php
--- /home/iisjsoo/turba-1.2/lib/Group.php Sat Sep 14 07:13:05 2002
+++ ./lib/Group.php Fri Aug 15 16:17:39 2003
@@ -60,6 +60,36 @@
}
}

+
+ /**
+ * iisjsoo:
+ * new function (wouldn't some OO overloading be good here?)
+ * Adds a new contact entry to this group, also takes in the name of the group
+ * to add it to.
+ *
+ * @param Turba_AbstractObject $object The object to add to the Group
+ *
+ * @since Turba 1.2
+ */
+ function addMemberSource($object, $source)
+ {
+ if ($source == "") {
+ return addMemberSource($object);
+ }
+ // Can't add itself.
+ if ($object->getValue('__key') != $this->attributes['__key']) {
+ $members = @unserialize($this->attributes['__members']);
+ if (!is_array($members)) {
+ $members = array();
+ }
+ $member_entry[] = $object->getSource();
+ $member_entry[] = $object->getValue('__key');
+ $members[] = $member_entry;
+ $this->attributes['__members'] = serialize($members);
+ }
+ }
+
+
/**
* Deletes a contact entry from this group.
*
@@ -81,6 +111,65 @@
return true;
}

+
+ /**
+ * iisjsoo: Deletes a contact entry from this group
+ * Passed the $key and $source
+ * e.g.for ldap:
+ * $key: 'uid=iisjsoo,dn=XX,dn=YY'
+ * $source: 'myldap'
+ *
+ * e.g.for sql:
+ * $key: '765ef989dc9a9d9c5'
+ * $source: 'localsql'
+ *
+ * @param Turba_AbstractObject $object The object to remove from the Group
+ *
+ * @since Turba 1.2
+ */
+ function removeMemberSource($object)
+ {
+ $members = unserialize($this->attributes['__members']);
+ $key = $object->getValue('__key');
+ $source = $object->getSource();
+ $memberToRemove = array($source,$key);
+
+ if(($i = array_search($memberToRemove, $members)) !== false) {
+// print "found and deleting
";
+ unset($members[$i]);
+ } else {
+ print "could not find the member
";
+ }
+
+
+ $this->attributes['__members'] = serialize($members);
+ $this->store();
+ return true;
+ }
+
+
+
+ /** iisjsoo
+ * Function to return a Turba_List of arrays containing the Source of
+ * an entry and the entry's Key (object_id for sql, dn for ldap)
+ * e.g.
+ * list => (array('localsql', '73ebb2f4623ec959e5c6b12608750f57'),
+ * array('localldap', 'uid=itpdfdr,ou=Users,dc=xxx,dc=xxx,dc=com,dc=au'))
+ */
+ function listMembersArray()
+ {
+ $children = unserialize($this->attributes['__members']);
+ if (!is_array($children)) {
+ $children = array();
+ }
+ reset($children);
+ $list = array();
+ foreach ($children as $member) {
+ $list[] = $member;
+ }
+ return $list; //we can't sort this yet, lets work it out later
+ }
+
/**
* Retrieve the Objects in this group
*
diff -burN --exclude='*.dist' --exclude=config --exclude='*.back' --exclude='*.modified' --exclude='*.sql' /home/iisjsoo/turba-1.2/lib/api.php ./lib/api.php
--- /home/iisjsoo/turba-1.2/lib/api.php Mon Feb 10 12:06:55 2003
+++ ./lib/api.php Fri Aug 15 16:31:46 2003
@@ -115,34 +115,27 @@
/* Is a Distribution List */
$listatt = $ob->getAttributes();
$seeninlist = array();
- $members = $ob->listMembers();
- if (get_class($members) == 'turba_list') {
- if ($members->count() == 1) {
- $ob = $members->next();
- $att = $ob->getAttributes();
- $email = '';
- foreach ($att as $key => $value) {
- if (!empty($value) && isset($attributes[$key]) &&
- $attributes[$key]['type'] == 'email') {
- $email = $value;
- }
- }
- $results[$name][] = array('name' => $listatt['name'] . ' - ' . $att['name'], 'email' => $email);
- } else {
+ $members = $ob->listMembersArray();
+
+/* iisjsoo
+ *
+ * i'm not sure how to get around this..
+ * members is no longer a 'turba_list', but an array of arrays...
+ * maybe this should just check the return value of $ob->listMembersArray()
+ */
+ if (get_class($members) == 'turba_list' || 1==1) {
$email = '';
- while ($ob = $members->next()) {
- $att = $ob->getAttributes();
- foreach ($att as $key => $value) {
- if (!empty($value) && isset($attributes[$key]) &&
- $attributes[$key]['type'] == 'email' &&
- empty($seeninlist[trim(strtolower($att['name'])) . trim(strtolower($value))])) {
-
- $email .= ($email == '') ? '' : ', ';
- $email .= '"' . $att['name'] . '" ';
- $seeninlist[trim(strtolower($att['name'])) . trim(strtolower($value))] = true;
- }
- }
+ $members = $ob->listMembersArray();
+
+ foreach($members as $key=>$val){
+ $driver = &Turba_Source::singleton($val[0], $cfgSources[$val[0]]);
+ $listMember= $driver->getObject($val[1]);
+ $emailAddress = '"'.$listMember->getValue('name').
+ '" getValue('email').'>';
+ $email .= $emailAddress .= ',';
}
+ // get rid of trailing ','
+ $email = preg_replace("/,$/","",$email);
$results[$name][] = array('name' => $listatt['name'], 'email' => $email);
}
}
@@ -151,7 +144,6 @@
}
}
}
- }
return $results;
}

diff -burN --exclude='*.dist' --exclude=config --exclude='*.back' --exclude='*.modified' --exclude='*.sql' /home/iisjsoo/turba-1.2/templates/browse/actions.inc ./templates/browse/actions.inc
--- /home/iisjsoo/turba-1.2/templates/browse/actions.inc Wed Mar 5 02:33:37 2003
+++ ./templates/browse/actions.inc Thu Aug 14 17:09:54 2003
@@ -12,7 +12,11 @@ -
+

<input type="button" class="button" onclick="ListUpdate(); Submit(); return false;" value="" />

diff -burN --exclude='*.dist' --exclude=config --exclude='*.back' --exclude='*.modified' --exclude='*.sql' /home/iisjsoo/turba-1.2/templates/browse/contactrow.inc ./templates/browse/contactrow.inc
--- /home/iisjsoo/turba-1.2/templates/browse/contactrow.inc Mon Feb 10 12:35:57 2003
+++ ./templates/browse/contactrow.inc Fri Aug 15 16:12:37 2003
@@ -66,7 +66,10 @@
?>
<tr class="" onmouseover="javascript:style.backgroundColor='';" onmouseout="javascript:style.backgroundColor='';">

- <input type="checkbox" name="objectkeys[]" value="getValue('__key')) ?>" />
+
+ <input type="checkbox" name="objectkeys[]" value="getSource()) . "|" .htmlspecialchars($ob->getValue('__key')) ?>" />
isGroup() ? Horde::img('group.gif', 'alt="' . _("Group") . '"') : '' ?>

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: