1: <?php
2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17:
18: class Turba_Api extends Horde_Registry_Api
19: {
20: 21: 22: 23: 24:
25: public $links = array(
26: 'show' => '%application%/contact.php?source=|source|&key=|key|&uid=|uid|'
27: );
28:
29: 30: 31: 32: 33:
34: public $noPerms = array(
35: 'getClientSource', 'getClient', 'getClients', 'searchClients'
36: );
37:
38: 39: 40: 41: 42: 43: 44:
45: public function ($id)
46: {
47: if (!$GLOBALS['conf']['comments']['allow']) {
48: return false;
49: }
50:
51: @list($source, $key) = explode('.', $id, 2);
52: if (isset($GLOBALS['cfgSources'][$source]) && $key) {
53: try {
54: return $GLOBALS['injector']->getInstance('Turba_Factory_Driver')->create($source)->getObject($key)->getValue('name');
55: } catch (Turba_Exception $e) {}
56: }
57:
58: return false;
59: }
60:
61: 62: 63: 64: 65:
66: public function ()
67: {
68: return $GLOBALS['conf']['comments']['allow'];
69: }
70:
71: 72: 73: 74: 75: 76: 77:
78: public function sources($writeable = false)
79: {
80: $addressbooks = Turba::getAddressBooks($writeable ? Horde_Perms::EDIT : Horde_Perms::READ);
81: foreach ($addressbooks as $addressbook => $config) {
82: $addressbooks[$addressbook] = $config['title'];
83: }
84:
85: return $addressbooks;
86: }
87:
88: 89: 90: 91: 92: 93: 94: 95:
96: public function fields($source = null)
97: {
98: global $cfgSources, $attributes;
99:
100: if (empty($source) || !isset($cfgSources[$source])) {
101: throw new Turba_Exception(sprintf(_("Invalid address book: %s"), $source));
102: }
103:
104: $fields = array();
105: foreach ($cfgSources[$source]['map'] as $field_name => $null) {
106: if (substr($field_name, 0, 2) != '__') {
107: $fields[$field_name] = array('name' => $field_name,
108: 'type' => $attributes[$field_name]['type'],
109: 'label' => $attributes[$field_name]['label'],
110: 'search' => in_array($field_name, $cfgSources[$source]['search']));
111: }
112: }
113:
114: return $fields;
115: }
116:
117: 118: 119:
120: public function getDefaultShare()
121: {
122: global $prefs, $session;
123:
124:
125: $cfgSources = Turba::availableSources();
126:
127: if ($session->get('turba', 'has_share')) {
128: $shares = Turba::listShares(true);
129: foreach ($shares as $uid => $share) {
130: $params = @unserialize($share->get('params'));
131: if (empty($params['source'])) {
132: continue;
133: }
134:
135: try {
136: $driver = $GLOBALS['injector']->getInstance('Turba_Factory_Driver')->create($uid);
137: if ($driver->checkDefaultShare($share, $cfgSources[$params['source']])) {
138: return $uid;
139: }
140: } catch (Turba_Exception $e) {}
141: }
142: }
143:
144:
145: return $prefs->getValue('default_dir');
146: }
147:
148: 149: 150: 151: 152: 153:
154: public function getGalUid()
155: {
156: if (!empty($GLOBALS['conf']['gal']['addressbook'])) {
157: return $GLOBALS['conf']['gal']['addressbook'];
158: }
159:
160: return false;
161: }
162:
163: private function _modified($uid)
164: {
165: $modified = $this->getActionTimestamp($uid, 'modify');
166: if (empty($modified)) {
167: $modified = $this->getActionTimestamp($uid, 'add');
168: }
169: return $modified;
170: }
171:
172: 173: 174: 175: 176: 177: 178: 179: 180: 181:
182: public function browse($path = '', $properties = array())
183: {
184: global $registry, $session, $cfgSources;
185:
186:
187: if (!$properties) {
188: $properties = array('name', 'icon', 'browseable');
189: }
190:
191:
192: if (substr($path, 0, 5) == 'turba') {
193: $path = substr($path, 5);
194: }
195: $path = trim($path, '/');
196: $parts = explode('/', $path);
197:
198: $now = time();
199: $results = array();
200: if (empty($path)) {
201:
202:
203:
204: $results = array();
205: $shares = Turba::listShares();
206: $owners = array('global' => true);
207: foreach ($shares as $share) {
208: $owners[$share->get('owner') ? $share->get('owner') : '-system-'] = true;
209: }
210:
211: foreach (array_keys($owners) as $owner) {
212: if (in_array('name', $properties)) {
213: $results['turba/' . $owner]['name'] = $owner;
214: }
215: if (in_array('icon', $properties)) {
216: $results['turba/' . $owner]['icon'] = Horde_Themes::img('turba.png');
217: }
218: if (in_array('browseable', $properties)) {
219: $results['turba/' . $owner]['browseable'] = true;
220: }
221: if (in_array('contenttype', $properties)) {
222: $results['turba/' . $owner]['contenttype'] = 'httpd/unix-directory';
223: }
224: if (in_array('contentlength', $properties)) {
225: $results['turba/' . $owner]['contentlength'] = 0;
226: }
227: if (in_array('modified', $properties)) {
228:
229: $results['turba/' . $owner]['modified'] = $now;
230: }
231: if (in_array('created', $properties)) {
232:
233: $results['turba/' . $owner]['created'] = 0;
234: }
235: }
236: return $results;
237: } elseif (count($parts) == 1) {
238:
239:
240:
241:
242: if (empty($parts[0])) {
243:
244: return array();
245: }
246:
247: if ($parts[0] == 'global') {
248:
249: $addressbooks = Turba::getAddressBooks();
250: foreach ($addressbooks as $addressbook => $info) {
251: if ($info['type'] == 'share') {
252:
253: unset($addressbooks[$addressbook]);
254: }
255: }
256: } else {
257:
258:
259: if (!$session->get('turba', 'has_share')) {
260:
261: return array();
262: }
263: $addressbooks = $GLOBALS['turba_shares']->listShares(
264: $parts[0],
265: array('perm' => Horde_Perms::READ,
266: 'attributes' => $parts[0]));
267:
268:
269:
270:
271: $addressbooks = Turba::permissionsFilter($addressbooks);
272: }
273:
274: $curpath = 'turba/' . $parts[0] . '/';
275: foreach ($addressbooks as $addressbook => $info) {
276: if (in_array('name', $properties)) {
277: if ($info instanceof Horde_Share_Object) {
278: $name = $info->get('title');
279: } else {
280: $name = $info['title'];
281: }
282: $results[$curpath . $addressbook]['name'] = $name;
283: }
284: if (in_array('icon', $properties)) {
285: $results[$curpath . $addressbook]['icon'] = Horde_Themes::img('turba.png');
286: }
287: if (in_array('browseable', $properties)) {
288: $results[$curpath . $addressbook]['browseable'] = true;
289: }
290: if (in_array('contenttype', $properties)) {
291: $results[$curpath . $addressbook]['contenttype'] = 'httpd/unix-directory';
292: }
293: if (in_array('contentlength', $properties)) {
294: $results[$curpath . $addressbook]['contentlength'] = 0;
295: }
296: if (in_array('modified', $properties)) {
297:
298: $results[$curpath . $addressbook]['modified'] = $now;
299: }
300: if (in_array('created', $properties)) {
301:
302: $results[$curpath . $addressbook]['created'] = 0;
303: }
304: }
305: return $results;
306:
307: } elseif (count($parts) == 2) {
308:
309:
310:
311: if (empty($parts[0]) || empty($parts[1])) {
312:
313:
314: return array();
315: }
316:
317: $addressbooks = Turba::getAddressBooks();
318: if (!isset($addressbooks[$parts[1]])) {
319:
320: return array();
321: }
322:
323:
324: $driver = $GLOBALS['injector']->getInstance('Turba_Factory_Driver')->create($parts[1]);
325:
326: $contacts = $driver->search(array());
327:
328: $contacts->reset();
329: $curpath = 'turba/' . $parts[0] . '/' . $parts[1] . '/';
330: while ($contact = $contacts->next()) {
331: $key = $curpath . $contact->getValue('__key');
332: if (in_array('name', $properties)) {
333: $results[$key]['name'] = Turba::formatName($contact);
334: }
335: if (in_array('icon', $properties)) {
336: $results[$key]['icon'] = Horde_Themes::img('mime/vcard.png');
337: }
338: if (in_array('browseable', $properties)) {
339: $results[$key]['browseable'] = false;
340: }
341: if (in_array('contenttype', $properties)) {
342: $results[$key]['contenttype'] = 'text/x-vcard';
343: }
344: if (in_array('contentlength', $properties)) {
345: try {
346: $data = $this->export($contact->getValue('__uid'), 'text/x-vcard', $contact->getSource());
347: } catch (Turba_Exception $e) {
348: $data = '';
349: }
350: $results[$key]['contentlength'] = strlen($data);
351: }
352: if (in_array('modified', $properties)) {
353: $results[$key]['modified'] = $this->_modified($contact->getValue('__uid'));
354: }
355: if (in_array('created', $properties)) {
356: $results[$key]['created'] = $this->getActionTimestamp($contact->getValue('__uid'), 'add');
357: }
358: }
359:
360: return $results;
361:
362: } elseif (count($parts) == 3) {
363:
364:
365:
366: $addressbooks = Turba::getAddressBooks();
367: if (!isset($addressbooks[$parts[1]])) {
368:
369: return array();
370: }
371:
372:
373: $driver = $GLOBALS['injector']->getInstance('Turba_Factory_Driver')->create($parts[1]);
374:
375: $contact = $driver->getObject($parts[2]);
376:
377: $result = array('data' => $this->export($contact->getValue('__uid'), 'text/x-vcard', $contact->getSource()),
378: 'mimetype' => 'text/x-vcard');
379: $modified = $this->_modified($contact->getValue('__uid'));
380: if (!empty($modified)) {
381: $result['mtime'] = $modified;
382: }
383: return $result;
384: } else {
385: throw new Turba_Exception(_("Malformed request."));
386: }
387: }
388:
389: 390: 391: 392: 393: 394: 395: 396:
397: public function path_delete($path)
398: {
399: global $registry, $cfgSources;
400:
401:
402: if (substr($path, 0, 5) == 'turba') {
403: $path = substr($path, 5);
404: }
405: $path = trim($path, '/');
406: $parts = explode('/', $path);
407:
408: $now = time();
409: $results = array();
410:
411: if (count($parts) < 3) {
412:
413: throw new Turba_Exception(_("Delete denied."));
414: }
415: if (!array_key_exists($parts[1], Turba::getAddressBooks())) {
416: throw new Turba_Exception("Address book does not exist");
417: }
418:
419:
420: $driver = $GLOBALS['injector']->getInstance('Turba_Factory_Driver')->create($parts[1]);
421:
422: return $driver->delete($parts[2]);
423: }
424:
425: 426: 427: 428: 429: 430: 431: 432: 433: 434: 435: 436:
437: public function listUids($sources = null)
438: {
439: global $cfgSources, $prefs;
440:
441:
442: if (empty($sources)) {
443: $sources = @unserialize($prefs->getValue('sync_books'));
444: } elseif (!is_array($sources)) {
445: $sources = array($sources);
446: }
447: if (empty($sources)) {
448: $sources = array(Turba::getDefaultAddressbook());
449: }
450: if (empty($sources)) {
451: throw new Turba_Exception(_("No address book specified"));
452: }
453:
454: $uids = array();
455: foreach ($sources as $source) {
456: if (empty($source) || !isset($cfgSources[$source])) {
457: throw new Turba_Exception(sprintf(_("Invalid address book: %s"), $source));
458: }
459:
460: $storage = $GLOBALS['injector']->getInstance('Turba_Factory_Driver')->create($source);
461:
462: try {
463: $results = $storage->search(array());
464: } catch (Turba_Exception $e) {
465: throw new Turba_Exception(sprintf(_("Error searching the address book: %s"), $e->getMessage()));
466: }
467:
468: foreach ($results->objects as $o) {
469: if (!$o->isGroup()) {
470: $uids[] = $o->getValue('__uid');
471: }
472: }
473: }
474:
475: return $uids;
476: }
477:
478: 479: 480: 481: 482: 483: 484: 485: 486: 487: 488: 489: 490: 491: 492: 493:
494: public function listBy($action, $timestamp, $sources = null, $end = null)
495: {
496: global $prefs, $cfgSources;
497:
498:
499: if (empty($sources)) {
500: $sources = @unserialize($prefs->getValue('sync_books'));
501: } elseif (!is_array($sources)) {
502: $sources = array($sources);
503: }
504: if (empty($sources)) {
505: $sources = array(Turba::getDefaultAddressbook());
506: }
507:
508: if (empty($sources)) {
509: throw new Turba_Exception(_("No address book specified"));
510: }
511:
512: $uids = array();
513: $history = $GLOBALS['injector']->getInstance('Horde_History');
514: $filter = array(array('op' => '=', 'field' => 'action', 'value' => $action));
515: if (!empty($end)) {
516: $filter[] = array('op' => '<', 'field' => 'ts', 'value' => $end);
517: }
518:
519: foreach ($sources as $source) {
520: if (empty($source) || !isset($cfgSources[$source])) {
521: throw new Turba_Exception(sprintf(_("Invalid address book: %s"), $source));
522: }
523:
524: $driver = $GLOBALS['injector']->getInstance('Turba_Factory_Driver')->create($source);
525:
526: $histories = $history->getByTimestamp(
527: '>', $timestamp, $filter,
528: 'turba:' . $driver->getName());
529:
530:
531: $nguids = str_replace(
532: 'turba:' . $driver->getName() . ':',
533: '',
534: array_keys($histories));
535:
536: $include = array();
537: foreach ($nguids as $uid) {
538: if ($action != 'delete') {
539: $list = $driver->search(array('__uid' => $uid));
540: if ($list->count()) {
541: $object = $list->next();
542: if ($object->isGroup()) {
543: continue;
544: }
545: }
546: }
547: $include[] = $uid;
548: }
549:
550:
551: $uids = array_merge($uids, $include);
552: }
553:
554: return $uids;
555: }
556:
557: 558: 559: 560: 561: 562: 563: 564: 565: 566:
567: public function getChanges($start, $end)
568: {
569: return array('add' => $this->listBy('add', $start, null, $end),
570: 'modify' => $this->listBy('modify', $start, null, $end),
571: 'delete' => $this->listBy('delete', $start, null, $end));
572: }
573:
574: 575: 576: 577: 578: 579: 580: 581: 582: 583: 584: 585: 586: 587:
588: public function getActionTimestamp($uid, $action, $sources = null)
589: {
590: global $prefs, $cfgSources;
591:
592:
593: if (empty($sources)) {
594: $sources = @unserialize($prefs->getValue('sync_books'));
595: } elseif (!is_array($sources)) {
596: $sources = array($sources);
597: }
598: if (empty($sources)) {
599: $sources = array(Turba::getDefaultAddressbook());
600: }
601: if (empty($sources)) {
602: throw new Turba_Exception(_("No address book specified"));
603: }
604:
605: $last = 0;
606: $history = $GLOBALS['injector']->getInstance('Horde_History');
607: foreach ($sources as $source) {
608: if (empty($source) || !isset($cfgSources[$source])) {
609: throw new Turba_Exception(sprintf(_("Invalid address book: %s"), $source));
610: }
611:
612: $driver = $GLOBALS['injector']->getInstance('Turba_Factory_Driver')->create($source);
613:
614: $ts = $history->getActionTimestamp('turba:' . $driver->getName()
615: . ':' . $uid,
616: $action);
617: if (!empty($ts) && $ts > $last) {
618: $last = $ts;
619: }
620: }
621:
622: return $last;
623: }
624:
625: 626: 627: 628: 629: 630: 631: 632: 633: 634: 635: 636: 637:
638: public function import($content, $contentType = 'array',
639: $import_source = null)
640: {
641: global $cfgSources, $prefs;
642:
643:
644: if (empty($import_source)) {
645: $import_source = $prefs->getValue('default_dir');
646:
647:
648: if (empty($import_source)) {
649: $import_source = key(Turba::getAddressBooks(Horde_Perms::EDIT));
650: }
651: }
652:
653:
654: if (!isset($cfgSources[$import_source])) {
655: throw new Turba_Exception(
656: sprintf(_("Invalid address book: %s"), $import_source));
657: }
658:
659: $driver = $GLOBALS['injector']
660: ->getInstance('Turba_Factory_Driver')
661: ->create($import_source);
662:
663: if (!$driver->hasPermission(Horde_Perms::EDIT)) {
664: throw new Turba_Exception(_("Permission denied"));
665: }
666:
667:
668: $cManager = new Horde_Prefs_CategoryManager();
669: $categories = $cManager->get();
670:
671:
672: $object = new Turba_Object($driver);
673:
674: if (!($content instanceof Horde_Icalendar_Vcard)) {
675: switch ($contentType) {
676: case 'array':
677: break;
678:
679: case 'text/x-vcard':
680: case 'text/vcard':
681: case 'text/directory':
682: $iCal = new Horde_Icalendar();
683: if (!$iCal->parsevCalendar($content)) {
684: throw new Turba_Exception(_("There was an error importing the iCalendar data."));
685: }
686: switch ($iCal->getComponentCount()) {
687: case 0:
688: throw new Turba_Exception(_("No vCard data was found."));
689:
690: case 1:
691: $content = $iCal->getComponent(0);
692: break;
693:
694: default:
695: $ids = array();
696: foreach ($iCal->getComponents() as $c) {
697: if ($c instanceof Horde_Icalendar_Vcard) {
698: $content = $driver->toHash($c);
699: $result = $driver->search($content);
700: if (count($result)) {
701: continue;
702: }
703:
704: $result = $driver->add($content);
705: if (!empty($content['category']) &&
706: !in_array($content['category'], $categories)) {
707: $cManager->add($content['category']);
708: $categories[] = $content['category'];
709: }
710: $ids[] = $result;
711: }
712: }
713:
714: return $ids;
715: }
716: break;
717:
718: case 'activesync':
719: $content = $driver->fromASContact($content);
720: break;
721:
722: default:
723: throw new Turba_Exception(sprintf(_("Unsupported Content-Type: %s"), $contentType));
724: }
725: }
726:
727: if ($content instanceof Horde_Icalendar_Vcard) {
728: $content = $driver->toHash($content);
729: }
730:
731:
732: $result = $driver->search($content);
733: if (count($result)) {
734: $o = $result->objects[0];
735: throw new Turba_Exception(_("Already Exists"));
736: }
737:
738:
739:
740: if (Horde::hookExists('encode_attribute', 'turba')) {
741: foreach ($content as $attribute => &$value) {
742: try {
743: $value = Horde::callHook('encode_attribute', array($attribute, $value, null, null), 'turba');
744: } catch (Turba_Exception $e) {}
745: }
746: }
747: $result = $driver->add($content);
748:
749: if (!empty($content['category']) &&
750: !in_array($content['category'], $categories)) {
751: $cManager->add($content['category']);
752: }
753:
754: return $driver->getObject($result)->getValue('__uid');
755: }
756:
757: 758: 759: 760: 761: 762: 763: 764: 765: 766: 767: 768: 769: 770: 771: 772: 773: 774: 775: 776:
777: public function export($uid, $contentType, $sources = null, $fields = null)
778: {
779: global $cfgSources, $prefs;
780:
781:
782: if (empty($sources)) {
783: $sources = @unserialize($prefs->getValue('sync_books'));
784: } elseif (!is_array($sources)) {
785: $sources = array($sources);
786: }
787: if (empty($sources)) {
788: $sources = array(Turba::getDefaultAddressbook());
789: }
790: if (empty($sources)) {
791: throw new Turba_Exception(_("No address book specified"));
792: }
793:
794: foreach ($sources as $source) {
795: if (empty($source) || !isset($cfgSources[$source])) {
796: throw new Turba_Exception(sprintf(_("Invalid address book: %s"), $source));
797: }
798:
799: if (empty($uid)) {
800: throw new Turba_Exception(_("Invalid ID"));
801: }
802:
803: $driver = $GLOBALS['injector']->getInstance('Turba_Factory_Driver')->create($source);
804:
805: if (!$driver->hasPermission(Horde_Perms::READ)) {
806: continue;
807: }
808:
809: $result = $driver->search(array('__uid' => $uid));
810: if (count($result) == 0) {
811: continue;
812: } elseif (count($result) > 1) {
813: throw new Turba_Exception("Internal Horde Error: multiple turba objects with same objectId.");
814: }
815:
816: $version = '3.0';
817: list($contentType,) = explode(';', $contentType);
818: switch ($contentType) {
819: case 'text/x-vcard':
820: $version = '2.1';
821:
822: case 'text/vcard':
823: case 'text/directory':
824: $export = '';
825: foreach ($result->objects as $obj) {
826: $vcard = $driver->tovCard($obj, $version, $fields);
827: 828: 829:
830: $export .= $vcard->exportvCalendar();
831: }
832: return $export;
833:
834: case 'array':
835: $attributes = array();
836: foreach ($result->objects as $object) {
837: foreach ($cfgSources[$source]['map'] as $field => $map) {
838: $attributes[$field] = $object->getValue($field);
839: }
840: }
841:
842: return $attributes;
843:
844: case 'activesync':
845: foreach ($result->objects as $object) {
846: $return = $object;
847: }
848:
849: return $driver->toASContact($return);
850: }
851:
852: throw new Turba_Exception(sprintf(_("Unsupported Content-Type: %s"), $contentType));
853: }
854:
855: throw new Turba_Exception(_("Object not found"));
856: }
857:
858: 859: 860: 861: 862: 863:
864: public function ownVCard()
865: {
866: $contact = $this->getOwnContactObject();
867: $driver = $GLOBALS['injector']->getInstance('Turba_Factory_Driver')->create($contact['source']);
868:
869: $vcard = $driver->tovCard($contact['contact'], '3.0', null, true);
870: $vcard->setAttribute('VERSION', '3.0');
871:
872: return $vcard->exportvCalendar();
873: }
874:
875: 876: 877: 878: 879: 880:
881: public function ownContact()
882: {
883: $contact = $this->getOwnContactObject();
884: return $contact['contact']->getAttributes();
885: }
886:
887: 888: 889: 890: 891: 892: 893:
894: public function getOwnContactObject()
895: {
896: global $cfgSources;
897:
898: $own_contact = $GLOBALS['prefs']->getValue('own_contact');
899: if (empty($own_contact)) {
900: throw new Turba_Exception(_("You didn't mark a contact as your own yet."));
901: }
902: @list($source, $id) = explode(';', $own_contact);
903:
904: if (!isset($cfgSources[$source])) {
905: throw new Turba_Exception(_("The address book with your own contact doesn't exist anymore."));
906: }
907:
908: $driver = $GLOBALS['injector']->getInstance('Turba_Factory_Driver')->create($source);
909:
910: if (!$driver->hasPermission(Horde_Perms::READ)) {
911: throw new Turba_Exception(_("You don't have sufficient permissions to read the address book that contains your own contact."));
912: }
913:
914: try {
915: $contact = $driver->getObject($id);
916: } catch (Turba_Exception $e) {
917: throw new Turba_Exception(_("Your own contact cannot be found in the address book."));
918: }
919:
920: return array(
921: 'contact' => $contact,
922: 'source'=> $source
923: );
924: }
925:
926: 927: 928: 929: 930: 931: 932: 933: 934: 935: 936:
937: public function delete($uid, $sources = null)
938: {
939:
940:
941: if (is_array($uid)) {
942: foreach ($uid as $g) {
943: $this->delete($g, $source);
944: }
945:
946: return true;
947: }
948:
949: global $cfgSources, $prefs;
950:
951:
952: if (empty($sources)) {
953: $sources = @unserialize($prefs->getValue('sync_books'));
954: } elseif (!is_array($sources)) {
955: $sources = array($sources);
956: }
957: if (empty($sources)) {
958: $sources = array(Turba::getDefaultAddressbook());
959: }
960: if (empty($sources)) {
961: throw new Turba_Exception(_("No address book specified"));
962: }
963:
964: foreach ($sources as $source) {
965: if (empty($source) || !isset($cfgSources[$source])) {
966: throw new Turba_Exception(sprintf(_("Invalid address book: %s"), $source));
967: }
968:
969: if (empty($uid)) {
970: throw new Turba_Exception(_("Invalid ID"));
971: }
972:
973: $driver = $GLOBALS['injector']->getInstance('Turba_Factory_Driver')->create($source);
974:
975: if (!$GLOBALS['registry']->isAdmin() &&
976: !$driver->hasPermission(Horde_Perms::DELETE)) {
977: continue;
978: }
979:
980:
981:
982: $result = $driver->search(array('__uid' => $uid));
983: if (count($result) == 0) {
984: continue;
985: }
986:
987: $r = $result->objects[0];
988: return $driver->delete($r->getValue('__key'));
989: }
990:
991: return true;
992: }
993:
994: 995: 996: 997: 998: 999: 1000: 1001: 1002: 1003: 1004: 1005: 1006: 1007: 1008:
1009: public function replace($uid, $content, $contentType, $sources = null)
1010: {
1011: global $cfgSources, $prefs;
1012:
1013:
1014: if (empty($sources)) {
1015: $sources = @unserialize($prefs->getValue('sync_books'));
1016: } elseif (!is_array($sources)) {
1017: $sources = array($sources);
1018: }
1019: if (empty($sources)) {
1020: $sources = array(Turba::getDefaultAddressbook());
1021: }
1022: if (empty($sources)) {
1023: throw new Turba_Exception(_("No address book specified"));
1024: }
1025:
1026: foreach ($sources as $source) {
1027: if (empty($source) || !isset($cfgSources[$source])) {
1028: throw new Turba_Exception(sprintf(_("Invalid address book: %s"), $source));
1029: }
1030:
1031: if (empty($uid)) {
1032: throw new Turba_Exception(_("Invalid contact unique ID"));
1033: }
1034:
1035:
1036: $driver = $GLOBALS['injector']->getInstance('Turba_Factory_Driver')->create($source);
1037: if (!$driver->hasPermission(Horde_Perms::EDIT)) {
1038: continue;
1039: }
1040: $result = $driver->search(array('__uid' => $uid));
1041: if (!count($result)) {
1042: continue;
1043: } elseif (count($result) > 1) {
1044: throw new Turba_Exception(_("Multiple contacts found with same unique ID."));
1045: }
1046:
1047: $object = $result->objects[0];
1048:
1049: switch ($contentType) {
1050: case 'array':
1051: break;
1052:
1053: case 'text/x-vcard':
1054: case 'text/vcard':
1055: case 'text/directory':
1056: $iCal = new Horde_Icalendar();
1057: if (!$iCal->parsevCalendar($content)) {
1058: throw new Turba_Exception(_("There was an error importing the iCalendar data."));
1059: }
1060:
1061: switch ($iCal->getComponentCount()) {
1062: case 0:
1063: throw new Turba_Exception(_("No vCard data was found."));
1064:
1065: case 1:
1066: $content = $iCal->getComponent(0);
1067: $content = $driver->toHash($content);
1068: break;
1069:
1070: default:
1071: throw new Turba_Exception(_("Only one vcard supported."));
1072: }
1073: break;
1074:
1075: case 'activesync':
1076: $content = $driver->fromASContact($content);
1077:
1078: foreach ($content as $attribute => $value) {
1079: if ($attribute != '__key') {
1080: $object->setValue($attribute, $value);
1081: }
1082: }
1083: return $object->store();
1084: break;
1085:
1086: default:
1087: throw new Turba_Exception(sprintf(_("Unsupported Content-Type: %s"), $contentType));
1088: }
1089:
1090: foreach ($content as $attribute => $value) {
1091: if ($attribute != '__key') {
1092: $object->setValue($attribute, $value);
1093: }
1094: }
1095:
1096: return $object->store();
1097: }
1098:
1099: throw new Turba_Exception(_("Object not found"));
1100: }
1101:
1102: 1103: 1104: 1105: 1106: 1107: 1108: 1109: 1110: 1111: 1112: 1113: 1114: 1115: 1116: 1117: 1118: 1119:
1120: public function search($names = array(), $sources = array(),
1121: $fields = array(), $matchBegin = false,
1122: $forceSource = false, $returnFields = array(),
1123: $count_only = false)
1124: {
1125: global $cfgSources, $attributes, $prefs;
1126:
1127: if (!isset($cfgSources) || !is_array($cfgSources) || !count($cfgSources)) {
1128: return array();
1129: }
1130:
1131: if (!is_array($names)) {
1132: $names = is_null($names) ? array() : array($names);
1133: }
1134:
1135: if (!$forceSource) {
1136:
1137: $addressbooks = array_keys(Turba::getAddressBooks());
1138: foreach (array_keys($sources) as $id) {
1139: if (!in_array($sources[$id], $addressbooks)) {
1140: unset($sources[$id]);
1141: }
1142: }
1143: }
1144:
1145:
1146: if (!count($sources)) {
1147: $sources = array(Turba::getDefaultAddressbook());
1148: }
1149:
1150:
1151: $sort_columns = Turba::getColumns();
1152:
1153: if ($count_only) {
1154: $results = 0;
1155: } else {
1156: $results = array();
1157: }
1158: $seen = array();
1159: foreach ($sources as $source) {
1160:
1161: if (!isset($cfgSources[$source])) {
1162: continue;
1163: }
1164:
1165:
1166: if (empty($cfgSources[$source]['browse']) &&
1167: (!count($names) || (count($names) == 1 && empty($names[0])))) {
1168: continue;
1169: }
1170:
1171: $driver = $GLOBALS['injector']
1172: ->getInstance('Turba_Factory_Driver')
1173: ->create($source);
1174:
1175:
1176: $columns = isset($sort_columns[$source])
1177: ? $sort_columns[$source] : array();
1178:
1179: foreach ($names as $name) {
1180: $trimname = trim($name);
1181: $criteria = array();
1182: if (strlen($trimname)) {
1183: if (isset($fields[$source])) {
1184: foreach ($fields[$source] as $field) {
1185: $criteria[$field] = $trimname;
1186: }
1187: }
1188: if (count($criteria) == 0) {
1189: $criteria['name'] = $trimname;
1190: }
1191: }
1192: $search = $driver->search(
1193: $criteria, Turba::getPreferredSortOrder(), 'OR', $returnFields, array(), $matchBegin, $count_only);
1194: if ($count_only) {
1195: $results += $search;
1196: continue;
1197: } elseif (!($search instanceof Turba_List)) {
1198: continue;
1199: }
1200:
1201: while ($ob = $search->next()) {
1202: if (!$ob->isGroup()) {
1203:
1204: $att = array('__key' => $ob->getValue('__key'));
1205: foreach ($ob->driver->getCriteria() as $info_key => $info_val) {
1206: $att[$info_key] = $ob->getValue($info_key);
1207: }
1208: $email = array();
1209: foreach (array_keys($att) as $key) {
1210: if (!$ob->getValue($key) ||
1211: !isset($attributes[$key]) ||
1212: $attributes[$key]['type'] != 'email') {
1213: continue;
1214: }
1215: $email_val = $ob->getValue($key);
1216:
1217:
1218: if (isset($attributes[$key]['params'])
1219: && is_array($attributes[$key]['params'])
1220: && !empty($attributes[$key]['params']['allow_multi'])) {
1221: $addrs = Horde_Mime_Address::explode($email_val);
1222: } else {
1223: $addrs = array($email_val);
1224: }
1225:
1226: foreach ($addrs as $addr) {
1227: $email[] = trim($addr);
1228: }
1229: }
1230:
1231: if ($ob->hasValue('name') ||
1232: !isset($ob->driver->alternativeName)) {
1233: $display_name = Turba::formatName($ob);
1234: } else {
1235: $display_name = $ob->getValue($ob->driver->alternativeName);
1236: }
1237: if (count($email)) {
1238: for ($i = 0; $i < count($email); $i++) {
1239: $seen_key = trim(Horde_String::lower($display_name)) . '/' . trim(Horde_String::lower($email[$i]));
1240: if (!empty($seen[$seen_key])) {
1241: continue;
1242: }
1243: $seen[$seen_key] = true;
1244: if (!isset($results[$name])) {
1245: $results[$name] = array();
1246: }
1247: $results[$name][] = array_merge($att,
1248: array('id' => $att['__key'],
1249: 'name' => $display_name,
1250: 'email' => $email[$i],
1251: '__type' => 'Object',
1252: 'source' => $source));
1253: }
1254: } else {
1255: if (!isset($results[$name])) {
1256: $results[$name] = array();
1257: }
1258: $results[$name][] = array_merge($att,
1259: array('id' => $att['__key'],
1260: 'name' => $display_name,
1261: 'email' => null,
1262: '__type' => 'Object',
1263: 'source' => $source));
1264: }
1265: } else {
1266:
1267: $listatt = $ob->getAttributes();
1268: $seeninlist = array();
1269: $members = $ob->listMembers();
1270: $listName = $ob->getValue('name');
1271: if (!($members instanceof Turba_List)) {
1272: continue;
1273: }
1274: if (count($members)) {
1275: if (!isset($results[$name])) {
1276: $results[$name] = array();
1277: }
1278: $emails = array();
1279: while ($ob = $members->next()) {
1280: $att = $ob->getAttributes();
1281: foreach (array_keys($att) as $key) {
1282: $value = $ob->getValue($key);
1283: if (empty($value)) {
1284: continue;
1285: }
1286: if (!is_array($value)) {
1287: $seen_key = trim(Horde_String::lower($ob->getValue('name')))
1288: . trim(Horde_String::lower($value));
1289: } else {
1290: $seen_key = trim(Horde_String::lower($ob->getValue('name')))
1291: . trim(Horde_String::lower($value['load']['file']));
1292: }
1293: if (isset($attributes[$key]) &&
1294: $attributes[$key]['type'] == 'email' &&
1295: empty($seeninlist[$seen_key])) {
1296: $emails[] = $value;
1297: $seeninlist[$seen_key] = true;
1298: }
1299: }
1300: }
1301: $results[$name][] = array('name' => $listName,
1302: 'email' => implode(', ', $emails),
1303: 'id' => $listatt['__key'],
1304: 'source' => $source);
1305: }
1306: }
1307: }
1308: }
1309: }
1310:
1311: return $results;
1312: }
1313:
1314: 1315: 1316: 1317: 1318: 1319: 1320: 1321: 1322:
1323: public function getContact($source = null, $objectId = '')
1324: {
1325: global $cfgSources;
1326:
1327: if (!isset($cfgSources) || !is_array($cfgSources) || !count($cfgSources)) {
1328: return array();
1329: }
1330:
1331: if (isset($cfgSources[$source])) {
1332: $driver = $GLOBALS['injector']->getInstance('Turba_Factory_Driver')->create($source);
1333:
1334: $object = $driver->getObject($objectId);
1335:
1336: $attributes = array();
1337: foreach ($cfgSources[$source]['map'] as $field => $map) {
1338: $attributes[$field] = $object->getValue($field);
1339: }
1340: return $attributes;
1341: }
1342:
1343: return array();
1344: }
1345:
1346: 1347: 1348: 1349: 1350: 1351: 1352: 1353: 1354:
1355: public function getContacts($source = '', $objectIds = array())
1356: {
1357: global $cfgSources;
1358: $results = array();
1359: if (!is_array($objectIds)) {
1360: $objectIds = array($objectIds);
1361: }
1362:
1363: if (!isset($cfgSources) || !is_array($cfgSources) || !count($cfgSources)) {
1364: return array();
1365: }
1366:
1367: if (isset($cfgSources[$source])) {
1368: $driver = $GLOBALS['injector']->getInstance('Turba_Factory_Driver')->create($source);
1369:
1370: $objects = $driver->getObjects($objectIds);
1371:
1372: foreach ($objects as $object) {
1373: $attributes = array();
1374: foreach ($cfgSources[$source]['map'] as $field => $map) {
1375: $attributes[$field] = $object->getValue($field);
1376: }
1377: $results[] = $attributes;
1378: }
1379: }
1380:
1381: return $results;
1382: }
1383:
1384: 1385: 1386: 1387: 1388: 1389: 1390: 1391: 1392: 1393:
1394: public function getAllAttributeValues($field = '', $sources = array())
1395: {
1396: global $cfgSources;
1397:
1398: if (!isset($cfgSources) || !is_array($cfgSources) || !count($cfgSources)) {
1399: return array();
1400: }
1401:
1402: if (!count($sources)) {
1403: $sources = array(Turba::getDefaultAddressbook());
1404: }
1405:
1406: $results = array();
1407: foreach ($sources as $source) {
1408: if (isset($cfgSources[$source])) {
1409: $driver = $GLOBALS['injector']->getInstance('Turba_Factory_Driver')->create($source);
1410:
1411: $res = $driver->search(array());
1412: if (!($res instanceof Turba_List)) {
1413: throw new Turba_Exception(_("Search failed"));
1414: }
1415:
1416: while ($ob = $res->next()) {
1417: if ($ob->hasValue($field)) {
1418: $results[$source . ':' . $ob->getValue('__key')] = array(
1419: 'name' => $ob->getValue('name'),
1420: 'email' => $ob->getValue('email'),
1421: $field => $ob->getValue($field));
1422: }
1423: }
1424: }
1425: }
1426:
1427: return $results;
1428: }
1429:
1430: 1431: 1432: 1433: 1434:
1435: public function listTimeObjectCategories()
1436: {
1437: $categories = array();
1438: foreach ($GLOBALS['attributes'] as $key => $attribute) {
1439: if ($attribute['type'] == 'monthdayyear' &&
1440: !empty($attribute['time_object_label'])) {
1441: foreach ($GLOBALS['cfgSources'] as $srcKey => $source) {
1442: if (!empty($source['map'][$key])) {
1443: $categories[$key . '/'. $srcKey] = sprintf(_("%s in %s"), $attribute['time_object_label'], $source['title']);
1444: }
1445: }
1446: }
1447: }
1448:
1449: return $categories;
1450: }
1451:
1452: 1453: 1454: 1455: 1456: 1457: 1458: 1459: 1460: 1461: 1462:
1463: public function listTimeObjects($time_categories, $start, $end)
1464: {
1465: global $cfgSources;
1466:
1467: $start = new Horde_Date($start);
1468: $end = new Horde_Date($end);
1469:
1470: if (!isset($cfgSources) || !is_array($cfgSources) || !count($cfgSources)) {
1471: return array();
1472: }
1473:
1474: $objects = array();
1475: foreach ($time_categories as $category) {
1476: list($category, $source) = explode('/', $category, 2);
1477: $driver = $GLOBALS['injector']->getInstance('Turba_Factory_Driver')->create($source);
1478: $objects = array_merge($objects, $driver->listTimeObjects($start, $end, $category));
1479: }
1480:
1481: return $objects;
1482: }
1483:
1484: 1485: 1486: 1487: 1488:
1489: public function getClientSource()
1490: {
1491: return !empty($GLOBALS['conf']['client']['addressbook']) ? $GLOBALS['conf']['client']['addressbook'] : false;
1492: }
1493:
1494: 1495: 1496: 1497: 1498:
1499: public function clientFields()
1500: {
1501: return $this->fields($GLOBALS['conf']['client']['addressbook']);
1502: }
1503:
1504: 1505: 1506: 1507: 1508: 1509: 1510: 1511:
1512: public function getClient($objectId = '')
1513: {
1514: return $this->getContact($GLOBALS['conf']['client']['addressbook'], $objectId);
1515: }
1516:
1517: 1518: 1519: 1520: 1521: 1522: 1523: 1524:
1525: public function getClients($objectIds = array())
1526: {
1527: return $this->getContacts($GLOBALS['conf']['client']['addressbook'], $objectIds);
1528: }
1529:
1530: 1531: 1532: 1533: 1534:
1535: public function addClient($attributes = array())
1536: {
1537: return $this->import($attributes, 'array', $this->getClientSource());
1538: }
1539:
1540: 1541: 1542: 1543: 1544: 1545: 1546: 1547:
1548: public function updateClient($objectId = '', $attributes = array())
1549: {
1550: return $this->replace($this->getClientSource() . ':' . $objectId, $attributes, 'array');
1551: }
1552:
1553: 1554: 1555: 1556: 1557: 1558: 1559:
1560: public function deleteClient($objectId = '')
1561: {
1562: return $this->delete($this->getClientSource() . ':' . $objectId);
1563: }
1564:
1565: 1566: 1567: 1568: 1569: 1570: 1571: 1572: 1573: 1574:
1575: public function searchClients($names = array(), $fields = array(),
1576: $matchBegin = false)
1577: {
1578: return $this->search(
1579: $names,
1580: array($GLOBALS['conf']['client']['addressbook']),
1581: array($GLOBALS['conf']['client']['addressbook'] => $fields),
1582: $matchBegin,
1583: true
1584: );
1585: }
1586:
1587: 1588: 1589: 1590: 1591: 1592: 1593: 1594: 1595: 1596: 1597:
1598: public function addField($address = '', $name = '', $field = '',
1599: $value = '', $source = '')
1600: {
1601: if (is_array($address)) {
1602: $exception = null;
1603: $success = 0;
1604: foreach ($address as $tmp) {
1605: try {
1606: $this->addField($tmp, $name, $field, $value, $source);
1607: $success++;
1608: } catch (Exception $exception) {
1609: }
1610: }
1611: if ($exception) {
1612: if ($success) {
1613: throw new Turba_Exception(sprintf(ngettext("Added or updated %d contact, but at least one contact failed:", "Added or updated %d contacts, but at least one contact failed:", $success), $success) . ' ' . $exception->getMessage());
1614: } else {
1615: throw $exception;
1616: }
1617: }
1618: }
1619:
1620: global $cfgSources;
1621:
1622: if (empty($source) || !isset($cfgSources[$source])) {
1623: throw new Turba_Exception(sprintf(_("Invalid address book: %s"), $source));
1624: }
1625:
1626: if (empty($address)) {
1627: throw new Turba_Exception(_("Invalid email"));
1628: }
1629:
1630: if (empty($name)) {
1631: throw new Turba_Exception(_("Invalid name"));
1632: }
1633:
1634: if (empty($value)) {
1635: throw new Turba_Exception(_("Invalid entry"));
1636: }
1637:
1638: $driver = $GLOBALS['injector']->getInstance('Turba_Factory_Driver')->create($source);
1639:
1640: if (!$driver->hasPermission(Horde_Perms::EDIT)) {
1641: throw new Turba_Exception(_("Permission denied"));
1642: }
1643:
1644: try {
1645: $res = $driver->search(array('email' => trim($address)), null, 'AND');
1646: } catch (Turba_Exception $e) {
1647: throw new Turba_Exception(sprintf(_("Search failed: %s"), $res->getMessage()));
1648: }
1649:
1650: if (count($res) > 1) {
1651: try {
1652: $res2 = $driver->search(array('email' => trim($address), 'name' => trim($name)), null, 'AND');
1653: } catch (Turba_Exception $e) {
1654: throw new Turba_Exception(sprintf(_("Search failed: %s"), $e->getMessage()));
1655: }
1656:
1657: if (!count($res2)) {
1658: throw new Turba_Exception(sprintf(_("Multiple persons with address [%s], but none with name [%s] already exist"), trim($address), trim($name)));
1659: }
1660:
1661: try {
1662: $res3 = $driver->search(array('email' => $address, 'name' => $name, $field => $value));
1663: } catch (Turba_Exception $e) {
1664: throw new Turba_Exception(sprintf(_("Search failed: %s"), $e->getMessage()));
1665: }
1666:
1667: if (count($res3)) {
1668: throw new Turba_Exception(sprintf(_("This person already has a %s entry in the address book"), $field));
1669: }
1670:
1671: $ob = $res2->next();
1672: $ob->setValue($field, $value);
1673: $ob->store();
1674: } elseif (count($res) == 1) {
1675: try {
1676: $res4 = $driver->search(array('email' => $address, $field => $value));
1677: } catch (Turba_Exception $e) {
1678: throw new Turba_Exception(sprintf(_("Search failed: %s"), $e->getMessage()));
1679: }
1680:
1681: if (count($res4)) {
1682: throw new Turba_Exception(sprintf(_("This person already has a %s entry in the address book"), $field));
1683: }
1684:
1685: $ob = $res->next();
1686: $ob->setValue($field, $value);
1687: $ob->store();
1688: } else {
1689: $driver->add(array('email' => $address, 'name' => $name, $field => $value, '__owner' => $GLOBALS['registry']->getAuth()));
1690: }
1691: }
1692:
1693: 1694: 1695: 1696: 1697: 1698: 1699: 1700: 1701: 1702: 1703: 1704: 1705:
1706: public function getField($address = '', $field = '', $sources = array(),
1707: $strict = false, $multiple = false)
1708: {
1709: global $cfgSources;
1710:
1711: if (empty($address)) {
1712: throw new Turba_Exception(_("Invalid email"));
1713: }
1714:
1715: if (!isset($cfgSources) || !is_array($cfgSources) || !count($cfgSources)) {
1716: return array();
1717: }
1718:
1719: if (!count($sources)) {
1720: $sources = array(Turba::getDefaultAddressbook());
1721: }
1722:
1723: $result = array();
1724: foreach ($sources as $source) {
1725: if (!isset($cfgSources[$source])) {
1726: continue;
1727: }
1728:
1729: $driver = $GLOBALS['injector']->getInstance('Turba_Factory_Driver')->create($source);
1730: $criterium = array('email' => $address);
1731: if (!isset($driver->map['email'])) {
1732: if (isset($driver->map['emails'])) {
1733: $criterium = array('emails' => $address);
1734: } else {
1735: continue;
1736: }
1737: }
1738:
1739: try {
1740: $list = $driver->search($criterium, null, 'AND', array(), $strict ? array('email') : array());
1741: } catch (Turba_Exception $e) {
1742: Horde::logMessage($e, 'ERR');
1743: }
1744: if (!($list instanceof Turba_List)) {
1745: continue;
1746: }
1747:
1748: while ($ob = $list->next()) {
1749: if ($ob->hasValue($field)) {
1750: $result[] = $ob->getValue($field);
1751: }
1752: }
1753: }
1754:
1755: if (count($result) > 1) {
1756: if ($multiple) {
1757: return $result;
1758: } else {
1759: throw new Turba_Exception(_("More than 1 entry found"));
1760: }
1761: } elseif (empty($result)) {
1762: throw new Turba_Exception(sprintf(_("No %s entry found for %s"), $field, $address));
1763: }
1764:
1765: return reset($result);
1766: }
1767:
1768: 1769: 1770: 1771: 1772: 1773: 1774: 1775: 1776: 1777:
1778: public function deleteField($address = '', $field = '', $sources = array())
1779: {
1780: global $cfgSources;
1781:
1782: if (empty($address)) {
1783: throw new Turba_Exception(_("Invalid email"));
1784: }
1785:
1786: if (!isset($cfgSources) || !is_array($cfgSources) || !count($cfgSources)) {
1787: return array();
1788: }
1789:
1790: if (count($sources) == 0) {
1791: $sources = array(Turba::getDefaultAddressbook());
1792: }
1793:
1794: $success = false;
1795:
1796: foreach ($sources as $source) {
1797: if (isset($cfgSources[$source])) {
1798: $driver = $GLOBALS['injector']->getInstance('Turba_Factory_Driver')->create($source);
1799: if (!$driver->hasPermission(Horde_Perms::EDIT)) {
1800: continue;
1801: }
1802:
1803: $res = $driver->search(array('email' => $address));
1804: if ($res instanceof Turba_List) {
1805: if (count($res) > 1) {
1806: continue;
1807: }
1808:
1809: $ob = $res->next();
1810: if (is_object($ob) && $ob->hasValue($field)) {
1811: $ob->setValue($field, '');
1812: $ob->store();
1813: $success = true;
1814: }
1815: }
1816: }
1817: }
1818:
1819: if (!$success) {
1820: throw new Turba_Exception(sprintf(_("No %s entry found for %s"), $field, $address));
1821: }
1822: }
1823:
1824: 1825: 1826: 1827: 1828: 1829: 1830:
1831: public function getSourcesConfig($filter = array())
1832: {
1833:
1834: $turba_sources = Horde::loadConfiguration('backends.php',
1835: 'cfgSources', 'turba');
1836: $results = array();
1837: foreach ($turba_sources as $key => $source) {
1838: if (!empty($filter)) {
1839: if(!empty($source[current(array_keys($filter))]) &&
1840: $source[current(array_keys($filter))] == current($filter)) {
1841:
1842: $results[$key] = $source;
1843:
1844: }
1845: }
1846: }
1847:
1848: return $results;
1849: }
1850:
1851: 1852: 1853: 1854: 1855: 1856: 1857:
1858: public function listShares($perms = Horde_Perms::READ)
1859: {
1860: return Turba::listShares(true, $perms);
1861: }
1862:
1863: 1864: 1865: 1866: 1867: 1868: 1869: 1870:
1871: public function listUserGroupObjects()
1872: {
1873: $groups = $owners = array();
1874:
1875:
1876: $sources = $this->getSourcesConfig(array('type' => 'sql'));
1877:
1878: foreach ($sources as $key => $source) {
1879:
1880: $db[$key] = empty($source['params']['sql'])
1881: ? $GLOBALS['injector']->getInstance('Horde_Db_Adapter')
1882: : $GLOBALS['injector']->getInstance('Horde_Core_Factory_Db')->create('turba', $source['params']['sql']);
1883:
1884: if ($source['use_shares']) {
1885: if (empty($contact_shares)) {
1886: $contact_shares = $this->listShares(Horde_Perms::SHOW);
1887: }
1888: foreach ($contact_shares as $id => $share) {
1889: $params = @unserialize($share->get('params'));
1890: if ($params['source'] == $key) {
1891: $owners[] = $params['name'];
1892: }
1893: }
1894: if (!$owners) {
1895: return array();
1896: }
1897: } else {
1898: $owners = array($GLOBALS['registry']->getAuth());
1899: }
1900:
1901: $owner_ids = array();
1902: foreach ($owners as $owner) {
1903: $owner_ids[] = $db[$key]->quoteString($owner);
1904: }
1905:
1906: $sql = 'SELECT ' . $source['map']['__key'] . ', ' . $source['map'][$source['list_name_field']]
1907: . ' FROM ' . $source['params']['table'] . ' WHERE '
1908: . $source['map']['__type'] . ' = \'Group\' AND '
1909: . $source['map']['__owner'] . ' IN (' . implode(',', $owner_ids ) . ')';
1910:
1911: try {
1912: $results = $db[$key]->selectAssoc($sql);
1913: } catch (Horde_Db_Exception $e) {
1914: Horde::logMessage($e);
1915: throw new Horde_Exception_Wrapped($e);
1916: }
1917: foreach ($results as $id => $name) {
1918: $groups[$key . ':' . $id] = $name;
1919: }
1920: }
1921:
1922: return $groups;
1923: }
1924:
1925: 1926: 1927: 1928: 1929: 1930:
1931: public function getGroupObjects()
1932: {
1933: $ret = array();
1934:
1935: foreach ($this->getSourcesConfig(array('type' => 'sql')) as $key => $source) {
1936: if (empty($source['map']['__type'])) {
1937: continue;
1938: }
1939:
1940: list($db, $sql) = $this->_getGroupObject($source, 'Group');
1941:
1942: try {
1943: $results = $db->selectAll($sql);
1944: } catch (Horde_Db_Exception $e) {
1945: Horde::logMessage($e);
1946: throw new Turba_Exception($e);
1947: }
1948:
1949: foreach ($results as $row) {
1950:
1951: $row['name'] = $row['lname'];
1952: unset($row['lname']);
1953: $ret[$key . ':' . $row['id']] = $row;
1954: }
1955: }
1956:
1957: return $ret;
1958: }
1959:
1960: 1961: 1962: 1963: 1964: 1965: 1966: 1967: 1968: 1969: 1970:
1971: public function getGroupMemberships($user, $parentGroups = false)
1972: {
1973: $lists = $this->getGroupObjects();
1974: $memberships = array();
1975: foreach ($lists as $id => $list) {
1976: $members = $this->getGroupMembers($id, $parentGroups);
1977: if (in_array($user, $members)) {
1978: $memberships[$id] = $list['name'];
1979: }
1980: }
1981: return $memberships;
1982: }
1983:
1984: 1985: 1986: 1987: 1988: 1989: 1990: 1991:
1992: public function getGroupObject($gid)
1993: {
1994: if (empty($gid) || (strpos($gid, ':') === false)) {
1995: throw new Turba_Exception(sprintf('Unsupported group id: %s', $gid));
1996: }
1997:
1998: $sources = $this->getSourcesConfig(array('type' => 'sql'));
1999: list($source, $id) = explode(':', $gid);
2000: if (empty($sources[$source])) {
2001: return array();
2002: }
2003:
2004: list($db, $sql) = $this->_getGroupObject($sources[$source], $id);
2005:
2006: try {
2007: $ret = $db->selectOne($sql);
2008: $ret['name'] = $ret['lname'];
2009: unset($ret['lname']);
2010: return $ret;
2011: } catch (Horde_Db_Exception $e) {
2012: Horde::logMessage($e);
2013: throw new Turba_Exception($e);
2014: }
2015: }
2016:
2017: 2018:
2019: protected function _getGroupObject($source, $key)
2020: {
2021: $db = empty($source['params']['sql'])
2022: ? $GLOBALS['injector']->getInstance('Horde_Db_Adapter')
2023: : $GLOBALS['injector']->getInstance('Horde_Core_Factory_Db')->create('turba', $source['params']['sql']);
2024:
2025: $sql = 'SELECT ' . $source['map']['__members'] . ' members,'
2026: . $source['map']['email'] . ' email,'
2027: . $source['map'][$source['list_name_field']]
2028: . ' lname FROM ' . $source['params']['table'] . ' WHERE '
2029: . $source['map']['__key'] . ' = ' . $db->quoteString($key);
2030:
2031: return array($db, $sql);
2032: }
2033:
2034: 2035: 2036: 2037: 2038: 2039: 2040: 2041: 2042:
2043: public function getGroupMembers($gid, $subGroups = false)
2044: {
2045: $contact_shares = $this->listShares(Horde_Perms::SHOW);
2046: $sources = $this->getSourcesConfig(array('type' => 'sql'));
2047:
2048: $entry = $this->getGroupObject($gid);
2049: if (!$entry) {
2050: return array();
2051: }
2052: list($source, $id) = explode(':', $gid);
2053: $members = @unserialize($entry['members']);
2054: if (!is_array($members)) {
2055: return array();
2056: }
2057:
2058: $db[$source] = empty($sources[$source]['params']['sql'])
2059: ? $GLOBALS['injector']->getInstance('Horde_Db_Adapter')
2060: : $GLOBALS['injector']->getInstance('Horde_Core_Factory_Db')->create('turba', $sources[$source]['params']['sql']);
2061:
2062: $users = array();
2063: foreach ($members as $member) {
2064:
2065: if (strpos($member, ':') !== false) {
2066: list($newSource, $uid) = explode(':', $member);
2067: if (!empty($contact_shares[$newSource])) {
2068: $params = @unserialize($contact_shares[$newSource]->get('params'));
2069: $newSource = $params['source'];
2070: $member = $uid;
2071: $db[$newSource] = empty($sources[$newSource]['params']['sql'])
2072: ? $GLOBALS['injector']->getInstance('Horde_Db_Adapter')
2073: : $GLOBALS['injector']->getInstance('Horde_Core_Factory_Db')->create('turba', $sources[$newSource]['params']['sql']);
2074:
2075: } elseif (empty($sources[$newSource])) {
2076:
2077: continue;
2078: }
2079: } else {
2080:
2081: $newSource = $source;
2082: }
2083:
2084: $type = $sources[$newSource]['map']['__type'];
2085: $email = $sources[$newSource]['map']['email'];
2086: $sql = 'SELECT ' . $email . ', ' . $type
2087: . ' FROM ' . $sources[$newSource]['params']['table']
2088: . ' WHERE ' . $sources[$newSource]['map']['__key']
2089: . ' = ' . $db[$newSource]->quoteString($member);
2090:
2091: try {
2092: $results = $db[$newSource]->selectOne($sql);
2093: } catch (Horde_Db_Exception $e) {
2094: Horde::logMessage($e);
2095: throw new Horde_Exception_Wrapped($e);
2096: }
2097:
2098:
2099: if ($subGroups && $results[$type] == 'Group') {
2100: $users = array_merge($users, $this->getGroupMembers($newSource . ':' . $member));
2101: }
2102: if (strlen($results[$email])) {
2103:
2104: $users[$results[$email]] = true;
2105: }
2106: }
2107:
2108: ksort($users);
2109: return array_keys($users);
2110: }
2111:
2112: }
2113: