1: <?php
2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14:
15: class Turba_Driver_Imsp extends Turba_Driver
16: {
17: 18: 19: 20: 21:
22: protected $_imsp;
23:
24: 25: 26: 27: 28:
29: protected $_bookName = '';
30:
31: 32: 33: 34: 35:
36: protected $_authenticated = '';
37:
38: 39: 40: 41: 42:
43: protected $_groupField = '';
44:
45: 46: 47: 48: 49:
50: protected $_groupValue = '';
51:
52: 53: 54: 55: 56:
57: protected $_noGroups = '';
58:
59: 60: 61: 62: 63:
64: protected $_capabilities = array(
65: 'delete_all' => true,
66: 'delete_addressbook' => true
67: );
68:
69: 70: 71: 72: 73: 74:
75: public function __construct($name = '', $params)
76: {
77: global $conf;
78: parent::__construct($name, $params);
79:
80: $this->params = $params;
81: $this->_groupField = $params['group_id_field'];
82: $this->_groupValue = $params['group_id_value'];
83: $this->_myRights = $params['my_rights'];
84: $this->_perms = $this->_aclToHordePerms($params['my_rights']);
85: $this->_bookName = $this->getContactOwner();
86:
87: try {
88: $this->_imsp = $GLOBALS['injector']
89: ->getInstance('Horde_Core_Factory_Imsp')
90: ->create('Book', $this->params);
91: } catch (Horde_Exception $e) {
92: $this->_authenticated = false;
93: throw new Turba_Exception($e);
94: }
95: $this->_authenticated = true;
96: }
97:
98: 99: 100: 101: 102: 103: 104: 105:
106: protected function _search(array $criteria, array $fields, array $blobFields = array(), $count_only)
107: {
108: $query = $results = array();
109:
110: if (!$this->_authenticated) {
111: return $query;
112: }
113:
114:
115: if (count($criteria)) {
116: foreach ($criteria as $key => $vals) {
117: $names = (strval($key) == 'OR')
118: ? $this->_doSearch($vals, 'OR')
119: : $this->_doSearch($vals, 'AND');
120: }
121: }
122:
123:
124: $result = $this->_read('name', $names, null, $fields);
125: if (is_array($result)) {
126: $results = $result;
127: }
128:
129: Horde::logMessage(sprintf('IMSP returned %s results', count($results)), 'DEBUG');
130:
131: return $count_only ? count($results) : array_values($results);
132: }
133:
134: 135: 136: 137: 138: 139: 140: 141: 142: 143: 144: 145: 146:
147: protected function _read($key, $ids, $owner, array $fields,
148: array $blobFields = array())
149: {
150: $results = array();
151:
152: if (!$this->_authenticated) {
153: return $results;
154: }
155:
156: $ids = array_values($ids);
157: $idCount = count($ids);
158: $IMSPGroups = $members = $tmembers = array();
159:
160: for ($i = 0; $i < $idCount; ++$i) {
161: $result = array();
162:
163: try {
164: $temp = isset($IMSPGroups[$ids[$i]])
165: ? $IMSPGroups[$ids[$i]]
166: : $this->_imsp->getEntry($this->_bookName, $ids[$i]);
167: } catch (Horde_Imsp_Exception $e) {
168: continue;
169: }
170:
171: $temp['fullname'] = $temp['name'];
172: $isIMSPGroup = false;
173: if (!isset($temp['__owner'])) {
174: $temp['__owner'] = $GLOBALS['registry']->getAuth();
175: }
176:
177: if ((isset($temp[$this->_groupField])) &&
178: ($temp[$this->_groupField] == $this->_groupValue)) {
179: if ($this->_noGroups) {
180: continue;
181: }
182: if (!isset($IMSPGroups[$ids[$i]])) {
183: $IMSPGroups[$ids[$i]] = $temp;
184: }
185:
186: if ($idCount > count($IMSPGroups) &&
187: $idCount - count($IMSPGroups) > $i) {
188: $ids[] = $ids[$i];
189: unset($ids[$i]);
190: $ids = array_values($ids);
191: --$i;
192: continue;
193: }
194: $isIMSPGroup = true;
195: }
196:
197:
198:
199: if ($isIMSPGroup &&
200: array_search('__members', $fields) !== false) {
201: if (isset($temp['email'])) {
202: $emailList = $this->_getGroupEmails($temp['email']);
203: $count = count($emailList);
204: for ($j = 0; $j < $count; ++$j) {
205: $needMember = true;
206: foreach ($results as $curResult) {
207: if (!empty($curResult['email']) &&
208: strtolower($emailList[$j]) == strtolower(trim($curResult['email']))) {
209: $members[] = $curResult['name'];
210: $needMember = false;
211: }
212: }
213: if ($needMember) {
214: $memberName = $this->_imsp->search
215: ($this->_bookName,
216: array('email' => trim($emailList[$j])));
217:
218: if (count($memberName)) {
219: $members[] = $memberName[0];
220: }
221: }
222: }
223: }
224: if (!empty($temp['__members'])) {
225: $tmembers = @unserialize($temp['__members']);
226: }
227:
228:
229:
230:
231:
232:
233:
234:
235: $temp['__members'] = serialize($this->_removeDuplicated(
236: array($members, $tmembers)));
237: $temp['__type'] = 'Group';
238: $temp['email'] = null;
239: $result = $temp;
240: } else {
241:
242: $count = count($fields);
243: for ($j = 0; $j < $count; ++$j) {
244: if (isset($temp[$fields[$j]])) {
245: $result[$fields[$j]] = $temp[$fields[$j]];
246: }
247: }
248: }
249:
250: $results[] = $result;
251: }
252:
253: return $results;
254: }
255:
256: 257: 258: 259: 260: 261: 262: 263:
264: protected function _add(array $attributes, array $blob_fields = array())
265: {
266: 267: 268:
269: if ($attributes['__type'] == 'Group') {
270:
271: $attributes[$this->_groupField] = $this->_groupValue;
272: if (!isset($attributes['__members'])) {
273: $attributes['__members'] = '';
274: $attributes['email'] = ' ';
275: }
276: $temp = unserialize($attributes['__members']);
277: if (is_array($temp)) {
278: $members = array_values($temp);
279: } else {
280: $members = array();
281: }
282:
283:
284:
285:
286:
287:
288:
289: try {
290: $result = $this->_read('name', $members, null, array('email'));
291: $count = count($result);
292: for ($i = 0; $i < $count; ++$i) {
293: if (isset($result[$i]['email'])) {
294: $contact = sprintf("%s<%s>\n", $members[$i],
295: $result[$i]['email']);
296: $attributes['email'] .= $contact;
297: }
298: }
299: } catch (Turba_Exception $e) {}
300: }
301:
302: unset($attributes['__type'], $attributes['fullname']);
303: if (!$this->params['contact_ownership']) {
304: unset($attributes['__owner']);
305: }
306:
307: return $this->_imsp->addEntry($this->_bookName, $attributes);
308: }
309:
310: 311: 312:
313: protected function _canAdd()
314: {
315: return true;
316: }
317:
318: 319: 320: 321: 322:
323: protected function _delete($object_key, $object_id)
324: {
325: try {
326: $this->_imsp->deleteEntry($this->_bookName, $object_id);
327: } catch (Horde_Imsp_Exception $e) {
328: throw new Turba_Exception($e);
329: }
330: }
331:
332: 333: 334: 335: 336:
337: protected function _deleteAll()
338: {
339: try {
340: $this->_imsp->deleteAddressbook($this->_bookName);
341: } catch (Horde_Imsp_Exception $e) {
342: throw new Turba_Exception($e);
343: }
344: }
345:
346: 347: 348: 349: 350: 351: 352: 353:
354: protected function _save($object)
355: {
356: list($object_key, $object_id) = each($this->toDriverKeys(array('__key' => $object->getValue('__key'))));
357: $attributes = $this->toDriverKeys($object->getAttributes());
358:
359: 360:
361: if ($attributes['name'] != $this->_makeKey($attributes)) {
362: $this->_delete($object_key, $attributes['name']);
363: $attributes['name'] = $this->_makeKey($attributes);
364: $object_id = $attributes['name'];
365: }
366:
367: $this->_add($attributes);
368:
369: return $object_id;
370: }
371:
372: 373: 374: 375: 376: 377: 378: 379:
380: protected function _makeKey($attributes)
381: {
382: return $attributes['fullname'];
383: }
384:
385: 386: 387: 388: 389: 390: 391: 392:
393: protected function _getGroupEmails($emailText)
394: {
395: preg_match_all("(\w[-._\w]*\w@\w[-._\w]*\w\.\w{2,3})", $emailText, $matches);
396: return $matches[0];
397: }
398:
399: 400: 401: 402: 403: 404: 405: 406: 407:
408: protected function _doSearch($criteria, $glue)
409: {
410: $results = array();
411: $names = array();
412: foreach ($criteria as $key => $vals) {
413: if (!empty($vals['OR'])) {
414: $results[] = $this->_doSearch($vals['OR'], 'OR');
415: } elseif (!empty($vals['AND'])) {
416: $results[] = $this->_doSearch($vals['AND'], 'AND');
417: } else {
418: 419:
420: if (isset($vals['field'])) {
421: $results[] = $this->_sendSearch($vals);
422: } else {
423: foreach ($vals as $test) {
424: if (!empty($test['OR'])) {
425: $results[] = $this->_doSearch($test['OR'], 'OR');
426: } elseif (!empty($test['AND'])) {
427: $results[] = $this->_doSearch($test['AND'], 'AND');
428: } else {
429: $results[] = $this->_doSearch(array($test), $glue);
430: }
431: }
432: }
433: }
434: }
435:
436: return ($glue == 'AND')
437: ? $this->_getDuplicated($results)
438: : $this->_removeDuplicated($results);
439: }
440:
441: 442: 443: 444: 445: 446: 447:
448: function _sendSearch($criteria)
449: {
450: global $conf;
451:
452: $names = '';
453: $imspSearch = array();
454: $searchkey = $criteria['field'];
455: $searchval = $criteria['test'];
456: $searchop = $criteria['op'];
457: $hasName = false;
458: $this->_noGroups = false;
459: $cache = $GLOBALS['injector']->getInstance('Horde_Cache');
460: $key = implode(".", array_merge($criteria, array($this->_bookName)));
461:
462: 463:
464: switch ($searchkey) {
465: case 'fullname':
466: if (!$hasName) {
467: $searchkey = 'name';
468: $hasName = true;
469: } else {
470: $searchkey = '';
471: }
472: break;
473:
474: case '__owner':
475: if (!$this->params['contact_ownership']) {
476: $searchkey = '';
477: $hasName = true;
478: }
479: break;
480: }
481:
482: 483: 484:
485: if ($searchkey == '__type') {
486: switch ($searchval) {
487: case 'Group':
488: $searchkey = $this->_groupField;
489: $searchval = $this->_groupValue;
490: break;
491:
492: case 'Object':
493: if (!$hasName) {
494: $searchkey = 'name';
495: $searchval = '';
496: $hasName = true;
497: } else {
498: $searchkey = '';
499: }
500: $this->_noGroups = true;
501: break;
502: }
503: }
504:
505: if (!$searchkey == '') {
506:
507: if (strlen($searchval) > 0) {
508: if ($searchop == 'LIKE') {
509: $searchval = '*' . $searchval . '*';
510: }
511: } else {
512: $searchval = '*';
513: }
514: $imspSearch[$searchkey] = $searchval;
515: }
516: if (!count($imspSearch)) {
517: $imspSearch['name'] = '*';
518: }
519:
520: 521: 522: 523: 524:
525: $results = $cache->get($key, 15);
526:
527: if ($results) {
528: $names = unserialize($results);
529: }
530:
531: if (!$names) {
532: try {
533: $names = $this->_imsp->search($this->_bookName, $imspSearch);
534: $cache->set($key, serialize($names));
535: return $names;
536: } catch (Horde_Imsp_Exception $e) {
537: $GLOBALS['notification']->push($names, 'horde.error');
538: }
539: } else {
540: return $names;
541: }
542: }
543:
544: 545: 546: 547: 548: 549: 550:
551: protected function _getDuplicated($names)
552: {
553: $matched = $results = array();
554:
555:
556: if (count($names) < 2) {
557: return $names[0];
558: }
559:
560: for ($i = 0; $i < count($names); ++$i) {
561: if (is_array($names[$i])) {
562: $results = array_merge($results, $names[$i]);
563: }
564: }
565:
566: $search = array_count_values($results);
567: foreach ($search as $key => $value) {
568: if ($value > 1) {
569: $matched[] = $key;
570: }
571: }
572:
573: return $matched;
574: }
575:
576: 577: 578: 579: 580: 581: 582:
583: protected function _removeDuplicated($names)
584: {
585: $unames = array();
586: for ($i = 0; $i < count($names); ++$i) {
587: if (is_array($names[$i])) {
588: $unames = array_merge($unames, $names[$i]);
589: }
590: }
591:
592: return array_unique($unames);
593: }
594:
595: 596: 597: 598: 599: 600: 601: 602:
603: public function hasPermission($perm)
604: {
605: return $this->_perms & $perm;
606: }
607:
608: 609: 610: 611: 612: 613: 614:
615: protected function _aclToHordePerms($acl)
616: {
617: $hPerms = 0;
618:
619: if (strpos($acl, 'w') !== false) {
620: $hPerms |= Horde_Perms::EDIT;
621: }
622: if (strpos($acl, 'r') !== false) {
623: $hPerms |= Horde_Perms::READ;
624: }
625: if (strpos($acl, 'd') !== false) {
626: $hPerms |= Horde_Perms::DELETE;
627: }
628: if (strpos($acl, 'l') !== false) {
629: $hPerms |= Horde_Perms::SHOW;
630: }
631:
632: return $hPerms;
633: }
634:
635: 636: 637: 638: 639: 640: 641: 642: 643:
644: public function createShare($share_id, $params)
645: {
646: $params['params']['name'] = $this->params['username'];
647: if (!isset($params['default']) || $params['default'] !== true) {
648: $params['params']['name'] .= '.' . $params['name'];
649: }
650:
651: $result = Turba::createShare($share_id, $params);
652: try {
653: $imsp_result = Horde_Core_Imsp_Utils::createBook($GLOBALS['cfgSources']['imsp'], $params['params']['name']);
654: } catch (Horde_Imsp_Exception $e) {
655: throw new Turba_Exception($e);
656: }
657:
658: return $result;
659: }
660:
661: 662: 663: 664: 665: 666: 667: 668:
669: protected function _countDelimiters($in)
670: {
671: $cnt = $pos = 0;
672: $i = -1;
673: while (($pos = strpos($in, ':', $pos + 1)) !== false) {
674: ++$cnt;
675: }
676:
677: return $cnt;
678: }
679:
680: 681: 682: 683: 684: 685:
686: protected function _getContactOwner()
687: {
688: return $this->params['name'];
689: }
690:
691: 692: 693: 694: 695: 696: 697:
698: public function checkDefaultShare($share, $srcConfig)
699: {
700: $params = @unserialize($share->get('params'));
701: if (!isset($params['default'])) {
702: $params['default'] = ($params['name'] == $srcConfig['params']['username']);
703: $share->set('params', serialize($params));
704: $share->save();
705: }
706:
707: return $params['default'];
708: }
709:
710: }
711: