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