75ce2ac0b0248497673ead098545b798cf2c612d
[tine20] / tine20 / Setup / Frontend / Cli.php
1 <?php
2 /**
3  * Tine 2.0
4  * @package     Tinebase
5  * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
6  * @author      Philipp Schüle <p.schuele@metaways.de>
7  * @copyright   Copyright (c) 2008-2012 Metaways Infosystems GmbH (http://www.metaways.de)
8  * 
9  * @todo        add ext check again
10  */
11
12 /**
13  * cli server
14  *
15  * This class handles all requests from cli scripts
16  *
17  * @package     Tinebase
18  *
19  * TODO extend TFCliAbstract
20  */
21 class Setup_Frontend_Cli
22 {
23     /**
24      * the internal name of the application
25      *
26      * @var string
27      */
28     protected $_appname = 'Setup';
29
30     /**
31      * authentication
32      *
33      * @param string $_username
34      * @param string $_password
35      * 
36      * @return boolean
37      */
38     public function authenticate($_username, $_password)
39     {
40         return false;
41     }
42     
43     /**
44      * handle request (call -ApplicationName-_Cli.-MethodName- or -ApplicationName-_Cli.getHelp)
45      *
46      * @param Zend_Console_Getopt $_opts
47      * @param boolean $exitAfterHandle
48      * @return void
49      */
50     public function handle(Zend_Console_Getopt $_opts, $exitAfterHandle = true)
51     {
52         // always set real setup user if Tinebase is installed
53         if (Setup_Controller::getInstance()->isInstalled('Tinebase')) {
54             $setupUser = Setup_Update_Abstract::getSetupFromConfigOrCreateOnTheFly();
55             if (!Setup_Core::getUser() instanceof Tinebase_Model_User) {
56                 Setup_Core::set(Tinebase_Core::USER, $setupUser);
57             }
58         } else {
59             Setup_Core::set(Setup_Core::USER, 'setupuser');
60         }
61
62         $result = 0;
63         if (isset($_opts->install)) {
64             $result = $this->_install($_opts);
65         } elseif(isset($_opts->update)) {
66             $result = $this->_update($_opts);
67         } elseif(isset($_opts->uninstall)) {
68             $this->_uninstall($_opts);
69         } elseif(isset($_opts->install_dump)) {
70             $this->_installDump($_opts);
71         } elseif(isset($_opts->list)) {
72             $result = $this->_listInstalled();
73         } elseif(isset($_opts->sync_accounts_from_ldap)) {
74             $this->_importAccounts($_opts);
75         } elseif(isset($_opts->sync_passwords_from_ldap)) {
76             $this->_syncPasswords($_opts);
77         } elseif(isset($_opts->egw14import)) {
78             $this->_egw14Import($_opts);
79         } elseif(isset($_opts->check_requirements)) {
80             $this->_checkRequirements($_opts);
81         } elseif(isset($_opts->setconfig)) {
82             $this->_setConfig($_opts);
83         } elseif(isset($_opts->create_admin)) {
84             $this->_createAdminUser($_opts);
85         } elseif(isset($_opts->getconfig)) {
86             $this->_getConfig($_opts);
87         } elseif(isset($_opts->reset_demodata)) {
88             $this->_resetDemodata($_opts);
89         } elseif(isset($_opts->updateAllImportExportDefinitions)) {
90             $this->_updateAllImportExportDefinitions($_opts);
91         } elseif(isset($_opts->backup)) {
92             $this->_backup($_opts);
93         } elseif(isset($_opts->restore)) {
94             $this->_restore($_opts);
95         } elseif(isset($_opts->compare)) {
96             $this->_compare($_opts);
97         } elseif(isset($_opts->setpassword)) {
98             $this->_setPassword($_opts);
99         }
100         
101         if ($exitAfterHandle) {
102             exit($result);
103         }
104     }
105     
106     /**
107      * install new applications
108      *
109      * @param Zend_Console_Getopt $_opts
110      * @return integer
111      */
112     protected function _install(Zend_Console_Getopt $_opts)
113     {
114         $controller = Setup_Controller::getInstance();
115
116         $options = $this->_parseRemainingArgs($_opts->getRemainingArgs());
117
118         if ($_opts->install === true) {
119             if (Setup_Controller::getInstance()->isInstalled('Tinebase')) {
120                 // nothing to do
121                 return 0;
122             }
123             $applications = $controller->getInstallableApplications();
124             $applications = array_keys($applications);
125         } else {
126             $applications = array();
127             $applicationNames = explode(',', $_opts->install);
128             if (count($applicationNames) === 1 && strtolower($applicationNames[0]) === 'all') {
129                 $applications = $controller->getInstallableApplications();
130                 $applications = array_keys($applications);
131             } else {
132                 foreach ($applicationNames as $applicationName) {
133                     $applicationName = ucfirst(trim($applicationName));
134                     try {
135                         $controller->getSetupXml($applicationName);
136                         $applications[] = $applicationName;
137                     } catch (Setup_Exception_NotFound $e) {
138                         echo "Application $applicationName not found! Skipped...\n";
139                     }
140                 }
141             }
142         }
143
144         $this->_promptRemainingOptions($applications, $options);
145         $controller->installApplications($applications, $options);
146         
147         if ((isset($options['acceptedTermsVersion']) || array_key_exists('acceptedTermsVersion', $options))) {
148             Setup_Controller::getInstance()->saveAcceptedTerms($options['acceptedTermsVersion']);
149         }
150         
151         echo "Successfully installed " . count($applications) . " applications.\n";
152         return 0;
153     }
154
155     /**
156      * prompt remaining options
157      * 
158      * @param array $_applications
159      * @param array $_options
160      * @return void
161      * 
162      * @todo add required version server side
163      */
164     protected function _promptRemainingOptions($_applications, &$_options)
165     {
166         if (in_array('Tinebase', $_applications)) {
167             
168             if (! isset($_options['acceptedTermsVersion'])) {
169                 fwrite(STDOUT, PHP_EOL . file_get_contents(dirname(dirname(dirname(__FILE__))) . '/LICENSE' ));
170                 $licenseAnswer = Tinebase_Server_Cli::promptInput('I have read the license agreement and accept it (type "yes" to accept)');
171                 
172                 
173                 fwrite(STDOUT, PHP_EOL . file_get_contents(dirname(dirname(dirname(__FILE__))) . '/PRIVACY' ));
174                 $privacyAnswer = Tinebase_Server_Cli::promptInput('I have read the privacy agreement and accept it (type "yes" to accept)');
175             
176                 if (! (strtoupper($licenseAnswer) == 'YES' && strtoupper($privacyAnswer) == 'YES')) {
177                     echo "error: you need to accept the terms! exiting \n";
178                     exit (1);
179                 }
180                 
181                 $_options['acceptedTermsVersion'] = 1;
182             }
183             
184             
185             // initial username
186             if (! isset($_options['adminLoginName'])) {
187                 $_options['adminLoginName'] = Tinebase_Server_Cli::promptInput('Inital Admin Users Username');
188                 if (! $_options['adminLoginName']) {
189                     echo "error: username must be given! exiting \n";
190                     exit (1);
191                 }
192             }
193             
194             // initial password / can be empty => will trigger password change dialogue
195             if (! array_key_exists('adminPassword', $_options)) {
196                 $_options['adminPassword'] = $this->_promptPassword();
197             }
198         }
199     }
200     
201     /**
202      * prompt password
203      * 
204      * @return string
205      */
206     protected function _promptPassword()
207     {
208         $password1 = Tinebase_Server_Cli::promptInput('Admin user password', TRUE);
209         if (! $password1) {
210             echo "Error: Password must not be empty! Exiting ... \n";
211             exit (1);
212         }
213         $password2 = Tinebase_Server_Cli::promptInput('Confirm password', TRUE);
214         if ($password1 !== $password2) {
215             echo "Error: Passwords do not match! Exiting ... \n";
216             exit (1);
217         }
218         
219         return $password1;
220     }
221
222     /**
223      * set system user password
224      *
225      * @param Zend_Console_Getopt $_opts
226      * @return integer
227      */
228     protected function _setPassword(Zend_Console_Getopt $_opts)
229     {
230         $options = $this->_parseRemainingArgs($_opts->getRemainingArgs());
231         if (empty($options['username']) || empty($options['password'])) {
232             echo "username and password parameters required\n";
233             return 2;
234         }
235
236         $username = $options['username'];
237         $password = $options['password'];
238         if (! in_array($username, Tinebase_User::getSystemUsernames(), /* strict */ true)) {
239             echo "it's only allowed to set system user passwords here\n";
240             return 2;
241         }
242
243         $user = Tinebase_User::getInstance()->getUserByLoginName($username);
244         Tinebase_User::getInstance()->setPassword($user, $password);
245         return 0;
246     }
247
248     /**
249      * update existing applications
250      *
251      * @param Zend_Console_Getopt $_opts
252      * @return integer
253      */
254     protected function _update(Zend_Console_Getopt $_opts)
255     {
256         $maxLoops = 50;
257         do {
258             $result = $this->_updateApplications();
259             if ($_opts->v && ! empty($result['messages'])) {
260                 echo "Messages:\n";
261                 foreach ($result['messages'] as $message) {
262                     echo "  " . $message . "\n";
263                 }
264             }
265             $maxLoops--;
266         } while ($result['updated'] > 0 && $maxLoops > 0);
267         
268         return ($maxLoops > 0) ? 0 : 1;
269     }
270     
271     /**
272      * update all applications
273      * 
274      * @return array
275      */
276     protected function _updateApplications()
277     {
278         $controller = Setup_Controller::getInstance();
279         $applications = Tinebase_Application::getInstance()->getApplications(NULL, 'id');
280         
281         foreach ($applications as $key => &$application) {
282             try {
283                 if (! $controller->updateNeeded($application)) {
284                     unset($applications[$key]);
285                 }
286             } catch (Setup_Exception_NotFound $e) {
287                 Tinebase_Core::getLogger()->warn(__METHOD__ . '::' . __LINE__ 
288                     . ' Failed to check if an application needs an update:' . $e->getMessage());
289                 unset($applications[$key]);
290             }
291         }
292
293         $result = array();
294         if (count($applications) > 0) {
295             $result = $controller->updateApplications($applications);
296             echo "Updated " . $result['updated'] . " application(s).\n";
297         } else {
298             $result['updated'] = 0;
299         }
300         
301         return $result;
302     }
303
304     /**
305      * uninstall applications
306      *
307      * @param Zend_Console_Getopt $_opts
308      */
309     protected function _uninstall(Zend_Console_Getopt $_opts)
310     {
311         $controller = Setup_Controller::getInstance();
312         
313         if($_opts->uninstall === true) {
314             $applications = Tinebase_Application::getInstance()->getApplications(NULL, 'id');
315         } else {
316             $applications = new Tinebase_Record_RecordSet('Tinebase_Model_Application');
317             $applicationNames = explode(',', $_opts->uninstall);
318             foreach($applicationNames as $applicationName) {
319                 $applicationName = ucfirst(trim($applicationName));
320                 try {
321                     $application = Tinebase_Application::getInstance()->getApplicationByName($applicationName);
322                     $applications->addRecord($application);
323                 } catch (Tinebase_Exception_NotFound $e) {
324                 }
325             }
326         }
327         
328         $controller->uninstallApplications($applications->name);
329         
330         echo "Successfully uninstalled " . count($applications) . " applications.\n";
331     }
332     
333     /**
334      * reinstall applications
335      * and reset Demodata
336      * php setup.php --reset_demodata USERNAME
337      * 
338      * @param Zend_Console_Getopt $_opts
339      */
340     protected function _resetDemodata(Zend_Console_Getopt $_opts)
341     {
342         $controller = Setup_Controller::getInstance();
343         $userController = Admin_Controller_User::getInstance();
344         $containerController = Tinebase_Container::getInstance();
345         $cli = new Tinebase_Frontend_Cli();
346         
347         //Don't reset this applications
348         $fixedApplications = array('Tinebase', 'Admin', 'Addressbook');
349         
350         //Log in
351         $opts = $_opts->getRemainingArgs();
352         $username = $opts[0];
353         if (empty($username)) {
354             echo "Username is missing!\n";
355             exit;
356         }
357         $user = Tinebase_User::getInstance()->getUserByLoginName($username);
358         Tinebase_Core::set(Tinebase_Core::USER, $user);
359         
360         //get all applications and remove some
361         $applications = Tinebase_Application::getInstance()->getApplications(NULL, 'id');
362         
363         foreach ($applications as $key => &$application) {
364             if (in_array($application, $fixedApplications)) {
365                 unset($applications[$key]);
366             }
367         }
368         
369         //get set rights
370         $users = Tinebase_Acl_Roles::getInstance()->getRoleByName('user role');
371         $rights = Tinebase_Acl_Roles::getInstance()->getRoleRights($users->getId());
372         
373         //Uninstall Applications
374         try {
375             $controller->uninstallApplications($applications->name);
376             echo "Successfully uninstalled " . count($applications) . " applications.\n";
377         } catch (Tinebase_Exception_NotFound $e) {
378         }
379         //Install Applications
380         try {
381             $controller->installApplications($applications->name);
382             echo "Successfully installed " . count($applications) . " applications.\n";
383         } catch (Tinebase_Exception_NotFound $e) {
384         }
385         
386         //set rights
387         foreach ($applications as $app) {
388             $newApplicationId = Tinebase_Application::getInstance()->getApplicationByName($app->name)->getId();
389             
390             foreach ($rights as &$right) {
391                 if ($right['application_id'] == $app->id) {
392                     $right['application_id'] = $newApplicationId;
393                 }
394             }
395         }
396         
397         Tinebase_Acl_Roles::getInstance()->setRoleRights($users->getId(), $rights);
398         echo "Successfully restored user rights.\n";
399         
400         //Clean up addressbooks
401         $internalContacts = $userController->getDefaultInternalAddressbook();
402         $containers = $containerController->getAll();
403         foreach ($containers as $key => &$container) {
404             if ($container->id == $internalContacts) {
405                 // Do nothing
406             } else {
407                 try {
408                     $containerController->deleteContainer($container, true);
409                 } catch (Exception $e) {
410                 }
411             }
412         }
413         unset($containers);
414         echo "Successfully cleand up containers.\n";
415         
416         //remove state
417         $db = Tinebase_Core::getDb();
418         $statement = "TRUNCATE TABLE " . $db->quoteIdentifier(SQL_TABLE_PREFIX . 'state');
419         $db->query($statement);
420         echo "Successfully truncated state table.\n";
421         
422         //Get Demodata
423         $cli->createAllDemoData();
424         
425         //clear Cache
426         Tinebase_Core::getCache()->clean(Zend_Cache::CLEANING_MODE_ALL);
427         echo "Successfully cleared Cache.\n";
428         
429         echo "Every thing done!\n";
430     }
431
432     /**
433      * Update Import Export Definitions for all applications
434      */
435     protected function _updateAllImportExportDefinitions(Zend_Console_Getopt $_opts){
436
437         //get all applications
438         $applications = Tinebase_Application::getInstance()->getApplications(NULL, 'id');
439         foreach ($applications as $application) {
440             Setup_Controller::getInstance()->createImportExportDefinitions($application);
441             echo "Update definitions for " . $application->name . "...\n";
442         }
443     }
444     
445     /**
446      * list installed apps
447      */
448     protected function _listInstalled()
449     {
450         try {
451             $applications = Tinebase_Application::getInstance()->getApplications(NULL, 'id');
452         } catch (Zend_Db_Statement_Exception $e) {
453             echo "No applications installed\n";
454             return 1;
455         }
456         
457         echo "Currently installed applications:\n";
458         foreach($applications as $application) {
459             echo "* $application\n";
460         }
461         
462         return 0;
463     }
464     
465     /**
466      * import accounts from ldap
467      *
468      * @param Zend_Console_Getopt $_opts
469      */
470     protected function _importAccounts(Zend_Console_Getopt $_opts)
471     {
472         // disable timelimit during import of user accounts
473         Setup_Core::setExecutionLifeTime(0);
474         
475         // import groups
476         if (! $_opts->onlyusers) {
477             Tinebase_Group::syncGroups();
478         }
479         
480         // import users
481         $options = array('syncContactData' => TRUE);
482         if ($_opts->dbmailldap) {
483             $options['ldapplugins'] = array(
484                 new Tinebase_EmailUser_Imap_LdapDbmailSchema(),
485                 new Tinebase_EmailUser_Smtp_LdapDbmailSchema()
486             );
487         }
488
489         if ($_opts->syncdeletedusers) {
490             $options['deleteUsers'] = true;
491         }
492         if ($_opts->syncaccountstatus) {
493             $options['syncAccountStatus'] = true;
494         }
495         if ($_opts->syncontactphoto) {
496             $options['syncContactPhoto'] = true;
497         }
498
499         Tinebase_User::syncUsers($options);
500     }
501     
502     /**
503      * sync ldap passwords
504      * 
505      * @param Zend_Console_Getopt $_opts
506      */
507     protected function _syncPasswords(Zend_Console_Getopt $_opts)
508     {
509         Tinebase_User::syncLdapPasswords();
510     }
511     
512     /**
513      * import from egw14
514      * 
515      * @param Zend_Console_Getopt $_opts
516      */
517     protected function _egw14Import(Zend_Console_Getopt $_opts)
518     {
519         $args = $_opts->getRemainingArgs();
520         
521         if (count($args) < 1 || ! is_readable($args[0])) {
522             echo "can not open config file \n";
523             echo "see tine20.org/wiki/EGW_Migration_Howto for details \n\n";
524             echo "usage: ./setup.php --egw14import /path/to/config.ini (see Tinebase/Setup/Import/Egw14/config.ini)\n\n";
525             exit(1);
526         }
527         
528         try {
529             $config = new Zend_Config(array(), TRUE);
530             $config->merge(new Zend_Config_Ini($args[0]));
531             $config = $config->merge($config->all);
532         } catch (Zend_Config_Exception $e) {
533             fwrite(STDERR, "Error while parsing config file($args[0]) " .  $e->getMessage() . PHP_EOL);
534             exit(1);
535         }
536         
537         $writer = new Zend_Log_Writer_Stream('php://output');
538         $logger = new Zend_Log($writer);
539         
540         $filter = new Zend_Log_Filter_Priority((int) $config->loglevel);
541         $logger->addFilter($filter);
542         
543         $importer = new Tinebase_Setup_Import_Egw14($config, $logger);
544         $importer->import();
545     }
546     
547     /**
548      * do the environment check
549      *
550      * @return array
551      */
552     protected function _checkRequirements(Zend_Console_Getopt $_opts)
553     {
554         $results = Setup_Controller::getInstance()->checkRequirements();
555         if ($results['success']) {
556           echo "OK - All requirements are met\n";
557         } else {
558           echo "ERRORS - The following requirements are not met: \n";
559           foreach ($results['results'] as $result) {
560             if (!empty($result['message'])) {
561               echo "- " . strip_tags($result['message']) . "\n";
562             }
563           }
564         }
565     }
566     
567     /**
568      * set config
569      *
570      * @return array
571      */
572     protected function _setConfig(Zend_Console_Getopt $_opts)
573     {
574         $options = $this->_parseRemainingArgs($_opts->getRemainingArgs());
575         $errors = array();
576         if (empty($options['configkey'])) {
577             $errors[] = 'Missing argument: configkey';
578         }
579         if (! isset($options['configvalue'])) {
580             $errors[] = 'Missing argument: configvalue';
581         }
582         $configKey = (string)$options['configkey'];
583         $configValue = self::parseConfigValue($options['configvalue']);
584         $applicationName = (isset($options['app'])) ? $options['app'] : 'Tinebase';
585
586         if (! Tinebase_Application::getInstance()->isInstalled('Tinebase') || ! Tinebase_Application::getInstance()->isInstalled($applicationName)) {
587             $errors[] = $applicationName . ' is not installed';
588         }
589         
590         if (empty($errors)) {
591            Setup_Controller::getInstance()->setConfigOption($configKey, $configValue, $applicationName);
592            echo "OK - Updated configuration option $configKey for application $applicationName\n";
593         } else {
594             echo "ERRORS - The following errors occured: \n";
595             foreach ($errors as $error) {
596                 echo "- " . $error . "\n";
597             }
598         }
599     }
600     
601     /**
602      * get config
603      *
604      */
605     protected function _getConfig(Zend_Console_Getopt $_opts)
606     {
607         $options = $this->_parseRemainingArgs($_opts->getRemainingArgs());
608         $applicationName = (isset($options['app'])) ? $options['app'] : 'Tinebase';
609
610         $errors = array();
611         if (! Tinebase_Application::getInstance()->isInstalled('Tinebase') || ! Tinebase_Application::getInstance()->isInstalled($applicationName)) {
612             $errors[] = $applicationName . ' is not installed';
613             $config = null;
614         } else {
615             $config = Tinebase_Config_Abstract::factory($applicationName);
616         }
617
618         if (empty($options['configkey'])) {
619             $errors[] = 'Missing argument: configkey';
620             if ($config) {
621                 $errors[] = 'Available config settings:';
622                 $errors[] = print_r($config::getProperties(), true);
623             }
624         }
625         $configKey = (string)$options['configkey'];
626         
627         if (empty($errors)) {
628             $value = $config->get($configKey);
629             $value = is_string($value) ? $value : Zend_Json::encode($value);
630             echo $value . " \n";
631         } else {
632             echo "ERRORS - The following errors occured: \n";
633             foreach ($errors as $error) {
634                 echo "- " . $error . "\n";
635             }
636         }
637     }
638     
639     /**
640      * create admin user / activate existing user / allow to reset password
641      * 
642      * @param Zend_Console_Getopt $_opts
643      * 
644      * @todo check role by rights and not by name
645      * @todo replace echos with stdout logger
646      */
647     protected function _createAdminUser(Zend_Console_Getopt $_opts)
648     {
649         if (! Setup_Controller::getInstance()->isInstalled('Tinebase')) {
650             die('Install Tinebase first.');
651         }
652
653         echo "Please enter a username. An existing user is reactivated and you can reset the password.\n";
654         $username = strtolower(Tinebase_Server_Cli::promptInput('Username'));
655         $tomorrow = Tinebase_DateTime::now()->addDay(1);
656         
657         try {
658             $user = Tinebase_User::getInstance()->getFullUserByLoginName($username);
659             echo "User $username already exists.\n";
660             Tinebase_User::getInstance()->setStatus($user->getId(), Tinebase_Model_User::ACCOUNT_STATUS_ENABLED);
661             echo "Activated admin user '$username'.\n";
662             
663             $expire = Tinebase_Server_Cli::promptInput('Should the admin user expire tomorrow (default: "no", "y" or "yes" for expiry)?');
664             if ($expire === 'y' or $expire === 'yes') {
665                 Tinebase_User::getInstance()->setExpiryDate($user->getId(), $tomorrow);
666                 echo "User expires tomorrow at $tomorrow.\n";
667             }
668             
669             $resetPw = Tinebase_Server_Cli::promptInput('Do you want to reset the password (default: "no", "y" or "yes" for reset)?');
670             if ($resetPw === 'y' or $resetPw === 'yes') {
671                 $password = $this->_promptPassword();
672                 Tinebase_User::getInstance()->setPassword($user, $password);
673                 echo "User password has been reset.\n";
674             }
675
676             try {
677                 Tinebase_User::getInstance()->assertAdminGroupMembership($user);
678                 echo "Added user to default admin group\n";
679             } catch (Exception $e) {
680                 Tinebase_Exception::log($e);
681                 echo "Could not add user to default admin group: " . $e->getMessage();
682             }
683
684             $this->_checkAdminRole($user);
685             
686         } catch (Tinebase_Exception_NotFound $tenf) {
687             // create new admin user that expires tomorrow
688             $password = $this->_promptPassword();
689             Tinebase_User::createInitialAccounts(array(
690                 'adminLoginName' => $username,
691                 'adminPassword'  => $password,
692                 'expires'        => $tomorrow,
693             ));
694             echo "Created new admin user '$username' that expires tomorrow.\n";
695         }
696     }
697
698
699     /**
700      * check admin role membership
701      * 
702      * @param Tinebase_Model_FullUser $user
703      */
704     protected function _checkAdminRole($user)
705     {
706         $roleMemberships = Tinebase_Acl_Roles::getInstance()->getRoleMemberships($user->getId());
707         $adminRoleFound = FALSE;
708         // TODO allow to configure this / pass it as param
709         $adminRoleName = 'admin role';
710
711         foreach ($roleMemberships as $roleId) {
712             $role = Tinebase_Acl_Roles::getInstance()->getRoleById($roleId);
713             if ($role->name === $adminRoleName) {
714                 $adminRoleFound = TRUE;
715                 break;
716             }
717         }
718
719         if (! $adminRoleFound || ! Tinebase_Acl_Roles::getInstance()->hasRight('Admin', $user->getId(), Tinebase_Acl_Rights::ADMIN)) {
720             echo "Admin role not found for user " . $user->accountLoginName . ".\n";
721
722             try {
723                 $adminRole = Tinebase_Acl_Roles::getInstance()->getRoleByName($adminRoleName);
724             } catch (Tinebase_Exception_NotFound $tenf) {
725                 $adminRole = $this->_createNewAdminRoleForAdmin($adminRoleName);
726             }
727
728             Tinebase_Acl_Roles::getInstance()->setRoleMembers($adminRole->getId(), array(
729                 array(
730                     'id'    => $user->getId(),
731                     'type'  => Tinebase_Acl_Rights::ACCOUNT_TYPE_USER, 
732                 )
733             ));
734             
735             echo "Added user " . $user->accountLoginName . " to role '$adminRoleName''.\n";
736             // @todo clear roles/groups cache
737         }
738     }
739
740     protected function _createNewAdminRoleForAdmin($adminRoleName)
741     {
742         $adminRole = new Tinebase_Model_Role(array(
743             'name'                  => $adminRoleName,
744             'description'           => 'admin role for tine. this role has all rights per default.',
745         ));
746
747         $adminRole = Tinebase_Acl_Roles::getInstance()->createRole($adminRole);
748         // add all rights for all apps
749         $enabledApps = Tinebase_Application::getInstance()->getApplicationsByState(Tinebase_Application::ENABLED);
750         $roleRights = array();
751         foreach ($enabledApps as $application) {
752             $allRights = Tinebase_Application::getInstance()->getAllRights($application->getId());
753             foreach ($allRights as $right) {
754                 $roleRights[] = array(
755                     'application_id' => $application->getId(),
756                     'right'          => $right,
757                 );
758             }
759         }
760         Tinebase_Acl_Roles::getInstance()->setRoleRights($adminRole->getId(), $roleRights);
761
762         return $adminRole;
763     }
764
765     /**
766      * @param Zend_Console_Getopt $_opts
767      * @throws Exception
768      */
769     protected function _backup(Zend_Console_Getopt $_opts)
770     {
771         $options = $this->_parseRemainingArgs($_opts->getRemainingArgs());
772         Setup_Controller::getInstance()->backup($options);
773     }
774
775     /**
776      * @param Zend_Console_Getopt $_opts
777      * @throws Exception
778      */
779     protected function _restore(Zend_Console_Getopt $_opts)
780     {
781         $options = $this->_parseRemainingArgs($_opts->getRemainingArgs());
782         Setup_Controller::getInstance()->restore($options);
783     }
784
785     /**
786      * @param Zend_Console_Getopt $_opts
787      * @throws Exception
788      */
789     protected function _installDump(Zend_Console_Getopt $_opts)
790     {
791         $options = $this->_parseRemainingArgs($_opts->getRemainingArgs());
792         Setup_Controller::getInstance()->installFromDump($options);
793     }
794
795     /**
796      * parse options
797      * 
798      * @param string $_value
799      * @return array|string
800      */
801     public static function parseConfigValue($_value)
802     {
803         if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) Tinebase_Core::getLogger()->trace(__METHOD__ . '::' . __LINE__ . ' ' . print_r($_value, TRUE));
804         
805         // check value is json encoded
806         if (Tinebase_Helper::is_json($_value)) {
807             return Zend_Json::decode($_value); 
808         }
809         
810         $result = array(
811             'active' => 1
812         );
813
814         // keep spaces, \: and \,
815         $_value = preg_replace(array('/ /', '/\\\:/', '/\\\,/', '/\s*/'), array('§', '@', ';', ''), $_value);
816         
817         $parts = explode(',', $_value);
818         
819         foreach ($parts as $part) {
820             $part = str_replace(';', ',', $part);
821             $part = str_replace('§', ' ', $part);
822             $part = str_replace('@', ':', $part);
823             if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) Tinebase_Core::getLogger()->trace(__METHOD__ . '::' . __LINE__ . ' ' . $part);
824             if (strpos($part, '_') !== FALSE) {
825                 list($key, $sub) = preg_split('/_/', $part, 2);
826                 if (preg_match('/:/', $sub)) {
827                     list($subKey, $value) = explode(':', $sub);
828                     $result[$key][$subKey] = $value;
829                 } else {
830                     // might be a '_' in the value
831                     if (preg_match('/:/', $part)) {
832                         $exploded = explode(':', $part);
833                         $key = array_shift($exploded);
834                         $result[$key] = implode(':', $exploded);
835                     } else {
836                         throw new Timetracker_Exception_UnexpectedValue('You have an error in the config syntax (":" expected): ' . $part);
837                     }
838                 }
839             } else {
840                 if (strpos($part, ':') !== FALSE) {
841                     list($key, $value) = preg_split('/:/', $part, 2);
842                     $result[$key] = $value;
843                 } else {
844                     $result = $part;
845                 }
846             }
847         }
848
849         return $result;
850     }
851     
852     /**
853      * parse remaining args
854      * 
855      * @param string $_args
856      * @return array
857      */
858     protected function _parseRemainingArgs($_args)
859     {
860         $options = array();
861         foreach ($_args as $arg) {
862             if (strpos($arg, '=') !== FALSE) {
863                 if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) Tinebase_Core::getLogger()->trace(__METHOD__ . '::' . __LINE__ . ' ' . $arg);
864                 list($key, $value) = preg_split('/=/', $arg, 2);
865                 $options[$key] = $value;
866             }
867         }
868         
869         return $options;
870     }
871
872     /**
873      * compare shema of two tine databases
874      *
875      * @param Zend_Console_Getopt $_opts
876      * @throws Exception
877      */
878     protected function _compare(Zend_Console_Getopt $_opts)
879     {
880         $options = $this->_parseRemainingArgs($_opts->getRemainingArgs());
881         print_r(Setup_Controller::getInstance()->compareSchema($options));
882     }
883 }