1: <?php
2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19:
20: class Horde_Registry
21: {
22:
23: const SESSION_NONE = 1;
24: const SESSION_READONLY = 2;
25:
26:
27: const AUTH_FAILURE = 1;
28: const NOT_ACTIVE = 2;
29: const PERMISSION_DENIED = 3;
30: const HOOK_FATAL = 4;
31:
32: 33: 34: 35: 36:
37: public $applications = array();
38:
39: 40: 41: 42: 43:
44: public $initialApp;
45:
46: 47: 48: 49: 50:
51: public $nlsconfig;
52:
53: 54: 55: 56: 57:
58: protected $_appStack = array();
59:
60: 61: 62: 63: 64:
65: protected $_apis;
66:
67: 68: 69: 70: 71:
72: protected $_apiList = array();
73:
74: 75: 76: 77: 78:
79: protected $_appsinit = array();
80:
81: 82: 83: 84: 85:
86: protected $_args = array();
87:
88: 89: 90: 91: 92:
93: protected $_confCache = array();
94:
95: 96: 97: 98: 99:
100: protected $_interfaces = array();
101:
102: 103: 104: 105: 106:
107: protected $_obCache = array();
108:
109: 110: 111: 112: 113:
114: protected $_regmtime;
115:
116: 117: 118: 119: 120:
121: protected $_vhost = null;
122:
123: 124: 125: 126: 127: 128: 129: 130: 131: 132: 133: 134: 135: 136: 137: 138: 139: 140: 141: 142: 143: 144: 145: 146: 147: 148: 149: 150: 151: 152: 153: 154: 155: 156: 157: 158: 159: 160: 161: 162: 163: 164: 165: 166: 167: 168: 169: 170: 171: 172: 173: 174: 175: 176: 177: 178: 179:
180: static public function appInit($app, $args = array())
181: {
182: if (isset($GLOBALS['registry'])) {
183: $appOb = $GLOBALS['registry']->getApiInstance($app, 'application');
184: $appOb->init();
185: return $appOb;
186: }
187:
188: $args = array_merge(array(
189: 'admin' => false,
190: 'authentication' => null,
191: 'cli' => null,
192: 'nocompress' => false,
193: 'nologintasks' => false,
194: 'session_cache_limiter' => null,
195: 'session_control' => null,
196: 'timezone' => false,
197: 'user_admin' => null
198: ), $args);
199:
200:
201: if ($args['cli']) {
202:
203: if (!Horde_Cli::runningFromCLI()) {
204: throw new Horde_Exception('Script must be run from the command line');
205: }
206:
207: 208:
209: $GLOBALS['cli'] = Horde_Cli::init();
210:
211: $args['nocompress'] = true;
212: $args['authentication'] = 'none';
213: }
214:
215:
216: $s_ctrl = 0;
217: switch ($args['session_control']) {
218: case 'netscape':
219:
220:
221:
222: $browser = new Horde_Browser();
223: if ($browser->isBrowser('mozilla')) {
224: $args['session_cache_limiter'] = 'private, must-revalidate';
225: }
226: break;
227:
228: case 'none':
229: $s_ctrl = self::SESSION_NONE;
230: break;
231:
232: case 'readonly':
233: $s_ctrl = self::SESSION_READONLY;
234: break;
235: }
236:
237: $classname = __CLASS__;
238: $registry = $GLOBALS['registry'] = new $classname($s_ctrl, $args);
239: $registry->initialApp = $app;
240:
241: $appob = $registry->getApiInstance($app, 'application');
242: $appob->initParams = $args;
243:
244: try {
245: $registry->pushApp($app, array('check_perms' => ($args['authentication'] != 'none'), 'logintasks' => !$args['nologintasks'], 'notransparent' => !empty($args['notransparent'])));
246:
247: if ($args['admin'] && !$registry->isAdmin()) {
248: throw new Horde_Exception('Not an admin');
249: }
250: } catch (Horde_Exception $e) {
251: $appob->appInitFailure($e);
252:
253: if ($args['authentication'] == 'throw') {
254: throw $e;
255: }
256:
257: $registry->authenticateFailure($app, $e);
258: }
259:
260: if ($args['timezone']) {
261: $registry->setTimeZone();
262: }
263:
264: if (!$args['nocompress']) {
265: Horde::compressOutput();
266: }
267:
268: if ($args['user_admin']) {
269: if (empty($GLOBALS['conf']['auth']['admins'])) {
270: throw new Horde_Exception('No admin users defined in configuration.');
271: }
272: $registry->setAuth(reset($GLOBALS['conf']['auth']['admins']), array());
273: }
274:
275: $appob->init();
276:
277: return $appob;
278: }
279:
280: 281: 282: 283: 284: 285: 286: 287:
288: public function __construct($session_flags = 0, array $args = array())
289: {
290:
291: $this->_args = $args;
292:
293:
294: $callbacks = array(
295: 'Horde_Mime' => 'Horde_Core_Autoloader_Callback_Mime',
296: 'Horde_Nls' => 'Horde_Core_Autoloader_Callback_Nls',
297: );
298:
299: 300: 301:
302: $factories = array(
303: 'Horde_ActiveSyncBackend' => 'Horde_Core_Factory_ActiveSyncBackend',
304: 'Horde_ActiveSyncServer' => 'Horde_Core_Factory_ActiveSyncServer',
305: 'Horde_ActiveSyncState' => 'Horde_Core_Factory_ActiveSyncState',
306: 'Horde_Alarm' => 'Horde_Core_Factory_Alarm',
307: 'Horde_Browser' => 'Horde_Core_Factory_Browser',
308: 'Horde_Cache' => 'Horde_Core_Factory_Cache',
309: 'Horde_Controller_Request' => 'Horde_Core_Factory_Request',
310: 'Horde_Controller_RequestConfiguration' => array(
311: 'Horde_Core_Controller_RequestMapper',
312: 'getRequestConfiguration',
313: ),
314: 'Horde_Core_Auth_Signup' => 'Horde_Core_Factory_AuthSignup',
315: 'Horde_Core_Perms' => 'Horde_Core_Factory_PermsCore',
316: 'Horde_Db_Adapter' => 'Horde_Core_Factory_DbBase',
317: 'Horde_Editor' => 'Horde_Core_Factory_Editor',
318: 'Horde_Group' => 'Horde_Core_Factory_Group',
319: 'Horde_History' => 'Horde_Core_Factory_History',
320: 'Horde_Log_Logger' => 'Horde_Core_Factory_Logger',
321: 'Horde_Service_Facebook' => 'Horde_Core_Factory_Facebook',
322: 'Horde_Kolab_Server_Composite' => 'Horde_Core_Factory_KolabServer',
323: 'Horde_Kolab_Session' => 'Horde_Core_Factory_KolabSession',
324: 'Horde_Kolab_Storage' => 'Horde_Core_Factory_KolabStorage',
325: 'Horde_Lock' => 'Horde_Core_Factory_Lock',
326: 'Horde_Mail' => 'Horde_Core_Factory_Mail',
327: 'Horde_Memcache' => 'Horde_Core_Factory_Memcache',
328: 'Horde_Notification' => 'Horde_Core_Factory_Notification',
329: 'Horde_Perms' => 'Horde_Core_Factory_Perms',
330: 'Horde_Routes_Mapper' => 'Horde_Core_Factory_Mapper',
331: 'Horde_Routes_Matcher' => 'Horde_Core_Factory_Matcher',
332: 'Horde_Secret' => 'Horde_Core_Factory_Secret',
333: 'Horde_Service_Facebook' => 'Horde_Core_Factory_Facebook',
334: 'Horde_Service_Twitter' => 'Horde_Core_Factory_Twitter',
335: 'Horde_SessionHandler' => 'Horde_Core_Factory_SessionHandler',
336: 'Horde_Template' => 'Horde_Core_Factory_Template',
337: 'Horde_Token' => 'Horde_Core_Factory_Token',
338: 'Horde_Service_UrlShortener' => 'Horde_Core_Factory_UrlShortener',
339: 'Horde_View' => 'Horde_Core_Factory_View',
340: 'Horde_View_Base' => 'Horde_Core_Factory_View',
341: 'Horde_Weather' => 'Horde_Core_Factory_Weather',
342: 'Net_DNS2_Resolver' => 'Horde_Core_Factory_Dns',
343: );
344:
345:
346: $implementations = array(
347: 'Horde_Controller_ResponseWriter' => 'Horde_Controller_ResponseWriter_Web',
348: );
349:
350:
351: $GLOBALS['injector'] = $injector = new Horde_Injector(new Horde_Injector_TopLevel());
352:
353: foreach ($factories as $key => $val) {
354: if (is_string($val)) {
355: $val = array($val, 'create');
356: }
357: $injector->bindFactory($key, $val[0], $val[1]);
358: }
359: foreach ($implementations as $key => $val) {
360: $injector->bindImplementation($key, $val);
361: }
362:
363: $GLOBALS['registry'] = $this;
364: $injector->setInstance(__CLASS__, $this);
365:
366: 367:
368: $injector->setInstance('Horde_Autoloader', $GLOBALS['__autoloader']);
369: foreach ($callbacks as $key => $val) {
370: $GLOBALS['__autoloader']->addCallback($key, array($val, 'callback'));
371: }
372:
373: 374: 375: 376: 377:
378: $this->importConfig('horde');
379: $conf = $GLOBALS['conf'];
380:
381:
382: $GLOBALS['browser'] = $injector->getInstance('Horde_Browser');
383:
384:
385:
386: 387:
388: if (!Horde_Cli::runningFromCLI()) {
389: set_time_limit($conf['max_exec_time']);
390: }
391:
392: 393:
394: error_reporting($conf['debug_level']);
395:
396:
397: if (isset($conf['umask'])) {
398: umask($conf['umask']);
399: }
400:
401:
402: $this->_regmtime = max(filemtime(HORDE_BASE . '/config/registry.php'),
403: filemtime(HORDE_BASE . '/config/registry.d'));
404: if (file_exists(HORDE_BASE . '/config/registry.local.php')) {
405: $this->_regmtime = max($this->_regmtime, filemtime(HORDE_BASE . '/config/registry.local.php'));
406: }
407: if (!empty($conf['vhosts'])) {
408: $this->_vhost = HORDE_BASE . '/config/registry-' . $conf['server']['name'] . '.php';
409: if (file_exists($this->_vhost)) {
410: $this->_regmtime = max($this->_regmtime, filemtime($this->_vhost));
411: } else {
412: $this->_vhost = null;
413: }
414: }
415:
416:
417: if ($session_flags & self::SESSION_NONE) {
418: 419:
420: $GLOBALS['session'] = $session = new Horde_Session_Null();
421: } elseif (PHP_SAPI == 'cli' ||
422: ((PHP_SAPI == 'cgi' || PHP_SAPI == 'cgi-fcgi') &&
423: empty($_SERVER['SERVER_NAME']))) {
424: $GLOBALS['session'] = $session = new Horde_Session();
425: $session->setup(false, $args['session_cache_limiter']);
426: } else {
427: $GLOBALS['session'] = $session = new Horde_Session();
428: $session->setup(true, $args['session_cache_limiter']);
429: if ($session_flags & self::SESSION_READONLY) {
430: 431:
432: $session->close();
433: }
434: }
435: $injector->setInstance('Horde_Session', $session);
436:
437:
438: $this->_loadApplications();
439:
440:
441: $this->nlsconfig = new Horde_Registry_Nlsconfig();
442:
443:
444: $this->setLanguageEnvironment(null, 'horde');
445:
446:
447: if ($this->applications['horde']['status'] == 'inactive') {
448: throw new Horde_Exception(Horde_Core_Translation::t("This system is currently deactivated."));
449: }
450:
451: 452: 453:
454: $GLOBALS['notification'] = $injector->getInstance('Horde_Notification');
455: if (Horde_Util::getFormData('ajaxui') &&
456: ($override = $session->get('horde', 'notification_override'))) {
457: require_once $override[0];
458: $GLOBALS['notification']->attach('status', null, $override[1]);
459: } else {
460: $GLOBALS['notification']->attach('status');
461: }
462:
463: register_shutdown_function(array($this, 'shutdown'));
464: }
465:
466: 467: 468:
469: public function shutdown()
470: {
471:
472: if (!empty($GLOBALS['conf']['log_accesskeys'])) {
473: Horde::getAccessKey(null, null, true);
474: }
475:
476:
477: if (function_exists('memory_get_peak_usage')) {
478: Horde::logMessage('Max memory usage: ' . memory_get_peak_usage(true) . ' bytes', 'DEBUG');
479: }
480: }
481:
482: 483: 484:
485: public function __get($api)
486: {
487: if (in_array($api, $this->listAPIs())) {
488: return new Horde_Registry_Caller($this, $api);
489: }
490: }
491:
492: 493: 494: 495: 496:
497: public function __clone()
498: {
499: throw new Horde_Exception('Registry objects should never be cloned.');
500: }
501:
502: 503: 504: 505: 506:
507: public function __sleep()
508: {
509: throw new Horde_Exception('Registry objects should never be serialized.');
510: }
511:
512: 513: 514:
515: public function rebuild()
516: {
517: $app = $this->getApp();
518:
519: $this->applications = $this->_apiList = $this->_confCache = $this->_interfaces = array();
520: unset($this->_apis);
521:
522: $GLOBALS['session']->remove('horde', 'nls/');
523: $GLOBALS['session']->remove('horde', 'registry/');
524: $this->_saveCache('apis');
525: $this->_saveCache('app');
526:
527: $this->_loadApplications();
528:
529: $this->importConfig('horde');
530: $this->importConfig($app);
531: }
532:
533: 534: 535:
536: protected function _loadApplications()
537: {
538:
539: if ($ret = $this->_loadCache('app')) {
540: $this->applications = $ret[0];
541: $this->_interfaces = $ret[1];
542: return;
543: }
544:
545:
546: if (!file_exists(HORDE_BASE . '/config/registry.php')) {
547: throw new Horde_Exception('Missing registry.php configuration file');
548: }
549:
550: 551:
552: if ($this->getApp() != 'horde') {
553: textdomain('horde');
554: }
555:
556: require HORDE_BASE . '/config/registry.php';
557: if ($files = glob(HORDE_BASE . '/config/registry.d/*.php')) {
558: foreach ($files as $r) {
559: include $r;
560: }
561: }
562: if (file_exists(HORDE_BASE . '/config/registry.local.php')) {
563: include HORDE_BASE . '/config/registry.local.php';
564: }
565: if ($this->_vhost) {
566: include $this->_vhost;
567: }
568:
569:
570: if ($this->getApp() != 'horde') {
571: textdomain($this->getApp());
572: }
573:
574: if (!isset($this->applications['horde']['fileroot'])) {
575: $this->applications['horde']['fileroot'] = isset($app_fileroot)
576: ? $app_fileroot
577: : HORDE_BASE;
578: }
579: if (!isset($app_fileroot)) {
580: $app_fileroot = $this->applications['horde']['fileroot'];
581: }
582:
583: 584:
585: $app_fileroot = rtrim($app_fileroot, '/') . '/';
586:
587: if (!isset($this->applications['horde']['webroot'])) {
588: $this->applications['horde']['webroot'] = isset($app_webroot)
589: ? $app_webroot
590: : $this->_detectWebroot();
591: }
592: if (!isset($app_webroot)) {
593: $app_webroot = $this->applications['horde']['webroot'];
594: }
595:
596: 597:
598: foreach ($this->applications as $appName => &$app) {
599: if (!isset($app['status'])) {
600: $app['status'] = 'active';
601: } elseif ($app['status'] == 'heading' ||
602: $app['status'] == 'sidebar') {
603: continue;
604: }
605:
606: $app['fileroot'] = isset($app['fileroot'])
607: ? rtrim($app['fileroot'], ' /')
608: : $app_fileroot . $appName;
609:
610: if (!isset($app['name'])) {
611: $app['name'] = '';
612: }
613:
614: if (!file_exists($app['fileroot']) ||
615: (empty($this->_args['test']) &&
616: file_exists($app['fileroot'] . '/config/conf.xml') &&
617: !file_exists($app['fileroot'] . '/config/conf.php'))) {
618: $app['status'] = 'inactive';
619: Horde::logMessage('Setting ' . $appName . ' inactive because the fileroot does not exist or the application is not configured yet.', 'DEBUG');
620: }
621:
622: $app['webroot'] = isset($app['webroot'])
623: ? rtrim($app['webroot'], ' /')
624: : $app_webroot . '/' . $appName;
625:
626: if (($app['status'] != 'inactive') &&
627: isset($app['provides']) &&
628: (($app['status'] != 'admin') || $this->isAdmin())) {
629: if (is_array($app['provides'])) {
630: foreach ($app['provides'] as $interface) {
631: $this->_interfaces[$interface] = $appName;
632: }
633: } else {
634: $this->_interfaces[$app['provides']] = $appName;
635: }
636: }
637:
638: if (!isset($app['templates']) && isset($app['fileroot'])) {
639: $app['templates'] = $app['fileroot'] . '/templates';
640: }
641: if (!isset($app['jsuri']) && isset($app['webroot'])) {
642: $app['jsuri'] = $app['webroot'] . '/js';
643: }
644: if (!isset($app['jsfs']) && isset($app['fileroot'])) {
645: $app['jsfs'] = $app['fileroot'] . '/js';
646: }
647: if (!isset($app['themesuri']) && isset($app['webroot'])) {
648: $app['themesuri'] = $app['webroot'] . '/themes';
649: }
650: if (!isset($app['themesfs']) && isset($app['fileroot'])) {
651: $app['themesfs'] = $app['fileroot'] . '/themes';
652: }
653: }
654:
655: $this->_saveCache('app', array(
656: $this->applications,
657: $this->_interfaces
658: ));
659: }
660:
661: 662: 663: 664: 665:
666: protected function _detectWebroot()
667: {
668:
669:
670: if (isset($_SERVER['SCRIPT_URL']) || isset($_SERVER['SCRIPT_NAME'])) {
671: $path = empty($_SERVER['SCRIPT_URL'])
672: ? $_SERVER['SCRIPT_NAME']
673: : $_SERVER['SCRIPT_URL'];
674: $hordedir = basename(str_replace(DIRECTORY_SEPARATOR, '/', realpath(HORDE_BASE)));
675: return (preg_match(';/' . $hordedir . ';', $path))
676: ? preg_replace(';/' . $hordedir . '.*;', '/' . $hordedir, $path)
677: : '';
678: }
679:
680: if (!isset($_SERVER['PHP_SELF'])) {
681: return '/horde';
682: }
683:
684: $webroot = preg_split(';/;', $_SERVER['PHP_SELF'], 2, PREG_SPLIT_NO_EMPTY);
685: $webroot = strstr(realpath(HORDE_BASE), DIRECTORY_SEPARATOR . array_shift($webroot));
686: if ($webroot !== false) {
687: return preg_replace(array('/\\\\/', ';/config$;'), array('/', ''), $webroot);
688: }
689:
690: return ($webroot === false)
691: ? ''
692: : '/horde';
693: }
694:
695: 696: 697: 698: 699:
700: protected function _loadApis()
701: {
702: if (isset($this->_apis) ||
703: ($this->_apis = $this->_loadCache('apis'))) {
704: return;
705: }
706:
707:
708: $status = array('active', 'notoolbar', 'hidden');
709: if ($this->isAdmin()) {
710: $status[] = 'admin';
711: } else {
712: $status[] = 'noadmin';
713: }
714:
715: $this->_apis = array();
716:
717: foreach (array_keys($this->applications) as $app) {
718: if (in_array($this->applications[$app]['status'], $status)) {
719: try {
720: $api = $this->getApiInstance($app, 'api');
721: $this->_apis[$app] = array(
722: 'api' => array_diff(get_class_methods($api), array('__construct')),
723: 'links' => $api->links,
724: 'noperms' => $api->noPerms
725: );
726: } catch (Horde_Exception $e) {
727: Horde::logMessage($e, 'DEBUG');
728: }
729: }
730: }
731:
732: $this->_saveCache('apis', $this->_api);
733: }
734:
735: 736: 737: 738: 739: 740: 741: 742: 743:
744: public function getApiInstance($app, $type)
745: {
746: if (isset($this->_obCache[$app][$type])) {
747: return $this->_obCache[$app][$type];
748: }
749:
750: $cname = Horde_String::ucfirst($type);
751:
752: 753:
754: $classname = Horde_String::ucfirst($app) . '_' . $cname;
755: $path = $this->get('fileroot', $app) . '/lib/' . $cname . '.php';
756: if (file_exists($path)) {
757: include_once $path;
758: } else {
759: $classname = __CLASS__ . '_' . $cname;
760: }
761:
762: if (!class_exists($classname, false)) {
763: throw new Horde_Exception("$app does not have an API");
764: }
765:
766: $this->_obCache[$app][$type] = new $classname();
767:
768: return $this->_obCache[$app][$type];
769: }
770:
771: 772: 773: 774: 775: 776: 777: 778: 779: 780: 781: 782: 783:
784: public function listApps($filter = null, $assoc = false,
785: $perms = Horde_Perms::SHOW)
786: {
787: if (is_null($filter)) {
788: $filter = array('notoolbar', 'active');
789: }
790: if (!$this->isAdmin() &&
791: in_array('active', $filter) &&
792: !in_array('noadmin', $filter)) {
793: $filter[] = 'noadmin';
794: }
795:
796: $apps = array();
797: foreach ($this->applications as $app => $params) {
798: if (in_array($params['status'], $filter)) {
799: 800:
801: if (($params['status'] == 'sidebar') &&
802: $this->isInactive($params['app'])) {
803: continue;
804: }
805:
806: if ((is_null($perms) || $this->hasPermission($app, $perms))) {
807: $apps[$app] = $params;
808: }
809: }
810: }
811:
812: return $assoc ? $apps : array_keys($apps);
813: }
814:
815: 816: 817: 818: 819:
820: public function listAllApps($filter = null)
821: {
822:
823: if (is_null($filter)) {
824: $filter = array(
825: 'active', 'admin', 'noadmin', 'hidden', 'inactive', 'notoolbar'
826: );
827: }
828:
829: return $this->listApps($filter, false, null);
830: }
831:
832: 833: 834: 835: 836: 837: 838:
839: public function isInactive($app)
840: {
841: return (!isset($this->applications[$app]) ||
842: ($this->applications[$app]['status'] == 'inactive') ||
843: (($this->applications[$app]['status'] == 'admin') &&
844: !$this->isAdmin()) ||
845: (($this->applications[$app]['status'] == 'noadmin') &&
846: $this->_args['authentication'] != 'none' &&
847: $this->isAdmin()));
848: }
849:
850: 851: 852: 853: 854:
855: public function listAPIs()
856: {
857: if (empty($this->_apiList) && !empty($this->_interfaces)) {
858: $apis = array();
859:
860: foreach (array_keys($this->_interfaces) as $interface) {
861: list($api,) = explode('/', $interface, 2);
862: $apis[$api] = true;
863: }
864:
865: $this->_apiList = array_keys($apis);
866: }
867:
868: return $this->_apiList;
869: }
870:
871: 872: 873: 874: 875: 876: 877: 878: 879:
880: public function listMethods($api = null)
881: {
882: $methods = array();
883:
884: $this->_loadApis();
885:
886: foreach (array_keys($this->applications) as $app) {
887: if (isset($this->applications[$app]['provides'])) {
888: $provides = $this->applications[$app]['provides'];
889: if (!is_array($provides)) {
890: $provides = array($provides);
891: }
892:
893: foreach ($provides as $method) {
894: if (strpos($method, '/') !== false) {
895: if (is_null($api) ||
896: (substr($method, 0, strlen($api)) == $api)) {
897: $methods[$method] = true;
898: }
899: } elseif (isset($this->_apis[$app]) &&
900: (is_null($api) || ($method == $api))) {
901: foreach ($this->_apis[$app]['api'] as $service) {
902: $methods[$method . '/' . $service] = true;
903: }
904: }
905: }
906: }
907: }
908:
909: return array_keys($methods);
910: }
911:
912: 913: 914: 915: 916: 917: 918: 919:
920: public function hasInterface($interface)
921: {
922: return !empty($this->_interfaces[$interface])
923: ? $this->_interfaces[$interface]
924: : false;
925: }
926:
927: 928: 929: 930: 931: 932: 933: 934: 935:
936: public function hasMethod($method, $app = null)
937: {
938: if (is_null($app)) {
939: list($interface, $call) = explode('/', $method, 2);
940: if (!empty($this->_interfaces[$method])) {
941: $app = $this->_interfaces[$method];
942: } elseif (!empty($this->_interfaces[$interface])) {
943: $app = $this->_interfaces[$interface];
944: } else {
945: return false;
946: }
947: } else {
948: $call = $method;
949: }
950:
951: $this->_loadApis();
952:
953: return (isset($this->_apis[$app]) && in_array($call, $this->_apis[$app]['api']))
954: ? $app
955: : false;
956: }
957:
958: 959: 960: 961: 962: 963: 964: 965: 966: 967: 968:
969: public function call($method, $args = array())
970: {
971: list($interface, $call) = explode('/', $method, 2);
972:
973: if (!empty($this->_interfaces[$method])) {
974: $app = $this->_interfaces[$method];
975: } elseif (!empty($this->_interfaces[$interface])) {
976: $app = $this->_interfaces[$interface];
977: } else {
978: throw new Horde_Exception('The method "' . $method . '" is not defined in the Horde Registry.');
979: }
980:
981: return $this->callByPackage($app, $call, $args);
982: }
983:
984: 985: 986: 987: 988: 989: 990: 991: 992: 993: 994: 995: 996: 997:
998: public function callByPackage($app, $call, $args = array(),
999: $options = array())
1000: {
1001: 1002: 1003:
1004: if (!$this->hasMethod($call, $app)) {
1005: throw new Horde_Exception(sprintf('The method "%s" is not defined in the API for %s.', $call, $app));
1006: }
1007:
1008:
1009: $api = $this->getApiInstance($app, 'api');
1010:
1011:
1012: if (!method_exists($api, $call)) {
1013: throw new Horde_Exception('The function implementing ' . $call . ' is not defined in ' . $app . '\'s API.');
1014: }
1015:
1016: 1017: 1018:
1019: $pushed = $this->pushApp($app, array('check_perms' => !in_array($call, $this->_apis[$app]['noperms']) && empty($options['noperms']) && $this->_args['authentication'] != 'none'));
1020:
1021: try {
1022: $result = call_user_func_array(array($api, $call), $args);
1023: if ($result instanceof PEAR_Error) {
1024: throw new Horde_Exception_Wrapped($result);
1025: }
1026: } catch (Horde_Exception $e) {
1027: $result = $e;
1028: }
1029:
1030: 1031:
1032: if ($pushed === true) {
1033: $this->popApp();
1034: }
1035:
1036: if ($result instanceof Horde_Exception) {
1037: throw $e;
1038: }
1039:
1040: return $result;
1041: }
1042:
1043: 1044: 1045: 1046: 1047: 1048: 1049: 1050: 1051: 1052: 1053: 1054: 1055: 1056: 1057: 1058: 1059:
1060: public function callAppMethod($app, $call, array $options = array())
1061: {
1062:
1063: try {
1064: $api = $this->getApiInstance($app, 'application');
1065: } catch (Horde_Exception $e) {
1066: if (empty($options['check_missing'])) {
1067: return null;
1068: }
1069: throw $e;
1070: }
1071:
1072: if (!method_exists($api, $call)) {
1073: if (empty($options['check_missing'])) {
1074: return null;
1075: }
1076: throw new Horde_Exception('Method does not exist.');
1077: }
1078:
1079: 1080: 1081:
1082: $pushed = $this->pushApp($app, array('check_perms' => empty($options['noperms']) && $this->_args['authentication'] != 'none'));
1083:
1084: try {
1085: $result = call_user_func_array(array($api, $call), empty($options['args']) ? array() : $options['args']);
1086: } catch (Horde_Exception $e) {
1087: $result = $e;
1088: }
1089:
1090: 1091:
1092: if ($pushed === true) {
1093: $this->popApp();
1094: }
1095:
1096: if ($result instanceof Exception) {
1097: throw $e;
1098: }
1099:
1100: return $result;
1101: }
1102:
1103: 1104: 1105: 1106: 1107: 1108: 1109: 1110: 1111: 1112: 1113: 1114:
1115: public function link($method, $args = array(), $extra = '')
1116: {
1117: list($interface, $call) = explode('/', $method, 2);
1118:
1119: if (!empty($this->_interfaces[$method])) {
1120: $app = $this->_interfaces[$method];
1121: } elseif (!empty($this->_interfaces[$interface])) {
1122: $app = $this->_interfaces[$interface];
1123: } else {
1124: throw new Horde_Exception('The method "' . $method . '" is not defined in the Horde Registry.');
1125: }
1126:
1127: return $this->linkByPackage($app, $call, $args, $extra);
1128: }
1129:
1130: 1131: 1132: 1133: 1134: 1135: 1136: 1137: 1138: 1139: 1140:
1141: public function linkByPackage($app, $call, $args = array(), $extra = '')
1142: {
1143:
1144: $this->_loadApis();
1145: if (empty($this->_apis[$app]['links'][$call])) {
1146: throw new Horde_Exception('The link ' . $call . ' is not defined in ' . $app . '\'s API.');
1147: }
1148:
1149:
1150: $link = $this->_apis[$app]['links'][$call];
1151:
1152:
1153: foreach ($args as $key => $val) {
1154: $link = str_replace('%' . $key . '%', htmlentities($val), $link);
1155: }
1156: if (isset($this->applications[$app]['webroot'])) {
1157: $link = str_replace('%application%', $this->get('webroot', $app), $link);
1158: }
1159:
1160: 1161: 1162:
1163: $link = preg_replace('|%.+%|U', '', $link);
1164:
1165:
1166: foreach ($args as $key => $val) {
1167: $link = str_replace('|' . Horde_String::lower($key) . '|', urlencode($val), $link);
1168: }
1169:
1170:
1171: if (is_array($extra)) {
1172: $extra_args = '';
1173: foreach ($extra as $key => $val) {
1174: $extra_args .= '&' . urlencode($key) . '=' . urlencode($val);
1175: }
1176: } else {
1177: $extra_args = $extra;
1178: }
1179: $link = str_replace('|extra|', $extra_args, $link);
1180:
1181: 1182: 1183:
1184: $link = preg_replace('|\|.+\||U', '', $link);
1185:
1186: return $link;
1187: }
1188:
1189: 1190: 1191: 1192: 1193: 1194: 1195: 1196: 1197: 1198:
1199: public function applicationFilePath($path, $app = null)
1200: {
1201: if (is_null($app)) {
1202: $app = $this->getApp();
1203: }
1204:
1205: if (!isset($this->applications[$app])) {
1206: throw new Horde_Exception(sprintf(Horde_Core_Translation::t("\"%s\" is not configured in the Horde Registry."), $app));
1207: }
1208:
1209: return str_replace('%application%', $this->applications[$app]['fileroot'], $path);
1210: }
1211:
1212: 1213: 1214: 1215: 1216: 1217: 1218: 1219:
1220: public function applicationWebPath($path, $app = null)
1221: {
1222: if (!isset($app)) {
1223: $app = $this->getApp();
1224: }
1225:
1226: return str_replace('%application%', $this->applications[$app]['webroot'], $path);
1227: }
1228:
1229: 1230: 1231: 1232: 1233: 1234: 1235: 1236: 1237: 1238: 1239: 1240: 1241: 1242: 1243: 1244: 1245: 1246: 1247: 1248: 1249: 1250: 1251: 1252: 1253: 1254: 1255: 1256: 1257: 1258: 1259: 1260:
1261: public function pushApp($app, $options = array())
1262: {
1263: if ($app == $this->getApp()) {
1264: return false;
1265: }
1266:
1267:
1268: if (!isset($this->applications[$app]) || $this->isInactive($app)) {
1269: throw new Horde_Exception($app . ' is not activated.', self::NOT_ACTIVE);
1270: }
1271:
1272: $app_mappers = array(
1273: 'Controller' => 'controllers',
1274: 'Helper' => 'helpers',
1275: 'SettingsExporter' => 'settings'
1276: );
1277:
1278: 1279: 1280:
1281: $autoloader = $GLOBALS['injector']->getInstance('Horde_Autoloader');
1282: $autoloader->addClassPathMapper(new Horde_Autoloader_ClassPathMapper_Prefix('/^' . $app . '(?:$|_)/i', $this->get('fileroot', $app) . '/lib'));
1283:
1284: $applicationMapper = new Horde_Autoloader_ClassPathMapper_Application($this->get('fileroot', $app) . '/app');
1285: foreach ($app_mappers as $key => $val) {
1286: $applicationMapper->addMapping($key, $val);
1287: }
1288: $autoloader->addClassPathMapper($applicationMapper);
1289:
1290: $checkPerms = (!isset($options['check_perms']) ||
1291: !empty($options['check_perms'])) &&
1292: $this->_args['authentication'] != 'none';
1293:
1294: 1295: 1296: 1297: 1298: 1299:
1300: if ($checkPerms) {
1301: if ($this->getAuth() && !$this->checkExistingAuth()) {
1302: throw new Horde_Exception('User is not authorized', self::AUTH_FAILURE);
1303: }
1304:
1305: if (!$this->hasPermission($app, Horde_Perms::READ, array('notransparent' => !empty($options['notransparent'])))) {
1306: if (!$this->isAuthenticated(array('app' => $app))) {
1307: throw new Horde_Exception('User is not authorized for ' . $app, self::AUTH_FAILURE);
1308: }
1309:
1310: Horde::logMessage(sprintf('%s does not have READ permission for %s', $this->getAuth() ? 'User ' . $this->getAuth() : 'Guest user', $app), 'DEBUG');
1311: throw new Horde_Exception(sprintf('%s is not authorized for %s.', $this->getAuth() ? 'User ' . $this->getAuth() : 'Guest user', $this->applications[$app]['name']), self::PERMISSION_DENIED);
1312: }
1313: }
1314:
1315:
1316: $this->_appStack[] = $app;
1317:
1318: 1319: 1320: 1321: 1322: 1323:
1324: $this->setLanguageEnvironment($GLOBALS['language'], $app);
1325:
1326:
1327: $this->importConfig($app);
1328: $this->loadPrefs($app);
1329:
1330:
1331: if (!$checkPerms && (count($this->_appStack) == 1)) {
1332: $this->setLanguageEnvironment(null, $app);
1333: }
1334:
1335:
1336: if (isset($this->_appsinit[$app])) {
1337: unset($this->_appsinit[$app]);
1338: try {
1339: Horde::callHook('appinitialized', array(), $app);
1340: } catch (Horde_Exception_HookNotSet $e) {}
1341: }
1342:
1343:
1344: if (Horde::hookExists('pushapp', $app)) {
1345: try {
1346: Horde::callHook('pushapp', array(), $app);
1347: } catch (Horde_Exception $e) {
1348: $e->setCode(self::HOOK_FATAL);
1349: $this->popApp();
1350: throw $e;
1351: }
1352: }
1353:
1354:
1355: if ($checkPerms || empty($options['noinit'])) {
1356: try {
1357: $this->callAppMethod($app, 'init');
1358: } catch (Horde_Exception $e) {
1359: $this->popApp();
1360: $this->applications[$app]['status'] = 'inactive';
1361: Horde::logMessage($e);
1362: throw $e;
1363: }
1364: }
1365:
1366:
1367: if (Horde::hookExists('pushapp_post', $app)) {
1368: try {
1369: Horde::callHook('pushapp_post', array(), $app);
1370: } catch (Exception $e) {}
1371: }
1372:
1373:
1374: if ($checkPerms &&
1375: ($tasks = $GLOBALS['injector']->getInstance('Horde_Core_Factory_LoginTasks')->create($app)) &&
1376: !empty($options['logintasks'])) {
1377: $tasks->runTasks();
1378: }
1379:
1380: return true;
1381: }
1382:
1383: 1384: 1385: 1386: 1387: 1388: 1389:
1390: public function popApp()
1391: {
1392:
1393: $previous = array_pop($this->_appStack);
1394:
1395: 1396:
1397: $app = $this->getApp();
1398: if ($app) {
1399:
1400: $this->importConfig($app);
1401: $this->loadPrefs($app);
1402: $this->setTextdomain(
1403: $app,
1404: $this->get('fileroot', $app) . '/locale'
1405: );
1406: }
1407:
1408: return $previous;
1409: }
1410:
1411: 1412: 1413: 1414: 1415: 1416:
1417: public function getApp()
1418: {
1419: return end($this->_appStack);
1420: }
1421:
1422: 1423: 1424: 1425: 1426: 1427: 1428: 1429: 1430: 1431: 1432: 1433: 1434:
1435: public function hasPermission($app, $perms = Horde_Perms::READ,
1436: array $params = array())
1437: {
1438: 1439: 1440:
1441: if (!$this->isAuthenticated(array('app' => $app, 'notransparent' => !empty($params['notransparent']))) &&
1442: $GLOBALS['injector']->getInstance('Horde_Core_Factory_Auth')->create($app)->requireAuth() &&
1443: ($perms != Horde_Perms::SHOW)) {
1444: return false;
1445: }
1446:
1447: 1448:
1449: return $this->isAdmin() ||
1450: ($GLOBALS['injector']->getInstance('Horde_Perms')->exists($app)
1451: ? $GLOBALS['injector']->getInstance('Horde_Perms')->hasPermission($app, $this->getAuth(), $perms)
1452: : (bool)$this->getAuth());
1453: }
1454:
1455: 1456: 1457: 1458: 1459: 1460:
1461: public function importConfig($app)
1462: {
1463: if (!isset($this->_confCache[$app])) {
1464: try {
1465: $config = Horde::loadConfiguration('conf.php', 'conf', $app);
1466: } catch (Horde_Exception $e) {
1467: $config = null;
1468: }
1469:
1470: $this->_confCache[$app] = empty($config)
1471: ? array()
1472: : $config;
1473: }
1474:
1475: $GLOBALS['conf'] = ($app == 'horde')
1476: ? $this->_confCache['horde']
1477: : $this->_mergeConfig($this->_confCache['horde'], $this->_confCache[$app]);
1478: }
1479:
1480: 1481: 1482: 1483: 1484: 1485: 1486: 1487: 1488:
1489: protected function _mergeConfig(array $a1, array $a2)
1490: {
1491: foreach ($a2 as $key => $val) {
1492: if (isset($a1[$key]) &&
1493: is_array($a1[$key])) {
1494: reset($a1[$key]);
1495: $a1[$key] = is_int(key($a1[$key]))
1496: ? $val
1497: : $this->_mergeConfig($a1[$key], $val);
1498: } else {
1499: $a1[$key] = $val;
1500: }
1501: }
1502:
1503: return $a1;
1504: }
1505:
1506: 1507: 1508: 1509: 1510: 1511: 1512: 1513: 1514:
1515: public function loadPrefs($app = null)
1516: {
1517: global $injector, $prefs;
1518:
1519: if (strlen($app)) {
1520: $this->pushApp($app);
1521: } elseif (($app = $this->getApp()) === false) {
1522: $app = 'horde';
1523: }
1524:
1525: $user = $this->getAuth();
1526: if ($user) {
1527: if (isset($prefs) && ($prefs->getUser() == $user)) {
1528: $prefs->retrieve($app);
1529: return;
1530: }
1531:
1532: $opts = array(
1533: 'password' => $this->getAuthCredential('password'),
1534: 'user' => $user,
1535: );
1536: } else {
1537: 1538:
1539: $opts = array(
1540: 'driver' => 'Horde_Prefs_Storage_Null'
1541: );
1542: }
1543:
1544: $prefs = $injector->getInstance('Horde_Core_Factory_Prefs')->create($app, $opts);
1545: }
1546:
1547: 1548: 1549: 1550: 1551: 1552: 1553: 1554: 1555: 1556: 1557: 1558:
1559: public function get($parameter, $app = null)
1560: {
1561: if (is_null($app)) {
1562: $app = $this->getApp();
1563: }
1564:
1565: if (isset($this->applications[$app][$parameter])) {
1566: $pval = $this->applications[$app][$parameter];
1567: } elseif ($parameter == 'icon') {
1568: $pval = Horde_Themes::img($app . '.png', $app);
1569: if ((string)$pval == '') {
1570: $pval = Horde_Themes::img('app-unknown.png', 'horde');
1571: }
1572: } else {
1573: $pval = isset($this->applications['horde'][$parameter]) ? $this->applications['horde'][$parameter] : null;
1574: }
1575:
1576: return ($parameter == 'name')
1577: ? (strlen($pval) ? _($pval) : '')
1578: : $pval;
1579: }
1580:
1581: 1582: 1583: 1584: 1585: 1586: 1587: 1588: 1589:
1590: public function getVersion($app = null, $number = false)
1591: {
1592: if (empty($app)) {
1593: $app = $this->getApp();
1594: }
1595:
1596: try {
1597: $api = $this->getApiInstance($app, 'application');
1598: } catch (Horde_Exception $e) {
1599: return 'unknown';
1600: }
1601:
1602: return $number
1603: ? preg_replace('/H\d \((.*)\)/', '$1', $api->version)
1604: : $api->version;
1605: }
1606:
1607: 1608: 1609: 1610: 1611: 1612: 1613:
1614: public function hasMobileView($app = null)
1615: {
1616: if (empty($app)) {
1617: $app = $this->getApp();
1618: }
1619:
1620: try {
1621: $api = $this->getApiInstance($app, 'application');
1622: return !empty($api->mobileView);
1623: } catch (Horde_Exception $e) {
1624: return false;
1625: }
1626: }
1627:
1628: 1629: 1630: 1631: 1632: 1633: 1634:
1635: public function hasAjaxView($app = null)
1636: {
1637: if (empty($app)) {
1638: $app = $this->getApp();
1639: }
1640:
1641: try {
1642: $api = $this->getApiInstance($app, 'application');
1643: return !empty($api->ajaxView);
1644: } catch (Horde_Exception $e) {
1645: return false;
1646: }
1647: }
1648:
1649: 1650: 1651: 1652: 1653: 1654: 1655: 1656: 1657:
1658: public function getAppDrivers($app, $prefix)
1659: {
1660: $classes = array();
1661: $fileprefix = strtr($prefix, '_', '/');
1662: $fileroot = $this->get('fileroot', $app);
1663:
1664: if (!is_null($fileroot)) {
1665: try {
1666: $pushed = $this->pushApp($app);
1667: } catch (Horde_Exception $e) {
1668: if ($e->getCode() == Horde_Registry::AUTH_FAILURE) {
1669: return array();
1670: }
1671: throw $e;
1672: }
1673:
1674: if (is_dir($fileroot . '/lib/' . $fileprefix)) {
1675: try {
1676: $di = new DirectoryIterator($fileroot . '/lib/' . $fileprefix);
1677:
1678: foreach ($di as $val) {
1679: if (!$val->isDir() && !$di->isDot()) {
1680: $class = $app . '_' . $prefix . '_' . basename($val, '.php');
1681: if (class_exists($class)) {
1682: $classes[] = $class;
1683: }
1684: }
1685: }
1686: } catch (UnexpectedValueException $e) {}
1687: }
1688:
1689: if ($pushed) {
1690: $this->popApp();
1691: }
1692: }
1693:
1694: return $classes;
1695: }
1696:
1697: 1698: 1699: 1700: 1701: 1702: 1703: 1704: 1705:
1706: public function getInitialPage($app = null)
1707: {
1708: if (is_null($app)) {
1709: $app = $this->getApp();
1710: }
1711:
1712: if (isset($this->applications[$app])) {
1713: return $this->applications[$app]['webroot'] . '/' . (isset($this->applications[$app]['initial_page']) ? $this->applications[$app]['initial_page'] : '');
1714: }
1715:
1716: throw new Horde_Exception(sprintf(Horde_Core_Translation::t("\"%s\" is not configured in the Horde Registry."), $app));
1717: }
1718:
1719: 1720: 1721: 1722: 1723: 1724: 1725:
1726: protected function _loadCache($name)
1727: {
1728: if (empty($this->_args['test']) &&
1729: ($id = $this->_getCacheId($name))) {
1730: $result = $GLOBALS['injector']->getInstance('Horde_Cache')->get($id, 86400);
1731: if ($result !== false) {
1732: Horde::logMessage(__CLASS__ . ': retrieved ' . $name . ' with cache ID ' . $id, 'DEBUG');
1733: return unserialize($result);
1734: }
1735: }
1736:
1737: return false;
1738: }
1739:
1740: 1741: 1742: 1743: 1744: 1745: 1746: 1747: 1748:
1749: protected function _getCacheId($name, $md5 = null)
1750: {
1751: $id = 'horde_registry|' . $name . '|' . $this->_regmtime;
1752:
1753: if (!is_null($md5) ||
1754: ($md5 = $GLOBALS['session']->get('horde', 'registry/' . $name))) {
1755: return $id . '|' . $md5;
1756: }
1757:
1758: return false;
1759: }
1760:
1761: 1762: 1763: 1764: 1765: 1766:
1767: protected function _saveCache($key, $data = null)
1768: {
1769: if (!empty($this->_args['test'])) {
1770: return;
1771: }
1772:
1773: $ob = $GLOBALS['injector']->getInstance('Horde_Cache');
1774:
1775: if (is_null($data)) {
1776: if ($id = $this->_getCacheId($key)) {
1777:
1778: $ob->expire($id);
1779: }
1780: } else {
1781:
1782: $data = serialize($data);
1783: $md5sum = hash('md5', $data);
1784: $GLOBALS['session']->set('horde', 'registry/' . $key, $md5sum);
1785: $id = $this->_getCacheId($key, $md5sum);
1786: if ($ob->set($id, $data, 86400)) {
1787: Horde::logMessage(__CLASS__ . ': stored ' . $key . ' with cache ID ' . $id, 'DEBUG');
1788: }
1789: }
1790: }
1791:
1792: 1793: 1794: 1795: 1796:
1797: public function getCleanSession()
1798: {
1799: if ($GLOBALS['session']->clean() &&
1800: !empty($GLOBALS['conf']['session']['timeout'])) {
1801:
1802: $secret = $GLOBALS['injector']->getInstance('Horde_Secret');
1803: $secret->setKey('auth');
1804: }
1805: }
1806:
1807: 1808: 1809: 1810: 1811:
1812: public function clearAuth($destroy = true)
1813: {
1814: global $session;
1815:
1816:
1817: foreach (array_keys($session->get('horde', 'auth_app/', Horde_Session::TYPE_ARRAY)) as $app) {
1818: try {
1819: $this->callAppMethod($app, 'logout');
1820: } catch (Horde_Exception $e) {}
1821: }
1822:
1823: $session->remove('horde', 'auth');
1824: $session->remove('horde', 'auth_app/');
1825:
1826:
1827: $GLOBALS['injector']->getInstance('Horde_Core_Factory_Prefs')->clearCache();
1828:
1829: if ($destroy) {
1830: $session->destroy();
1831: }
1832: }
1833:
1834: 1835: 1836: 1837: 1838: 1839: 1840: 1841: 1842: 1843: 1844: 1845: 1846: 1847: 1848:
1849: public function isAdmin(array $options = array())
1850: {
1851: $user = isset($options['user'])
1852: ? $options['user']
1853: : $this->getAuth();
1854:
1855: if ($user &&
1856: @is_array($GLOBALS['conf']['auth']['admins']) &&
1857: in_array($user, $GLOBALS['conf']['auth']['admins'])) {
1858: return true;
1859: }
1860:
1861: return isset($options['permission'])
1862: ? $GLOBALS['injector']->getInstance('Horde_Perms')->hasPermission($options['permission'], $user, isset($options['permlevel']) ? $options['permlevel'] : Horde_Perms::EDIT)
1863: : false;
1864: }
1865:
1866: 1867: 1868: 1869: 1870: 1871: 1872: 1873: 1874: 1875: 1876: 1877: 1878: 1879: 1880:
1881: public function isAuthenticated(array $options = array())
1882: {
1883: $app = empty($options['app'])
1884: ? 'horde'
1885: : $options['app'];
1886:
1887:
1888: if ($this->getAuth() &&
1889: (($app == 'horde') ||
1890: $GLOBALS['session']->exists('horde', 'auth_app/' . $app))) {
1891: if ($this->checkExistingAuth($app)) {
1892: return true;
1893: }
1894: }
1895:
1896:
1897: if (!empty($options['notransparent'])) {
1898: return false;
1899: }
1900: try {
1901: return $GLOBALS['injector']
1902: ->getInstance('Horde_Core_Factory_Auth')
1903: ->create($app)
1904: ->transparent();
1905: } catch (Horde_Exception $e) {
1906: Horde::logMessage($e);
1907: return false;
1908: }
1909: }
1910:
1911: 1912: 1913: 1914: 1915: 1916: 1917: 1918: 1919:
1920: public function authenticateFailure($app = 'horde', $e = null)
1921: {
1922: if (Horde_Cli::runningFromCLI()) {
1923: $cli = new Horde_Cli();
1924: $cli->fatal($e ? $e : Horde_Core_Translation::t("You are not authenticated."));
1925: }
1926:
1927: if (is_null($e)) {
1928: $params = array();
1929: } else {
1930: switch ($e->getCode()) {
1931: case self::PERMISSION_DENIED:
1932: $params = array('app' => $app, 'reason' => Horde_Auth::REASON_MESSAGE, 'msg' => $e->getMessage());
1933: break;
1934:
1935: case self::AUTH_FAILURE:
1936: $params = array('app' => $app);
1937: break;
1938:
1939: default:
1940: throw $e;
1941: }
1942: }
1943:
1944: header('Location: ' . $this->getLogoutUrl($params));
1945: exit;
1946: }
1947:
1948: 1949: 1950: 1951: 1952: 1953: 1954: 1955: 1956: 1957: 1958: 1959: 1960: 1961: 1962: 1963: 1964: 1965: 1966: 1967: 1968:
1969: public function getLogoutUrl(array $options = array())
1970: {
1971: if (!isset($options['reason'])) {
1972:
1973:
1974: $options['reason'] = $GLOBALS['injector']->getInstance('Horde_Core_Factory_Auth')->create()->getError();
1975: }
1976:
1977: $params = array();
1978: if ($options['reason'] != Horde_Auth::REASON_LOGOUT) {
1979: $params['url'] = Horde::selfUrl(true, true, true);
1980: }
1981:
1982: if (empty($options['app']) ||
1983: ($options['app'] == 'horde') ||
1984: ($options['reason'] == Horde_Auth::REASON_LOGOUT)) {
1985: $params['horde_logout_token'] = $GLOBALS['injector']->getInstance('Horde_Token')->get('horde.logout');
1986: }
1987:
1988: if (isset($options['app'])) {
1989: $params['app'] = $options['app'];
1990: }
1991:
1992: if ($options['reason']) {
1993: $params['logout_reason'] = $options['reason'];
1994: if ($options['reason'] == Horde_Auth::REASON_MESSAGE) {
1995: $params['logout_msg'] = empty($options['msg'])
1996: ? $GLOBALS['injector']->getInstance('Horde_Core_Factory_Auth')->create()->getError(true)
1997: : $options['msg'];
1998: }
1999: }
2000:
2001: return Horde::getServiceLink('login', 'horde')->add($params)->setRaw(true);
2002: }
2003:
2004: 2005: 2006: 2007: 2008: 2009: 2010: 2011: 2012: 2013:
2014: public function convertUsername($userId, $toHorde)
2015: {
2016: try {
2017: return Horde::callHook('authusername', array($userId, $toHorde));
2018: } catch (Horde_Exception_HookNotSet $e) {
2019: return $userId;
2020: }
2021: }
2022:
2023: 2024: 2025: 2026: 2027: 2028: 2029: 2030: 2031: 2032: 2033: 2034: 2035: 2036: 2037:
2038: public function getAuth($format = null)
2039: {
2040: global $session;
2041:
2042: if (!isset($session)) {
2043: return false;
2044: }
2045:
2046: if ($format == 'original') {
2047: return $session->exists('horde', 'auth/authId')
2048: ? $session->get('horde', 'auth/authId')
2049: : false;
2050: }
2051:
2052: $user = $session->get('horde', 'auth/userId');
2053: if (is_null($user)) {
2054: return false;
2055: }
2056:
2057: switch ($format) {
2058: case 'bare':
2059: return (($pos = strpos($user, '@')) === false)
2060: ? $user
2061: : substr($user, 0, $pos);
2062:
2063: case 'domain':
2064: return (($pos = strpos($user, '@')) === false)
2065: ? false
2066: : substr($user, $pos + 1);
2067:
2068: default:
2069: return $user;
2070: }
2071: }
2072:
2073: 2074: 2075: 2076: 2077:
2078: public function passwordChangeRequested()
2079: {
2080: return (bool)$GLOBALS['session']->get('horde', 'auth/change');
2081: }
2082:
2083: 2084: 2085: 2086: 2087: 2088: 2089: 2090: 2091: 2092:
2093: public function getAuthCredential($credential = null, $app = null)
2094: {
2095: if (!$this->getAuth()) {
2096: return false;
2097: }
2098:
2099: $credentials = $this->_getAuthCredentials($app);
2100:
2101: return is_null($credential)
2102: ? $credentials
2103: : ((is_array($credentials) && isset($credentials[$credential]))
2104: ? $credentials[$credential]
2105: : false);
2106: }
2107:
2108: 2109: 2110: 2111: 2112: 2113: 2114: 2115: 2116: 2117:
2118: public function setAuthCredential($credential, $value = null, $app = null)
2119: {
2120: global $session;
2121:
2122: if (!$this->getAuth()) {
2123: return;
2124: }
2125:
2126: if (is_array($credential)) {
2127: $credentials = $credential;
2128: } else {
2129: if (($credentials = $this->_getAuthCredentials($app)) === false) {
2130: return;
2131: }
2132:
2133: if (!is_array($credentials)) {
2134: $credentials = array();
2135: }
2136:
2137: $credentials[$credential] = $value;
2138: }
2139:
2140: $secret = $GLOBALS['injector']->getInstance('Horde_Secret');
2141: $entry = $secret->write($secret->getKey('auth'), serialize($credentials));
2142:
2143: if (($base_app = $session->get('horde', 'auth/credentials')) &&
2144: ($session->get('horde', 'auth_app/' . $base_app) == $entry)) {
2145: $entry = true;
2146: }
2147:
2148: if (is_null($app)) {
2149: $app = $base_app;
2150: }
2151:
2152: $session->set('horde', 'auth_app/' . $app, $entry);
2153: }
2154:
2155: 2156: 2157: 2158: 2159: 2160: 2161:
2162: protected function _getAuthCredentials($app)
2163: {
2164: global $session;
2165:
2166: $base_app = $session->get('horde', 'auth/credentials');
2167: if (is_null($base_app)) {
2168: return false;
2169: }
2170:
2171: if (is_null($app)) {
2172: $app = $base_app;
2173: }
2174:
2175: if (!$session->exists('horde', 'auth_app/' . $app)) {
2176: return ($base_app != $app)
2177: ? $this->_getAuthCredentials($base_app)
2178: : false;
2179: }
2180:
2181: $secret = $GLOBALS['injector']->getInstance('Horde_Secret');
2182: $data = $secret->read($secret->getKey('auth'),
2183: $session->get('horde', 'auth_app/' . $app));
2184: return @unserialize($data);
2185: }
2186:
2187: 2188: 2189: 2190: 2191: 2192: 2193: 2194: 2195: 2196: 2197: 2198: 2199: 2200: 2201: 2202: 2203: 2204: 2205: 2206: 2207: 2208: 2209: 2210: 2211: 2212: 2213: 2214: 2215: 2216: 2217: 2218: 2219: 2220: 2221: 2222: 2223: 2224:
2225: public function setAuth($authId, $credentials, array $options = array())
2226: {
2227: global $browser, $injector, $session;
2228:
2229: $app = empty($options['app'])
2230: ? 'horde'
2231: : $options['app'];
2232:
2233: $this->_appsinit[$app] = true;
2234:
2235: if ($this->getAuth() == $authId) {
2236:
2237: $this->setAuthCredential($credentials, null, $app);
2238: return;
2239: }
2240:
2241:
2242: $session->set('horde', 'auth/authId', $authId);
2243: $session->set('horde', 'auth/browser', $browser->getAgentString());
2244: if (!empty($options['change'])) {
2245: $session->set('horde', 'auth/change', 1);
2246: }
2247: $session->set('horde', 'auth/credentials', $app);
2248: if (isset($_SERVER['REMOTE_ADDR'])) {
2249: $session->set('horde', 'auth/remoteAddr', $_SERVER['REMOTE_ADDR']);
2250: }
2251: $session->set('horde', 'auth/timestamp', time());
2252: $session->set('horde', 'auth/userId', $this->convertUsername(trim($authId), true));
2253:
2254: $this->setAuthCredential($credentials, null, $app);
2255:
2256:
2257: unset($GLOBALS['prefs']);
2258: $injector->getInstance('Horde_Core_Factory_Prefs')->clearCache();
2259: $this->loadPrefs($this->getApp());
2260:
2261: unset($this->_appsinit['horde']);
2262: try {
2263: Horde::callHook('appinitialized', array(), 'horde');
2264: } catch (Horde_Exception_HookNotSet $e) {}
2265:
2266: $this->setLanguageEnvironment(isset($options['language']) ? $this->preferredLang($options['language']) : null, $app);
2267: }
2268:
2269: 2270: 2271: 2272: 2273: 2274: 2275: 2276:
2277: public function checkExistingAuth($app = 'horde')
2278: {
2279: global $session;
2280:
2281: $auth = $GLOBALS['injector']
2282: ->getInstance('Horde_Core_Factory_Auth')
2283: ->create();
2284:
2285: if (!empty($GLOBALS['conf']['auth']['checkip']) &&
2286: ($remoteaddr = $session->get('horde', 'auth/remoteAddr')) &&
2287: ($remoteaddr != $_SERVER['REMOTE_ADDR'])) {
2288: $auth->setError(Horde_Core_Auth_Application::REASON_SESSIONIP);
2289: return false;
2290: }
2291:
2292: if (!empty($GLOBALS['conf']['auth']['checkbrowser']) &&
2293: ($session->get('horde', 'auth/browser') != $GLOBALS['browser']->getAgentString())) {
2294: $auth->setError(Horde_Core_Auth_Application::REASON_BROWSER);
2295: return false;
2296: }
2297:
2298: if ($auth->validateAuth()) {
2299: if ($app != 'horde') {
2300: $auth = $GLOBALS['injector']
2301: ->getInstance('Horde_Core_Factory_Auth')
2302: ->create($app);
2303: if (!$auth->validateAuth()) {
2304: return false;
2305: }
2306: }
2307: return true;
2308: }
2309:
2310:
2311: if (!$auth->getError()) {
2312: $auth->setError(Horde_Auth::REASON_SESSION);
2313: }
2314:
2315: return false;
2316: }
2317:
2318: 2319: 2320: 2321: 2322: 2323: 2324: 2325:
2326: public function removeUser($userId)
2327: {
2328: $GLOBALS['injector']
2329: ->getInstance('Horde_Core_Factory_Auth')
2330: ->create()
2331: ->removeUser($userId);
2332: $this->removeUserData($userId);
2333: }
2334:
2335: 2336: 2337: 2338: 2339: 2340: 2341: 2342: 2343:
2344: public function removeUserData($user, $app = null)
2345: {
2346: if (!$this->isAdmin() && ($user != $this->getAuth())) {
2347: throw new Horde_Exception(Horde_Core_Translation::t("You are not allowed to remove user data."));
2348: }
2349:
2350: $applist = empty($app)
2351: ? $this->listApps(array('notoolbar', 'hidden', 'active', 'admin', 'noadmin'))
2352: : array($app);
2353: $errApps = array();
2354: if (!empty($applist)) {
2355: $prefs_ob = $GLOBALS['injector']->getInstance('Horde_Core_Factory_Prefs')->create('horde', array(
2356: 'user' => $user
2357: ));
2358: }
2359:
2360: foreach ($applist as $app) {
2361: try {
2362: $this->callAppMethod($app, 'removeUserData', array(
2363: 'args' => array($user)
2364: ));
2365: } catch (Exception $e) {
2366: Horde::logMessage($e);
2367: $errApps[] = $app;
2368: }
2369:
2370: try {
2371: $prefs_ob->retrieve($app);
2372: $prefs_ob->remove();
2373: } catch (Horde_Exception $e) {
2374: Horde::logMessage($e);
2375: $errApps[] = $app;
2376: }
2377: }
2378:
2379: if (count($errApps)) {
2380: throw new Horde_Exception(sprintf(Horde_Core_Translation::t("The following applications encountered errors removing user data: %s"), implode(', ', array_unique($errApps))));
2381: }
2382: }
2383:
2384:
2385:
2386: 2387: 2388: 2389: 2390: 2391:
2392: public function getLanguageCharset()
2393: {
2394: return ($charset = $this->nlsconfig->curr_charset)
2395: ? $charset
2396: : 'ISO-8859-1';
2397: }
2398:
2399: 2400: 2401: 2402: 2403: 2404:
2405: public function getEmailCharset()
2406: {
2407: if (isset($GLOBALS['prefs']) && ($charset = $GLOBALS['prefs']->getValue('sending_charset'))) {
2408: return $charset;
2409: }
2410:
2411: return ($charset = $this->nlsconfig->curr_emails)
2412: ? $charset
2413: : $this->getLanguageCharset();
2414: }
2415:
2416: 2417: 2418: 2419: 2420: 2421: 2422:
2423: public function preferredLang($lang = null)
2424: {
2425:
2426: if (isset($GLOBALS['prefs']) &&
2427: ($language = $GLOBALS['prefs']->getValue('language'))) {
2428: return basename($language);
2429: }
2430:
2431:
2432: if (!empty($lang) && $this->nlsconfig->validLang($lang)) {
2433: return basename($lang);
2434: }
2435:
2436:
2437: if ($GLOBALS['session']->exists('horde', 'language')) {
2438: return basename($GLOBALS['session']->get('horde', 'language'));
2439: }
2440:
2441:
2442: if (!empty($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
2443:
2444: $browser_langs = explode(',', $_SERVER['HTTP_ACCEPT_LANGUAGE']);
2445: foreach ($browser_langs as $lang) {
2446:
2447: if (($pos = strpos($lang, ';')) !== false) {
2448: $lang = substr($lang, 0, $pos);
2449: }
2450:
2451: $lang = $this->_mapLang(trim($lang));
2452: if ($this->nlsconfig->validLang($lang)) {
2453: return basename($lang);
2454: }
2455:
2456: 2457:
2458: if (!isset($partial_lang)) {
2459: $ll_LL = Horde_String::lower(substr($lang, 0, 2)) . '_' . Horde_String::upper(substr($lang, 0, 2));
2460: if ($this->nlsconfig->validLang($ll_LL)) {
2461: $partial_lang = $ll_LL;
2462: } else {
2463: $ll = $this->_mapLang(substr($lang, 0, 2));
2464: if ($this->nlsconfig->validLang($ll)) {
2465: $partial_lang = $ll;
2466: }
2467: }
2468: }
2469: }
2470:
2471: if (isset($partial_lang)) {
2472: return basename($partial_lang);
2473: }
2474: }
2475:
2476:
2477: return $this->nlsconfig->curr_default
2478: ? basename($this->nlsconfig->curr_default)
2479:
2480: : 'en_US';
2481: }
2482:
2483: 2484: 2485: 2486: 2487: 2488: 2489:
2490: public function setLanguage($lang = null)
2491: {
2492: if (empty($lang) || !$this->nlsconfig->validLang($lang)) {
2493: $lang = $this->preferredLang();
2494: }
2495:
2496: $GLOBALS['session']->set('horde', 'language', $lang);
2497:
2498: $changed = false;
2499: if (isset($GLOBALS['language'])) {
2500: if ($GLOBALS['language'] == $lang) {
2501: return;
2502: }
2503: $changed = true;
2504: }
2505: $GLOBALS['language'] = $lang;
2506:
2507: $lang_charset = $lang . '.UTF-8';
2508: if (setlocale(LC_ALL, $lang_charset)) {
2509: putenv('LC_ALL=' . $lang_charset);
2510: putenv('LANG=' . $lang_charset);
2511: putenv('LANGUAGE=' . $lang_charset);
2512: } else {
2513: $changed = false;
2514: }
2515:
2516: if ($changed) {
2517: $this->rebuild();
2518: }
2519: }
2520:
2521: 2522: 2523: 2524: 2525: 2526: 2527: 2528: 2529: 2530: 2531:
2532: public function setLanguageEnvironment($lang = null, $app = null)
2533: {
2534: if (empty($app)) {
2535: $app = $this->getApp();
2536: }
2537:
2538: $this->setLanguage($lang);
2539: $this->setTextdomain(
2540: $app,
2541: $this->get('fileroot', $app) . '/locale'
2542: );
2543: }
2544:
2545: 2546: 2547: 2548: 2549: 2550: 2551:
2552: public function setTextdomain($app, $directory)
2553: {
2554: bindtextdomain($app, $directory);
2555: textdomain($app);
2556:
2557:
2558: if (function_exists('bind_textdomain_codeset')) {
2559: bind_textdomain_codeset($app, 'UTF-8');
2560: }
2561: }
2562:
2563: 2564: 2565:
2566: public function setTimeZone()
2567: {
2568: $tz = $GLOBALS['prefs']->getValue('timezone');
2569: if (!empty($tz)) {
2570: @date_default_timezone_set($tz);
2571: }
2572: }
2573:
2574: 2575: 2576: 2577: 2578: 2579: 2580: 2581: 2582:
2583: protected function _mapLang($language)
2584: {
2585:
2586:
2587: $trans_lang = str_replace('-', '_', $language);
2588: $lang_parts = explode('_', $trans_lang);
2589: $trans_lang = Horde_String::lower($lang_parts[0]);
2590: if (isset($lang_parts[1])) {
2591: $trans_lang .= '_' . Horde_String::upper($lang_parts[1]);
2592: }
2593:
2594: return empty($this->nlsconfig->aliases[$trans_lang])
2595: ? $trans_lang
2596: : $this->nlsconfig->aliases[$trans_lang];
2597: }
2598: }
2599: