]> CyberLeo.Net >> Repos - Github/sugarcrm.git/blob - ModuleInstall/ModuleInstaller.php
Release 6.5.5
[Github/sugarcrm.git] / ModuleInstall / ModuleInstaller.php
1 <?php
2 if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
3 /*********************************************************************************
4  * SugarCRM Community Edition is a customer relationship management program developed by
5  * SugarCRM, Inc. Copyright (C) 2004-2012 SugarCRM Inc.
6  * 
7  * This program is free software; you can redistribute it and/or modify it under
8  * the terms of the GNU Affero General Public License version 3 as published by the
9  * Free Software Foundation with the addition of the following permission added
10  * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
11  * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY
12  * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
13  * 
14  * This program is distributed in the hope that it will be useful, but WITHOUT
15  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
16  * FOR A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more
17  * details.
18  * 
19  * You should have received a copy of the GNU Affero General Public License along with
20  * this program; if not, see http://www.gnu.org/licenses or write to the Free
21  * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
22  * 02110-1301 USA.
23  * 
24  * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road,
25  * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com.
26  * 
27  * The interactive user interfaces in modified source and object code versions
28  * of this program must display Appropriate Legal Notices, as required under
29  * Section 5 of the GNU Affero General Public License version 3.
30  * 
31  * In accordance with Section 7(b) of the GNU Affero General Public License version 3,
32  * these Appropriate Legal Notices must retain the display of the "Powered by
33  * SugarCRM" logo. If the display of the logo is not reasonably feasible for
34  * technical reasons, the Appropriate Legal Notices must display the words
35  * "Powered by SugarCRM".
36  ********************************************************************************/
37
38
39 /*
40  * ModuleInstaller - takes an installation package from files in the custom/Extension/X directories, and moves them into custom/X to install them.
41  * If a directory has multiple files they are concatenated together.
42  * Relevant directories (X) are Layoutdefs, Vardefs, Include (bean stuff), Language, TableDictionary (relationships)
43  *
44  * Installation steps that involve more than just copying files:
45  * 1. installing custom fields - calls bean->custom_fields->addField
46  * 2. installing relationships - calls createTableParams to build the relationship table, and createRelationshipMeta to add the relationship to the relationship table
47  * 3. rebuilding the relationships - at almost the last step in install(), calls modules/Administration/RebuildRelationship.php
48  * 4. repair indices - uses "modules/Administration/RepairIndex.php";
49  */
50
51
52
53 require_once('include/utils/progress_bar_utils.php');
54
55 require_once('ModuleInstall/ModuleScanner.php');
56 define('DISABLED_PATH', 'Disabled');
57
58 class ModuleInstaller{
59         var $modules = array();
60         var $silent = false;
61         var $base_dir  = '';
62         var $modulesInPackage = array();
63         public $disabled_path = DISABLED_PATH;
64
65         function ModuleInstaller(){
66                 $this->ms = new ModuleScanner();
67                 $this->modules = get_module_dir_list();
68                 $this->db = & DBManagerFactory::getInstance();
69         include("ModuleInstall/extensions.php");
70         $this->extensions = $extensions;
71         }
72
73    /*
74     * ModuleInstaller->install includes the manifest.php from the base directory it has been given. If it has been asked to do an upgrade it checks to see if there is
75     * an upgrade_manifest defined in the manifest; if not it errors. It then adds the bean into the custom/Extension/application/Ext/Include/<module>.php - sets beanList, beanFiles
76     * and moduleList - and then calls ModuleInstaller->merge_files('Ext/Include', 'modules.ext.php', '', true) to merge the individual module files into a combined file
77     * /custom/Extension/application/Ext/Include/modules.ext.php (which now contains a list of all $beanList, $beanFiles and $moduleList for all extension modules) -
78     * this file modules.ext.php is included at the end of modules.php.
79     *
80     * Finally it runs over a list of defined tasks; then install_beans, then install_custom_fields, then clear the Vardefs, run a RepairAndClear, then finally call rebuild_relationships.
81     */
82         function install($base_dir, $is_upgrade = false, $previous_version = ''){
83                 if(defined('TEMPLATE_URL'))SugarTemplateUtilities::disableCache();
84                 if(!empty($GLOBALS['sugar_config']['moduleInstaller']['packageScan'])){
85                         $this->ms->scanPackage($base_dir);
86                         if($this->ms->hasIssues()){
87                                 $this->ms->displayIssues();
88                                 sugar_cleanup(true);
89                         }
90                 }
91
92         // workaround for bug 45812 - refresh vardefs cache before unpacking to avoid partial vardefs in cache
93         global $beanList;
94         foreach ($this->modules as $module_name) {
95             if (!empty($beanList[$module_name])) {
96                 $objectName = BeanFactory::getObjectName($module_name);
97                 VardefManager::loadVardef($module_name, $objectName);
98             }
99         }
100
101                 global $app_strings, $mod_strings;
102                 $this->base_dir = $base_dir;
103                 $total_steps = 5; //minimum number of steps with no tasks
104                 $current_step = 0;
105                 $tasks = array(
106                         'pre_execute',
107                         'install_copy',
108                     'install_extensions',
109                         'install_images',
110                         'install_dcactions',
111                         'install_dashlets',
112                         'install_connectors',
113                         'install_layoutfields',
114                         'install_relationships',
115             'enable_manifest_logichooks',
116                         'post_execute',
117                         'reset_opcodes',
118                 );
119
120                 $total_steps += count($tasks);
121                 if(file_exists($this->base_dir . '/manifest.php')){
122                                 if(!$this->silent){
123                                         $current_step++;
124                                         display_progress_bar('install', $current_step, $total_steps);
125                                         echo '<div id ="displayLoglink" ><a href="#" onclick="document.getElementById(\'displayLog\').style.display=\'\'">'
126                                                 .$app_strings['LBL_DISPLAY_LOG'].'</a> </div><div id="displayLog" style="display:none">';
127                                 }
128
129                                 include($this->base_dir . '/manifest.php');
130                                 if($is_upgrade && !empty($previous_version)){
131                                         //check if the upgrade path exists
132                                         if(!empty($upgrade_manifest)){
133                                                 if(!empty($upgrade_manifest['upgrade_paths'])){
134                                                         if(!empty($upgrade_manifest['upgrade_paths'][$previous_version])){
135                                                                 $installdefs =  $upgrade_manifest['upgrade_paths'][$previous_version];
136                                                         }else{
137                                                                 $errors[] = 'No Upgrade Path Found in manifest.';
138                                                                 $this->abort($errors);
139                                                         }//fi
140                                                 }//fi
141                                         }//fi
142                                 }//fi
143                                 $this->id_name = $installdefs['id'];
144                                 $this->installdefs = $installdefs;
145                                 if(!$this->silent){
146                                         $current_step++;
147                                         update_progress_bar('install', $current_step, $total_steps);
148                                 }
149
150                                 foreach($tasks as $task){
151                                         $this->$task();
152                                         if(!$this->silent){
153                                                 $current_step++;
154                                                 update_progress_bar('install', $current_step, $total_steps);
155                                         }
156                                 }
157                                 $this->install_beans($this->installed_modules);
158                                 if(!$this->silent){
159                                         $current_step++;
160                                         update_progress_bar('install', $total_steps, $total_steps);
161                                 }
162                                 if(isset($installdefs['custom_fields'])){
163                                         $this->log(translate('LBL_MI_IN_CUSTOMFIELD'));
164                                         $this->install_custom_fields($installdefs['custom_fields']);
165                                 }
166                                 if(!$this->silent){
167                                         $current_step++;
168                                         update_progress_bar('install', $current_step, $total_steps);
169                                         echo '</div>';
170                                 }
171                                 if(!$this->silent){
172                                         $current_step++;
173                                         update_progress_bar('install', $current_step, $total_steps);
174                                         echo '</div>';
175                                 }
176                                 $selectedActions = array(
177                         'clearTpls',
178                         'clearJsFiles',
179                         'clearDashlets',
180                         'clearVardefs',
181                         'clearJsLangFiles',
182                         'rebuildAuditTables',
183                         'repairDatabase',
184                 );
185                                 VardefManager::clearVardef();
186                                 global $beanList, $beanFiles, $moduleList;
187                                 if (file_exists('custom/application/Ext/Include/modules.ext.php'))
188                                 {
189                                     include('custom/application/Ext/Include/modules.ext.php');
190                                 }
191                                 require_once("modules/Administration/upgrade_custom_relationships.php");
192                 upgrade_custom_relationships($this->installed_modules);
193                                 $this->rebuild_all(true);
194                                 require_once('modules/Administration/QuickRepairAndRebuild.php');
195                                 $rac = new RepairAndClear();
196                                 $rac->repairAndClearAll($selectedActions, $this->installed_modules,true, false);
197                                 $this->rebuild_relationships();
198                                 UpdateSystemTabs('Add',$this->tab_modules);
199                 //Clear out all the langauge cache files.
200                 clearAllJsAndJsLangFilesWithoutOutput();
201                 $cache_key = 'app_list_strings.'.$GLOBALS['current_language'];
202                 sugar_cache_clear($cache_key );
203                 sugar_cache_reset();
204
205                                 //clear the unified_search_module.php file
206                     require_once('modules/Home/UnifiedSearchAdvanced.php');
207                     UnifiedSearchAdvanced::unlinkUnifiedSearchModulesFile();
208
209                                 $this->log('<br><b>' . translate('LBL_MI_COMPLETE') . '</b>');
210                 }else{
211                         die("No \$installdefs Defined In $this->base_dir/manifest.php");
212                 }
213
214         }
215
216         function install_user_prefs($module, $hide_from_user=false){
217                 UserPreference::updateAllUserPrefs('display_tabs', $module, '', true, !$hide_from_user);
218                 UserPreference::updateAllUserPrefs('hide_tabs', $module, '', true, $hide_from_user);
219                 UserPreference::updateAllUserPrefs('remove_tabs', $module, '', true, $hide_from_user);
220         }
221         function uninstall_user_prefs($module){
222                 UserPreference::updateAllUserPrefs('display_tabs', $module, '', true, true);
223                 UserPreference::updateAllUserPrefs('hide_tabs', $module, '', true, true);
224                 UserPreference::updateAllUserPrefs('remove_tabs', $module, '', true, true);
225         }
226
227         function pre_execute(){
228                 require_once($this->base_dir . '/manifest.php');
229                 if(isset($this->installdefs['pre_execute']) && is_array($this->installdefs['pre_execute'])){
230                         foreach($this->installdefs['pre_execute'] as $includefile){
231                                 require_once(str_replace('<basepath>', $this->base_dir, $includefile));
232                         }
233                 }
234         }
235
236         function post_execute(){
237                 require_once($this->base_dir . '/manifest.php');
238                 if(isset($this->installdefs['post_execute']) && is_array($this->installdefs['post_execute'])){
239                         foreach($this->installdefs['post_execute'] as $includefile){
240                                 require_once(str_replace('<basepath>', $this->base_dir, $includefile));
241                         }
242                 }
243         }
244
245         function pre_uninstall(){
246                 require_once($this->base_dir . '/manifest.php');
247                 if(isset($this->installdefs['pre_uninstall']) && is_array($this->installdefs['pre_uninstall'])){
248                         foreach($this->installdefs['pre_uninstall'] as $includefile){
249                                 require_once(str_replace('<basepath>', $this->base_dir, $includefile));
250                         }
251                 }
252         }
253
254         function post_uninstall(){
255                 require_once($this->base_dir . '/manifest.php');
256                 if(isset($this->installdefs['post_uninstall']) && is_array($this->installdefs['post_uninstall'])){
257                         foreach($this->installdefs['post_uninstall'] as $includefile){
258                                 require_once(str_replace('<basepath>', $this->base_dir, $includefile));
259                         }
260                 }
261         }
262
263         /*
264      * ModuleInstaller->install_copy gets the copy section of installdefs in the manifest and calls copy_path to copy each path (file or directory) to its final location
265      * (specified as from and to in the manifest), replacing <basepath> by the base_dir value passed in to install.
266      */
267         function install_copy(){
268                 if(isset($this->installdefs['copy'])){
269                         /* BEGIN - RESTORE POINT - by MR. MILK August 31, 2005 02:22:11 PM */
270                         $backup_path = clean_path( remove_file_extension(urldecode($_REQUEST['install_file']))."-restore" );
271                         /* END - RESTORE POINT - by MR. MILK August 31, 2005 02:22:18 PM */
272                         foreach($this->installdefs['copy'] as $cp){
273                                 $GLOBALS['log']->debug("Copying ..." . $cp['from'].  " to " .$cp['to'] );
274                                 /* BEGIN - RESTORE POINT - by MR. MILK August 31, 2005 02:22:11 PM */
275                                 //$this->copy_path($cp['from'], $cp['to']);
276                                 $this->copy_path($cp['from'], $cp['to'], $backup_path);
277                                 /* END - RESTORE POINT - by MR. MILK August 31, 2005 02:22:18 PM */
278                         }
279                         //here we should get the module list again as we could have copied something to the modules dir
280                         $this->modules = get_module_dir_list();
281                 }
282         }
283         function uninstall_copy(){
284                 if(!empty($this->installdefs['copy'])){
285                                         foreach($this->installdefs['copy'] as $cp){
286                                                 $cp['to'] = clean_path(str_replace('<basepath>', $this->base_dir, $cp['to']));
287                                                 $cp['from'] = clean_path(str_replace('<basepath>', $this->base_dir, $cp['from']));
288                                                 $GLOBALS['log']->debug('Unlink ' . $cp['to']);
289                                 /* BEGIN - RESTORE POINT - by MR. MILK August 31, 2005 02:22:11 PM */
290                                                 //rmdir_recursive($cp['to']);
291
292                                                 $backup_path = clean_path( remove_file_extension(urldecode(hashToFile($_REQUEST['install_file'])))."-restore/".$cp['to'] );
293                                                 $this->uninstall_new_files($cp, $backup_path);
294                                                 $this->copy_path($backup_path, $cp['to'], $backup_path, true);
295                                 /* END - RESTORE POINT - by MR. MILK August 31, 2005 02:22:18 PM */
296                                         }
297                                         $backup_path = clean_path( remove_file_extension(urldecode(hashToFile($_REQUEST['install_file'])))."-restore");
298                                         if(file_exists($backup_path))
299                                                 rmdir_recursive($backup_path);
300                                 }
301         }
302
303
304         /**
305          * Removes any files that were added by the loaded module. If the files already existed prior to install
306          * it will be handled by copy_path with the uninstall parameter.
307          *
308          */
309         function uninstall_new_files($cp, $backup_path){
310                 $zip_files = $this->dir_get_files($cp['from'],$cp['from']);
311                 $backup_files = $this->dir_get_files($backup_path, $backup_path);
312                 foreach($zip_files as $k=>$v){
313                         //if it's not a backup then it is probably a new file but we'll check that it is not in the md5.files first
314                         if(!isset($backup_files[$k])){
315                                 $to = $cp['to'] . $k;
316                                 //if it's not a sugar file then we remove it otherwise we can't restor it
317                                 if(!$this->ms->sugarFileExists($to)){
318                                         $GLOBALS['log']->debug('ModuleInstaller[uninstall_new_file] deleting file ' . $to);
319                                         if(file_exists($to)) {
320                                             unlink($to);
321                                         }
322                                 }else{
323                                         $GLOBALS['log']->fatal('ModuleInstaller[uninstall_new_file] Could not remove file ' . $to . ' as no backup file was found to restore to');
324                                 }
325                         }
326                 }
327                 //lets check if the directory is empty if it is we will delete it as well
328                 $files_remaining = $this->dir_file_count($cp['to']);
329                 if(file_exists($cp['to']) && $files_remaining == 0){
330                         $GLOBALS['log']->debug('ModuleInstaller[uninstall_new_file] deleting directory ' . $cp['to']);
331                         rmdir_recursive($cp['to']);
332                 }
333
334         }
335
336         /**
337          * Get directory where module's extensions go
338          * @param string $module Module name
339          */
340     public function getExtDir($module)
341     {
342             if($module == 'application') {
343             return "custom/Extension/application/Ext";
344         } else {
345                         return "custom/Extension/modules/$module/Ext";
346         }
347     }
348
349         /**
350          * Install file(s) into Ext/ part
351          * @param string $section Name of the install file section
352          * @param string $extname Name in Ext directory
353          * @param string $module This extension belongs to a specific module
354          */
355         public function installExt($section, $extname, $module = '')
356         {
357         if(isset($this->installdefs[$section])){
358                         $this->log(sprintf(translate("LBL_MI_IN_EXT"), $section));
359                         foreach($this->installdefs[$section] as $item){
360                             if(isset($item['from'])) {
361                                     $from = str_replace('<basepath>', $this->base_dir, $item['from']);
362                             } else {
363                                 $from = '';
364                             }
365                                 if(!empty($module)) {
366                                     $item['to_module'] = $module;
367                                 }
368                                 $GLOBALS['log']->debug("Installing section $section from $from for " .$item['to_module'] );
369                 if($item['to_module'] == 'application') {
370                     $path = "custom/Extension/application/Ext/$extname";
371                 } else {
372                                     $path = "custom/Extension/modules/{$item['to_module']}/Ext/$extname";
373                 }
374                                 if(!file_exists($path)){
375                                         mkdir_recursive($path, true);
376                                 }
377                                 if(isset($item["name"])) {
378                                     $target = $item["name"];
379                                 } else if (!empty($from)){
380                     $target = basename($from, ".php");
381                 } else {
382                                     $target = $this->id_name;
383                                 }
384                                 if(!empty($from)) {
385                                     copy_recursive($from , "$path/$target.php");
386                                 }
387                         }
388                 }
389         }
390
391         /**
392          * Uninstall file(s) into Ext/ part
393          * @param string $section Name of the install file section
394          * @param string $extname Name in Ext directory
395          * @param string $module This extension belongs to a specific module
396          */
397         public function uninstallExt($section, $extname, $module = '')
398         {
399         if(isset($this->installdefs[$section])){
400                         $this->log(sprintf(translate("LBL_MI_UN_EXT"), $section));
401                         foreach($this->installdefs[$section] as $item){
402                             if(isset($item['from'])) {
403                                     $from = str_replace('<basepath>', $this->base_dir, $item['from']);
404                             } else {
405                                 $from = '';
406                             }
407                             if(!empty($module)) {
408                                     $item['to_module'] = $module;
409                                 }
410                                 $GLOBALS['log']->debug("Uninstalling section $section from $from for " .$item['to_module'] );
411                 if($item['to_module'] == 'application') {
412                     $path = "custom/Extension/application/Ext/$extname";
413                 } else {
414                                     $path = "custom/Extension/modules/{$item['to_module']}/Ext/$extname";
415                 }
416                                 if(isset($item["name"])) {
417                                     $target = $item["name"];
418                                 } else if (!empty($from)){
419                     $target = basename($from, ".php");
420                 } else {
421                                     $target = $this->id_name;
422                                 }
423                                 $disabled_path = $path.'/'.DISABLED_PATH;
424                                 if (file_exists("$path/$target.php")) {
425                                     rmdir_recursive("$path/$target.php");
426                 } else if (file_exists("$disabled_path/$target.php")) {
427                     rmdir_recursive("$disabled_path/$target.php");
428                                 } else if (!empty($from) && file_exists($path . '/'. basename($from))) {
429                                     rmdir_recursive( $path . '/'. basename($from));
430                 } else if (!empty($from) && file_exists($disabled_path . '/'. basename($from))) {
431                                         rmdir_recursive( $disabled_path . '/'. basename($from));
432                                 }
433                     }
434             }
435         }
436
437         /**
438      * Rebuild generic extension
439      * @param string $ext Extension directory
440      * @param string $filename Target filename
441      */
442         public function rebuildExt($ext, $filename)
443         {
444             $this->log(translate('LBL_MI_REBUILDING') . " $ext...");
445                         $this->merge_files("Ext/$ext/", $filename);
446         }
447
448         /**
449          * Disable generic extension
450          * @param string $section Install file section name
451          * @param string $extname Extension directory
452          * @param string $module This extension belongs to a specific module
453          */
454         public function disableExt($section, $extname, $module = '')
455         {
456                 if(isset($this->installdefs[$section])) {
457                         foreach($this->installdefs[$section] as $item) {
458                             if(isset($item['from'])) {
459                                     $from = str_replace('<basepath>', $this->base_dir, $item['from']);
460                             } else {
461                                 $from = '';
462                             }
463                                 if(!empty($module)) {
464                                     $item['to_module'] = $module;
465                                 }
466                                 $GLOBALS['log']->debug("Disabling $extname ... from $from for " .$item['to_module']);
467                 if($item['to_module'] == 'application') {
468                     $path = "custom/Extension/application/Ext/$extname";
469                 } else {
470                                     $path = "custom/Extension/modules/{$item['to_module']}/Ext/$extname";
471                 }
472                                 if(isset($item["name"])) {
473                                     $target = $item["name"];
474                                 } else if (!empty($from)){
475                     $target = basename($from, ".php");
476                 }else {
477                                     $target = $this->id_name;
478                                 }
479                                 $disabled_path = $path.'/'.DISABLED_PATH;
480                 if (file_exists("$path/$target.php")) {
481                                         mkdir_recursive($disabled_path, true);
482                                         rename("$path/$target.php", "$disabled_path/$target.php");
483                                 } else if (!empty($from) && file_exists($path . '/'. basename($from))) {
484                                         mkdir_recursive($disabled_path, true);
485                                     rename( $path . '/'. basename($from), $disabled_path.'/'. basename($from));
486                                 }
487                         }
488                 }
489         }
490
491         /**
492          * Enable generic extension
493          * @param string $section Install file section name
494          * @param string $extname Extension directory
495          * @param string $module This extension belongs to a specific module
496          */
497         public function enableExt($section, $extname, $module = '')
498         {
499                 if(isset($this->installdefs[$section])) {
500                         foreach($this->installdefs[$section] as $item) {
501                             if(isset($item['from'])) {
502                                     $from = str_replace('<basepath>', $this->base_dir, $item['from']);
503                             } else {
504                                 $from = '';
505                             }
506                             if(!empty($module)) {
507                                     $item['to_module'] = $module;
508                                 }
509                                 $GLOBALS['log']->debug("Enabling $extname ... from $from for " .$item['to_module']);
510
511                 if($item['to_module'] == 'application') {
512                     $path = "custom/Extension/application/Ext/$extname";
513                 } else {
514                                     $path = "custom/Extension/modules/{$item['to_module']}/Ext/$extname";
515                 }
516                                 if(isset($item["name"])) {
517                                     $target = $item["name"];
518                                 } else if (!empty($from)){
519                     $target = basename($from, ".php");
520                 } else {
521                                     $target = $this->id_name;
522                                 }
523                                 if(!file_exists($path)) {
524                                     mkdir_recursive($path, true);
525                                 }
526                 $disabled_path = $path.'/'.DISABLED_PATH;
527                                 if (file_exists("$disabled_path/$target.php")) {
528                                         rename("$disabled_path/$target.php",  "$path/$target.php");
529                                 }
530                                 if (!empty($from) && file_exists($disabled_path . '/'. basename($from))) {
531                                         rename($disabled_path.'/'. basename($from),  $path . '/'. basename($from));
532                                 }
533                         }
534                 }
535     }
536
537     /**
538      * Method removes module from global search configurations
539      *
540      * return bool
541      */
542     public function uninstall_global_search()
543     {
544         if (empty($this->installdefs['beans']))
545         {
546             return true;
547         }
548
549         if (is_file('custom/modules/unified_search_modules_display.php') == false)
550         {
551             return true;
552         }
553
554         $user = new User();
555         $users = get_user_array();
556         $unified_search_modules_display = array();
557         require('custom/modules/unified_search_modules_display.php');
558
559         foreach($this->installdefs['beans'] as $beanDefs)
560         {
561             if (array_key_exists($beanDefs['module'], $unified_search_modules_display) == false)
562             {
563                 continue;
564             }
565             unset($unified_search_modules_display[$beanDefs['module']]);
566             foreach($users as $userId => $userName)
567             {
568                 if (empty($userId))
569                 {
570                     continue;
571                 }
572                 $user->retrieve($userId);
573                 $prefs = $user->getPreference('globalSearch', 'search');
574                 if (array_key_exists($beanDefs['module'], $prefs) == false)
575                 {
576                     continue;
577                 }
578                 unset($prefs[$beanDefs['module']]);
579                 $user->setPreference('globalSearch', $prefs, 0, 'search');
580                 $user->savePreferencesToDB();
581             }
582         }
583
584         if (write_array_to_file("unified_search_modules_display", $unified_search_modules_display, 'custom/modules/unified_search_modules_display.php') == false)
585         {
586             global $app_strings;
587             $msg = string_format($app_strings['ERR_FILE_WRITE'], array('custom/modules/unified_search_modules_display.php'));
588             $GLOBALS['log']->error($msg);
589             throw new Exception($msg);
590             return false;
591         }
592         return true;
593     }
594
595     /**
596      * Method enables module in global search configurations by disabled_module_visible key
597      *
598      * return bool
599      */
600     public function enable_global_search()
601     {
602         if (empty($this->installdefs['beans']))
603         {
604             return true;
605         }
606
607         if (is_file('custom/modules/unified_search_modules_display.php') == false)
608         {
609             return true;
610         }
611
612         $unified_search_modules_display = array();
613         require('custom/modules/unified_search_modules_display.php');
614
615         foreach($this->installdefs['beans'] as $beanDefs)
616         {
617             if (array_key_exists($beanDefs['module'], $unified_search_modules_display) == false)
618             {
619                 continue;
620             }
621             if (isset($unified_search_modules_display[$beanDefs['module']]['disabled_module_visible']) == false)
622             {
623                 continue;
624             }
625             $unified_search_modules_display[$beanDefs['module']]['visible'] = $unified_search_modules_display[$beanDefs['module']]['disabled_module_visible'];
626             unset($unified_search_modules_display[$beanDefs['module']]['disabled_module_visible']);
627         }
628
629         if (write_array_to_file("unified_search_modules_display", $unified_search_modules_display, 'custom/modules/unified_search_modules_display.php') == false)
630         {
631             global $app_strings;
632             $msg = string_format($app_strings['ERR_FILE_WRITE'], array('custom/modules/unified_search_modules_display.php'));
633             $GLOBALS['log']->error($msg);
634             throw new Exception($msg);
635             return false;
636         }
637         return true;
638     }
639
640     /**
641      * Method disables module in global search configurations by disabled_module_visible key
642      *
643      * return bool
644      */
645     public function disable_global_search()
646     {
647         if (empty($this->installdefs['beans']))
648         {
649             return true;
650         }
651
652         if (is_file('custom/modules/unified_search_modules_display.php') == false)
653         {
654             return true;
655         }
656
657         $unified_search_modules_display = array();
658         require('custom/modules/unified_search_modules_display.php');
659
660         foreach($this->installdefs['beans'] as $beanDefs)
661         {
662             if (array_key_exists($beanDefs['module'], $unified_search_modules_display) == false)
663             {
664                 continue;
665             }
666             if (isset($unified_search_modules_display[$beanDefs['module']]['visible']) == false)
667             {
668                 continue;
669             }
670             $unified_search_modules_display[$beanDefs['module']]['disabled_module_visible'] = $unified_search_modules_display[$beanDefs['module']]['visible'];
671             $unified_search_modules_display[$beanDefs['module']]['visible'] = false;
672         }
673
674         if (write_array_to_file("unified_search_modules_display", $unified_search_modules_display, 'custom/modules/unified_search_modules_display.php') == false)
675         {
676             global $app_strings;
677             $msg = string_format($app_strings['ERR_FILE_WRITE'], array('custom/modules/unified_search_modules_display.php'));
678             $GLOBALS['log']->error($msg);
679             throw new Exception($msg);
680             return false;
681         }
682         return true;
683     }
684
685     public function install_extensions()
686         {
687             foreach($this->extensions as $extname => $ext) {
688                 $install = "install_$extname";
689                 if(method_exists($this, $install)) {
690                     // non-standard function
691                 $this->$install();
692                 } else {
693                     if(!empty($ext["section"])) {
694                         $module = isset($ext['module'])?$ext['module']:'';
695                         $this->installExt($ext["section"], $ext["extdir"], $module);
696                     }
697                 }
698             }
699             $this->rebuild_extensions();
700         }
701
702         public function uninstall_extensions()
703         {
704             foreach($this->extensions as $extname => $ext) {
705                 $func = "uninstall_$extname";
706                 if(method_exists($this, $func)) {
707                     // non-standard function
708                 $this->$func();
709                 } else {
710                     if(!empty($ext["section"])) {
711                         $module = isset($ext['module'])?$ext['module']:'';
712                         $this->uninstallExt($ext["section"], $ext["extdir"], $module);
713                     }
714                 }
715             }
716             $this->rebuild_extensions();
717         }
718
719         public function rebuild_extensions()
720         {
721             foreach($this->extensions as $extname => $ext) {
722                 $func = "rebuild_$extname";
723                 if(method_exists($this, $func)) {
724                     // non-standard function
725                 $this->$func();
726                 } else {
727                 $this->rebuildExt($ext["extdir"], $ext["file"]);
728                 }
729             }
730         }
731
732         public function disable_extensions()
733         {
734             foreach($this->extensions as $extname => $ext) {
735                 $func = "disable_$extname";
736                 if(method_exists($this, $func)) {
737                     // non-standard install
738                 $this->$func();
739                 } else {
740                     if(!empty($ext["section"])) {
741                         $module = isset($ext['module'])?$ext['module']:'';
742                         $this->disableExt($ext["section"], $ext["extdir"], $module);
743                     }
744                 }
745             }
746             $this->rebuild_extensions();
747         }
748
749         public function enable_extensions()
750         {
751             foreach($this->extensions as $extname => $ext) {
752                 $func = "enable_$extname";
753                 if(method_exists($this, $func)) {
754                     // non-standard install
755                 $this->$func();
756                 } else {
757                     if(!empty($ext["section"])) {
758                         $module = isset($ext['module'])?$ext['module']:'';
759                         $this->enableExt($ext["section"], $ext["extdir"], $module);
760                     }
761                 }
762             }
763             $this->rebuild_extensions();
764         }
765
766         function install_dashlets()
767         {
768         if(isset($this->installdefs['dashlets'])){
769                         foreach($this->installdefs['dashlets'] as $cp){
770                                 $this->log(translate('LBL_MI_IN_DASHLETS') . $cp['name']);
771                                 $cp['from'] = str_replace('<basepath>', $this->base_dir, $cp['from']);
772                                 $path = 'custom/modules/Home/Dashlets/' . $cp['name'] . '/';
773                                 $GLOBALS['log']->debug("Installing Dashlet " . $cp['name'] . "..." . $cp['from'] );
774                                 if(!file_exists($path)){
775                                         mkdir_recursive($path, true);
776                                 }
777                                 copy_recursive($cp['from'] , $path);
778                         }
779                         include('modules/Administration/RebuildDashlets.php');
780
781                 }
782         }
783
784         function uninstall_dashlets(){
785         if(isset($this->installdefs['dashlets'])){
786                         foreach($this->installdefs['dashlets'] as $cp){
787                                 $this->log(translate('LBL_MI_UN_DASHLETS') . $cp['name']);
788                                 $path = 'custom/modules/Home/Dashlets/' . $cp['name'];
789                                 $GLOBALS['log']->debug('Unlink ' .$path);
790                                 if (file_exists($path))
791                                         rmdir_recursive($path);
792                         }
793                         include('modules/Administration/RebuildDashlets.php');
794                 }
795         }
796
797
798         function install_images(){
799         if(isset($this->installdefs['image_dir'])){
800                         $this->log( translate('LBL_MI_IN_IMAGES') );
801                         $this->copy_path($this->installdefs['image_dir'] , 'custom/themes');
802
803                 }
804         }
805
806         function install_dcactions(){
807                 if(isset($this->installdefs['dcaction'])){
808                         $this->log(translate('LBL_MI_IN_MENUS'));
809                         foreach($this->installdefs['dcaction'] as $action){
810                                 $action['from'] = str_replace('<basepath>', $this->base_dir, $action['from']);
811                                 $GLOBALS['log']->debug("Installing DCActions ..." . $action['from']);
812                                 $path = 'custom/Extension/application/Ext/DashletContainer/Containers';
813                                 if(!file_exists($path)){
814                                         mkdir_recursive($path, true);
815                                 }
816                                 copy_recursive($action['from'] , $path . '/'. $this->id_name . '.php');
817                         }
818                         $this->rebuild_dashletcontainers();
819                 }
820         }
821
822         function uninstall_dcactions(){
823         if(isset($this->installdefs['dcaction'])){
824                         $this->log(translate('LBL_MI_UN_MENUS'));
825                         foreach($this->installdefs['dcaction'] as $action){
826                                 $action['from'] = str_replace('<basepath>', $this->base_dir, $action['from']);
827                                 $GLOBALS['log']->debug("Uninstalling DCActions ..." . $action['from'] );
828                                 $path = 'custom/Extension/application/Ext/DashletContainer/Containers';
829                                 if (sugar_is_file($path . '/'. $this->id_name . '.php', 'w'))
830                                 {
831                                         rmdir_recursive( $path . '/'. $this->id_name . '.php');
832                                 }
833                                 else if (sugar_is_file($path . '/'. DISABLED_PATH . '/'. $this->id_name . '.php', 'w'))
834                                 {
835                                         rmdir_recursive( $path . '/'. DISABLED_PATH . '/'. $this->id_name . '.php');
836                                 }
837                         }
838                         $this->rebuild_dashletcontainers();
839                 }
840         }
841
842         function install_connectors(){
843         if(isset($this->installdefs['connectors'])){
844                 foreach($this->installdefs['connectors'] as $cp){
845                                 $this->log(translate('LBL_MI_IN_CONNECTORS') . $cp['name']);
846                                 $dir = str_replace('_','/',$cp['name']);
847                                 $cp['connector'] = str_replace('<basepath>', $this->base_dir, $cp['connector']);
848                                 $source_path = 'custom/modules/Connectors/connectors/sources/' . $dir. '/';
849                                 $GLOBALS['log']->debug("Installing Connector " . $cp['name'] . "..." . $cp['connector'] );
850                                 if(!file_exists($source_path)){
851                                         mkdir_recursive($source_path, true);
852                                 }
853                                 copy_recursive($cp['connector'] , $source_path);
854
855                                 //Install optional formatter code if it is specified
856                                 if(!empty($cp['formatter'])) {
857                                         $cp['formatter'] = str_replace('<basepath>', $this->base_dir, $cp['formatter']);
858                                         $formatter_path = 'custom/modules/Connectors/connectors/formatters/' . $dir. '/';
859                                         if(!file_exists($formatter_path)){
860                                                 mkdir_recursive($formatter_path, true);
861                                         }
862                                         copy_recursive($cp['formatter'] , $formatter_path);
863                                 }
864                         }
865                         require_once('include/connectors/utils/ConnectorUtils.php');
866                         ConnectorUtils::installSource($cp['name']);
867                 }
868
869         }
870         function uninstall_connectors(){
871         if(isset($this->installdefs['connectors'])){
872                 foreach($this->installdefs['connectors'] as $cp){
873                                 $this->log(translate('LBL_MI_UN_CONNECTORS') . $cp['name']);
874                                 $dir = str_replace('_','/',$cp['name']);
875                                 $source_path = 'custom/modules/Connectors/connectors/sources/' . $dir;
876                                 $formatter_path = 'custom/modules/Connectors/connectors/formatters/' . $dir;
877                                 $GLOBALS['log']->debug('Unlink ' .$source_path);
878                                 rmdir_recursive($source_path);
879                                 rmdir_recursive($formatter_path);
880                         }
881                         require_once('include/connectors/utils/ConnectorUtils.php');
882                         //ConnectorUtils::getConnectors(true);
883                         ConnectorUtils::uninstallSource($cp['name']);
884                 }
885         }
886
887         function install_vardef($from, $to_module)
888         {
889                         $GLOBALS['log']->debug("Installing Vardefs ..." . $from .  " for " .$to_module);
890                         $path = 'custom/Extension/modules/' . $to_module. '/Ext/Vardefs';
891                         if($to_module == 'application'){
892                                 $path ='custom/Extension/' . $to_module. '/Ext/Vardefs';
893                         }
894                         if(!file_exists($path)){
895                                 mkdir_recursive($path, true);
896                         }
897                         copy_recursive($from , $path.'/'. basename($from));
898         }
899
900         function install_layoutdef($from, $to_module){
901                         $GLOBALS['log']->debug("Installing Layout Defs ..." . $from .  " for " .$to_module);
902                         $path = 'custom/Extension/modules/' . $to_module. '/Ext/Layoutdefs';
903                         if($to_module == 'application'){
904                                 $path ='custom/Extension/' . $to_module. '/Ext/Layoutdefs';
905                         }
906                         if(!file_exists($path)){
907                                 mkdir_recursive($path, true);
908                         }
909                         copy_recursive($from , $path.'/'. basename($from));
910         }
911
912     // Non-standard - needs special rebuild call
913         function install_languages()
914         {
915         $languages = array();
916         if(isset($this->installdefs['language']))
917         {
918             $this->log(translate('LBL_MI_IN_LANG') );
919             foreach($this->installdefs['language'] as $packs)
920             {
921                 $modules[]=$packs['to_module'];
922                 $languages[$packs['language']] = $packs['language'];
923                                 $packs['from'] = str_replace('<basepath>', $this->base_dir, $packs['from']);
924                                 $GLOBALS['log']->debug("Installing Language Pack ..." . $packs['from']  .  " for " .$packs['to_module']);
925                             $path = 'custom/Extension/modules/' . $packs['to_module']. '/Ext/Language';
926                                 if($packs['to_module'] == 'application'){
927                                     $path ='custom/Extension/' . $packs['to_module']. '/Ext/Language';
928                                 }
929
930                                 if(!file_exists($path)){
931                                     mkdir_recursive($path, true);
932                 }
933                                 copy_recursive($packs['from'] , $path.'/'.$packs['language'].'.'. $this->id_name . '.php');
934                         }
935                         $this->rebuild_languages($languages, $modules);
936
937                 }
938         }
939
940     // Non-standard, needs special rebuild
941         function uninstall_languages(){
942         $languages = array();
943                                 if(isset($this->installdefs['language'])){
944                                         $this->log(translate('LBL_MI_UN_LANG') );
945                                         foreach($this->installdefs['language'] as $packs){
946                                                 $modules[]=$packs['to_module'];
947                                                 $languages[$packs['language']] = $packs['language'];
948                                                 $packs['from'] = str_replace('<basepath>', $this->base_dir, $packs['from']);
949                                                 $GLOBALS['log']->debug("Uninstalling Language Pack ..." . $packs['from']  .  " for " .$packs['to_module']);
950                                                 $path = 'custom/Extension/modules/' . $packs['to_module']. '/Ext/Language';
951                                                 if($packs['to_module'] == 'application'){
952                                                         $path ='custom/Extension/' . $packs['to_module']. '/Ext/Language';
953                                                 }
954                                                 if (sugar_is_file($path.'/'.$packs['language'].'.'. $this->id_name . '.php', 'w')) {
955                                                         rmdir_recursive( $path.'/'.$packs['language'].'.'. $this->id_name . '.php');
956                                                 } else if (sugar_is_file($path.'/'.DISABLED_PATH.'/'.$packs['language'].'.'. $this->id_name . '.php', 'w')) {
957                                                         rmdir_recursive($path.'/'.DISABLED_PATH.'/'.$packs['language'].'.'. $this->id_name . '.php', 'w');
958                                                 }
959                                         }
960                                         $this->rebuild_languages($languages, $modules);
961
962                                 }
963         }
964
965     // Non-standard, needs special rebuild
966         public function disable_languages()
967         {
968                 if(isset($this->installdefs['language'])) {
969                     $languages = $modules = array();
970                         foreach($this->installdefs['language'] as $item) {
971                                 $from = str_replace('<basepath>', $this->base_dir, $item['from']);
972                                 $GLOBALS['log']->debug("Disabling Language {$item['language']}... from $from for " .$item['to_module']);
973                                 $modules[]=$item['to_module'];
974                                 $languages[$item['language']] = $item['language'];
975                                 if($item['to_module'] == 'application') {
976                     $path = "custom/Extension/application/Ext/Language";
977                 } else {
978                                     $path = "custom/Extension/modules/{$item['to_module']}/Ext/Language";
979                 }
980                                 if(isset($item["name"])) {
981                                     $target = $item["name"];
982                                 } else {
983                                     $target = $this->id_name;
984                                 }
985                                 $target = "{$item['language']}.$target";
986
987                                 $disabled_path = $path.'/'.DISABLED_PATH;
988                 if (file_exists("$path/$target.php")) {
989                                         mkdir_recursive($disabled_path, true);
990                                         rename("$path/$target.php", "$disabled_path/$target.php");
991                                 } else if (file_exists($path . '/'. basename($from))) {
992                                         mkdir_recursive($disabled_path, true);
993                                     rename( $path . '/'. basename($from), $disabled_path.'/'. basename($from));
994                                 }
995                         }
996                         $this->rebuild_languages($languages, $modules);
997                 }
998         }
999
1000     // Non-standard, needs special rebuild
1001         public function enable_languages()
1002         {
1003                 if(isset($this->installdefs['language'])) {
1004                         foreach($this->installdefs['language'] as $item) {
1005                                 $from = str_replace('<basepath>', $this->base_dir, $item['from']);
1006                                 $GLOBALS['log']->debug("Enabling Language {$item['language']}... from $from for " .$item['to_module']);
1007                                 $modules[]=$item['to_module'];
1008                                 $languages[$item['language']] = $item['language'];
1009                                 if(!empty($module)) {
1010                                     $item['to_module'] = $module;
1011                                 }
1012
1013                 if($item['to_module'] == 'application') {
1014                     $path = "custom/Extension/application/Ext/Language";
1015                 } else {
1016                                     $path = "custom/Extension/modules/{$item['to_module']}/Ext/Language";
1017                 }
1018                                 if(isset($item["name"])) {
1019                                     $target = $item["name"];
1020                                 } else {
1021                                     $target = $this->id_name;
1022                                 }
1023                                 $target = "{$item['language']}.$target";
1024
1025                                 if(!file_exists($path)) {
1026                                     mkdir_recursive($path, true);
1027                                 }
1028                 $disabled_path = $path.'/'.DISABLED_PATH;
1029                                 if (file_exists("$disabled_path/$target.php")) {
1030                                         rename("$disabled_path/$target.php",  "$path/$target.php");
1031                                 }
1032                                 if (file_exists($disabled_path . '/'. basename($from))) {
1033                                         rename($disabled_path.'/'. basename($from),  $path . '/'. basename($from));
1034                                 }
1035                         }
1036                         $this->rebuild_languages($languages, $modules);
1037                 }
1038     }
1039
1040     // Functions for adding and removing logic hooks from uploaded files
1041     // Since one class/file can be used by multiple logic hooks, I'm not going to touch the file labeled in the logic_hook entry
1042     /* The module hook definition should look like this:
1043      $installdefs = array(
1044      ... blah blah ...
1045          'logic_hooks' => array(
1046              array('module'      => 'Accounts',
1047                    'hook'        => 'after_save',
1048                    'order'       => 99,
1049                    'description' => 'Account sample logic hook',
1050                    'file'        => 'modules/Sample/sample_account_logic_hook_file.php',
1051                    'class'       => 'SampleLogicClass',
1052                    'function'    => 'accountAfterSave',
1053              ),
1054          ),
1055      ... blah blah ...
1056      );
1057      */
1058     function enable_manifest_logichooks() {
1059         if(empty($this->installdefs['logic_hooks']) || !is_array($this->installdefs['logic_hooks'])) {
1060            return;
1061         }
1062
1063
1064
1065         foreach($this->installdefs['logic_hooks'] as $hook ) {
1066             check_logic_hook_file($hook['module'], $hook['hook'], array($hook['order'], $hook['description'],  $hook['file'], $hook['class'], $hook['function']));
1067         }
1068     }
1069
1070     function disable_manifest_logichooks() {
1071         if(empty($this->installdefs['logic_hooks']) || !is_array($this->installdefs['logic_hooks'])) {
1072             return;
1073         }
1074
1075         foreach($this->installdefs['logic_hooks'] as $hook ) {
1076             remove_logic_hook($hook['module'], $hook['hook'], array($hook['order'], $hook['description'],  $hook['file'], $hook['class'], $hook['function']));
1077         }
1078     }
1079
1080 /* BEGIN - RESTORE POINT - by MR. MILK August 31, 2005 02:22:18 PM */
1081         function copy_path($from, $to, $backup_path='', $uninstall=false){
1082         //function copy_path($from, $to){
1083 /* END - RESTORE POINT - by MR. MILK August 31, 2005 02:22:18 PM */
1084                 $to = str_replace('<basepath>', $this->base_dir, $to);
1085
1086                 if(!$uninstall) {
1087                 $from = str_replace('<basepath>', $this->base_dir, $from);
1088                 $GLOBALS['log']->debug('Copy ' . $from);
1089                 }
1090                 else {
1091                         $from = str_replace('<basepath>', $backup_path, $from);
1092                         //$GLOBALS['log']->debug('Restore ' . $from);
1093                 }
1094                 $from = clean_path($from);
1095                 $to = clean_path($to);
1096
1097                 $dir = dirname($to);
1098                 //there are cases where if we need to create a directory in the root directory
1099                 if($dir == '.' && is_dir($from)){
1100                         $dir = $to;
1101                 }
1102                 if(!sugar_is_dir($dir, 'instance'))
1103                         mkdir_recursive($dir, true);
1104 /* BEGIN - RESTORE POINT - by MR. MILK August 31, 2005 02:22:18 PM */
1105                 if(empty($backup_path)) {
1106 /* END - RESTORE POINT - by MR. MILK August 31, 2005 02:22:18 PM */
1107                 if(!copy_recursive($from, $to)){
1108                         die('Failed to copy ' . $from. ' ' . $to);
1109                 }
1110 /* BEGIN - RESTORE POINT - by MR. MILK August 31, 2005 02:22:18 PM */
1111                 }
1112                 elseif(!$this->copy_recursive_with_backup($from, $to, $backup_path, $uninstall)){
1113                         die('Failed to copy ' . $from. ' to ' . $to);
1114                 }
1115 /* END - RESTORE POINT - by MR. MILK August 31, 2005 02:22:18 PM */
1116         }
1117
1118         function install_custom_fields($fields){
1119                 global $beanList, $beanFiles;
1120                 include('include/modules.php');
1121                 require_once('modules/DynamicFields/FieldCases.php');
1122                 foreach($fields as $field){
1123                         $installed = false;
1124                         if(isset($beanList[ $field['module']])){
1125                                 $class = $beanList[ $field['module']];
1126                 if(!isset($field['ext4']))$field['ext4'] = '';
1127                 if(!isset($field['mass_update']))$field['mass_update'] = 0;
1128                 if(!isset($field['duplicate_merge']))$field['duplicate_merge'] = 0;
1129                 if(!isset($field['help']))$field['help'] = '';
1130
1131                 //Merge contents of the sugar field extension if we copied one over
1132                 if (file_exists("custom/Extension/modules/{$field['module']}/Ext/Vardefs/sugarfield_{$field['name']}.php"))
1133                 {
1134                     $dictionary = array();
1135                     include ("custom/Extension/modules/{$field['module']}/Ext/Vardefs/sugarfield_{$field['name']}.php");
1136                     $obj = BeanFactory::getObjectName($field['module']);
1137                     if (!empty($dictionary[$obj]['fields'][$field['name']])) {
1138                         $field = array_merge($dictionary[$obj]['fields'][$field['name']], $field);
1139                     }
1140                 }
1141
1142                 if(file_exists($beanFiles[$class])){
1143                                         require_once($beanFiles[$class]);
1144                                         $mod = new $class();
1145                                         $installed = true;
1146                                         $fieldObject = get_widget($field['type']);
1147                                         $fieldObject->populateFromRow($field);
1148                                         $mod->custom_fields->use_existing_labels =  true;
1149                                         $mod->custom_fields->addFieldObject($fieldObject);
1150                                 }
1151                         }
1152                         if(!$installed){
1153                                 $GLOBALS['log']->debug('Could not install custom field ' . $field['name'] . ' for module ' .  $field['module'] . ': Module does not exist');
1154                         }
1155                 }
1156         }
1157
1158         function uninstall_custom_fields($fields){
1159                 global $beanList, $beanFiles;
1160                 require_once('modules/DynamicFields/DynamicField.php');
1161                 $dyField = new DynamicField();
1162
1163                 foreach($fields as $field){
1164                         $class = $beanList[ $field['module']];
1165                         if(file_exists($beanFiles[$class])){
1166                                         require_once($beanFiles[$class]);
1167                                         $mod = new $class();
1168                                         $dyField->bean = $mod;
1169                                         $dyField->module = $field['module'];
1170                                         $dyField->deleteField($field['name']);
1171                         }
1172                 }
1173         }
1174
1175         /*
1176      * ModuleInstaller->install_relationships calls install_relationship for every file included in the module package that defines a relationship, and then
1177      * writes a custom/Extension/application/Ext/TableDictionary/$module.php file containing an include_once for every relationship metadata file passed to install_relationship.
1178      * Next it calls install_vardef and install_layoutdef. Finally, it rebuilds the vardefs and layoutdefs (by calling merge_files as usual), and then calls merge_files to merge
1179      * everything in 'Ext/TableDictionary/' into 'tabledictionary.ext.php'
1180      */
1181     function install_relationships ()
1182     {
1183         if (isset ( $this->installdefs [ 'relationships' ] ))
1184         {
1185             $this->log ( translate ( 'LBL_MI_IN_RELATIONSHIPS' ) ) ;
1186             $str = "<?php \n //WARNING: The contents of this file are auto-generated\n" ;
1187             $save_table_dictionary = false ;
1188
1189             if (! file_exists ( "custom/Extension/application/Ext/TableDictionary" ))
1190             {
1191                 mkdir_recursive ( "custom/Extension/application/Ext/TableDictionary", true ) ;
1192             }
1193
1194             foreach ( $this->installdefs [ 'relationships' ] as $key => $relationship )
1195             {
1196                 $filename = basename ( $relationship [ 'meta_data' ] ) ;
1197                 $this->copy_path ( $relationship [ 'meta_data' ], 'custom/metadata/' . $filename ) ;
1198                 $this->install_relationship ( 'custom/metadata/' . $filename ) ;
1199                 $save_table_dictionary = true ;
1200
1201                 if (! empty ( $relationship [ 'module_vardefs' ] ))
1202                 {
1203                     $relationship [ 'module_vardefs' ] = str_replace ( '<basepath>', $this->base_dir, $relationship [ 'module_vardefs' ] ) ;
1204                     $this->install_vardef ( $relationship [ 'module_vardefs' ], $relationship [ 'module' ] ) ;
1205                 }
1206
1207                 if (! empty ( $relationship [ 'module_layoutdefs' ] ))
1208                 {
1209                     $relationship [ 'module_layoutdefs' ] = str_replace ( '<basepath>', $this->base_dir, $relationship [ 'module_layoutdefs' ] ) ;
1210                     $this->install_layoutdef ( $relationship [ 'module_layoutdefs' ], $relationship [ 'module' ] ) ;
1211                 }
1212
1213                 $relName = strpos($filename, "MetaData") !== false ? substr($filename, 0, strlen($filename) - 12) : $filename;
1214                 $out = sugar_fopen ( "custom/Extension/application/Ext/TableDictionary/$relName.php", 'w' ) ;
1215                 fwrite ( $out, $str . "include('custom/metadata/$filename');\n\n?>" ) ;
1216                 fclose ( $out ) ;
1217             }
1218
1219
1220
1221
1222             Relationship::delete_cache();
1223             $this->rebuild_vardefs () ;
1224             $this->rebuild_layoutdefs () ;
1225             if ($save_table_dictionary)
1226             {
1227                 $this->rebuild_tabledictionary () ;
1228             }
1229             require_once("data/Relationships/RelationshipFactory.php");
1230             SugarRelationshipFactory::deleteCache();
1231         }
1232     }
1233
1234         /*
1235      * Install_relationship obtains a set of relationship definitions from the filename passed in as a parameter.
1236      * For each definition it calls db->createTableParams to build the relationships table if it does not exist,
1237      * and SugarBean::createRelationshipMeta to add the relationship into the 'relationships' table.
1238      */
1239         function install_relationship($file)
1240         {
1241                 $_REQUEST['moduleInstaller'] = true;
1242                 if(!file_exists($file))
1243                 {
1244                         $GLOBALS['log']->debug( 'File does not exists : '.$file);
1245                         return;
1246                 }
1247                 include($file);
1248                 $rel_dictionary = $dictionary;
1249                 foreach ($rel_dictionary as $rel_name => $rel_data)
1250             {
1251                 $table = ''; // table is actually optional
1252                 // check if we have a table definition - not all relationships require a join table
1253             if ( isset( $rel_data[ 'table' ] ) )
1254             {
1255                 $table = $rel_data[ 'table' ];
1256
1257                 if(!$this->db->tableExists($table))
1258                 {
1259                     $this->db->createTableParams($table, $rel_data[ 'fields' ], $rel_data[ 'indices' ]);
1260                 }
1261             }
1262
1263             if(!$this->silent)
1264                 $GLOBALS['log']->debug("Processing relationship meta for ". $rel_name."...");
1265             SugarBean::createRelationshipMeta($rel_name, $this->db,$table,$rel_dictionary,'');
1266             Relationship::delete_cache();
1267             if(!$this->silent)
1268                 $GLOBALS['log']->debug( 'done<br>');
1269         }
1270         }
1271
1272         function install_layoutfields() {
1273                  if (!empty ( $this->installdefs [ 'layoutfields' ] ))
1274                  {
1275                         foreach ( $this->installdefs [ 'layoutfields' ] as $fieldSet )
1276             {
1277                                 if (!empty($fieldSet['additional_fields']))
1278                                 {
1279                                         $this->addFieldsToLayout($fieldSet['additional_fields']);
1280                                 }
1281             }
1282                  }
1283         }
1284
1285         function uninstall_layoutfields() {
1286                  if (!empty ( $this->installdefs [ 'layoutfields' ] ))
1287                  {
1288                         foreach ( $this->installdefs [ 'layoutfields' ] as $fieldSet )
1289             {
1290                                 if (!empty($fieldSet['additional_fields']))
1291                                 {
1292                                         $this->removeFieldsFromLayout($fieldSet['additional_fields']);
1293                                 }
1294             }
1295                  }
1296         }
1297
1298         function uninstall_relationship($file, $rel_dictionary = null){
1299         if ($rel_dictionary == null)
1300                 {
1301                         if(!file_exists($file)){
1302                                 $GLOBALS['log']->debug( 'File does not exists : '.$file);
1303                                 return;
1304                         }
1305                         include($file);
1306                         $rel_dictionary = $dictionary;
1307                 }
1308
1309                 foreach ($rel_dictionary as $rel_name => $rel_data)
1310                 {
1311                         if (!empty($rel_data['table'])){
1312                                 $table = $rel_data['table'];
1313                         }
1314                         else{
1315                                 $table = ' One-to-Many ';
1316                         }
1317
1318                         if ($this->db->tableExists($table) && isset($GLOBALS['mi_remove_tables']) && $GLOBALS['mi_remove_tables'])
1319                         {
1320                                 SugarBean::removeRelationshipMeta($rel_name, $this->db,$table,$rel_dictionary,'');
1321                                 $this->db->dropTableName($table);
1322                                 if(!$this->silent) $this->log( translate('LBL_MI_UN_RELATIONSHIPS_DROP') . $table);
1323                         }
1324
1325                         //Delete Layout defs
1326                         // check to see if we have any vardef or layoutdef entries to remove - must have a relationship['module'] parameter if we do
1327                         if (!isset($rel_data[ 'module' ]))
1328                                 $mods = array(
1329                                         $rel_data['relationships'][$rel_name]['lhs_module'],
1330                                         $rel_data['relationships'][$rel_name]['rhs_module'],
1331                                 );
1332                         else
1333                                 $mods = array($rel_data[ 'module' ]);
1334
1335                         $filename = "$rel_name.php";
1336
1337                         foreach($mods as $mod) {
1338                                 if ($mod != 'application' )  {
1339                                         $basepath = "custom/Extension/modules/$mod/Ext/";
1340                                 } else {
1341                                         $basepath = "custom/Extension/application/Ext/";
1342                                 }
1343
1344                                 foreach (array($filename , "custom" . $filename, $rel_name ."_". $mod. ".php") as $fn) {
1345                                         //remove any vardefs
1346                                         $path = $basepath . "Vardefs/$fn" ;
1347                                         if (file_exists( $path ))
1348                                                 rmdir_recursive( $path );
1349
1350                                         //remove any layoutdefs
1351                                         $path = $basepath . "Layoutdefs/$fn" ;
1352                                         if( file_exists( $path ))
1353                                         {
1354                                                 rmdir_recursive( $path );
1355                                         }
1356                                 }
1357                         }
1358
1359                         foreach (array($filename , "custom" . $filename, $rel_name ."_". $mod. ".php") as $fn) {
1360                                 // remove the table dictionary extension
1361                                 if ( file_exists("custom/Extension/application/Ext/TableDictionary/$fn"))
1362                                     unlink("custom/Extension/application/Ext/TableDictionary/$fn");
1363
1364                                 if (file_exists("custom/metadata/{$rel_name}MetaData.php"))
1365                                         unlink( "custom/metadata/{$rel_name}MetaData.php" );
1366                         }
1367                 }
1368         }
1369
1370         function uninstall_relationships($include_studio_relationships = false){
1371                 $relationships = array();
1372
1373                 //Find and remove studio created relationships.
1374                 global $beanList, $beanFiles, $dictionary;
1375                 //Load up the custom relationship definitions.
1376                 if(file_exists('custom/application/Ext/TableDictionary/tabledictionary.ext.php')){
1377                         include('custom/application/Ext/TableDictionary/tabledictionary.ext.php');
1378                 }
1379                 //Find all the relatioships/relate fields involving this module.
1380                 $rels_to_remove = array();
1381                 foreach($beanList as $mod => $bean) {
1382                         //Some modules like cases have a bean name that doesn't match the object name
1383                         $bean = BeanFactory::getObjectName($mod);
1384             VardefManager::loadVardef($mod, $bean);
1385                         //We can skip modules that are in this package as they will be removed anyhow
1386                         if (!in_array($mod, $this->modulesInPackage) && !empty($dictionary[$bean]) && !empty($dictionary[$bean]['fields']))
1387                         {
1388                                 $field_defs = $dictionary[$bean]['fields'];
1389                                 foreach($field_defs as $field => $def)
1390                                 {
1391                                         //Weed out most fields first
1392                                         if (isset ($def['type']))
1393                                         {
1394                                                 //Custom relationships created in the relationship editor
1395                                                 if ($def['type'] == "link" && !empty($def['relationship']) && !empty($dictionary[$def['relationship']]))
1396                                                 {
1397                                                         $rel_name = $def['relationship'];
1398
1399                                                         $rel_def = $dictionary[$rel_name]['relationships'][$rel_name];
1400
1401                                                         //Check against mods to be removed.
1402                                                         foreach($this->modulesInPackage as $removed_mod) {
1403                                                                 if ($rel_def['lhs_module'] == $removed_mod || $rel_def['rhs_module'] == $removed_mod )
1404                                                                 {
1405                                                                         $dictionary[$rel_name]['from_studio'] = true;
1406                                                                         $relationships[$rel_name] = $dictionary[$rel_name];
1407                                                                 }
1408                                                         }
1409                                                 }
1410                                                 //Custom "relate" fields created in studio also need to be removed
1411                                                 if ($def['type'] == 'relate' && isset($def['module'])) {
1412                                                         foreach($this->modulesInPackage as $removed_mod) {
1413                                                                 if ($def['module'] == $removed_mod)
1414                                                                 {
1415                                                                         require_once 'modules/ModuleBuilder/Module/StudioModule.php' ;
1416                                                                         $studioMod = new StudioModule ( $mod );
1417                                                                         $studioMod->removeFieldFromLayouts( $field );
1418                                                                         if (isset($def['custom_module'])) {
1419                                                                                 require_once ('modules/DynamicFields/DynamicField.php') ;
1420                                                                                 require_once ($beanFiles [ $bean ]) ;
1421                                                                                 $seed = new $bean ( ) ;
1422                                                                                 $df = new DynamicField ( $mod ) ;
1423                                                                                 $df->setup ( $seed ) ;
1424                                                                                 //Need to load the entire field_meta_data for some field types
1425                                                                                 $field_obj = $df->getFieldWidget($mod, $field);
1426                                                                                 $field_obj->delete ( $df ) ;
1427                                                                         }
1428                                                                 }
1429                                                         }
1430                                                 }
1431                                         }
1432                                 }
1433                         }
1434                 }
1435
1436
1437
1438                 $this->uninstall_relationship(null, $relationships);
1439
1440                 if(isset($this->installdefs['relationships'])) {
1441                         $relationships = $this->installdefs['relationships'];
1442                         $this->log(translate('LBL_MI_UN_RELATIONSHIPS') );
1443                         foreach($relationships as $relationship)
1444                         {
1445                                 // remove the metadata entry
1446                                 $filename = basename ( $relationship['meta_data'] );
1447                                 $pathname = (file_exists("custom/metadata/$filename")) ? "custom/metadata/$filename" : "metadata/$filename" ;
1448                                 if(isset($GLOBALS['mi_remove_tables']) && $GLOBALS['mi_remove_tables'])
1449                                 $this->uninstall_relationship( $pathname );
1450                                 if (file_exists($pathname))
1451                                         unlink( $pathname );
1452                         }
1453                 }
1454
1455                 if (file_exists("custom/Extension/application/Ext/TableDictionary/{$this->id_name}.php"))
1456                         unlink("custom/Extension/application/Ext/TableDictionary/{$this->id_name}.php");
1457                 Relationship::delete_cache();
1458                 $this->rebuild_tabledictionary();
1459         }
1460
1461
1462
1463
1464         function uninstall($base_dir){
1465                 if(defined('TEMPLATE_URL'))SugarTemplateUtilities::disableCache();
1466                 global $app_strings;
1467                 $total_steps = 5; //min steps with no tasks
1468                 $current_step = 0;
1469                 $this->base_dir = $base_dir;
1470                 $tasks = array(
1471                         'pre_uninstall',
1472                         'uninstall_relationships',
1473                         'uninstall_copy',
1474                         'uninstall_dcactions',
1475                         'uninstall_dashlets',
1476                         'uninstall_connectors',
1477                         'uninstall_layoutfields',
1478                     'uninstall_extensions',
1479             'uninstall_global_search',
1480                         'disable_manifest_logichooks',
1481                         'post_uninstall',
1482                 );
1483                 $total_steps += count($tasks); //now the real number of steps
1484                 if(file_exists($this->base_dir . '/manifest.php')){
1485                                 if(!$this->silent){
1486                                         $current_step++;
1487                                         display_progress_bar('install', $current_step, $total_steps);
1488                                         echo '<div id ="displayLoglink" ><a href="#" onclick="toggleDisplay(\'displayLog\')">'.$app_strings['LBL_DISPLAY_LOG'].'</a> </div><div id="displayLog" style="display:none">';
1489                                 }
1490
1491                                 global $moduleList;
1492                                 include($this->base_dir . '/manifest.php');
1493                                 $this->installdefs = $installdefs;
1494                                 $this->id_name = $this->installdefs['id'];
1495                                 $installed_modules = array();
1496                                 if(isset($this->installdefs['beans'])){
1497                                         foreach($this->installdefs['beans'] as $bean){
1498
1499                                                 $installed_modules[] = $bean['module'];
1500                                                 $this->uninstall_user_prefs($bean['module']);
1501                                         }
1502                                         $this->modulesInPackage = $installed_modules;
1503                                         $this->uninstall_beans($installed_modules);
1504                                         $this->uninstall_customizations($installed_modules);
1505                                         if(!$this->silent){
1506                                                 $current_step++;
1507                                                 update_progress_bar('install', $total_steps, $total_steps);
1508                                         }
1509                                 }
1510                                 if(!$this->silent){
1511                                         $current_step++;
1512                                         update_progress_bar('install', $current_step, $total_steps);
1513                                 }
1514                                 foreach($tasks as $task){
1515                                         $this->$task();
1516                                         if(!$this->silent){
1517                                                 $current_step++;
1518                                                 update_progress_bar('install', $current_step, $total_steps);
1519                                         }
1520                                 }
1521                                 if(isset($installdefs['custom_fields']) && (isset($GLOBALS['mi_remove_tables']) && $GLOBALS['mi_remove_tables'])){
1522                                         $this->log(translate('LBL_MI_UN_CUSTOMFIELD'));
1523                                         $this->uninstall_custom_fields($installdefs['custom_fields']);
1524                                 }
1525                                 if(!$this->silent){
1526                                         $current_step++;
1527                                         update_progress_bar('install', $current_step, $total_steps);
1528                                         echo '</div>';
1529                                 }
1530                                 //since we are passing $silent = true to rebuildAll() in that method it will set $this->silent = true, so
1531                                 //we need to save the setting to set it back after rebuildAll() completes.
1532                                 $silentBak = $this->silent;
1533                                 $this->rebuild_all(true);
1534                                 $this->silent = $silentBak;
1535
1536                                 //#27877, If the request from MB redeploy a custom module , we will not remove the ACL actions for this package.
1537                                 if( !isset($_REQUEST['action']) || $_REQUEST['action']!='DeployPackage' ){
1538                                         $this->remove_acl_actions();
1539                                 }
1540                                 //end
1541
1542                                 if(!$this->silent){
1543                                         $current_step++;
1544                                         update_progress_bar('install', $current_step, $total_steps);
1545                                         echo '</div>';
1546                                 }
1547
1548                                 UpdateSystemTabs('Restore',$installed_modules);
1549
1550                     //clear the unified_search_module.php file
1551                     require_once('modules/Home/UnifiedSearchAdvanced.php');
1552                     UnifiedSearchAdvanced::unlinkUnifiedSearchModulesFile();
1553
1554                                 $this->log('<br><b>' . translate('LBL_MI_COMPLETE') . '</b>');
1555                                 if(!$this->silent){
1556                                         update_progress_bar('install', $total_steps, $total_steps);
1557                                 }
1558                 }else{
1559                         die("No manifest.php Defined In $this->base_dir/manifest.php");
1560                 }
1561         }
1562
1563         function rebuild_languages($languages = array(), $modules="")
1564         {
1565             foreach($languages as $language=>$value){
1566                                 $this->log(translate('LBL_MI_REBUILDING') . " Language...$language");
1567                                 $this->merge_files('Ext/Language/', $language.'.lang.ext.php', $language);
1568                     if($modules!=""){
1569                         foreach($modules as $module){
1570                                 LanguageManager::clearLanguageCache($module, $language);
1571                         }
1572                     }
1573                         }
1574                         sugar_cache_reset();
1575         }
1576
1577         function rebuild_vardefs()
1578         {
1579             $this->rebuildExt("Vardefs", 'vardefs.ext.php');
1580                 sugar_cache_reset();
1581         }
1582
1583         function rebuild_dashletcontainers(){
1584             $this->log(translate('LBL_MI_REBUILDING') . " DC Actions...");
1585                         $this->merge_files('Ext/DashletContainer/Containers/', 'dcactions.ext.php');
1586         }
1587
1588         function rebuild_tabledictionary()
1589         {
1590             $this->rebuildExt("TableDictionary", 'tabledictionary.ext.php');
1591         }
1592
1593         function rebuild_relationships() {
1594         if(!$this->silent) echo translate('LBL_MI_REBUILDING') . ' Relationships';
1595                 $_REQUEST['silent'] = true;
1596                 global $beanFiles;
1597                 include('include/modules.php');
1598                 include("modules/Administration/RebuildRelationship.php");
1599         }
1600
1601         function remove_acl_actions() {
1602                 global $beanFiles, $beanList, $current_user;
1603                 include('include/modules.php');
1604                 include("modules/ACL/remove_actions.php");
1605         }
1606
1607         /**
1608          * Wrapper call to modules/Administration/RepairIndex.php
1609          */
1610         function repair_indices() {
1611                 global $current_user,$beanFiles,$dictionary;
1612                 $this->log(translate('LBL_MI_REPAIR_INDICES'));
1613                 $_REQUEST['silent'] = true; // local var flagging echo'd output in repair script
1614                 $_REQUEST['mode'] = 'execute'; // flag to just go ahead and run the script
1615                 include("modules/Administration/RepairIndex.php");
1616         }
1617
1618         /**
1619          * Rebuilds the extension files found in custom/Extension
1620          * @param boolean $silent
1621          */
1622         function rebuild_all($silent=false){
1623                 if(defined('TEMPLATE_URL'))SugarTemplateUtilities::disableCache();
1624                 $this->silent=$silent;
1625                 global $sugar_config;
1626
1627                 //Check for new module extensions
1628                 $this->rebuild_modules();
1629
1630                 $this->rebuild_languages($sugar_config['languages']);
1631                 $this->rebuild_extensions();
1632                 $this->rebuild_dashletcontainers();
1633                 $this->rebuild_relationships();
1634                 $this->rebuild_tabledictionary();
1635         $this->reset_opcodes();
1636                 sugar_cache_reset();
1637         }
1638
1639         /*
1640      * ModuleInstaller->merge_files runs over the list of all modules already installed in /modules. For each $module it reads the contents of every file in
1641      * custom/Extension/modules/$module/<path> (_override files last) and concatenates them to custom/modules/$module/<path>/<file>.
1642      * Then it does the same thing in custom/Extension/application/<path>, concatenating those files and copying the result to custom/application/<path>/<file>
1643      */
1644         function merge_files($path, $name, $filter = '', $application = false){
1645                 if(!$application){
1646                 $GLOBALS['log']->debug( get_class($this)."->merge_files() : merging module files in custom/Extension/modules/<module>/$path to custom/modules/<module>/$path$name");
1647                 foreach($this->modules as $module){
1648                                 //$GLOBALS['log']->debug("Merging Files for: ".$module);
1649                                 //$GLOBALS['log']->debug("Merging Files for path: ".$path);
1650                                 $extension = "<?php \n //WARNING: The contents of this file are auto-generated\n";
1651                                 $extpath = "modules/$module/$path";
1652                                 $module_install  = 'custom/Extension/'.$extpath;
1653                                 $shouldSave = false;
1654                                 if(is_dir($module_install)){
1655                                         $dir = dir($module_install);
1656                                         $shouldSave = true;
1657                                         $override = array();
1658                                         while($entry = $dir->read()){
1659                                                 if((empty($filter) || substr_count($entry, $filter) > 0) && is_file($module_install.'/'.$entry)
1660                                                   && $entry != '.' && $entry != '..' && strtolower(substr($entry, -4)) == ".php")
1661                                                 {
1662                                                      if (substr($entry, 0, 9) == '_override') {
1663                                                         $override[] = $entry;
1664                                                     } else {
1665                                                             $file = file_get_contents($module_install . '/' . $entry);
1666                                                             $GLOBALS['log']->debug(get_class($this)."->merge_files(): found {$module_install}{$entry}") ;
1667                                                             $extension .= "\n". str_replace(array('<?php', '?>', '<?PHP', '<?'), array('','', '' ,'') , $file);
1668                                                     }
1669                                                 }
1670                                         }
1671                                         foreach ($override as $entry) {
1672                         $file = file_get_contents($module_install . '/' . $entry);
1673                         $extension .= "\n". str_replace(array('<?php', '?>', '<?PHP', '<?'), array('','', '' ,'') , $file);
1674                                         }
1675                                 }
1676                                 $extension .= "\n?>";
1677
1678                                 if($shouldSave){
1679                                         if(!file_exists("custom/$extpath")) {
1680                                             mkdir_recursive("custom/$extpath", true);
1681                                     }
1682                                         $out = sugar_fopen("custom/$extpath/$name", 'w');
1683                                         fwrite($out,$extension);
1684                                         fclose($out);
1685                                 }else{
1686                                         if(file_exists("custom/$extpath/$name")){
1687                                                 unlink("custom/$extpath/$name");
1688                                         }
1689                                 }
1690                         }
1691
1692                 }
1693
1694                 $GLOBALS['log']->debug("Merging application files for $name in $path");
1695                 //Now the application stuff
1696                 $extension = "<?php \n //WARNING: The contents of this file are auto-generated\n";
1697                 $extpath = "application/$path";
1698                 $module_install  = 'custom/Extension/'.$extpath;
1699                 $shouldSave = false;
1700                                         if(is_dir($module_install)){
1701                                                 $dir = dir($module_install);
1702                                                 while($entry = $dir->read()){
1703                                                                 $shouldSave = true;
1704                                                                 if((empty($filter) || substr_count($entry, $filter) > 0) && is_file($module_install.'/'.$entry)
1705                                                                   && $entry != '.' && $entry != '..' && strtolower(substr($entry, -4)) == ".php")
1706                                                                 {
1707                                                                         $file = file_get_contents($module_install . '/' . $entry);
1708                                                                         $extension .= "\n". str_replace(array('<?php', '?>', '<?PHP', '<?'), array('','', '' ,'') , $file);
1709                                                                 }
1710                                                 }
1711                                         }
1712                                         $extension .= "\n?>";
1713                                         if($shouldSave){
1714                                                 if(!file_exists("custom/$extpath")){
1715                                                         mkdir_recursive("custom/$extpath", true);
1716                                                 }
1717                                                 $out = sugar_fopen("custom/$extpath/$name", 'w');
1718                                                 fwrite($out,$extension);
1719                                                 fclose($out);
1720                                         }else{
1721                                         if(file_exists("custom/$extpath/$name")){
1722                                                 unlink("custom/$extpath/$name");
1723                                         }
1724                                 }
1725
1726 }
1727
1728     function install_modules()
1729     {
1730             $this->installed_modules = array();
1731                 $this->tab_modules = array();
1732         if(isset($this->installdefs['beans'])){
1733                         $str = "<?php \n //WARNING: The contents of this file are auto-generated\n";
1734                         foreach($this->installdefs['beans'] as $bean){
1735                                 if(!empty($bean['module']) && !empty($bean['class']) && !empty($bean['path'])){
1736                                         $module = $bean['module'];
1737                                         $class = $bean['class'];
1738                                         $path = $bean['path'];
1739
1740                                         $str .= "\$beanList['$module'] = '$class';\n";
1741                                         $str .= "\$beanFiles['$class'] = '$path';\n";
1742                                         if($bean['tab']){
1743                                                 $str .= "\$moduleList[] = '$module';\n";
1744                                                 $this->install_user_prefs($module, empty($bean['hide_by_default']));
1745                                                 $this->tab_modules[] = $module;
1746                                         }else{
1747                                                 $str .= "\$modules_exempt_from_availability_check['$module'] = '$module';\n";
1748                                                 $str .= "\$report_include_modules['$module'] = '$module';\n";
1749                                                 $str .= "\$modInvisList[] = '$module';\n";
1750                                         }
1751                                     $this->installed_modules[] = $module;
1752                                 }else{
1753                                                 $errors[] = 'Bean array not well defined.';
1754                                                 $this->abort($errors);
1755                                 }
1756                         }
1757                         $str.= "\n?>";
1758                         if(!file_exists("custom/Extension/application/Ext/Include")){
1759                                 mkdir_recursive("custom/Extension/application/Ext/Include", true);
1760                         }
1761                         file_put_contents("custom/Extension/application/Ext/Include/{$this->id_name}.php", $str);
1762         }
1763     }
1764
1765     /*
1766      * ModuleInstaller->install_beans runs through the list of beans given, instantiates each bean, calls bean->create_tables, and then calls SugarBean::createRelationshipMeta for the
1767      * bean/module.
1768      */
1769         function install_beans($beans){
1770         include('include/modules.php');
1771                 foreach($beans as $bean){
1772                         $this->log( translate('LBL_MI_IN_BEAN') . " $bean");
1773                         if(isset($beanList[$bean])){
1774                                 $class = $beanList[$bean];
1775                                 if(file_exists($beanFiles[$class])){
1776                                         require_once($beanFiles[$class]);
1777                                         $mod = new $class();
1778                                         //#30273
1779                                         if(is_subclass_of($mod, 'SugarBean')  && $mod->disable_vardefs == false ){
1780                                                 $GLOBALS['log']->debug( "Creating Tables Bean : $bean");
1781                                                 $mod->create_tables();
1782                                                 SugarBean::createRelationshipMeta($mod->getObjectName(), $mod->db,$mod->table_name,'',$mod->module_dir);    
1783                                         }
1784                                 }else{
1785                                         $GLOBALS['log']->debug( "File Does Not Exist:" . $beanFiles[$class] );
1786                                 }
1787                         }
1788                 }
1789         }
1790
1791                 function uninstall_beans($beans){
1792                 include('include/modules.php');
1793         foreach($beans as $bean){
1794                         $this->log( translate('LBL_MI_UN_BEAN') . " $bean");
1795                         if(isset($beanList[$bean])){
1796                                 $class = $beanList[$bean];
1797
1798                                 if(file_exists($beanFiles[$class])){
1799                                         require_once($beanFiles[$class]);
1800                                         $mod = new $class();
1801
1802                                         if(is_subclass_of($mod, 'SugarBean')){
1803                                                 $GLOBALS['log']->debug( "Drop Tables : $bean");
1804                                                 if(isset($GLOBALS['mi_remove_tables']) && $GLOBALS['mi_remove_tables'])
1805                                                         $mod->drop_tables();
1806                                         }
1807                                 }else{
1808                                         $GLOBALS['log']->debug( "File Does Not Exist:" . $beanFiles[$class] );
1809                                 }
1810                         }
1811                 }
1812         }
1813
1814         /**
1815          * Remove any customizations made within Studio while the module was installed.
1816          */
1817         function uninstall_customizations($beans){
1818         foreach($beans as $bean){
1819                         $dirs = array(
1820                                 'custom/modules/' . $bean,
1821                                 'custom/Extension/modules/' . $bean,
1822                 'custom/working/modules/' . $bean
1823                         );
1824                 foreach($dirs as $dir)
1825                 {
1826                                 if(is_dir($dir)){
1827                                         rmdir_recursive($dir);
1828                                 }
1829                 }
1830                 }
1831         }
1832
1833         function log($str){
1834                 $GLOBALS['log']->debug('ModuleInstaller:'. $str);
1835                 if(!$this->silent){
1836                         echo $str . '<br>';
1837                 }
1838         }
1839
1840 /* BEGIN - RESTORE POINT - by MR. MILK August 31, 2005 02:15:18 PM      */
1841 function copy_recursive_with_backup( $source, $dest, $backup_path, $uninstall=false ) {
1842         if(is_file($source)) {
1843             if($uninstall) {
1844                     $GLOBALS['log']->debug("Restoring ... " . $source.  " to " .$dest );
1845                     if(copy( $source, $dest)) {
1846                             if(is_writable($dest))
1847                                 sugar_touch( $dest, filemtime($source) );
1848                         return(unlink($source));
1849                 }
1850                     else {
1851                         $GLOBALS['log']->debug( "Can't restore file: " . $source );
1852                         return true;
1853                 }
1854             }
1855             else {
1856                         if(file_exists($dest)) {
1857                                 $rest = clean_path($backup_path."/$dest");
1858                                 if( !is_dir(dirname($rest)) )
1859                                         mkdir_recursive(dirname($rest), true);
1860
1861                                 $GLOBALS['log']->debug("Backup ... " . $dest.  " to " .$rest );
1862                                 if(copy( $dest, $rest)) {
1863                                         if(is_writable($rest))
1864                                                 sugar_touch( $rest, filemtime($dest) );
1865                                 }
1866                                 else {
1867                                         $GLOBALS['log']->debug( "Can't backup file: " . $dest );
1868                                 }
1869                         }
1870                         return( copy( $source, $dest ) );
1871                 }
1872     }
1873     elseif(!is_dir($source)) {
1874             if($uninstall) {
1875                         if(is_file($dest))
1876                                 return(unlink($dest));
1877                         else {
1878                                 //don't do anything we already cleaned up the files using uninstall_new_files
1879                                 return true;
1880                         }
1881                 }
1882                 else
1883                         return false;
1884         }
1885
1886     if( !is_dir($dest) && !$uninstall){
1887         sugar_mkdir( $dest );
1888     }
1889
1890     $status = true;
1891
1892     $d = dir( $source );
1893     while( $f = $d->read() ){
1894         if( $f == "." || $f == ".." ){
1895             continue;
1896         }
1897         $status &= $this->copy_recursive_with_backup( "$source/$f", "$dest/$f", $backup_path, $uninstall );
1898     }
1899     $d->close();
1900     return( $status );
1901 }
1902
1903 private function dir_get_files($path, $base_path){
1904         $files = array();
1905         if(!is_dir($path))return $files;
1906         $d = dir($path);
1907         while ($e = $d->read()){
1908                 //ignore invisible files . .. ._MACOSX
1909                 if(substr($e, 0, 1) == '.')continue;
1910                 if(is_file($path . '/' . $e))$files[str_replace($base_path , '', $path . '/' . $e)] = str_replace($base_path , '', $path . '/' . $e);
1911                 if(is_dir($path . '/' . $e))$files = array_merge($files, $this->dir_get_files($path . '/' . $e, $base_path));
1912         }
1913         $d->close();
1914         return $files;
1915
1916 }
1917
1918 private function dir_file_count($path){
1919         //if its a file then it has at least 1 file in the directory
1920         if(is_file($path)) return 1;
1921         if(!is_dir($path)) return 0;
1922         $d = dir($path);
1923         $count = 0;
1924         while ($e = $d->read()){
1925                 //ignore invisible files . .. ._MACOSX
1926                 if(substr($e, 0, 1) == '.')continue;
1927                 if(is_file($path . '/' . $e))$count++;
1928                 if(is_dir($path . '/' . $e))$count += $this->dir_file_count($path . '/' . $e);
1929         }
1930         $d->close();
1931         return $count;
1932
1933
1934 }
1935 /* END - RESTORE POINT - by MR. MILK August 31, 2005 02:15:34 PM */
1936
1937
1938         /**
1939          * Static function which allows a module developer to abort their progress, pass in an array of errors and
1940          * redirect back to the main module loader page
1941          *
1942          * @param errors        an array of error messages which will be displayed on the
1943          *                                      main module loader page once it is loaded.
1944          */
1945         function abort($errors = array()){
1946                 //set the errors onto the session so we can display them one the moduler loader page loads
1947                 $_SESSION['MODULEINSTALLER_ERRORS'] = $errors;
1948                 echo '<META HTTP-EQUIV="Refresh" content="0;url=index.php?module=Administration&action=UpgradeWizard&view=module">';
1949                 die();
1950                 //header('Location: index.php?module=Administration&action=UpgradeWizard&view=module');
1951         }
1952
1953         /**
1954          * Return the set of errors stored in the SESSION
1955          *
1956          * @return an array of errors
1957          */
1958         function getErrors(){
1959                 if(!empty($_SESSION['MODULEINSTALLER_ERRORS'])){
1960                         $errors = $_SESSION['MODULEINSTALLER_ERRORS'];
1961                         unset($_SESSION['MODULEINSTALLER_ERRORS']);
1962                         return $errors;
1963                 }
1964                 else
1965                         return null;
1966         }
1967
1968         /*
1969      * Add any fields to the DetailView and EditView of the appropriate modules
1970      * Only add into deployed modules, as addFieldsToUndeployedLayouts has done this already for undeployed modules (and the admin might have edited the layouts already)
1971      * @param array $layoutAdditions  An array of module => fieldname
1972      * return null
1973      */
1974         function addFieldsToLayout($layoutAdditions) {
1975         require_once 'modules/ModuleBuilder/parsers/views/GridLayoutMetaDataParser.php' ;
1976
1977         // these modules either lack editviews/detailviews or use custom mechanisms for the editview/detailview.
1978         // In either case, we don't want to attempt to add a relate field to them
1979         // would be better if GridLayoutMetaDataParser could handle this gracefully, so we don't have to maintain this list here
1980         $invalidModules = array ( 'emails' , 'kbdocuments' ) ;
1981
1982         foreach ( $layoutAdditions as $deployedModuleName => $fieldName )
1983         {
1984             if ( ! in_array( strtolower ( $deployedModuleName ) , $invalidModules ) )
1985             {
1986                 foreach ( array ( MB_EDITVIEW , MB_DETAILVIEW ) as $view )
1987                 {
1988                     $GLOBALS [ 'log' ]->debug ( get_class ( $this ) . ": adding $fieldName to $view layout for module $deployedModuleName" ) ;
1989                     $parser = new GridLayoutMetaDataParser ( $view, $deployedModuleName ) ;
1990                     $parser->addField ( array ( 'name' => $fieldName ) ) ;
1991                     $parser->handleSave ( false ) ;
1992                 }
1993             }
1994         }
1995
1996         }
1997
1998         function removeFieldsFromLayout($layoutAdditions) {
1999         require_once 'modules/ModuleBuilder/parsers/views/GridLayoutMetaDataParser.php' ;
2000
2001         // these modules either lack editviews/detailviews or use custom mechanisms for the editview/detailview.
2002         // In either case, we don't want to attempt to add a relate field to them
2003         // would be better if GridLayoutMetaDataParser could handle this gracefully, so we don't have to maintain this list here
2004         $invalidModules = array ( 'emails' , 'kbdocuments' ) ;
2005
2006         foreach ( $layoutAdditions as $deployedModuleName => $fieldName )
2007         {
2008             if ( ! in_array( strtolower ( $deployedModuleName ) , $invalidModules ) )
2009             {
2010                 foreach ( array ( MB_EDITVIEW , MB_DETAILVIEW ) as $view )
2011                 {
2012                     $GLOBALS [ 'log' ]->debug ( get_class ( $this ) . ": adding $fieldName to $view layout for module $deployedModuleName" ) ;
2013                     $parser = new GridLayoutMetaDataParser ( $view, $deployedModuleName ) ;
2014                     $parser->removeField ( $fieldName ) ;
2015                     $parser->handleSave ( false ) ;
2016                 }
2017             }
2018         }
2019
2020         }
2021
2022         ///////////////////
2023         //********** DISABLE/ENABLE FUNCTIONS
2024         ///////////////////
2025         function enable($base_dir, $is_upgrade = false, $previous_version = ''){
2026                 global $app_strings;
2027                 $this->base_dir = $base_dir;
2028                 $total_steps = 3; //minimum number of steps with no tasks
2029                 $current_step = 0;
2030                 $tasks = array(
2031                                                                 'enable_copy',
2032                                                                 'enable_dashlets',
2033                                                                 'enable_relationships',
2034                                         'enable_extensions',
2035                                 'enable_global_search',
2036                                         'enable_manifest_logichooks',
2037                                                                 'reset_opcodes',
2038                 );
2039                 $total_steps += count($tasks);
2040                 if(file_exists($this->base_dir . '/manifest.php')){
2041                                 if(!$this->silent){
2042                                         $current_step++;
2043                                         display_progress_bar('install', $current_step, $total_steps);
2044                                         echo '<div id ="displayLoglink" ><a href="#" onclick="toggleDisplay(\'displayLog\')">'.$app_strings['LBL_DISPLAY_LOG'].'</a> </div><div id="displayLog" style="display:none">';
2045                                 }
2046
2047                                 require_once($this->base_dir . '/manifest.php');
2048                                 if($is_upgrade && !empty($previous_version)){
2049                                         //check if the upgrade path exists
2050                                         if(!empty($upgrade_manifest)){
2051                                                 if(!empty($upgrade_manifest['upgrade_paths'])){
2052                                                         if(!empty($upgrade_manifest['upgrade_paths'][$previous_version])){
2053                                                                 $installdefs =  $upgrade_manifest['upgrade_paths'][$previous_version];
2054                                                         }else{
2055                                                                 $errors[] = 'No Upgrade Path Found in manifest.';
2056                                                                 $this->abort($errors);
2057                                                         }//fi
2058                                                 }//fi
2059                                         }//fi
2060                                 }//fi
2061                                 $this->id_name = $installdefs['id'];
2062                                 $this->installdefs = $installdefs;
2063                                 $installed_modules = array();
2064                                 if(isset($installdefs['beans'])){
2065                                         foreach($this->installdefs['beans'] as $bean){
2066                                                 $installed_modules[] = $bean['module'];
2067                                         }
2068                                 }
2069                                 if(!$this->silent){
2070                                         $current_step++;
2071                                         update_progress_bar('install', $current_step, $total_steps);
2072                                 }
2073
2074                                 foreach($tasks as $task){
2075                                         $this->$task();
2076                                         if(!$this->silent){
2077                                                 $current_step++;
2078                                                 update_progress_bar('install', $current_step, $total_steps);
2079                                         }
2080                                 }
2081
2082                                 if(!$this->silent){
2083                                         $current_step++;
2084                                         update_progress_bar('install', $current_step, $total_steps);
2085                                         echo '</div>';
2086                                 }
2087                                 UpdateSystemTabs('Add',$installed_modules);
2088                                 $GLOBALS['log']->debug('Complete');
2089
2090                 }else{
2091                         die("No \$installdefs Defined In $this->base_dir/manifest.php");
2092                 }
2093
2094         }
2095         function disable($base_dir){
2096                 global $app_strings;
2097                 $total_steps = 3; //min steps with no tasks
2098                 $current_step = 0;
2099                 $this->base_dir = $base_dir;
2100                 $tasks = array(
2101                                                         'disable_copy',
2102                                                         'disable_dashlets',
2103                                                         'disable_relationships',
2104                                     'disable_extensions',
2105                             'disable_global_search',
2106                                                         'disable_manifest_logichooks',
2107                                                         'reset_opcodes',
2108                                                         );
2109                 $total_steps += count($tasks); //now the real number of steps
2110                 if(file_exists($this->base_dir . '/manifest.php')){
2111                                 if(!$this->silent){
2112                                         $current_step++;
2113                                         display_progress_bar('install', $current_step, $total_steps);
2114                                         echo '<div id ="displayLoglink" ><a href="#" onclick="toggleDisplay(\'displayLog\')">'.$app_strings['LBL_DISPLAY_LOG'].'</a> </div><div id="displayLog" style="display:none">';
2115                                 }
2116
2117                                 require_once($this->base_dir . '/manifest.php');
2118                                 $this->installdefs = $installdefs;
2119                                 $this->id_name = $this->installdefs['id'];
2120                                 $installed_modules = array();
2121                                 if(isset($this->installdefs['beans'])){
2122                                         foreach($this->installdefs['beans'] as $bean){
2123                                                 $installed_modules[] = $bean['module'];
2124                                         }
2125                                 }
2126                                 if(!$this->silent){
2127                                         $current_step++;
2128                                         update_progress_bar('install', $current_step, $total_steps);
2129                                 }
2130                                 foreach($tasks as $task){
2131                                         $this->$task();
2132                                         if(!$this->silent){
2133                                                 $current_step++;
2134                                                 update_progress_bar('install', $current_step, $total_steps);
2135                                         }
2136                                 }
2137                                 if(!$this->silent){
2138                                         $current_step++;
2139                                         update_progress_bar('install', $current_step, $total_steps);
2140                                         echo '</div>';
2141                                 }
2142                         UpdateSystemTabs('Restore',$installed_modules);
2143
2144                 }else{
2145                         die("No manifest.php Defined In $this->base_dir/manifest.php");
2146                 }
2147         }
2148
2149         function enable_vardef($to_module)
2150         {
2151             $this->enableExt("vardefs", "Vardefs", $to_module);
2152         }
2153
2154         function enable_layoutdef($to_module)
2155         {
2156             $this->enableExt("layoutdefs", "Layoutdefs", $to_module);
2157         }
2158
2159         function enable_relationships(){
2160                 if(isset($this->installdefs['relationships'])){
2161                         $str = "<?php \n //WARNING: The contents of this file are auto-generated\n";
2162                         $save_table_dictionary = false;
2163                         foreach($this->installdefs['relationships'] as $relationship){
2164                 $filename       =basename($relationship['meta_data']);
2165
2166                                 $save_table_dictionary  = true;
2167                                 $str .= "include_once('metadata/$filename');\n";
2168                                 if (empty($relationship['module']))
2169                                     continue;
2170
2171                                 if(!empty($relationship['module_vardefs'])){
2172                                         $this->enable_vardef($relationship['module']);
2173                                 }
2174                                 if(!empty($relationship['module_layoutdefs'])){
2175                                         $this->enable_layoutdef($relationship['module']);
2176                                 }
2177                         }
2178                         $this->rebuild_vardefs();
2179                         $this->rebuild_layoutdefs();
2180                         if($save_table_dictionary){
2181                                 if(!file_exists("custom/Extension/application/Ext/TableDictionary")){
2182                                         mkdir_recursive("custom/Extension/application/Ext/TableDictionary", true);
2183                                 }
2184                                 if (file_exists("custom/Extension/application/Ext/TableDictionary/".DISABLED_PATH."/$this->id_name.php"))
2185                                    rename("custom/Extension/application/Ext/TableDictionary/".DISABLED_PATH."/$this->id_name.php", "custom/Extension/application/Ext/TableDictionary/$this->id_name.php");
2186                                 $this->rebuild_tabledictionary();
2187                         }
2188                 }
2189         }
2190
2191         function disable_relationships($action = 'disable'){
2192                 if(isset($this->installdefs['relationships'])){
2193                         foreach($this->installdefs['relationships'] as $relationship){
2194                                 $filename = basename($relationship['meta_data']);
2195                 $relName = substr($filename, -12) == "MetaData.php" ? substr($filename,0,strlen($filename) - 12) : "";
2196                                 if (empty($relationship['module']) && empty($relName))
2197                         continue;
2198
2199                                 //remove the vardefs
2200                                 if (empty($relName))
2201                                         $path = 'custom/Extension/modules/' . $relationship['module']. '/Ext/Vardefs';
2202                                 if(!empty($relationship['module']) && $relationship['module'] == 'application'){
2203                                         $path ='custom/Extension/' . $relationship['module']. '/Ext/Vardefs';
2204                                 }
2205                                 if(!empty($relationship['module_vardefs']) && file_exists($path . '/'. $this->id_name . '.php')){
2206                                         mkdir_recursive($path . '/'.DISABLED_PATH, true);
2207                                         rename( $path . '/'. $this->id_name . '.php', $path . '/'.DISABLED_PATH.'/'. $this->id_name . '.php');
2208                                 }
2209                                 //remove the layoutdefs
2210                                 if ( !empty($relationship['module']) ) {
2211                     $path = 'custom/Extension/modules/' . $relationship['module']. '/Ext/Layoutdefs';
2212                     if($relationship['module'] == 'application'){
2213                         $path ='custom/Extension/' . $relationship['module']. '/Ext/Layoutdefs';
2214                     }
2215                                 }
2216
2217                                 if(!empty($relationship['module_layoutdefs']) && file_exists($path . '/'. $this->id_name . '.php')){
2218                                         mkdir_recursive($path . '/'.DISABLED_PATH, true);
2219                                         rename( $path . '/'. $this->id_name . '.php', $path . '/'.DISABLED_PATH.'/'. $this->id_name . '.php');
2220                                 }
2221
2222                         }
2223                         if(file_exists("custom/Extension/application/Ext/TableDictionary/$this->id_name.php")){
2224                                 mkdir_recursive("custom/Extension/application/Ext/TableDictionary/".DISABLED_PATH, true);
2225                                 rename("custom/Extension/application/Ext/TableDictionary/$this->id_name.php", "custom/Extension/application/Ext/TableDictionary/".DISABLED_PATH."/$this->id_name.php");
2226                         }
2227                         $this->rebuild_tabledictionary();
2228                         $this->rebuild_vardefs();
2229                         $this->rebuild_layoutdefs();
2230                 }
2231         }
2232
2233         function enable_dashlets(){
2234                 if(isset($this->installdefs['dashlets'])){
2235                         foreach($this->installdefs['dashlets'] as $cp){
2236                                 $cp['from'] = str_replace('<basepath>', $this->base_dir, $cp['from']);
2237                                 $path = 'custom/modules/Home/Dashlets/' . $cp['name'] . '/';
2238                                 $disabled_path = 'custom/modules/Home/'.DISABLED_PATH.'Dashlets/' . $cp['name'];
2239                                 $GLOBALS['log']->debug("Enabling Dashlet " . $cp['name'] . "..." . $cp['from'] );
2240                                 if (file_exists($disabled_path))
2241                                 {
2242                                         rename($disabled_path,  $path);
2243                                 }
2244                         }
2245                         include('modules/Administration/RebuildDashlets.php');
2246
2247                 }
2248         }
2249
2250         function disable_dashlets(){
2251                 if(isset($this->installdefs['dashlets'])){
2252                                         foreach($this->installdefs['dashlets'] as $cp){
2253                                                 $path = 'custom/modules/Home/Dashlets/' . $cp['name'];
2254                                                 $disabled_path = 'custom/modules/Home/'.DISABLED_PATH.'Dashlets/' . $cp['name'];
2255                                                 $GLOBALS['log']->debug('Disabling ' .$path);
2256                                                 if (file_exists($path))
2257                                                 {
2258                                                         mkdir_recursive('custom/modules/Home/'.DISABLED_PATH.'Dashlets/', true);
2259                                                         rename( $path, $disabled_path);
2260                                                 }
2261                                         }
2262                                         include('modules/Administration/RebuildDashlets.php');
2263                                 }
2264         }
2265
2266         function enable_copy(){
2267                 //copy files back onto file system. first perform md5 check to determine if anything has been modified
2268                 //here we should just go through the files in the -restore directory and copy those back
2269                 if(isset($GLOBALS['mi_overwrite_files']) && $GLOBALS['mi_overwrite_files']){
2270                         if(!empty($this->installdefs['copy'])){
2271                                 foreach($this->installdefs['copy'] as $cp){
2272                                         $cp['to'] = clean_path(str_replace('<basepath>', $this->base_dir, $cp['to']));
2273                                         $backup_path = clean_path( remove_file_extension(urldecode(hashToFile($_REQUEST['install_file'])))."-restore/".$cp['to'] );
2274
2275                                         //check if this file exists in the -restore directory
2276                                         if(file_exists($backup_path)){
2277                                                 //since the file exists, then we want do an md5 of the install version and the file system version
2278                                                 //if(is_file($backup_path) && md5_file($backup_path) == md5_file($cp['to'])){
2279                                                         //since the files are the same then we can safely move back from the -restore
2280                                                         //directory into the file system
2281                                                         $GLOBALS['log']->debug("ENABLE COPY:: FROM: ".$cp['from']. " TO: ".$cp['to']);
2282                                                         $this->copy_path($cp['from'], $cp['to']);
2283                                                 /*}else{
2284                                                         //since they are not equal then we need to prompt the user
2285                                                 }*/
2286                                         }//fi
2287                                 }//rof
2288                         }//fi
2289                 }//fi
2290         }
2291
2292         function disable_copy(){
2293                 //when we disable we want to copy the -restore files back into the file system
2294                 //but we should check the version in the module install against the version on the file system
2295                 //if they match then we can copy the file back, but otherwise we should ask the user.
2296
2297 //              $GLOBALS['log']->debug('ModuleInstaller.php->disable_copy()');
2298                 if(isset($GLOBALS['mi_overwrite_files']) && $GLOBALS['mi_overwrite_files']){
2299 //              $GLOBALS['log']->debug('ModuleInstaller.php->disable_copy():mi_overwrite_files=true');
2300                         if(!empty($this->installdefs['copy'])){
2301 //                              $GLOBALS['log']->debug('ModuleInstaller.php->disable_copy(): installdefs not empty');
2302                                 foreach($this->installdefs['copy'] as $cp){
2303                                         $cp['to'] = clean_path(str_replace('<basepath>', $this->base_dir, $cp['to']));
2304                                         $backup_path = clean_path( remove_file_extension(urldecode(hashToFile($_REQUEST['install_file'])))."-restore/".$cp['to'] ); // bug 16966 tyoung - replaced missing assignment to $backup_path
2305                                         //check if this file exists in the -restore directory
2306 //                                      $GLOBALS['log']->debug("ModuleInstaller.php->disable_copy(): backup_path=".$backup_path);
2307                                         if(file_exists($backup_path)){
2308                                                 //since the file exists, then we want do an md5 of the install version and the file system version
2309                                                 $from = str_replace('<basepath>', $this->base_dir, $cp['from']);
2310
2311                                                 //if(is_file($from) && md5_file($from) == md5_file($cp['to'])){
2312                                                         //since the files are the same then we can safely move back from the -restore
2313                                                         //directory into the file system
2314                                                         $GLOBALS['log']->debug("DISABLE COPY:: FROM: ".$backup_path. " TO: ".$cp['to']);
2315                                                         $this->copy_path($backup_path, $cp['to']);
2316                                                 /*}else{
2317                                                         //since they are not equal then we need to prompt the user
2318                                                 }*/
2319                                         }//fi
2320                                 }//rof
2321                         }//fi
2322                 }//fi
2323         }
2324
2325         public function reset_opcodes()
2326     {
2327         /* Bug 39354 - added function_exists check. Not optimal fix, but safe nonetheless.
2328          * This is for the upgrade to 6.1 from pre 6.1, since the utils files haven't been updated to 6.1 when this is called,
2329          * but this file has been updated to 6.1
2330          */
2331         if(function_exists('sugar_clean_opcodes')){
2332             sugar_clean_opcodes();
2333         }
2334     }
2335
2336     /**
2337      * BC implementation to provide specific calls to extensions
2338      */
2339     public function __call($name, $args)
2340     {
2341         $nameparts = explode('_', $name);
2342         // name is something_something
2343         if(count($nameparts) == 2 && isset($this->extensions[$nameparts[1]])) {
2344             $ext = $this->extensions[$nameparts[1]];
2345             switch($nameparts[0]) {
2346                 case 'enable':
2347                     return $this->enableExt($ext['section'], $ext['extdir']);
2348                 case 'disable':
2349                     return $this->disableExt($ext['section'], $ext['extdir']);
2350                 case 'install':
2351                     return $this->installExt($ext['section'], $ext['extdir']);
2352                 case 'uninstall':
2353                     return $this->uninstallExt($ext['section'], $ext['extdir']);
2354                 case 'rebuild':
2355                     return $this->rebuildExt($ext['extdir'], $ext['file']);
2356             }
2357         }
2358         sugar_die("Unknown method ModuleInstaller::$name called");
2359     }
2360
2361 }
2362
2363     function UpdateSystemTabs($action, $installed_modules){
2364         require_once("modules/MySettings/TabController.php");
2365         $controller = new TabController();
2366         $isSystemTabsInDB = $controller->is_system_tabs_in_db();
2367         if ($isSystemTabsInDB && !empty($installed_modules))
2368         {
2369             global $moduleList;
2370             switch ($action)
2371             {
2372                 case 'Restore' :
2373                     $currentTabs = $controller->get_system_tabs();
2374                     foreach ($installed_modules as $module)
2375                     {
2376                         if(in_array($module, $currentTabs)){
2377                             unset($currentTabs[$module]);
2378                         }
2379                     }
2380                     $controller->set_system_tabs($currentTabs);;
2381                     break;
2382                 case 'Add' :
2383                     $currentTabs = $controller->get_system_tabs();
2384                     foreach ($installed_modules as $module)
2385                     {
2386                         if(!in_array($module, $currentTabs)){
2387                             $currentTabs[$module] = $module;
2388                         }
2389                     }
2390                     $controller->set_system_tabs($currentTabs);
2391                 default:
2392                     break;
2393             }
2394     }
2395
2396 }