1: <?php
2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16:
17: class Turba_Driver_Kolab extends Turba_Driver
18: {
19: 20: 21: 22: 23:
24: protected $_kolab;
25:
26: 27: 28: 29: 30: 31:
32: protected $_connected = false;
33:
34: 35: 36: 37: 38:
39: private $_data;
40:
41: 42: 43: 44: 45:
46: private $_share;
47:
48: 49: 50: 51: 52:
53: protected $_capabilities = array(
54: 'delete_addressbook' => true,
55: 'delete_all' => true,
56: );
57:
58: 59: 60:
61: public function __construct($name = '', $params = array())
62: {
63: if (empty($params['storage'])) {
64: throw new InvalidArgumentException('Missing required storage handler.');
65: }
66: $this->_kolab = $params['storage'];
67: unset($params['storage']);
68:
69: if (isset($params['share'])) {
70: $this->_share = $params['share'];
71: }
72: if (isset($params['name'])) {
73: $name = $params['name'];
74: }
75:
76: parent::__construct($name, $params);
77: }
78:
79: 80: 81: 82: 83:
84: private function _getData()
85: {
86: if ($this->_data === null) {
87: if (!empty($this->_share)) {
88: $this->_data = $this->_kolab->getData(
89: $this->_share->get('folder'),
90: 'contact'
91: );
92: $this->setContactOwner($this->_share->get('owner'));
93: } else if (empty($this->_name)) {
94: throw new Turba_Exception(
95: 'The addressbook has been left undefined but is required!'
96: );
97: } else {
98: $this->_data = $this->_getDataForAddressbook($this->_name);
99: }
100: }
101: return $this->_data;
102: }
103:
104: 105: 106: 107: 108: 109: 110:
111: private function _getDataForAddressbook($addressbook)
112: {
113: $share = $GLOBALS['turba_shares']->getShare($addressbook);
114: $this->setContactOwner($share->get('owner'));
115: return $this->_kolab->getData($share->get('folder'), 'contact');
116: }
117:
118: 119: 120: 121: 122:
123: function connect()
124: {
125:
126: $raw_contacts = $this->_getData()->getObjects();
127: if (!$raw_contacts) {
128: $raw_contacts = array();
129: }
130: $contacts = array();
131: foreach ($raw_contacts as $id => $contact) {
132: if (isset($contact['email'])) {
133: unset($contact['email']);
134: }
135: if (isset($contact['picture'])) {
136: $name = $contact['picture'];
137: if (isset($contact['_attachments'][$name])) {
138: $contact['photo'] = $this->_getData()->getAttachment($contact['_attachments'][$name]['key']);
139: $contact['phototype'] = $contact['_attachments'][$name]['type'];
140: }
141: }
142: if (isset($contact['name'])) {
143: foreach ($contact['name'] as $detail => $value) {
144: $contact[$detail] = $value;
145: }
146: unset($contact['name']);
147: }
148: $contacts[$id] = $contact;
149: }
150:
151:
152: $groups = array();
153:
154:
155:
156:
157:
158:
159:
160:
161: $this->_contacts_cache = array_merge($contacts, $groups);
162: }
163:
164: 165: 166: 167: 168: 169: 170: 171: 172: 173: 174: 175:
176: protected function _search(array $criteria, array $fields,
177: array $blobFields = array(), $count_only = false)
178: {
179: $this->connect();
180:
181: if (!count($criteria)) {
182: return $this->_contacts_cache;
183: }
184:
185:
186: $ids = array();
187: foreach ($criteria as $key => $criteria) {
188: $ids[] = $this->_doSearch($criteria, strval($key), $this->_contacts_cache);
189: }
190: $ids = $this->_removeDuplicated($ids);
191:
192:
193: $this->_read('uid', $ids, null, $fields);
194:
195: Horde::logMessage(sprintf('Kolab returned %s results',
196: count($result)), 'DEBUG');
197:
198: return $count_only ? count($result) : array_values($result);
199: }
200:
201: 202: 203: 204: 205: 206: 207: 208:
209: protected function _doSearch($criteria, $glue, &$entries)
210: {
211: $ids = array();
212:
213: foreach ($criteria as $key => $vals) {
214: if (!empty($vals['OR'])) {
215: $ids[] = $this->_doSearch($vals['OR'], 'OR', $entries);
216: } elseif (!empty($vals['AND'])) {
217: $ids[] = $this->_doSearch($vals['AND'], 'AND', $entries);
218: } else {
219: 220:
221: if (isset($vals['field'])) {
222: $ids[] = $this->_selectEntries($vals, $entries);
223: } else {
224: foreach ($vals as $test) {
225: if (!empty($test['OR'])) {
226: $ids[] = $this->_doSearch($test['OR'], 'OR');
227: } elseif (!empty($test['AND'])) {
228: $ids[] = $this->_doSearch($test['AND'], 'AND');
229: } else {
230: $ids[] = $this->_doSearch(array($test), $glue);
231: }
232: }
233: }
234: }
235: }
236:
237: if ($glue == 'AND') {
238: $ids = $this->_getAND($ids);
239: } elseif ($glue == 'OR') {
240: $ids = $this->_removeDuplicated($ids);
241: }
242:
243: return $ids;
244: }
245:
246: 247: 248: 249: 250: 251: 252: 253:
254: protected function _selectEntries($test, &$entries)
255: {
256: $ids = array();
257:
258: if (!isset($test['field'])) {
259: Horde::logMessage('Search field not set. Returning all entries.', 'DEBUG');
260: foreach ($entries as $entry) {
261: $ids[] = $entry['uid'];
262: }
263: } else {
264: $field = $test['field'];
265: $value = isset($test['test'])
266: ? $test['test']
267: : '';
268:
269:
270: if ($field == 'email') {
271: $field = 'emails';
272: $test['op'] = 'LIKE';
273: $test['begin'] = false;
274: }
275: if (!isset($test['op']) || $test['op'] == '=') {
276: foreach ($entries as $entry) {
277: if (isset($entry[$field]) && $entry[$field] == $value) {
278: $ids[] = $entry['uid'];
279: }
280: }
281: } else {
282:
283: foreach ($entries as $entry) {
284: if (empty($value) ||
285: (isset($entry[$field]) &&
286: !empty($test['begin']) &&
287: (($pos = stripos($entry[$field], $value)) !== false) &&
288: ($pos == 0))) {
289: $ids[] = $entry['uid'];
290: }
291: }
292: }
293: }
294:
295: return $ids;
296: }
297:
298: 299: 300: 301: 302: 303: 304:
305: protected function _getAND($ids)
306: {
307: $matched = $results = array();
308:
309:
310: if (count($ids) < 2) {
311: return $ids[0];
312: }
313:
314: for ($i = 0; $i < count($ids); ++$i) {
315: if (is_array($ids[$i])) {
316: $results = array_merge($results, $ids[$i]);
317: }
318: }
319:
320: $search = array_count_values($results);
321: foreach ($search as $key => $value) {
322: if ($value == count($ids)) {
323: $matched[] = $key;
324: }
325: }
326:
327: return $matched;
328: }
329:
330: 331: 332: 333: 334: 335: 336:
337: protected function _removeDuplicated($ids)
338: {
339: for ($i = 0; $i < count($ids); ++$i) {
340: if (is_array($ids[$i])) {
341: $unames = array_merge($unames, $ids[$i]);
342: }
343: }
344:
345: return array_unique($unames);
346: }
347:
348: 349: 350: 351: 352: 353: 354: 355: 356: 357: 358: 359:
360: protected function _read($key, $ids, $owner, array $fields,
361: array $blobFields = array())
362: {
363: $this->connect();
364:
365: $results = array();
366:
367: if (!is_array($ids)) {
368: $ids = array($ids);
369: }
370:
371: $count = count($fields);
372: foreach ($ids as $id) {
373: if (in_array($id, array_keys($this->_contacts_cache))) {
374: $object = $this->_contacts_cache[$id];
375:
376: if (!isset($object['__type']) || $object['__type'] == 'Object') {
377: if ($count) {
378: $result = array();
379: foreach ($fields as $field) {
380: if (isset($object[$field])) {
381: $result[$field] = $object[$field];
382: }
383: }
384: $results[] = $result;
385: } else {
386: $results[] = $object;
387: }
388: } else {
389: $member_ids = array();
390: if (isset($object['member'])) {
391: foreach ($object['member'] as $member) {
392: if (isset($member['uid'])) {
393: $member_ids[] = $member['uid'];
394: continue;
395: }
396: $display_name = $member['display-name'];
397: $smtp_address = $member['smtp-address'];
398: $criteria = array(
399: 'AND' => array(
400: array(
401: 'field' => 'full-name',
402: 'op' => 'LIKE',
403: 'test' => $display_name,
404: 'begin' => false,
405: ),
406: array(
407: 'field' => 'emails',
408: 'op' => 'LIKE',
409: 'test' => $smtp_address,
410: 'begin' => false,
411: ),
412: ),
413: );
414: $fields = array('uid');
415:
416:
417: $contacts = $this->_search($criteria, $fields);
418:
419:
420: $member_ids[] = $contacts[0]['uid'];
421: }
422: $object['__members'] = serialize($member_ids);
423: unset($object['member']);
424: }
425: $results[] = $object;;
426: }
427: }
428: }
429:
430: return $results;
431: }
432:
433: 434: 435: 436: 437: 438: 439: 440:
441: protected function _add(array $attributes, array $blob_fields = array())
442: {
443: $this->connect();
444:
445: if (isset($attributes['last-name'])) {
446: $attributes['full-name'] = $attributes['last-name'];
447: }
448: if (isset($attributes['middle-names'])) {
449: $attributes['full-name'] = $attributes['middle-names'] . ' ' . $attributes['full-name'];
450: }
451: if (isset($attributes['given-name'])) {
452: $attributes['full-name'] = $attributes['given-name'] . ' ' . $attributes['full-name'];
453: }
454:
455: $attributes['name'] = array(
456: 'last-name' => $attributes['last-name'],
457: );
458:
459: $this->_store($attributes);
460: }
461:
462: protected function _canAdd()
463: {
464: return true;
465: }
466:
467: 468: 469:
470: protected function _delete($object_key, $object_id)
471: {
472: $this->connect();
473:
474: if ($object_key != 'uid') {
475: throw new Turba_Exception(sprintf('Key for saving must be a UID not %s!', $object_key));
476: }
477:
478: if (!in_array($object_id, array_keys($this->_contacts_cache))) {
479: throw new Turba_Exception(sprintf(_("Object with UID %s does not exist!"), $object_id));
480: }
481:
482: $group = (isset($this->_contacts_cache[$object_id]['__type']) &&
483: $this->_contacts_cache[$object_id]['__type'] == 'Group');
484:
485: if ($group) {
486:
487:
488: }
489:
490: $result = $this->_getData()->delete($object_id);
491:
492: return $result;
493: }
494:
495: 496: 497: 498: 499:
500: protected function _deleteAll($sourceName = null)
501: {
502: $this->connect();
503:
504:
505: $result = $this->_getData()->deleteAll();
506:
507:
508:
509:
510:
511: }
512:
513: 514: 515: 516: 517: 518: 519: 520:
521: protected function _save(Turba_Object $object)
522: {
523: $this->connect();
524:
525: if ($object_key != 'uid') {
526: throw new Turba_Exception(sprintf('Key for saving must be \'uid\' not %s!', $object_key));
527: }
528:
529: return $this->_store($attributes, $object_id);
530: }
531:
532: 533: 534: 535: 536: 537: 538: 539:
540: protected function _store($attributes, $object_id = null)
541: {
542: $group = false;
543: if (isset($attributes['__type']) && $attributes['__type'] == 'Group') {
544: return;
545:
546:
547:
548:
549: }
550:
551: if (isset($attributes['photo']) && isset($attributes['phototype'])) {
552: $attributes['_attachments']['photo.attachment'] = array(
553: 'type' => $attributes['phototype'],
554: 'content' => $attributes['photo']
555: );
556: $attributes['picture'] = 'photo.attachment';
557: unset($attributes['photo'], $attributes['phototype']);
558: }
559:
560: if ($object_id === null) {
561: $result = $this->_getData()->create($attributes);
562: } else {
563: $result = $this->_getData()->modify($attributes);
564: }
565: if ($group) {
566: $result = $this->_store->setObjectType('contact');
567: }
568:
569: return $object_id;
570: }
571:
572: 573: 574:
575: function _convertMembers(&$attributes)
576: {
577: if (isset($attributes['__members'])) {
578: $member_ids = unserialize($attributes['__members']);
579: $attributes['member'] = array();
580: foreach ($member_ids as $member_id) {
581: if (isset($this->_contacts_cache[$member_id])) {
582: $member = $this->_contacts_cache[$member_id];
583: $mail = array('uid' => $member_id);
584: if (!empty($member['full-name'])) {
585: $mail['display-name'] = $member['full-name'];
586: }
587: if (!empty($member['emails'])) {
588: $emails = explode(',', $member['emails']);
589: $mail['smtp-address'] = trim($emails[0]);
590: if (!isset($mail['display-name'])) {
591: $mail['display-name'] = $mail['smtp-address'];
592: }
593: }
594: $attributes['member'][] = $mail;
595: }
596: }
597: unset($attributes['__members']);
598: }
599: }
600:
601:
602: 603: 604: 605: 606: 607: 608: 609:
610: protected function _makeKey(array $attributes)
611: {
612: return isset($attributes['uid'])
613: ? $attributes['uid']
614: : $this->_generateUid();
615: }
616:
617: 618: 619: 620: 621:
622: protected function _makeUid()
623: {
624: return $this->_generateUid();
625: }
626:
627: 628: 629: 630: 631:
632: private function _generateUid()
633: {
634: return $this->_getData()->generateUID();
635: }
636:
637: 638: 639: 640: 641: 642: 643: 644:
645: public function createShare($share_name, array $params)
646: {
647: if (!isset($params['name'])) {
648: $params['name'] = _('Contacts');
649: }
650: return Turba::createShare($share_name, $params);
651: }
652:
653: 654: 655: 656: 657: 658: 659: 660:
661: public function checkDefaultShare(Horde_Share_Object $share, array $srcconfig)
662: {
663: $params = @unserialize($share->get('params'));
664: return isset($params['default'])
665: ? $params['default']
666: : false;
667: }
668: }
669: