Overview

Packages

  • Horde
    • Data
  • None
  • Turba

Classes

  • Turba
  • Turba_Api
  • Turba_Driver
  • Turba_Driver_Facebook
  • Turba_Driver_Favourites
  • Turba_Driver_Group
  • Turba_Driver_Imsp
  • Turba_Driver_Kolab
  • Turba_Driver_Ldap
  • Turba_Driver_Prefs
  • Turba_Driver_Share
  • Turba_Driver_Sql
  • Turba_Driver_Vbook
  • Turba_Exception
  • Turba_Factory_Driver
  • Turba_Form_AddContact
  • Turba_Form_Contact
  • Turba_Form_ContactBase
  • Turba_Form_CreateAddressBook
  • Turba_Form_DeleteAddressBook
  • Turba_Form_EditAddressBook
  • Turba_Form_EditContact
  • Turba_Form_EditContactGroup
  • Turba_List
  • Turba_LoginTasks_SystemTask_Upgrade
  • Turba_Object
  • Turba_Object_Group
  • Turba_Test
  • Turba_View_Browse
  • Turba_View_Contact
  • Turba_View_DeleteContact
  • Turba_View_Duplicates
  • Turba_View_EditContact
  • Turba_View_List
  • Overview
  • Package
  • Class
  • Tree
  1: <?php
  2: /**
  3:  * Turba Base Class.
  4:  *
  5:  * @author  Chuck Hagenbuch <chuck@horde.org>
  6:  * @author  Jon Parise <jon@horde.org>
  7:  * @package Turba
  8:  */
  9: class Turba
 10: {
 11:     /**
 12:      *  The virtual path to use for VFS data.
 13:      */
 14:     const VFS_PATH = '.horde/turba/documents';
 15: 
 16:     /**
 17:      * Returns the source entries from config/backends.php that have been
 18:      * configured as available sources in the main Turba configuration.
 19:      *
 20:      * @return array  List of available sources.
 21:      */
 22:     static public function availableSources()
 23:     {
 24:         $cfgSources = Horde::loadConfiguration('backends.php', 'cfgSources', 'turba');
 25:         $sources = array();
 26:         foreach ($cfgSources as $key => $source) {
 27:             if (empty($source['disabled'])) {
 28:                 $sources[$key] = $source;
 29:             }
 30:         }
 31:         return $sources;
 32:     }
 33: 
 34:     /**
 35:      * Get all the address books the user has the requested permissions to and
 36:      * return them in the user's preferred order.
 37:      *
 38:      * @param integer $permission  The Horde_Perms::* constant to filter on.
 39:      * @param array $options       Any additional options.
 40:      *
 41:      * @return array  The filtered, ordered $cfgSources entries.
 42:      */
 43:     static public function getAddressBooks($permission = Horde_Perms::READ,
 44:                                            array $options = array())
 45:     {
 46:         $addressbooks = array();
 47:         foreach (array_keys(self::getAddressBookOrder()) as $addressbook) {
 48:             $addressbooks[$addressbook] = $GLOBALS['cfgSources'][$addressbook];
 49:         }
 50: 
 51:         if (!$addressbooks) {
 52:             $addressbooks = $GLOBALS['cfgSources'];
 53:         }
 54: 
 55:         return self::permissionsFilter($addressbooks, $permission, $options);
 56:     }
 57: 
 58:     /**
 59:      * Get the order the user selected for displaying address books.
 60:      *
 61:      * @return array  An array describing the order to display the address
 62:      *                books.
 63:      */
 64:     static public function getAddressBookOrder()
 65:     {
 66:         $lines = json_decode($GLOBALS['prefs']->getValue('addressbooks'));
 67:         $addressbooks = array();
 68:         if (!empty($lines)) {
 69:             $i = 0;
 70:             foreach ($lines as $line) {
 71:                 $line = trim($line);
 72:                 if ($line && isset($GLOBALS['cfgSources'][$line])) {
 73:                     $addressbooks[$line] = $i++;
 74:                 }
 75:             }
 76:         }
 77:         return $addressbooks;
 78:     }
 79: 
 80:     /**
 81:      * Returns the current user's default address book.
 82:      *
 83:      * @return string  The default address book name.
 84:      */
 85:     static public function getDefaultAddressbook()
 86:     {
 87:         $lines = json_decode($GLOBALS['prefs']->getValue('addressbooks'));
 88:         if (!empty($lines)) {
 89:             foreach ($lines as $line) {
 90:                 $line = trim($line);
 91:                 if ($line && isset($GLOBALS['cfgSources'][$line])) {
 92:                     return $line;
 93:                 }
 94:             }
 95:         }
 96: 
 97:         /* In case of shares select first user owned address book as default */
 98:         if (!empty($_SESSION['turba']['has_share'])) {
 99:             try {
100:                 $owned_shares = self::listShares(true);
101:                 if (count($owned_shares) > 0) {
102:                     return key($owned_shares);
103:                 }
104:             } catch (Exception $e) {}
105:         }
106: 
107:         reset($GLOBALS['cfgSources']);
108:         return key($GLOBALS['cfgSources']);
109:     }
110: 
111:     /**
112:      * Returns the sort order selected by the user
113:      */
114:     static public function getPreferredSortOrder()
115:     {
116:         return @unserialize($GLOBALS['prefs']->getValue('sortorder'));
117:     }
118: 
119:     /**
120:      * Saves the sort order to the preferences backend.
121:      *
122:      * @param Horde_Variables $vars  Variables object.
123:      * @param string $source         Source.
124:      */
125:     static public function setPreferredSortOrder(Horde_Variables $vars,
126:                                                  $source)
127:     {
128:         if (!strlen($sortby = $vars->get('sortby'))) {
129:             return;
130:         }
131: 
132:         $sources = self::getColumns();
133:         $columns = isset($sources[$source])
134:             ? $sources[$source]
135:             : array();
136:         $column_name = self::getColumnName($sortby, $columns);
137: 
138:         $append = true;
139:         $ascending = ($vars->get('sortdir') == 0);
140: 
141:         if ($vars->get('sortadd')) {
142:             $sortorder = self::getPreferredSortOrder();
143:             foreach ($sortorder as $i => $elt) {
144:                 if ($elt['field'] == $column_name) {
145:                     $sortorder[$i]['ascending'] = $ascending;
146:                     $append = false;
147:                 }
148:             }
149:         } else {
150:             $sortorder = array();
151:         }
152: 
153:         if ($append) {
154:             $sortorder[] = array(
155:                 'ascending' => $ascending,
156:                 'field' => $column_name
157:             );
158:         }
159: 
160:         $GLOBALS['prefs']->setValue('sortorder', serialize($sortorder));
161:     }
162: 
163:     /**
164:      * Retrieves a column's field name.
165:      *
166:      * @param integer $i      TODO
167:      * @param array $columns  TODO
168:      *
169:      * @return string  TODO
170:      */
171:     static public function getColumnName($i, $columns)
172:     {
173:         return (($i == 0) || !isset($columns[$i - 1]))
174:             ? 'name'
175:             : $columns[$i - 1];
176:     }
177: 
178:     /**
179:      */
180:     static public function getColumns()
181:     {
182:         $columns = array();
183:         $lines = explode("\n", $GLOBALS['prefs']->getValue('columns'));
184:         foreach ($lines as $line) {
185:             $line = trim($line);
186:             if ($line) {
187:                 $cols = explode("\t", $line);
188:                 if (count($cols) > 1) {
189:                     $source = array_splice($cols, 0, 1);
190:                     $columns[$source[0]] = $cols;
191:                 }
192:             }
193:         }
194: 
195:         return $columns;
196:     }
197: 
198:     /**
199:      * Builds and cleans up a composite field.
200:      *
201:      * @param string $format  The sprintf field format.
202:      * @param array $fields   The fields that compose the composite field.
203:      *
204:      * @return string  The formatted composite field.
205:      */
206:     static public function formatCompositeField($format, $fields)
207:     {
208:         return preg_replace('/ +/', ' ', trim(vsprintf($format, $fields), " \t\n\r\0\x0B,"));
209:     }
210: 
211:     /**
212:      * Returns a best guess at the lastname in a string.
213:      *
214:      * @param string $name  String contain the full name.
215:      *
216:      * @return string  String containing the last name.
217:      */
218:     static public function guessLastname($name)
219:     {
220:         $name = trim(preg_replace('|\s|', ' ', $name));
221:         if (!empty($name)) {
222:             /* Assume that last names are always before any commas. */
223:             if (is_int(strpos($name, ','))) {
224:                 $name = Horde_String::substr($name, 0, strpos($name, ','));
225:             }
226: 
227:             /* Take out anything in parentheses. */
228:             $name = trim(preg_replace('|\(.*\)|', '', $name));
229: 
230:             $namelist = explode(' ', $name);
231:             $name = $namelist[($nameindex = (count($namelist) - 1))];
232: 
233:             while (!empty($name) && Horde_String::length($name) < 5 &&
234:                    strspn($name[(Horde_String::length($name) - 1)], '.:-') &&
235:                    !empty($namelist[($nameindex - 1)])) {
236:                 $nameindex--;
237:                 $name = $namelist[$nameindex];
238:             }
239:         }
240:         return strlen($name) ? $name : null;
241:     }
242: 
243:     /**
244:      * Formats the name according to the user's preference.
245:      *
246:      * If the format is 'none', the full name with all parts is returned. If
247:      * the format is 'last_first' or 'first_last', only the first name and
248:      * last name are returned.
249:      *
250:      * @param Turba_Object $ob     The object to get a name from.
251:      * @param string $name_format  The formatting. One of 'none', 'last_first'
252:      *                             or 'first_last'. Defaults to the user
253:      *                             preference.
254:      *
255:      * @return string  The formatted name, either "Firstname Lastname"
256:      *                 or "Lastname, Firstname" depending on $name_format or
257:      *                 the user's preference.
258:      */
259:     static public function formatName(Turba_Object $ob, $name_format = null)
260:     {
261:         static $default_format;
262: 
263:         if (!$name_format) {
264:             if (!isset($default_format)) {
265:                 $default_format = $GLOBALS['prefs']->getValue('name_format');
266:             }
267:             $name_format = $default_format;
268:         }
269: 
270:         /* if no formatting, return original name */
271:         if ($name_format != 'first_last' && $name_format != 'last_first') {
272:             return $ob->getValue('name');
273:         }
274: 
275:         /* See if we have the name fields split out explicitly. */
276:         if ($ob->hasValue('firstname') && $ob->hasValue('lastname')) {
277:             if ($name_format == 'last_first') {
278:                 return $ob->getValue('lastname') . ', ' . $ob->getValue('firstname');
279:             } else {
280:                 return $ob->getValue('firstname') . ' ' . $ob->getValue('lastname');
281:             }
282:         } else {
283:             /* One field, we'll have to guess. */
284:             $name = $ob->getValue('name');
285:             $lastname = self::guessLastname($name);
286:             if ($name_format == 'last_first' &&
287:                 !is_int(strpos($name, ',')) &&
288:                 Horde_String::length($name) > Horde_String::length($lastname)) {
289:                 $name = preg_replace('/\s+' . preg_quote($lastname, '/') . '/', '', $name);
290:                 $name = $lastname . ', ' . $name;
291:             }
292:             if ($name_format == 'first_last' &&
293:                 is_int(strpos($name, ',')) &&
294:                 Horde_String::length($name) > Horde_String::length($lastname)) {
295:                 $name = preg_replace('/' . preg_quote($lastname, '/') . ',\s*/', '', $name);
296:                 $name = $name . ' ' . $lastname;
297:             }
298: 
299:             return $name;
300:         }
301:     }
302: 
303:     /**
304:      * @todo Consolidate on a single mail/compose method.
305:      *
306:      * @param mixed $data  Either a single email address or an array of email
307:      *                     addresses to format.
308:      * @param string $name  The personal name phrase.
309:      *
310:      * @return mixed Either the formatted address or an array of formatted
311:      *               addresses.
312:      */
313:     static public function formatEmailAddresses($data, $name)
314:     {
315:         global $registry;
316:         static $useRegistry;
317: 
318:         if (!isset($useRegistry)) {
319:             $useRegistry = $registry->hasMethod('mail/batchCompose');
320:         }
321: 
322:         $array = is_array($data);
323:         if (!$array) {
324:             $data = array($data);
325:         }
326: 
327:         $addresses = array();
328:         foreach ($data as $i => $email_vals) {
329:             $email_vals = explode(',', $email_vals);
330:             foreach ($email_vals as $j => $email_val) {
331:                 $email_val = trim($email_val);
332: 
333:                 // Format the address according to RFC822.
334:                 $mailbox_host = explode('@', $email_val);
335:                 if (!isset($mailbox_host[1])) {
336:                     $mailbox_host[1] = '';
337:                 }
338:                 $address = Horde_Mime_Address::writeAddress($mailbox_host[0], $mailbox_host[1], $name);
339: 
340:                 // Get rid of the trailing @ (when no host is included in
341:                 // the email address).
342:                 $addresses[$i . ':' . $j] = array('to' => addslashes(str_replace('@>', '>', $address)));
343:             }
344:         }
345: 
346:         if ($useRegistry) {
347:             try {
348:                 $addresses = $GLOBALS['registry']->call('mail/batchCompose', array($addresses));
349:             } catch (Horde_Exception $e) {
350:                 $useRegistry = false;
351:                 $addresses = array();
352:             }
353:         } else {
354:             $addresses = array();
355:         }
356: 
357:         foreach ($data as $i => $email_vals) {
358:             $email_vals = explode(',', $email_vals);
359:             $email_values = false;
360:             foreach ($email_vals as $j => $email_val) {
361:                 if (isset($addresses[$i . ':' . $j])) {
362:                     $mail_link = $addresses[$i . ':' . $j];
363:                 } else {
364:                     $mail_link = 'mailto:' . urlencode($email_val);
365:                 }
366: 
367:                 $email_value = Horde::link($mail_link) . htmlspecialchars($email_val) . '</a>';
368:                 if ($email_values) {
369:                     $email_values .= ', ' . $email_value;
370:                 } else {
371:                     $email_values = $email_value;
372:                 }
373:             }
374:         }
375: 
376:         if ($array) {
377:             return $email_values[0];
378:         } else {
379:             return $email_values;
380:         }
381:     }
382: 
383:     /**
384:      * Returns the real name, if available, of a user.
385:      *
386:      * @param string $uid  The uid of the name to return.
387:      *
388:      * @return string  The user's full, real name.
389:      */
390:     static public function getUserName($uid)
391:     {
392:         static $names = array();
393: 
394:         if (!isset($names[$uid])) {
395:             $ident = $GLOBALS['injector']->getInstance('Horde_Core_Factory_Identity')->create($uid);
396:             $ident->setDefault($ident->getDefault());
397:             $names[$uid] = $ident->getValue('fullname');
398:             if (empty($names[$uid])) {
399:                 $names[$uid] = $uid;
400:             }
401:         }
402: 
403:         return $names[$uid];
404:     }
405: 
406:     /**
407:      * Gets extended permissions on an address book.
408:      *
409:      * @param Turba_Driver $addressBook  The address book to get extended
410:      *                                   permissions for.
411:      * @param string $permission         What extended permission to get.
412:      *
413:      * @return mixed  The requested extended permissions value, or true if it
414:      *                doesn't exist.
415:      */
416:     static public function getExtendedPermission(Turba_Driver $addressBook, $permission)
417:     {
418:         // We want to check the base source as extended permissions
419:         // are enforced per backend, not per share.
420:         $key = $addressBook->getName() . ':' . $permission;
421: 
422:         $perms = $GLOBALS['injector']->getInstance('Horde_Perms');
423:         if (!$perms->exists('turba:sources:' . $key)) {
424:             return true;
425:         }
426: 
427:         $allowed = $perms->getPermissions('turba:sources:' . $key, $GLOBALS['registry']->getAuth());
428:         if (is_array($allowed)) {
429:             switch ($permission) {
430:             case 'max_contacts':
431:                 $allowed = max($allowed);
432:                 break;
433:             }
434:         }
435:         return $allowed;
436:     }
437: 
438:     /**
439:      * Filters data based on permissions.
440:      *
441:      * @param array $in            The data we want filtered.
442:      * @param string $filter       What type of data we are filtering.
443:      * @param integer $permission  The Horde_Perms::* constant we will filter
444:      *                             on.
445:      * @param array $options       Additional options.
446:      *
447:      * @return array  The filtered data.
448:      */
449:     static public function permissionsFilter(array $in, $permission = Horde_Perms::READ, array $options = array())
450:     {
451:         $out = array();
452: 
453:         foreach ($in as $sourceId => $source) {
454:             try {
455:                 $driver = $GLOBALS['injector']->getInstance('Turba_Factory_Driver')->create($sourceId);
456:             } catch (Turba_Exception $e) {
457:                 Horde::logMessage($e, 'ERR');
458:                 continue;
459:             }
460: 
461:             if ($driver->hasPermission($permission)) {
462:                 if (!empty($options['require_add']) && !$driver->canAdd()) {
463:                     continue;
464:                 }
465:                 $out[$sourceId] = $source;
466:             }
467:         }
468: 
469:         return $out;
470:     }
471: 
472:     /**
473:      * Replaces all share-enabled sources in a source list with all shares
474:      * from this source that the current user has access to.
475:      *
476:      * This will only sync shares that are unique to Horde (such as a SQL
477:      * source).  Any backend that supports ACLs or similar mechanism should be
478:      * configured from within backends.php or via Horde's share_* hooks.
479:      *
480:      * @param array $sources  The default $cfgSources array.
481:      *
482:      * @return array  The $cfgSources array.
483:      */
484:     static public function getConfigFromShares(array $sources)
485:     {
486:         try {
487:             $shares = self::listShares();
488:         } catch (Horde_Share_Exception $e) {
489:             // Notify the user if we failed, but still return the $cfgSource
490:             // array.
491:             $GLOBALS['notification']->push($e, 'horde.error');
492:             return $sources;
493:         }
494: 
495:         /* See if any of our sources are configured to handle all otherwise
496:          * unassigned Horde_Share objects. */
497:         $all_shares = null;
498:         foreach ($sources as $key => $cfg) {
499:             if (!empty($cfg['all_shares'])) {
500:                 // Indicate the source handler that catches unassigned shares.
501:                 $all_shares = $key;
502:             }
503:         }
504: 
505:         $sortedSources = $defaults = $vbooks = array();
506:         $personal = false;
507:         foreach ($shares as $name => &$share) {
508:             if (isset($sources[$name])) {
509:                 continue;
510:             }
511: 
512:             $personal |= $share->get('owner') == $GLOBALS['registry']->getAuth();
513: 
514:             $params = @unserialize($share->get('params'));
515:             if (empty($params['source']) && !empty($all_shares)) {
516:                 $params['source'] = $all_shares;
517:             }
518:             if (isset($params['type']) && $params['type'] == 'vbook') {
519:                 // We load vbooks last in case they're based on other shares.
520:                 $params['share'] = $share;
521:                 $vbooks[$name] = $params;
522:             } elseif (!empty($params['source']) &&
523:                       !empty($sources[$params['source']]['use_shares'])) {
524:                 if (empty($params['name'])) {
525:                     $params['name'] = $name;
526:                     $share->set('params', serialize($params));
527:                     try {
528:                         $share->save();
529:                     } catch (Horde_Share_Exception $e) {
530:                         Horde::logMessage($e, 'ERR');
531:                     }
532:                 }
533: 
534:                 $info = $sources[$params['source']];
535:                 $info['params']['config'] = $sources[$params['source']];
536:                 $info['params']['config']['params']['share'] = $share;
537:                 $info['params']['config']['params']['name'] = $params['name'];
538:                 $info['title'] = $share->get('name');
539:                 $info['type'] = 'share';
540:                 $info['use_shares'] = false;
541:                 $sortedSources[$params['source']][$name] = $info;
542:             }
543:         }
544: 
545:         // Check for the user's default share and built new source list.
546:         $newSources = array();
547:         foreach (array_keys($sources) as $source) {
548:             if (empty($sources[$source]['use_shares'])) {
549:                 $newSources[$source] = $sources[$source];
550:                 continue;
551:             }
552:             if (isset($sortedSources[$source])) {
553:                 $newSources = array_merge($newSources, $sortedSources[$source]);
554:             }
555:             if (!empty($GLOBALS['conf']['share']['auto_create']) &&
556:                 $GLOBALS['registry']->getAuth() && !$personal) {
557: 
558:                 // User's default share is missing.
559:                 try {
560:                     $driver = $GLOBALS['injector']->getInstance('Turba_Factory_Driver')->create($source);
561:                 } catch (Turba_Exception $e) {
562:                     $GLOBALS['notification']->push($e->getMessage(), 'horde.error');
563:                     continue;
564:                 }
565: 
566:                 $sourceKey = strval(new Horde_Support_Randomid());
567:                 try {
568:                     $share = $driver->createShare(
569:                         $sourceKey,
570:                         array(
571:                             'params' => array(
572:                                 'source' => $source,
573:                                 'default' => true,
574:                                 'name' => $GLOBALS['registry']->getAuth()
575:                             )
576:                         )
577:                     );
578:                 } catch (Horde_Share_Exception $e) {
579:                     Horde::logMessage($e, 'ERR');
580:                     continue;
581:                 }
582: 
583:                 $source_config = $sources[$source];
584:                 $source_config['params']['share'] = $share;
585:                 $newSources[$sourceKey] = $source_config;
586:                 $personal = true;
587:             }
588:         }
589: 
590:         // Add vbooks now that all available address books are loaded.
591:         foreach ($vbooks as $name => $params) {
592:             if (!isset($newSources[$params['source']])) {
593:                 continue;
594:             }
595:             $newSources[$name] = array(
596:                 'title' => $shares[$name]->get('name'),
597:                 'type' => 'vbook',
598:                 'params' => $params,
599:                 'export' => true,
600:                 'browse' => true,
601:                 'map' => $newSources[$params['source']]['map'],
602:                 'search' => $newSources[$params['source']]['search'],
603:                 'strict' => $newSources[$params['source']]['strict'],
604:                 'use_shares' => false,
605:             );
606:         }
607: 
608:         return $newSources;
609:     }
610: 
611:     /**
612:      * Retrieve a new source config entry based on a Turba share.
613:      *
614:      * @param Horde_Share object  The share to base config on.
615:      *
616:      * @return array  The $cfgSource entry for this share source.
617:      */
618:     static public function getSourceFromShare(Horde_Share $share)
619:     {
620:         // Require a fresh config file.
621:         $cfgSources = Turba::availableSources();
622: 
623:         $params = @unserialize($share->get('params'));
624:         $newConfig = $cfgSources[$params['source']];
625:         $newConfig['params']['config'] = $cfgSources[$params['source']];
626:         $newConfig['params']['config']['params']['share'] = $share;
627:         $newConfig['params']['config']['params']['name'] = $params['name'];
628:         $newConfig['title'] = $share->get('name');
629:         $newConfig['type'] = 'share';
630:         $newConfig['use_shares'] = false;
631: 
632:         return $newConfig;
633:     }
634: 
635:     /**
636:      * Returns all shares the current user has specified permissions to.
637:      *
638:      * @param boolean $owneronly   Only return address books owned by the user?
639:      *                             Defaults to false.
640:      * @param integer $permission  Permissions to filter by.
641:      *
642:      * @return array  Shares the user has the requested permissions to.
643:      */
644:     static public function listShares($owneronly = false, $permission = Horde_Perms::READ)
645:     {
646:         if (!$GLOBALS['session']->get('turba', 'has_share')) {
647:             // No backends are configured to provide shares
648:             return array();
649:         }
650:         if ($owneronly && !$GLOBALS['registry']->getAuth()) {
651:             return array();
652:         }
653: 
654:         try {
655:             $sources = $GLOBALS['turba_shares']->listShares(
656:                 $GLOBALS['registry']->getAuth(),
657:                 array('perm' => $permission,
658:                       'attributes' => $owneronly ? $GLOBALS['registry']->getAuth() : null));
659:         } catch (Horde_Share_Exception $e) {
660:             Horde::logMessage($e, 'ERR');
661:             return array();
662:         }
663: 
664:         return $sources;
665:     }
666: 
667:     /**
668:      * Create a new Turba share.
669:      *
670:      * @param string $share_name  The id for the new share.
671:      * @param array  $params      Parameters for the new share.
672:      *
673:      * @return Horde_Share  The new share object.
674:      * @throws Turba_Exception
675:      */
676:     static public function createShare($share_name, $params)
677:     {
678:         if (!isset($params['name'])) {
679:             /* Sensible default for empty display names */
680:             $identity = $GLOBALS['injector']->getInstance('Horde_Core_Factory_Identity')->create();
681:             $name = sprintf(_("Address book of %s"), $identity->getName());
682:         } else {
683:             $name = $params['name'];
684:             unset($params['name']);
685:         }
686: 
687:         /* Generate the new share. */
688:         try {
689:             $share = $GLOBALS['turba_shares']->newShare($GLOBALS['registry']->getAuth(), $share_name, $name);
690: 
691:             /* Now any other params. */
692:             foreach ($params as $key => $value) {
693:                 if (!is_scalar($value)) {
694:                     $value = serialize($value);
695:                 }
696:                 $share->set($key, $value);
697:             }
698:             $GLOBALS['turba_shares']->addShare($share);
699:             $result = $share->save();
700:         } catch (Horde_Share_Exception $e) {
701:             Horde::logMessage($e, 'ERR');
702:             throw new Turba_Exception($e);
703:         }
704: 
705:         /* Update share_id as backends like Kolab change it to the IMAP folder
706:          * name. */
707:         $share_name = $share->getName();
708: 
709:         /* Add the new addressbook to the user's list of visible address
710:          * books. */
711:         $prefs = json_decode($GLOBALS['prefs']->getValue('addressbooks'), true);
712:         if (!is_array($prefs) || array_search($share_name, $prefs) === false) {
713:             $prefs[] = $share_name;
714:             $GLOBALS['prefs']->setValue('addressbooks', json_encode($prefs));
715:         }
716: 
717:         return $share;
718:     }
719: 
720:     /**
721:      * Add browse.js javascript to page.
722:      */
723:     static public function addBrowseJs()
724:     {
725:         Horde::addScriptFile('browse.js', 'turba');
726:         Horde::addInlineJsVars(array(
727:             'TurbaBrowse.confirmdelete' => _("Are you sure that you want to delete %s?"),
728:             'TurbaBrowse.contact1' => _("You must select at least one contact first."),
729:             'TurbaBrowse.contact2' => _("You must select a target contact list."),
730:             'TurbaBrowse.contact3' => _("Please name the new contact list:"),
731:             'TurbaBrowse.copymove' => _("You must select a target address book."),
732:             'TurbaBrowse.submit' => _("Are you sure that you want to delete the selected contacts?")
733:         ));
734:     }
735: 
736: }
737: 
API documentation generated by ApiGen