]> CyberLeo.Net >> Repos - Github/sugarcrm.git/blob - include/utils.php
Release 6.1.4
[Github/sugarcrm.git] / include / utils.php
1 <?php
2 /*********************************************************************************
3  * SugarCRM is a customer relationship management program developed by
4  * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc.
5  * 
6  * This program is free software; you can redistribute it and/or modify it under
7  * the terms of the GNU Affero General Public License version 3 as published by the
8  * Free Software Foundation with the addition of the following permission added
9  * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
10  * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY
11  * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
12  * 
13  * This program is distributed in the hope that it will be useful, but WITHOUT
14  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
15  * FOR A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more
16  * details.
17  * 
18  * You should have received a copy of the GNU Affero General Public License along with
19  * this program; if not, see http://www.gnu.org/licenses or write to the Free
20  * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21  * 02110-1301 USA.
22  * 
23  * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road,
24  * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com.
25  * 
26  * The interactive user interfaces in modified source and object code versions
27  * of this program must display Appropriate Legal Notices, as required under
28  * Section 5 of the GNU Affero General Public License version 3.
29  * 
30  * In accordance with Section 7(b) of the GNU Affero General Public License version 3,
31  * these Appropriate Legal Notices must retain the display of the "Powered by
32  * SugarCRM" logo. If the display of the logo is not reasonably feasible for
33  * technical reasons, the Appropriate Legal Notices must display the words
34  * "Powered by SugarCRM".
35  ********************************************************************************/
36
37 /*********************************************************************************
38
39  * Description:  Includes generic helper functions used throughout the application.
40  * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
41  * All Rights Reserved.
42  * Contributor(s): ______________________________________..
43  ********************************************************************************/
44 require_once('include/SugarObjects/SugarConfig.php');
45 require_once('include/utils/external_cache.php');
46 require_once('include/utils/security_utils.php');
47
48
49
50 function make_sugar_config(&$sugar_config)
51 {
52         /* used to convert non-array config.php file to array format */
53         global $admin_export_only;
54         global $cache_dir;
55         global $calculate_response_time;
56         global $create_default_user;
57         global $dateFormats;
58         global $dbconfig;
59         global $dbconfigoption;
60         global $default_action;
61         global $default_charset;
62         global $default_currency_name;
63         global $default_currency_symbol;
64         global $default_currency_iso4217;
65         global $defaultDateFormat;
66         global $default_language;
67         global $default_module;
68         global $default_password;
69         global $default_permission_mode;
70         global $default_theme;
71         global $defaultTimeFormat;
72         global $default_user_is_admin;
73         global $default_user_name;
74         global $disable_export;
75         global $disable_persistent_connections;
76         global $display_email_template_variable_chooser;
77         global $display_inbound_email_buttons;
78         global $history_max_viewed;
79         global $host_name;
80         global $import_dir;
81         global $languages;
82         global $list_max_entries_per_page;
83         global $lock_default_user_name;
84         global $log_memory_usage;
85         global $requireAccounts;
86         global $RSS_CACHE_TIME;
87         global $session_dir;
88         global $site_URL;
89         global $site_url;
90         global $sugar_version;
91         global $timeFormats;
92         global $tmp_dir;
93         global $translation_string_prefix;
94         global $unique_key;
95         global $upload_badext;
96         global $upload_dir;
97         global $upload_maxsize;
98         global $import_max_execution_time;
99         global $list_max_entries_per_subpanel;
100         global $passwordsetting;
101
102         // assumes the following variables must be set:
103         // $dbconfig, $dbconfigoption, $cache_dir, $import_dir, $session_dir, $site_URL, $tmp_dir, $upload_dir
104
105         $sugar_config = array (
106         'admin_export_only' => empty($admin_export_only) ? false : $admin_export_only,
107         'export_delimiter' => empty($export_delimiter) ? ',' : $export_delimiter,
108         'cache_dir' => empty($cache_dir) ? 'cache/' : $cache_dir,
109         'calculate_response_time' => empty($calculate_response_time) ? true : $calculate_response_time,
110         'create_default_user' => empty($create_default_user) ? false : $create_default_user,
111         'date_formats' => empty($dateFormats) ? array(
112         'Y-m-d'=>'2010-12-23',
113         'd-m-Y' => '23-12-2010',
114         'm-d-Y'=>'12-23-2010',
115         'Y/m/d'=>'2010/12/23',
116         'd/m/Y' => '23/12/2010',
117         'm/d/Y'=>'12/23/2010',
118         'Y.m.d' => '2010.12.23',
119         'd.m.Y' => '23.12.2010',
120         'm.d.Y' => '12.23.2010'
121                 ) : $dateFormats,
122         'dbconfig' => $dbconfig,  // this must be set!!
123         'dbconfigoption' => $dbconfigoption,  // this must be set!!
124         'default_action' => empty($default_action) ? 'index' : $default_action,
125         'default_charset' => empty($default_charset) ? 'UTF-8' : $default_charset,
126         'default_currency_name' => empty($default_currency_name) ? 'US Dollar' : $default_currency_name,
127         'default_currency_symbol' => empty($default_currency_symbol) ? '$' : $default_currency_symbol,
128         'default_currency_iso4217' => empty($default_currency_iso4217) ? '$' : $default_currency_iso4217,
129         'default_date_format' => empty($defaultDateFormat) ? 'm/d/Y' : $defaultDateFormat,
130         'default_export_charset' => 'UTF-8',
131         'default_language' => empty($default_language) ? 'en_us' : $default_language,
132         'default_module' => empty($default_module) ? 'Home' : $default_module,
133         'default_password' => empty($default_password) ? '' : $default_password,
134         'default_permissions' => array (
135                 'dir_mode' => 02770,
136                 'file_mode' => 0660,
137                 'chown' => '',
138                 'chgrp' => '',
139         ),
140     'default_theme' => empty($default_theme) ? 'Sugar5' : $default_theme,
141     'default_time_format' => empty($defaultTimeFormat) ? 'h:ia' : $defaultTimeFormat,
142         'default_user_is_admin' => empty($default_user_is_admin) ? false : $default_user_is_admin,
143         'default_user_name' => empty($default_user_name) ? '' : $default_user_name,
144         'disable_export' => empty($disable_export) ? false : $disable_export,
145     'disable_persistent_connections' => empty($disable_persistent_connections) ? false : $disable_persistent_connections,
146     'display_email_template_variable_chooser' => empty($display_email_template_variable_chooser) ? false : $display_email_template_variable_chooser,
147         'display_inbound_email_buttons' => empty($display_inbound_email_buttons) ? false : $display_inbound_email_buttons,
148         'history_max_viewed' => empty($history_max_viewed) ? 50 : $history_max_viewed,
149         'host_name' => empty($host_name) ? 'localhost' : $host_name,
150         'import_dir' => $import_dir,  // this must be set!!
151         'import_max_records_per_file' => 100,
152         'languages' => empty($languages) ? array('en_us' => 'English (US)') : $languages,
153         'list_max_entries_per_page' => empty($list_max_entries_per_page) ? 20 : $list_max_entries_per_page,
154         'list_max_entries_per_subpanel' => empty($list_max_entries_per_subpanel) ? 10 : $list_max_entries_per_subpanel,
155         'lock_default_user_name' => empty($lock_default_user_name) ? false : $lock_default_user_name,
156         'log_memory_usage' => empty($log_memory_usage) ? false : $log_memory_usage,
157     'portal_view' => 'single_user',
158         'resource_management' => array (
159             'special_query_limit' => 50000,
160             'special_query_modules' => array('Reports', 'Export', 'Import', 'Administration', 'Sync'),
161             'default_limit' => 1000,
162     ),
163         'require_accounts' => empty($requireAccounts) ? true : $requireAccounts,
164         'rss_cache_time' => empty($RSS_CACHE_TIME) ? '10800' : $RSS_CACHE_TIME,
165         'session_dir' => $session_dir,  // this must be set!!
166         'site_url' => empty($site_URL) ? $site_url : $site_URL,  // this must be set!!
167         'showDetailData' => true, // if true, read-only ACL fields will still appear on EditViews as non-editable
168         'showThemePicker' => true,
169         'sugar_version' => empty($sugar_version) ? 'unknown' : $sugar_version,
170         'time_formats' => empty($timeFormats) ? array (
171         'H:i'=>'23:00', 'h:ia'=>'11:00 pm', 'h:iA'=>'11:00PM',
172         'H.i'=>'23.00', 'h.ia'=>'11.00 pm', 'h.iA'=>'11.00PM' ) : $timeFormats,
173         'tmp_dir' => $tmp_dir,  // this must be set!!
174         'translation_string_prefix' => empty($translation_string_prefix) ? false : $translation_string_prefix,
175         'unique_key' => empty($unique_key) ? md5(create_guid()) : $unique_key,
176         'upload_badext' => empty($upload_badext) ? array (
177         'php', 'php3', 'php4', 'php5', 'pl', 'cgi', 'py',
178         'asp', 'cfm', 'js', 'vbs', 'html', 'htm' ) : $upload_badext,
179         'upload_dir' => $upload_dir,  // this must be set!!
180         'upload_maxsize' => empty($upload_maxsize) ? 3000000 : $upload_maxsize,
181         'import_max_execution_time' => empty($import_max_execution_time) ? 3600 : $import_max_execution_time,
182         'lock_homepage' => false,
183         'lock_subpanels' => false,
184         'max_dashlets_homepage' => 15,
185         'dashlet_display_row_options' => array('1','3','5','10'),
186         'default_max_tabs' => empty($max_tabs) ? '7' : $max_tabs,
187         'default_subpanel_tabs' =>  empty($subpanel_tabs) ? true : $subpanel_tabs,
188         'default_subpanel_links' => empty($subpanel_links) ? false : $subpanel_links,
189         'default_swap_last_viewed' => empty($swap_last_viewed) ? false : $swap_last_viewed,
190         'default_swap_shortcuts' => empty($swap_shortcuts) ? false : $swap_shortcuts,
191         'default_navigation_paradigm' => empty($navigation_paradigm) ? 'gm' : $navigation_paradigm,
192         'js_lang_version' => 1,
193         'passwordsetting' => empty($passwordsetting) ? array (
194             'SystemGeneratedPasswordON' => '',
195             'generatepasswordtmpl' => '',
196             'lostpasswordtmpl' => '',
197             'forgotpasswordON' => true,
198         'linkexpiration' => '1',
199         'linkexpirationtime' => '30',
200         'linkexpirationtype' => '1',
201             'systexpiration' => '0',
202             'systexpirationtime' => '',
203             'systexpirationtype' => '0',
204             'systexpirationlogin' => '',
205                 ) : $passwordsetting,
206
207         );
208 }
209
210 function get_sugar_config_defaults() {
211         global $locale;
212         /**
213          * used for getting base values for array style config.php.  used by the
214          * installer and to fill in new entries on upgrades.  see also:
215          * sugar_config_union
216          */
217
218         $sugar_config_defaults = array (
219         'admin_export_only' => false,
220         'export_delimiter' => ',',
221         'cache_dir' => 'cache/',
222         'calculate_response_time' => true,
223         'create_default_user' => false,
224         'date_formats' => array (
225         'Y-m-d' => '2010-12-23', 'm-d-Y' => '12-23-2010', 'd-m-Y' => '23-12-2010',
226         'Y/m/d' => '2010/12/23', 'm/d/Y' => '12/23/2010', 'd/m/Y' => '23/12/2010',
227         'Y.m.d' => '2010.12.23', 'd.m.Y' => '23.12.2010', 'm.d.Y' => '12.23.2010',),
228         'dbconfigoption' => array (
229         'persistent' => true,
230         'autofree' => false,
231         'debug' => 0,
232         'seqname_format' => '%s_seq',
233         'portability' => 0,
234         'ssl' => false ),
235         'default_action' => 'index',
236         'default_charset' => return_session_value_or_default('default_charset',
237         'UTF-8'),
238         'default_currency_name' => return_session_value_or_default('default_currency_name', 'US Dollar'),
239         'default_currency_symbol' => return_session_value_or_default('default_currency_symbol', '$'),
240         'default_currency_iso4217' => return_session_value_or_default('default_currency_iso4217', 'USD'),
241         'default_currency_significant_digits' => return_session_value_or_default('default_currency_significant_digits', 2),
242         'default_number_grouping_seperator' => return_session_value_or_default('default_number_grouping_seperator', ','),
243         'default_decimal_seperator' => return_session_value_or_default('default_decimal_seperator', '.'),
244         'default_date_format' => 'm/d/Y',
245         'default_export_charset' => 'UTF-8',
246         'default_language' => return_session_value_or_default('default_language',
247         'en_us'),
248         'default_module' => 'Home',
249         'default_password' => '',
250         'default_permissions' => array (
251                 'dir_mode' => 02770,
252                 'file_mode' => 0660,
253                 'user' => '',
254                 'group' => '',
255         ),
256         'default_theme' => return_session_value_or_default('site_default_theme', 'Sugar5'),
257         'default_time_format' => 'h:ia',
258         'default_user_is_admin' => false,
259         'default_user_name' => '',
260         'disable_export' => false,
261         'disable_persistent_connections' =>
262         return_session_value_or_default('disable_persistent_connections',
263         'false'),
264     'display_email_template_variable_chooser' => false,
265         'display_inbound_email_buttons' => false,
266         'dump_slow_queries' => false,
267         'email_default_editor' => 'html',
268         'email_default_client' => 'sugar',
269         'email_default_delete_attachments' => true,
270         'history_max_viewed' => 50,
271         'installer_locked' => true,
272         'import_max_records_per_file' => 100,
273         'languages' => array('en_us' => 'English (US)'),
274         'large_scale_test' => false,
275         'list_max_entries_per_page' => 20,
276         'list_max_entries_per_subpanel' => 10,
277         'lock_default_user_name' => false,
278         'log_memory_usage' => false,
279         'portal_view' => 'single_user',
280     'resource_management' => array (
281             'special_query_limit' => 50000,
282             'special_query_modules' => array('Reports', 'Export', 'Import', 'Administration', 'Sync'),
283             'default_limit' => 1000,
284     ),
285         'require_accounts' => true,
286         'rss_cache_time' => return_session_value_or_default('rss_cache_time',
287         '10800'),
288         'save_query' => 'all',
289         'showDetailData' => true, // if true, read-only ACL fields will still appear on EditViews as non-editable
290         'showThemePicker' => true,
291         'slow_query_time_msec' => '100',
292     'sugarbeet' => true,
293     'time_formats' => array (
294         'H:i'=>'23:00', 'h:ia'=>'11:00pm', 'h:iA'=>'11:00PM',
295         'H.i'=>'23.00', 'h.ia'=>'11.00pm', 'h.iA'=>'11.00PM' ),
296     'tracker_max_display_length' => 15,
297         'translation_string_prefix' =>
298         return_session_value_or_default('translation_string_prefix', false),
299         'upload_badext' => array (
300         'php', 'php3', 'php4', 'php5', 'pl', 'cgi', 'py',
301         'asp', 'cfm', 'js', 'vbs', 'html', 'htm' ),
302         'upload_maxsize' => 3000000,
303         'import_max_execution_time' => 3600,
304         'use_php_code_json' => returnPhpJsonStatus(),
305         'verify_client_ip' => true,
306         'js_custom_version' => '',
307         'js_lang_version' => 1,
308         'default_number_grouping_seperator' => ',',
309         'default_decimal_seperator' => '.',
310         'lock_homepage' => false,
311         'lock_subpanels' => false,
312         'max_dashlets_homepage' => '15',
313         'default_max_tabs' => '7',
314         'dashlet_display_row_options' => array('1','3','5','10'),
315         'default_subpanel_tabs' =>  true,
316         'default_subpanel_links' => false,
317         'default_swap_last_viewed' => false,
318         'default_swap_shortcuts' => false,
319         'default_navigation_paradigm' => 'gm',
320         'admin_access_control' => false,
321         'use_common_ml_dir'     => false,
322         'common_ml_dir' => '',
323         'vcal_time' => '2',
324         'passwordsetting' => empty($passwordsetting) ? array (
325             'SystemGeneratedPasswordON' => '',
326             'generatepasswordtmpl' => '',
327             'lostpasswordtmpl' => '',
328             'forgotpasswordON' => false,
329         'linkexpiration' => '1',
330         'linkexpirationtime' => '30',
331         'linkexpirationtype' => '1',
332             'systexpiration' => '0',
333             'systexpirationtime' => '',
334             'systexpirationtype' => '0',
335             'systexpirationlogin' => '',
336                 ) : $passwordsetting,
337         'use_real_names' => true,
338         );
339
340         if(!is_object($locale)) {
341                 $locale = new Localization();
342         }
343
344         $sugar_config_defaults['default_currencies'] = $locale->getDefaultCurrencies();
345
346         $sugar_config_defaults = sugarArrayMerge($locale->getLocaleConfigDefaults(), $sugar_config_defaults);
347         return( $sugar_config_defaults );
348 }
349
350 /**
351  * @deprecated use SugarView::getMenu() instead
352  */
353 function load_menu($path){
354         global $module_menu;
355
356         if(file_exists($path . 'Menu.php'))
357         {
358                 require($path . 'Menu.php');
359         }
360         if(file_exists('custom/' . $path . 'Ext/Menus/menu.ext.php'))
361         {
362                 require('custom/' . $path . 'Ext/Menus/menu.ext.php');
363         }
364         if(file_exists('custom/application/Ext/Menus/menu.ext.php'))
365         {
366                 require('custom/application/Ext/Menus/menu.ext.php');
367         }
368         return $module_menu;
369 }
370
371 /**
372  * get_notify_template_file
373  * This function will return the location of the email notifications template to use
374  *
375  * @return string relative file path to email notifications template file
376  */
377 function get_notify_template_file($language){
378         /*
379          * Order of operation:
380          * 1) custom version of specified language
381          * 2) stock version of specified language
382          * 3) custom version of en_us template
383          * 4) stock en_us template
384          */
385
386         // set $file to the base code template so it's set if none of the conditions pass
387         $file = "include/language/en_us.notify_template.html";
388
389         if(file_exists("custom/include/language/{$language}.notify_template.html")){
390                 $file = "custom/include/language/{$language}.notify_template.html";
391         }
392         else if(file_exists("include/language/{$language}.notify_template.html")){
393                 $file = "include/language/{$language}.notify_template.html";
394         }
395         else if(file_exists("custom/include/language/en_us.notify_template.html")){
396                 $file = "custom/include/language/en_us.notify_template.html";
397         }
398
399         return $file;
400 }
401
402 function sugar_config_union( $default, $override ){
403         // a little different then array_merge and array_merge_recursive.  we want
404         // the second array to override the first array if the same value exists,
405         // otherwise merge the unique keys.  it handles arrays of arrays recursively
406         // might be suitable for a generic array_union
407         if( !is_array( $override ) ){
408                 $override = array();
409         }
410         foreach( $default as $key => $value ){
411                 if( !array_key_exists($key, $override) ){
412                         $override[$key] = $value;
413                 }
414                 else if( is_array( $key ) ){
415                         $override[$key] = sugar_config_union( $value, $override[$key] );
416                 }
417         }
418         return( $override );
419 }
420
421 function make_not_writable( $file ){
422         // Returns true if the given file/dir has been made not writable
423         $ret_val = false;
424         if( is_file($file) || is_dir($file) ){
425                 if( !is_writable($file) ){
426                         $ret_val = true;
427                 }
428                 else {
429                         $original_fileperms = fileperms($file);
430
431                         // take away writable permissions
432                         $new_fileperms = $original_fileperms & ~0x0092;
433                         @sugar_chmod($file, $new_fileperms);
434
435                         if( !is_writable($file) ){
436                                 $ret_val = true;
437                         }
438                 }
439         }
440         return $ret_val;
441 }
442
443
444 /** This function returns the name of the person.
445  * It currently returns "first last".  It should not put the space if either name is not available.
446  * It should not return errors if either name is not available.
447  * If no names are present, it will return ""
448  * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
449  * All Rights Reserved.
450  * Contributor(s): ______________________________________..
451  */
452 function return_name($row, $first_column, $last_column)
453 {
454         $first_name = "";
455         $last_name = "";
456         $full_name = "";
457
458         if(isset($row[$first_column]))
459         {
460                 $first_name = stripslashes($row[$first_column]);
461         }
462
463         if(isset($row[$last_column]))
464         {
465                 $last_name = stripslashes($row[$last_column]);
466         }
467
468         $full_name = $first_name;
469
470         // If we have a first name and we have a last name
471         if($full_name != "" && $last_name != "")
472         {
473                 // append a space, then the last name
474                 $full_name .= " ".$last_name;
475         }
476         // If we have no first name, but we have a last name
477         else if($last_name != "")
478         {
479                 // append the last name without the space.
480                 $full_name .= $last_name;
481         }
482
483         return $full_name;
484 }
485
486
487 function get_languages()
488 {
489         global $sugar_config;
490         return $sugar_config['languages'];
491 }
492
493 function get_language_display($key)
494 {
495         global $sugar_config;
496         return $sugar_config['languages'][$key];
497 }
498
499 function get_assigned_user_name($assigned_user_id, $is_group = '') {
500         static $saved_user_list = null;
501
502         if(empty($saved_user_list)) {
503                 $saved_user_list = get_user_array(false, '', '', false, null, $is_group);
504         }
505
506         if(isset($saved_user_list[$assigned_user_id])) {
507                 return $saved_user_list[$assigned_user_id];
508         }
509
510         return '';
511 }
512
513 /**
514  * retrieves the user_name column value (login)
515  * @param string id GUID of user
516  * @return string
517  */
518 function get_user_name($id) {
519         global $db;
520
521         if(empty($db))
522         $db = DBManagerFactory::getInstance();
523
524         $q = "SELECT user_name FROM users WHERE id='{$id}'";
525         $r = $db->query($q);
526         $a = $db->fetchByAssoc($r);
527
528         return (empty($a)) ? '' : $a['user_name'];
529 }
530
531
532 //TODO Update to use global cache
533 function get_user_array($add_blank=true, $status="Active", $assigned_user="", $use_real_name=false, $user_name_begins = null, $is_group=' AND portal_only=0 ', $from_cache = true) {
534         global $locale;
535         global $sugar_config;
536
537         if(empty($locale)) {
538
539                 $locale = new Localization();
540         }
541         if($from_cache)
542                 $user_array = get_register_value('user_array', $add_blank. $status . $assigned_user);
543
544         if(!isset($user_array)) {
545                 $db = DBManagerFactory::getInstance();
546                 $temp_result = Array();
547                 // Including deleted users for now.
548                 if (empty($status)) {
549                         $query = "SELECT id, first_name, last_name, user_name from users WHERE 1=1".$is_group;
550                 }
551                 else {
552                         $query = "SELECT id, first_name, last_name, user_name from users WHERE status='$status'".$is_group;
553                 }
554
555                 if (!empty($user_name_begins)) {
556                         $query .= " AND user_name LIKE '$user_name_begins%' ";
557                 }
558                 if (!empty($assigned_user)) {
559                         $query .= " OR id='$assigned_user'";
560                 }
561                 $query = $query.' ORDER BY user_name ASC';
562                 $GLOBALS['log']->debug("get_user_array query: $query");
563                 $result = $db->query($query, true, "Error filling in user array: ");
564
565                 if ($add_blank==true) {
566                         // Add in a blank row
567                         $temp_result[''] = '';
568                 }
569
570                 // Get the id and the name.
571                 while($row = $db->fetchByAssoc($result)) {
572                         if($use_real_name == true || showFullName()) {
573                                 if(isset($row['last_name'])) { // cn: we will ALWAYS have both first_name and last_name (empty value if blank in db)
574                                         $temp_result[$row['id']] = $locale->getLocaleFormattedName($row['first_name'],$row['last_name']);
575                                 } else {
576                                         $temp_result[$row['id']] = $row['user_name'];
577                                 }
578                         } else {
579                                 $temp_result[$row['id']] = $row['user_name'];
580                         }
581                 }
582
583                 $user_array = $temp_result;
584                 if($from_cache)
585                         set_register_value('user_array', $add_blank. $status . $assigned_user, $temp_result);
586         }
587
588
589         return $user_array;
590 }
591
592
593 /**
594  * uses a different query to return a list of users than get_user_array()
595  * @param args string where clause entry
596  * @return array Array of Users' details that match passed criteria
597  */
598 function getUserArrayFromFullName($args) {
599         global $locale;
600         $db = DBManagerFactory::getInstance();
601
602         $argArray = array();
603         if(strpos($args, " ")) {
604                 $argArray = explode(" ", $args);
605         } else {
606                 $argArray[] = $args;
607         }
608
609         $inClause = '';
610         foreach($argArray as $arg) {
611                 if(!empty($inClause)) {
612                         $inClause .= ' OR ';
613                 }
614                 if(empty($arg))
615                 continue;
616
617                 $inClause .= "(first_name LIKE '{$arg}%' OR last_name LIKE '{$arg}%')";
618         }
619
620         $query  = "SELECT id, first_name, last_name, user_name FROM users WHERE status='Active' AND deleted=0 AND ";
621         $query .= $inClause;
622         $query .= " ORDER BY last_name ASC";
623
624         $r = $db->query($query);
625         $ret = array();
626         while($a = $db->fetchByAssoc($r)) {
627                 $ret[$a['id']] = $locale->getLocaleFormattedName($a['first_name'], $a['last_name']);
628         }
629
630         return $ret;
631 }
632
633 /**
634  *
635  * based on user pref then system pref
636  */
637 function showFullName() {
638         global $sugar_config;
639         global $current_user;
640         static $showFullName = null;
641
642         if (is_null($showFullName)) {
643                 $sysPref = (isset($sugar_config['use_real_names']) && $sugar_config['use_real_names'] == true) ? true : false;
644                 $userPref = (is_object($current_user)) ? $current_user->getPreference('use_real_names') : null;
645
646                 if($userPref != null) {
647                         $bool = ($userPref == 'on') ? true : false;
648                         $showFullName = $bool;
649                 } else {
650                         $showFullName = $sysPref;
651                 }
652         }
653
654         return $showFullName;
655 }
656
657 function clean($string, $maxLength)
658 {
659         $string = substr($string, 0, $maxLength);
660         return escapeshellcmd($string);
661 }
662
663 /**
664  * Copy the specified request variable to the member variable of the specified object.
665  * Do no copy if the member variable is already set.
666  * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
667  * All Rights Reserved.
668  * Contributor(s): ______________________________________..
669  */
670 function safe_map($request_var, & $focus, $always_copy = false)
671 {
672         safe_map_named($request_var, $focus, $request_var, $always_copy);
673 }
674
675 /**
676  * Copy the specified request variable to the member variable of the specified object.
677  * Do no copy if the member variable is already set.
678  * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
679  * All Rights Reserved.
680  * Contributor(s): ______________________________________..
681  */
682 function safe_map_named($request_var, & $focus, $member_var, $always_copy)
683 {
684         if (isset($_REQUEST[$request_var]) && ($always_copy || is_null($focus->$member_var))) {
685                 $GLOBALS['log']->debug("safe map named called assigning '{$_REQUEST[$request_var]}' to $member_var");
686                 $focus->$member_var = $_REQUEST[$request_var];
687         }
688 }
689
690 /** 
691  * This function retrieves an application language file and returns the array of strings included in the $app_list_strings var.
692  * 
693  * @param string $language specific language to load
694  * @return array lang strings
695  */
696 function return_app_list_strings_language($language) 
697 {
698         global $app_list_strings;
699         global $sugar_config;
700
701         $cache_key = 'app_list_strings.'.$language;
702
703         // Check for cached value
704         $cache_entry = sugar_cache_retrieve($cache_key);
705         if(!empty($cache_entry))
706         {
707                 return $cache_entry;
708         }
709
710         $default_language = $sugar_config['default_language'];
711         $temp_app_list_strings = $app_list_strings;
712         
713         $langs = array();
714         if ($language != 'en_us') {
715             $langs[] = 'en_us';
716         }
717         if ($default_language != 'en_us' && $language != $default_language) {
718             $langs[] = $default_language;
719         }
720         $langs[] = $language;
721         
722         $app_list_strings_array = array();
723         
724         foreach ( $langs as $lang ) {
725             $app_list_strings = array();
726             if(file_exists("include/language/$lang.lang.php")) {
727             include("include/language/$lang.lang.php");
728             $GLOBALS['log']->info("Found language file: $lang.lang.php");
729         }
730         if(file_exists("include/language/$lang.lang.override.php")) {
731             include("include/language/$lang.lang.override.php");
732             $GLOBALS['log']->info("Found override language file: $lang.lang.override.php");
733         }
734         if(file_exists("include/language/$lang.lang.php.override")) {
735             include("include/language/$lang.lang.php.override");
736             $GLOBALS['log']->info("Found override language file: $lang.lang.php.override");
737         }
738
739         $app_list_strings_array[] = $app_list_strings;
740     }
741
742         $app_list_strings = array();
743         foreach ( $app_list_strings_array as $app_list_strings_item ) {
744             $app_list_strings = sugarArrayMerge($app_list_strings, $app_list_strings_item);
745         }       
746
747     foreach ( $langs as $lang ) {
748         if(file_exists("custom/application/Ext/Language/$lang.lang.ext.php")) {
749             $app_list_strings = _mergeCustomAppListStrings("custom/application/Ext/Language/$lang.lang.ext.php" , $app_list_strings);
750             $GLOBALS['log']->info("Found extended language file: $lang.lang.ext.php");
751         }
752         if(file_exists("custom/include/language/$lang.lang.php")) {
753             include("custom/include/language/$lang.lang.php");
754             $GLOBALS['log']->info("Found custom language file: $lang.lang.php");
755         }
756     }
757
758         if(!isset($app_list_strings)) {
759                 $GLOBALS['log']->fatal("Unable to load the application language file for the selected language ($language) or the default language ($default_language) or the en_us language");
760                 return null;
761         }
762
763         $return_value = $app_list_strings;
764         $app_list_strings = $temp_app_list_strings;
765
766         sugar_cache_put($cache_key, $return_value);
767
768         return $return_value;
769 }
770
771 /**
772 * The dropdown items in custom language files is $app_list_strings['$key']['$second_key'] = $value not
773 * $GLOBALS['app_list_strings']['$key'] = $value, so we have to delete the original ones in app_list_strings and relace it with the custom ones.
774  * @param file string the language that you want include,
775  * @param app_list_strings array the golbal strings
776  * @return array
777  */
778  //jchi 25347
779 function _mergeCustomAppListStrings($file , $app_list_strings){
780         $app_list_strings_original = $app_list_strings;
781         unset($app_list_strings);
782         include($file);
783         if(!isset($app_list_strings) || !is_array($app_list_strings)){
784                 return $app_list_strings_original;
785         }
786         //Bug 25347: We should not merge custom dropdown fields unless they relate to parent fields or the module list.
787         foreach($app_list_strings as $key=>$value)
788         {
789                 $exemptDropdowns = array("moduleList", "parent_type_display", "record_type_display", "record_type_display_notes");
790                 if (!in_array($key, $exemptDropdowns) && array_key_exists($key, $app_list_strings_original))
791                 {
792                         unset($app_list_strings_original["$key"]);
793                 }
794    }
795    $app_list_strings = sugarArrayMergeRecursive($app_list_strings_original , $app_list_strings);
796    return $app_list_strings;
797 }
798
799 /** 
800  * This function retrieves an application language file and returns the array of strings included.
801  * 
802  * @param string $language specific language to load
803  * @return array lang strings
804  */
805 function return_application_language($language) 
806 {
807         global $app_strings, $sugar_config;
808
809         $cache_key = 'app_strings.'.$language;
810
811         // Check for cached value
812         $cache_entry = sugar_cache_retrieve($cache_key);
813         if(!empty($cache_entry))
814         {
815                 return $cache_entry;
816         }
817
818         $temp_app_strings = $app_strings;
819         $default_language = $sugar_config['default_language'];
820
821         $langs = array();
822         if ($language != 'en_us') {
823             $langs[] = 'en_us';
824         }
825         if ($default_language != 'en_us' && $language != $default_language) {
826             $langs[] = $default_language;
827         }
828         $langs[] = $language;
829         
830         $app_strings_array = array();
831         
832         foreach ( $langs as $lang ) {
833             $app_strings = array();
834             if(file_exists("include/language/$lang.lang.php")) {
835             include("include/language/$lang.lang.php");
836             $GLOBALS['log']->info("Found language file: $lang.lang.php");
837         }
838         if(file_exists("include/language/$lang.lang.override.php")) {
839             include("include/language/$lang.lang.override.php");
840             $GLOBALS['log']->info("Found override language file: $lang.lang.override.php");
841         }
842         if(file_exists("include/language/$lang.lang.php.override")) {
843             include("include/language/$lang.lang.php.override");
844             $GLOBALS['log']->info("Found override language file: $lang.lang.php.override");
845         }
846         if(file_exists("custom/application/Ext/Language/$lang.lang.ext.php")) {
847             include("custom/application/Ext/Language/$lang.lang.ext.php");
848             $GLOBALS['log']->info("Found extended language file: $lang.lang.ext.php");
849         }
850         if(file_exists("custom/include/language/$lang.lang.php")) {
851             include("custom/include/language/$lang.lang.php");
852             $GLOBALS['log']->info("Found custom language file: $lang.lang.php");
853         }
854         $app_strings_array[] = $app_strings;
855         }
856
857         $app_strings = array();
858     foreach ( $app_strings_array as $app_strings_item ) {
859         $app_strings = sugarArrayMerge($app_strings, $app_strings_item);
860     }
861         
862         if(!isset($app_strings)) {
863                 $GLOBALS['log']->fatal("Unable to load the application language strings");
864                 return null;
865         }
866
867         // If we are in debug mode for translating, turn on the prefix now!
868         if($sugar_config['translation_string_prefix']) {
869                 foreach($app_strings as $entry_key=>$entry_value) {
870                         $app_strings[$entry_key] = $language.' '.$entry_value;
871                 }
872         }
873         if(isset($_SESSION['show_deleted'])) {
874                 $app_strings['LBL_DELETE_BUTTON'] = $app_strings['LBL_UNDELETE_BUTTON'];
875                 $app_strings['LBL_DELETE_BUTTON_LABEL'] = $app_strings['LBL_UNDELETE_BUTTON_LABEL'];
876                 $app_strings['LBL_DELETE_BUTTON_TITLE'] = $app_strings['LBL_UNDELETE_BUTTON_TITLE'];
877                 $app_strings['LBL_DELETE'] = $app_strings['LBL_UNDELETE'];
878         }
879
880         $app_strings['LBL_ALT_HOT_KEY'] = get_alt_hot_key();
881
882         $return_value = $app_strings;
883         $app_strings = $temp_app_strings;
884
885         sugar_cache_put($cache_key, $return_value);
886         
887         return $return_value;
888 }
889
890 /** 
891  * This function retrieves a module's language file and returns the array of strings included.
892  * 
893  * @param string $language specific language to load
894  * @param string $module module name to load strings for
895  * @param bool $refresh optional, true if you want to rebuild the language strings
896  * @return array lang strings
897  */
898 function return_module_language($language, $module, $refresh=false) 
899 {
900         global $mod_strings;
901         global $sugar_config;
902         global $currentModule;
903
904         // Jenny - Bug 8119: Need to check if $module is not empty
905         if (empty($module)) {
906                 $stack  = debug_backtrace();
907                 $GLOBALS['log']->warn("Variable module is not in return_module_language ". var_export($stack, true));
908                 return array();
909         }
910
911         // Store the current mod strings for later
912         $temp_mod_strings = $mod_strings;
913         $loaded_mod_strings = array();
914         $language_used = $language;
915         $default_language = $sugar_config['default_language'];
916
917         if(empty($language)) {
918                 $language = $default_language;
919         }
920
921         // Bug 21559 - So we can get all the strings defined in the template, refresh
922         // the vardefs file if the cached language file doesn't exist.
923     if(!file_exists($GLOBALS['sugar_config']['cache_dir'].'modules/'. $module . '/language/'.$language.'.lang.php')
924                         && !empty($GLOBALS['beanList'][$module])){
925                 $object = $GLOBALS['beanList'][$module];
926                 if ($object == 'aCase') {
927             $object = 'Case';
928                 }
929                 VardefManager::refreshVardefs($module,$object);
930         }
931
932         $loaded_mod_strings = LanguageManager::loadModuleLanguage($module, $language,$refresh);
933
934         // cn: bug 6048 - merge en_us with requested language
935         if($language != $sugar_config['default_language'])
936         $loaded_mod_strings = sugarArrayMerge(
937             LanguageManager::loadModuleLanguage($module, $sugar_config['default_language'],$refresh),
938                 $loaded_mod_strings
939             );
940      
941     // Load in en_us strings by default
942     if($language != 'en_us' && $sugar_config['default_language'] != 'en_us')
943         $loaded_mod_strings = sugarArrayMerge(
944             LanguageManager::loadModuleLanguage($module, 'en_us', $refresh),
945                 $loaded_mod_strings
946             );
947
948         // If we are in debug mode for translating, turn on the prefix now!
949         if($sugar_config['translation_string_prefix']) {
950                 foreach($loaded_mod_strings as $entry_key=>$entry_value) {
951                         $loaded_mod_strings[$entry_key] = $language_used.' '.$entry_value;
952                 }
953         }
954
955         $return_value = $loaded_mod_strings;
956         if(!isset($mod_strings)){
957                 $mod_strings = $return_value;
958         }
959         else
960                 $mod_strings = $temp_mod_strings;
961
962         return $return_value;
963 }
964
965
966 /** This function retrieves an application language file and returns the array of strings included in the $mod_list_strings var.
967  * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
968  * All Rights Reserved.
969  * Contributor(s): ______________________________________..
970  * If you are using the current language, do not call this function unless you are loading it for the first time */
971 function return_mod_list_strings_language($language,$module) {
972         global $mod_list_strings;
973         global $sugar_config;
974         global $currentModule;
975
976         $cache_key = "mod_list_str_lang.".$language.$module;
977
978         // Check for cached value
979         $cache_entry = sugar_cache_retrieve($cache_key);
980         if(!empty($cache_entry))
981         {
982                 return $cache_entry;
983         }
984
985         $language_used = $language;
986         $temp_mod_list_strings = $mod_list_strings;
987         $default_language = $sugar_config['default_language'];
988
989         if($currentModule == $module && isset($mod_list_strings) && $mod_list_strings != null) {
990                 return $mod_list_strings;
991         }
992
993         // cn: bug 6351 - include en_us if file langpack not available
994         // cn: bug 6048 - merge en_us with requested language
995         include("modules/$module/language/en_us.lang.php");
996         $en_mod_list_strings = array();
997         if($language_used != $default_language)
998         $en_mod_list_strings = $mod_list_strings;
999
1000         if(file_exists("modules/$module/language/$language.lang.php")) {
1001                 include("modules/$module/language/$language.lang.php");
1002         }
1003
1004         if(file_exists("modules/$module/language/$language.lang.override.php")){
1005                 include("modules/$module/language/$language.lang.override.php");
1006         }
1007
1008         if(file_exists("modules/$module/language/$language.lang.php.override")){
1009                 echo 'Please Change:<br>' . "modules/$module/language/$language.lang.php.override" . '<br>to<br>' . 'Please Change:<br>' . "modules/$module/language/$language.lang.override.php";
1010                 include("modules/$module/language/$language.lang.php.override");
1011         }
1012
1013         // cn: bug 6048 - merge en_us with requested language
1014         $mod_list_strings = sugarArrayMerge($en_mod_list_strings, $mod_list_strings);
1015
1016         // if we still don't have a language pack, then log an error
1017         if(!isset($mod_list_strings)) {
1018                 $GLOBALS['log']->fatal("Unable to load the application list language file for the selected language($language) or the default language($default_language) for module({$module})");
1019                 return null;
1020         }
1021
1022         $return_value = $mod_list_strings;
1023         $mod_list_strings = $temp_mod_list_strings;
1024
1025         sugar_cache_put($cache_key, $return_value);
1026         return $return_value;
1027 }
1028
1029
1030 /** This function retrieves a theme's language file and returns the array of strings included.
1031  * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1032  * All Rights Reserved.
1033  * Contributor(s): ______________________________________..
1034  */
1035 function return_theme_language($language, $theme)
1036 {
1037         global $mod_strings, $sugar_config, $currentModule;
1038
1039         $language_used = $language;
1040         $default_language = $sugar_config['default_language'];
1041
1042         include(SugarThemeRegistry::get($theme)->getFilePath()."/language/$current_language.lang.php");
1043         if(file_exists(SugarThemeRegistry::get($theme)->getFilePath()."/language/$current_language.lang.override.php")){
1044                 include(SugarThemeRegistry::get($theme)->getFilePath()."/language/$current_language.lang.override.php");
1045         }
1046         if(file_exists(SugarThemeRegistry::get($theme)->getFilePath()."/language/$current_language.lang.php.override")){
1047                 echo 'Please Change:<br>' . SugarThemeRegistry::get($theme)->getFilePath()."/language/$current_language.lang.php.override" . '<br>to<br>' . 'Please Change:<br>' . SugarThemeRegistry::get($theme)->getFilePath()."/language/$current_language.lang.override.php";
1048                 include(SugarThemeRegistry::get($theme)->getFilePath()."/language/$current_language.lang.php.override");
1049         }
1050         if(!isset($theme_strings))
1051         {
1052                 $GLOBALS['log']->warn("Unable to find the theme file for language: ".$language." and theme: ".$theme);
1053                 require(SugarThemeRegistry::get($theme)->getFilePath()."/language/$default_language.lang.php");
1054                 $language_used = $default_language;
1055         }
1056
1057         if(!isset($theme_strings))
1058         {
1059                 $GLOBALS['log']->fatal("Unable to load the theme($theme) language file for the selected language($language) or the default language($default_language)");
1060                 return null;
1061         }
1062
1063         // If we are in debug mode for translating, turn on the prefix now!
1064         if($sugar_config['translation_string_prefix'])
1065         {
1066                 foreach($theme_strings as $entry_key=>$entry_value)
1067                 {
1068                         $theme_strings[$entry_key] = $language_used.' '.$entry_value;
1069                 }
1070         }
1071
1072         return $theme_strings;
1073 }
1074
1075
1076
1077 /** If the session variable is defined and is not equal to "" then return it.  Otherwise, return the default value.
1078  * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1079  * All Rights Reserved.
1080  * Contributor(s): ______________________________________..
1081  */
1082 function return_session_value_or_default($varname, $default)
1083 {
1084         if(isset($_SESSION[$varname]) && $_SESSION[$varname] != "")
1085         {
1086                 return $_SESSION[$varname];
1087         }
1088
1089         return $default;
1090 }
1091
1092 /**
1093  * Creates an array of where restrictions.  These are used to construct a where SQL statement on the query
1094  * It looks for the variable in the $_REQUEST array.  If it is set and is not "" it will create a where clause out of it.
1095  * @param &$where_clauses - The array to append the clause to
1096  * @param $variable_name - The name of the variable to look for an add to the where clause if found
1097  * @param $SQL_name - [Optional] If specified, this is the SQL column name that is used.  If not specified, the $variable_name is used as the SQL_name.
1098  * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1099  * All Rights Reserved.
1100  * Contributor(s): ______________________________________..
1101  */
1102 function append_where_clause(&$where_clauses, $variable_name, $SQL_name = null)
1103 {
1104         if($SQL_name == null)
1105         {
1106                 $SQL_name = $variable_name;
1107         }
1108
1109         if(isset($_REQUEST[$variable_name]) && $_REQUEST[$variable_name] != "")
1110         {
1111                 array_push($where_clauses, "$SQL_name like '".$GLOBALS['db']->quote($_REQUEST[$variable_name])."%'");
1112         }
1113 }
1114
1115 /**
1116  * Generate the appropriate SQL based on the where clauses.
1117  * @param $where_clauses - An Array of individual where clauses stored as strings
1118  * @returns string where_clause - The final SQL where clause to be executed.
1119  * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1120  * All Rights Reserved.
1121  * Contributor(s): ______________________________________..
1122  */
1123 function generate_where_statement($where_clauses)
1124 {
1125         $where = "";
1126         foreach($where_clauses as $clause)
1127         {
1128                 if($where != "")
1129                 $where .= " and ";
1130                 $where .= $clause;
1131         }
1132
1133         $GLOBALS['log']->info("Here is the where clause for the list view: $where");
1134         return $where;
1135 }
1136
1137 /**
1138  * determines if a passed string matches the criteria for a Sugar GUID
1139  * @param string $guid
1140  * @return bool False on failure
1141  */
1142 function is_guid($guid) {
1143         if(strlen($guid) != 36) {
1144                 return false;
1145         }
1146
1147         if(preg_match("/\w{8}-\w{4}-\w{4}-\w{4}-\w{12}/i", $guid)) {
1148                 return true;
1149         }
1150
1151         return true;;
1152 }
1153
1154
1155 /**
1156  * A temporary method of generating GUIDs of the correct format for our DB.
1157  * @return String contianing a GUID in the format: aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee
1158  *
1159  * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1160  * All Rights Reserved.
1161  * Contributor(s): ______________________________________..
1162  */
1163 function create_guid()
1164 {
1165         $microTime = microtime();
1166         list($a_dec, $a_sec) = explode(" ", $microTime);
1167
1168         $dec_hex = dechex($a_dec* 1000000);
1169         $sec_hex = dechex($a_sec);
1170
1171         ensure_length($dec_hex, 5);
1172         ensure_length($sec_hex, 6);
1173
1174         $guid = "";
1175         $guid .= $dec_hex;
1176         $guid .= create_guid_section(3);
1177         $guid .= '-';
1178         $guid .= create_guid_section(4);
1179         $guid .= '-';
1180         $guid .= create_guid_section(4);
1181         $guid .= '-';
1182         $guid .= create_guid_section(4);
1183         $guid .= '-';
1184         $guid .= $sec_hex;
1185         $guid .= create_guid_section(6);
1186
1187         return $guid;
1188
1189 }
1190
1191 function create_guid_section($characters)
1192 {
1193         $return = "";
1194         for($i=0; $i<$characters; $i++)
1195         {
1196                 $return .= dechex(mt_rand(0,15));
1197         }
1198         return $return;
1199 }
1200
1201 function ensure_length(&$string, $length)
1202 {
1203         $strlen = strlen($string);
1204         if($strlen < $length)
1205         {
1206                 $string = str_pad($string,$length,"0");
1207         }
1208         else if($strlen > $length)
1209         {
1210                 $string = substr($string, 0, $length);
1211         }
1212 }
1213
1214 function microtime_diff($a, $b) {
1215         list($a_dec, $a_sec) = explode(" ", $a);
1216         list($b_dec, $b_sec) = explode(" ", $b);
1217         return $b_sec - $a_sec + $b_dec - $a_dec;
1218 }
1219
1220 // check if Studio is displayed.
1221 function displayStudioForCurrentUser()
1222 {
1223     if ( is_admin($GLOBALS['current_user']) ) {
1224         return true;
1225     }
1226
1227
1228
1229         return true;
1230
1231 }
1232
1233 function displayWorkflowForCurrentUser()
1234 {
1235     $_SESSION['display_workflow_for_user'] = false;
1236     return false;
1237 }
1238
1239 // return an array with all modules where the user is an admin.
1240 function get_admin_modules_for_user($user) {
1241     global $beanList;
1242     $admin_modules = array();
1243
1244     return ($admin_modules);
1245 }
1246
1247  function get_workflow_admin_modules_for_user($user){
1248     if (isset($_SESSION['get_workflow_admin_modules_for_user'])) {
1249         return $_SESSION['get_workflow_admin_modules_for_user'];
1250     }
1251
1252     global $moduleList;
1253     $workflow_mod_list = array();
1254     foreach($moduleList as $module){
1255                 $workflow_mod_list[$module] = $module;
1256         }
1257
1258         // This list is taken from teh previous version of workflow_utils.php
1259     $workflow_mod_list['Tasks'] = "Tasks";
1260     $workflow_mod_list['Calls'] = "Calls";
1261     $workflow_mod_list['Meetings'] = "Meetings";
1262     $workflow_mod_list['Notes'] = "Notes";
1263     $workflow_mod_list['ProjectTask'] = "Project Tasks";
1264         $workflow_mod_list['Leads'] = "Leads";
1265         $workflow_mod_list['Opportunities'] = "Opportunities";
1266         // End of list
1267
1268     $workflow_admin_modules = array();
1269     if(empty($user)) {
1270         return $workflow_admin_modules;
1271     }
1272     $actions = ACLAction::getUserActions($user->id);
1273     //check for ForecastSchedule because it doesn't exist in $workflow_mod_list
1274     if (isset($actions['ForecastSchedule']['module']['admin']['aclaccess']) && ($actions['ForecastSchedule']['module']['admin']['aclaccess']==ACL_ALLOW_DEV ||
1275         $actions['ForecastSchedule']['module']['admin']['aclaccess']==ACL_ALLOW_ADMIN_DEV)) {
1276         $workflow_admin_modules['Forecasts'] = 'Forecasts';
1277     }
1278     foreach ($workflow_mod_list as $key=>$val) {
1279         if(!in_array($val, $workflow_admin_modules) && ($val!='iFrames' && $val!='Feeds' && $val!='Home' && $val!='Dashboard'
1280             && $val!='Calendar' && $val!='Activities' && $val!='Reports') &&
1281             (is_admin_for_module($user,$key))) {
1282                 $workflow_admin_modules[$key] = $val;
1283         }
1284     }
1285     $_SESSION['get_workflow_admin_modules_for_user'] = $workflow_admin_modules;
1286     return ($workflow_admin_modules);
1287 }
1288
1289 // Check if user is admin for at least one module.
1290 function is_admin_for_any_module($user) {
1291     return false;
1292 }
1293
1294
1295 // Check if user is admin for a specific module.
1296 function is_admin_for_module($user,$module) {
1297     return false;
1298 }
1299
1300
1301 /**
1302  * Check if user id belongs to a system admin.
1303  * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1304  * All Rights Reserved.
1305  * Contributor(s): ______________________________________..
1306  */
1307 function is_admin($user) {
1308         if(!empty($user) && ($user->is_admin == '1' || $user->is_admin === 'on')){
1309                 return true;
1310         }
1311
1312         return false;
1313 }
1314
1315 /**
1316  * Return the display name for a theme if it exists.
1317  * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1318  * All Rights Reserved.
1319  * Contributor(s): ______________________________________..
1320  *
1321  * @deprecated use SugarThemeRegistry::get($theme)->name instead
1322  */
1323 function get_theme_display($theme)
1324 {
1325         return SugarThemeRegistry::get($theme)->name;
1326 }
1327
1328 /**
1329  * Return an array of directory names.
1330  * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1331  * All Rights Reserved.
1332  * Contributor(s): ______________________________________..
1333  *
1334  * @deprecated use SugarThemeRegistry::availableThemes() instead.
1335  */
1336 function get_themes()
1337 {
1338     return SugarThemeRegistry::availableThemes();
1339 }
1340
1341 /**
1342  * THIS FUNCTION IS DEPRECATED AND SHOULD NOT BE USED; USE get_select_options_with_id()
1343  * Create HTML to display select options in a dropdown list.  To be used inside
1344  * of a select statement in a form.
1345  * param $option_list - the array of strings to that contains the option list
1346  * param $selected - the string which contains the default value
1347  * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1348  * All Rights Reserved.
1349  * Contributor(s): ______________________________________..
1350  */
1351 function get_select_options ($option_list, $selected) {
1352         return get_select_options_with_id($option_list, $selected);
1353 }
1354
1355 /**
1356  * Create HTML to display select options in a dropdown list.  To be used inside
1357  * of a select statement in a form.   This method expects the option list to have keys and values.  The keys are the ids.  The values are the display strings.
1358  * param $option_list - the array of strings to that contains the option list
1359  * param $selected - the string which contains the default value
1360  * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1361  * All Rights Reserved.
1362  * Contributor(s): ______________________________________..
1363  */
1364 function get_select_options_with_id ($option_list, $selected_key) {
1365         return get_select_options_with_id_separate_key($option_list, $option_list, $selected_key);
1366 }
1367
1368
1369 /**
1370  * Create HTML to display select options in a dropdown list.  To be used inside
1371  * of a select statement in a form.   This method expects the option list to have keys and values.  The keys are the ids.  The values are the display strings.
1372  * param $label_list - the array of strings to that contains the option list
1373  * param $key_list - the array of strings to that contains the values list
1374  * param $selected - the string which contains the default value
1375  * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1376  * All Rights Reserved.
1377  * Contributor(s): ______________________________________..
1378  */
1379 function get_select_options_with_id_separate_key ($label_list, $key_list, $selected_key, $massupdate=false) {
1380         global $app_strings;
1381         $select_options = "";
1382
1383         //for setting null selection values to human readable --None--
1384         $pattern = "/'0?'></";
1385         $replacement = "''>".$app_strings['LBL_NONE']."<";
1386
1387         if (empty($key_list)) $key_list = array();
1388         //create the type dropdown domain and set the selected value if $opp value already exists
1389         foreach ($key_list as $option_key=>$option_value) {
1390
1391                 $selected_string = '';
1392                 // the system is evaluating $selected_key == 0 || '' to true.  Be very careful when changing this.  Test all cases.
1393                 // The bug was only happening with one of the users in the drop down.  It was being replaced by none.
1394                 if (($option_key != '' && $selected_key == $option_key) || ($selected_key == '' && $option_key == '' && !$massupdate) || (is_array($selected_key) &&  in_array($option_key, $selected_key)))
1395                 {
1396                         $selected_string = 'selected ';
1397                 }
1398
1399                 $html_value = $option_key;
1400
1401                 $select_options .= "\n<OPTION ".$selected_string."value='$html_value'>$label_list[$option_key]</OPTION>";
1402         }
1403         $select_options = preg_replace($pattern, $replacement, $select_options);
1404         return $select_options;
1405 }
1406
1407
1408 /**
1409  * Call this method instead of die().
1410  * Then we call the die method with the error message that is passed in.
1411  */
1412 function sugar_die($error_message)
1413 {
1414         global $focus;
1415         sugar_cleanup();
1416         die($error_message);
1417 }
1418
1419
1420 /**
1421  * Create javascript to clear values of all elements in a form.
1422  * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1423  * All Rights Reserved.
1424  * Contributor(s): ______________________________________..
1425  */
1426 function get_clear_form_js () {
1427         $the_script = <<<EOQ
1428 <script type="text/javascript" language="JavaScript">
1429 function clear_form(form) {
1430         var newLoc = 'index.php?action=' + form.action.value + '&module=' + form.module.value + '&query=true&clear_query=true';
1431         if(typeof(form.advanced) != 'undefined'){
1432                 newLoc += '&advanced=' + form.advanced.value;
1433         }
1434         document.location.href= newLoc;
1435 }
1436 </script>
1437 EOQ;
1438
1439         return $the_script;
1440 }
1441
1442 /**
1443  * Create javascript to set the cursor focus to specific field in a form
1444  * when the screen is rendered.  The field name is currently hardcoded into the
1445  * the function.
1446  * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1447  * All Rights Reserved.
1448  * Contributor(s): ______________________________________..
1449  */
1450 function get_set_focus_js () {
1451         //TODO Clint 5/20 - Make this function more generic so that it can take in the target form and field names as variables
1452         $the_script = <<<EOQ
1453 <script type="text/javascript" language="JavaScript">
1454 <!-- Begin
1455 function set_focus() {
1456         if (document.forms.length > 0) {
1457                 for (i = 0; i < document.forms.length; i++) {
1458                         for (j = 0; j < document.forms[i].elements.length; j++) {
1459                                 var field = document.forms[i].elements[j];
1460                                 if ((field.type == "text" || field.type == "textarea" || field.type == "password") &&
1461                                                 !field.disabled && (field.name == "first_name" || field.name == "name" || field.name == "user_name" || field.name=="document_name")) {
1462                                         field.focus();
1463                     if (field.type == "text") {
1464                         field.select();
1465                     }
1466                                         break;
1467                         }
1468                         }
1469         }
1470         }
1471 }
1472 //  End -->
1473 </script>
1474 EOQ;
1475
1476         return $the_script;
1477 }
1478
1479 /**
1480  * Very cool algorithm for sorting multi-dimensional arrays.  Found at http://us2.php.net/manual/en/function.array-multisort.php
1481  * Syntax: $new_array = array_csort($array [, 'col1' [, SORT_FLAG [, SORT_FLAG]]]...);
1482  * Explanation: $array is the array you want to sort, 'col1' is the name of the column
1483  * you want to sort, SORT_FLAGS are : SORT_ASC, SORT_DESC, SORT_REGULAR, SORT_NUMERIC, SORT_STRING
1484  * you can repeat the 'col',FLAG,FLAG, as often you want, the highest prioritiy is given to
1485  * the first - so the array is sorted by the last given column first, then the one before ...
1486  * Example: $array = array_csort($array,'town','age',SORT_DESC,'name');
1487  * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1488  * All Rights Reserved.
1489  * Contributor(s): ______________________________________..
1490  */
1491 function array_csort() {
1492         $args = func_get_args();
1493         $marray = array_shift($args);
1494         $i = 0;
1495
1496         $msortline = "return(array_multisort(";
1497         foreach ($args as $arg) {
1498                 $i++;
1499                 if (is_string($arg)) {
1500                         foreach ($marray as $row) {
1501                                 $sortarr[$i][] = $row[$arg];
1502                         }
1503                 } else {
1504                         $sortarr[$i] = $arg;
1505                 }
1506                 $msortline .= "\$sortarr[".$i."],";
1507         }
1508         $msortline .= "\$marray));";
1509
1510         eval($msortline);
1511         return $marray;
1512 }
1513
1514 /**
1515  * Converts localized date format string to jscalendar format
1516  * Example: $array = array_csort($array,'town','age',SORT_DESC,'name');
1517  * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
1518  * All Rights Reserved.
1519  * Contributor(s): ______________________________________..
1520  */
1521 function parse_calendardate($local_format) {
1522         preg_match("/\(?([^-]{1})[^-]*-([^-]{1})[^-]*-([^-]{1})[^-]*\)/", $local_format, $matches);
1523         $calendar_format = "%" . $matches[1] . "-%" . $matches[2] . "-%" . $matches[3];
1524         return str_replace(array("y", "ï¿„1�7", "a", "j"), array("Y", "Y", "Y", "d"), $calendar_format);
1525 }
1526
1527
1528
1529
1530
1531 function translate($string, $mod='', $selectedValue=''){
1532         //$test_start = microtime();
1533         //static $mod_strings_results = array();
1534         if(!empty($mod)){
1535                 global $current_language;
1536                 //Bug 31275
1537                 if(isset($_REQUEST['login_language'])){
1538                     $current_language = ($_REQUEST['login_language'] == $current_language)? $current_language : $_REQUEST['login_language'];
1539                 }
1540                 $mod_strings = return_module_language($current_language, $mod);
1541
1542         }else{
1543                 global $mod_strings;
1544         }
1545
1546         $returnValue = '';
1547         global $app_strings, $app_list_strings;
1548
1549         if(isset($mod_strings[$string]))
1550         $returnValue = $mod_strings[$string];
1551         else if(isset($app_strings[$string]))
1552         $returnValue = $app_strings[$string];
1553         else if(isset($app_list_strings[$string]))
1554         $returnValue = $app_list_strings[$string];
1555         else if(isset($app_list_strings['moduleList']) && isset($app_list_strings['moduleList'][$string]))
1556         $returnValue = $app_list_strings['moduleList'][$string];
1557
1558
1559         //$test_end = microtime();
1560         //
1561         //    $mod_strings_results[$mod] = microtime_diff($test_start,$test_end);
1562         //
1563         //    echo("translate results:");
1564         //    $total_time = 0;
1565         //    $total_strings = 0;
1566         //    foreach($mod_strings_results as $key=>$value)
1567         //    {
1568         //        echo("Module $key \t\t time $value \t\t<br>");
1569         //        $total_time += $value;
1570         //    }
1571         //
1572         //    echo("Total time: $total_time<br>");
1573
1574
1575
1576         if(empty($returnValue)){
1577                 return $string;
1578         }
1579
1580         if(is_array($returnValue) && ! empty($selectedValue) && isset($returnValue[$selectedValue]) ){
1581                 return $returnValue[$selectedValue];
1582         }
1583
1584         return $returnValue;
1585 }
1586
1587 function unTranslateNum($num) {
1588         static $dec_sep;
1589         static $num_grp_sep;
1590         global $current_user, $sugar_config;
1591
1592         if($dec_sep == null) {
1593             $user_dec_sep = $current_user->getPreference('dec_sep');
1594             $dec_sep = (empty($user_dec_sep) ? $sugar_config['default_decimal_seperator'] : $user_dec_sep);
1595         }
1596         if($num_grp_sep == null) {
1597             $user_num_grp_sep = $current_user->getPreference('num_grp_sep');
1598             $num_grp_sep = (empty($user_num_grp_sep) ? $sugar_config['default_number_grouping_seperator'] : $user_num_grp_sep);
1599         }
1600
1601         $num = preg_replace("'" . preg_quote($num_grp_sep) . "'", '', $num);
1602         $num = preg_replace("'" . preg_quote($dec_sep) . "'", '.', $num);
1603         return $num;
1604
1605 }
1606
1607 function add_http($url) {
1608         if(!preg_match("@://@i", $url)) {
1609                 $scheme = "http";
1610                 if(!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on') {
1611                         $scheme = 'https';
1612                 }
1613
1614                 return "{$scheme}://{$url}";
1615         }
1616
1617         return $url;
1618 }
1619
1620 /**
1621  * returns a default array of XSS tags to clean
1622  * @return array
1623  */
1624 function getDefaultXssTags() {
1625         $tmp = array(
1626         "applet" => "applet",
1627         "base" => "base",
1628         "embed" => "embed",
1629         "form" => "form",
1630         "frame" => "frame",
1631         "frameset" => "frameset",
1632         "iframe" => "iframe",
1633         "import" => "\?import",
1634         "layer" => "layer",
1635         "link" => "link",
1636         "object" => "object",
1637         "script" => "script",
1638         "xmp" => "xmp",
1639         );
1640
1641         $ret = base64_encode(serialize($tmp));
1642
1643         return $ret;
1644 }
1645
1646 /**
1647  * Detects typical XSS attack patterns
1648  * @param string str String to search for XSS attack vectors
1649  * @param bool cleanImg Flag to allow <img> tags to survive - only used by InboundEmail for inline images.
1650  * @return array Array of matches, empty on clean string
1651  */
1652 function clean_xss($str, $cleanImg=true) {
1653         global $sugar_config;
1654
1655         if(empty($sugar_config['email_xss']))
1656         $sugar_config['email_xss'] = getDefaultXssTags();
1657
1658         $arr = unserialize(base64_decode($sugar_config['email_xss']));
1659
1660         $regex = '';
1661         foreach($arr as $v) {
1662                 if(!empty($regex)) {
1663                         $regex .= "|";
1664                 }
1665                 $regex .= $v;
1666         }
1667
1668         $tag_regex        = "#<({$regex})[^>]*>?#sim";
1669
1670         // cn: bug 13079 - "on\w" matched too many non-events (cONTact, strONG, etc.)
1671         $jsEvents  = "onblur|onfocus|oncontextmenu|onresize|onscroll|onunload|ondblclick|onclick|";
1672         $jsEvents .= "onmouseup|onmouseover|onmousedown|onmouseenter|onmouseleave|onmousemove|onload|onchange|";
1673         $jsEvents .= "onreset|onselect|onsubmit|onkeydown|onkeypress|onkeyup|onabort|onerror";
1674
1675         $attribute_regex        = "#<[^/>][^>]+({$jsEvents}\w+)[^=>]*=[^>]*>#sim";
1676         $javascript_regex       = '@<[^/>][^>]+(expression\(|j\W*a\W*v\W*a|v\W*b\W*s\W*c\W*r|&#|/\*|\*/)[^>]*>@sim';
1677         $imgsrc_regex           = '#<[^>]+src[^=]*=([^>]*?http://[^>]*)>#sim';
1678         $css_url                        = "#url\(.*\.\w+\)#";
1679
1680
1681         $str = str_replace("\t", "", $str);
1682
1683         $matches = array_merge(
1684         xss_check_pattern($tag_regex, $str),
1685         xss_check_pattern($javascript_regex, $str),
1686         xss_check_pattern($attribute_regex, $str)
1687         );
1688
1689         if($cleanImg) {
1690                 $matches = array_merge($matches,
1691                 xss_check_pattern($imgsrc_regex, $str)
1692                 );
1693         }
1694
1695         // cn: bug 13498 - custom white-list of allowed domains that vet remote images
1696         preg_match_all($css_url, $str, $cssUrlMatches, PREG_PATTERN_ORDER);
1697
1698         if(isset($sugar_config['security_trusted_domains']) && !empty($sugar_config['security_trusted_domains']) && is_array($sugar_config['security_trusted_domains'])) {
1699                 if(is_array($cssUrlMatches) && count($cssUrlMatches) > 0) {
1700                         // normalize whitelist
1701                         foreach($sugar_config['security_trusted_domains'] as $k => $v) {
1702                                 $sugar_config['security_trusted_domains'][$k] = strtolower($v);
1703                         }
1704
1705                         foreach($cssUrlMatches[0] as $match) {
1706                                 $domain = strtolower(substr(strstr($match, "://"), 3));
1707                                 $baseUrl = substr($domain, 0, strpos($domain, "/"));
1708
1709                                 if(!in_array($baseUrl, $sugar_config['security_trusted_domains'])) {
1710                                         $matches[] = $match;
1711                                 }
1712                         }
1713                 }
1714         } else {
1715                 $matches = array_merge($matches, $cssUrlMatches[0]);
1716         }
1717
1718         return $matches;
1719 }
1720
1721 /**
1722  * Helper function used by clean_xss() to parse for known-bad vectors
1723  * @param string pattern Regex pattern to use
1724  * @param string str String to parse for badness
1725  * @return array
1726  */
1727 function xss_check_pattern($pattern, $str) {
1728         preg_match_all($pattern, $str, $matches, PREG_PATTERN_ORDER);
1729         return $matches[1];
1730 }
1731
1732 // Designed to take a string passed in the URL as a parameter and clean all "bad" data from it
1733 // The second argument is a string, "filter," which corresponds to a regular expression
1734 function clean_string($str, $filter = "STANDARD") {
1735         global  $sugar_config;
1736
1737         $filters = Array(
1738         "STANDARD"        => "#[^A-Z0-9\-_\.\@]#i",
1739         "STANDARDSPACE"   => "#[^A-Z0-9\-_\.\@\ ]#i",
1740         "FILE"            => "#[^A-Z0-9\-_\.]#i",
1741         "NUMBER"          => "#[^0-9\-]#i",
1742         "SQL_COLUMN_LIST" => "#[^A-Z0-9,_\.]#i",
1743         "PATH_NO_URL"     => "#://#i",
1744         "SAFED_GET"               => "#[^A-Z0-9\@\=\&\?\.\/\-_~]#i", /* range of allowed characters in a GET string */
1745         "UNIFIED_SEARCH"        => "#[\\x00]#", /* cn: bug 3356 & 9236 - MBCS search strings */
1746         "AUTO_INCREMENT"        => "#[^0-9\-,\ ]#i",
1747         "ALPHANUM"        => "#[^A-Z0-9\-]#i",
1748         );
1749
1750         if (preg_match($filters[$filter], $str)) {
1751                 if (isset($GLOBALS['log']) && is_object($GLOBALS['log'])) {
1752                         $GLOBALS['log']->fatal("SECURITY: bad data passed in; string: {$str}");
1753                 }
1754                 die("Bad data passed in; <a href=\"{$sugar_config['site_url']}\">Return to Home</a>");
1755         }
1756         else {
1757                 return $str;
1758         }
1759 }
1760
1761 function clean_special_arguments() {
1762         if(isset($_SERVER['PHP_SELF'])) {
1763                 if (!empty($_SERVER['PHP_SELF'])) clean_string($_SERVER['PHP_SELF'], 'SAFED_GET');
1764         }
1765         if (!empty($_REQUEST) && !empty($_REQUEST['login_theme'])) clean_string($_REQUEST['login_theme'], "STANDARD");
1766         if (!empty($_REQUEST) && !empty($_REQUEST['login_module'])) clean_string($_REQUEST['login_module'], "STANDARD");
1767         if (!empty($_REQUEST) && !empty($_REQUEST['login_action'])) clean_string($_REQUEST['login_action'], "STANDARD");
1768         if (!empty($_REQUEST) && !empty($_REQUEST['ck_login_theme_20'])) clean_string($_REQUEST['ck_login_theme_20'], "STANDARD");
1769         if (!empty($_SESSION) && !empty($_SESSION['authenticated_user_theme'])) clean_string($_SESSION['authenticated_user_theme'], "STANDARD");
1770         if (!empty($_REQUEST) && !empty($_REQUEST['module_name'])) clean_string($_REQUEST['module_name'], "STANDARD");
1771         if (!empty($_REQUEST) && !empty($_REQUEST['module'])) clean_string($_REQUEST['module'], "STANDARD");
1772         if (!empty($_POST) && !empty($_POST['parent_type'])) clean_string($_POST['parent_type'], "STANDARD");
1773         if (!empty($_REQUEST) && !empty($_REQUEST['mod_lang'])) clean_string($_REQUEST['mod_lang'], "STANDARD");
1774         if (!empty($_SESSION) && !empty($_SESSION['authenticated_user_language'])) clean_string($_SESSION['authenticated_user_language'], "STANDARD");
1775         if (!empty($_SESSION) && !empty($_SESSION['dyn_layout_file'])) clean_string($_SESSION['dyn_layout_file'], "PATH_NO_URL");
1776         if (!empty($_GET) && !empty($_GET['from'])) clean_string($_GET['from']);
1777         if (!empty($_GET) && !empty($_GET['gmto'])) clean_string($_GET['gmto'], "NUMBER");
1778         if (!empty($_GET) && !empty($_GET['case_number'])) clean_string($_GET['case_number'], "AUTO_INCREMENT");
1779         if (!empty($_GET) && !empty($_GET['bug_number'])) clean_string($_GET['bug_number'], "AUTO_INCREMENT");
1780         if (!empty($_GET) && !empty($_GET['quote_num'])) clean_string($_GET['quote_num'], "AUTO_INCREMENT");
1781         clean_superglobals('stamp', 'ALPHANUM'); // for vcr controls
1782         clean_superglobals('offset', 'ALPHANUM');
1783         clean_superglobals('return_action');
1784         clean_superglobals('return_module');
1785         return TRUE;
1786 }
1787
1788 /**
1789  * cleans the given key in superglobals $_GET, $_POST, $_REQUEST
1790  */
1791 function clean_superglobals($key, $filter = 'STANDARD') {
1792         if(isset($_GET[$key])) clean_string($_GET[$key], $filter);
1793         if(isset($_POST[$key])) clean_string($_POST[$key], $filter);
1794         if(isset($_REQUEST[$key])) clean_string($_REQUEST[$key], $filter);
1795 }
1796
1797 function set_superglobals($key, $val){
1798         $_GET[$key] = $val;
1799         $_POST[$key] = $val;
1800         $_REQUEST[$key] = $val;
1801 }
1802
1803 // Works in conjunction with clean_string() to defeat SQL injection, file inclusion attacks, and XSS
1804 function clean_incoming_data() {
1805         global $sugar_config;
1806
1807         if (get_magic_quotes_gpc() == 1) {
1808                 $req  = array_map("preprocess_param", $_REQUEST);
1809                 $post = array_map("preprocess_param", $_POST);
1810                 $get  = array_map("preprocess_param", $_GET);
1811         } else {
1812
1813                 $req  = array_map("securexss", $_REQUEST);
1814                 $post = array_map("securexss", $_POST);
1815                 $get  = array_map("securexss", $_GET);
1816         }
1817
1818         // PHP cannot stomp out superglobals reliably
1819         foreach($post as $k => $v) { $_POST[$k] = $v; }
1820         foreach($get  as $k => $v) { $_GET[$k] = $v; }
1821         foreach($req  as $k => $v) {
1822                  $_REQUEST[$k] = $v;
1823                  //ensure the keys are safe as well
1824                  securexsskey($k);
1825         }
1826         // Any additional variables that need to be cleaned should be added here
1827         if (isset($_REQUEST['login_theme'])) clean_string($_REQUEST['login_theme']);
1828         if (isset($_REQUEST['login_module'])) clean_string($_REQUEST['login_module']);
1829         if (isset($_REQUEST['login_action'])) clean_string($_REQUEST['login_action']);
1830         if (isset($_REQUEST['login_language'])) clean_string($_REQUEST['login_language']);
1831         if (isset($_REQUEST['action'])) clean_string($_REQUEST['action']);
1832         if (isset($_REQUEST['module'])) clean_string($_REQUEST['module']);
1833         if (isset($_REQUEST['record'])) clean_string($_REQUEST['record'], 'STANDARDSPACE');
1834         if (isset($_SESSION['authenticated_user_theme'])) clean_string($_SESSION['authenticated_user_theme']);
1835         if (isset($_SESSION['authenticated_user_language'])) clean_string($_SESSION['authenticated_user_language']);
1836         if (isset($_REQUEST['language'])) clean_string($_REQUEST['language']);
1837         if (isset($sugar_config['default_theme'])) clean_string($sugar_config['default_theme']);
1838         if (isset($_REQUEST['offset'])) clean_string($_REQUEST['offset']);
1839         if (isset($_REQUEST['stamp'])) clean_string($_REQUEST['stamp']);
1840
1841         if(isset($_REQUEST['lvso'])){
1842                         set_superglobals('lvso', (strtolower($_REQUEST['lvso']) === 'desc')?'desc':'asc');
1843         }
1844         // Clean "offset" and "order_by" parameters in URL
1845         foreach ($_REQUEST as $key => $val) {
1846                 if (str_end($key, "_offset")) {
1847                         clean_string($_REQUEST[$key], "ALPHANUM"); // keep this ALPHANUM for disable_count_query
1848                         set_superglobals($key, $_REQUEST[$key]);
1849                 }
1850                 elseif (str_end($key, "_ORDER_BY")) {
1851                         clean_string($_REQUEST[$key], "SQL_COLUMN_LIST");
1852                         set_superglobals($key, $_REQUEST[$key]);
1853                 }
1854         }
1855
1856
1857         return 0;
1858 }
1859
1860 // Returns TRUE if $str begins with $begin
1861 function str_begin($str, $begin) {
1862         return (substr($str, 0, strlen($begin)) == $begin);
1863 }
1864
1865 // Returns TRUE if $str ends with $end
1866 function str_end($str, $end) {
1867         return (substr($str, strlen($str) - strlen($end)) == $end);
1868 }
1869
1870 function securexss($value) {
1871         if(is_array($value)){
1872         $new = array();
1873         foreach($value as $key=>$val){
1874                 $new[$key] = securexss($val);
1875         }
1876         return $new;
1877     }
1878         static $xss_cleanup=  array('"' =>'&quot;', "'" =>  '&#039;' , '<' =>'&lt;' , '>'=>'&gt;');
1879         $value = preg_replace(array('/javascript:/i', '/\0/'), array('java script:', ''), $value);
1880         $value = preg_replace('/javascript:/i', 'java script:', $value);
1881         return str_replace(array_keys($xss_cleanup), array_values($xss_cleanup), $value);
1882 }
1883
1884 function securexsskey($value, $die=true){
1885         global $sugar_config;
1886         $matches = array();
1887         preg_match("/[\'\"\<\>]/", $value, $matches);
1888         if(!empty($matches)){
1889                 if($die){
1890                         die("Bad data passed in; <a href=\"{$sugar_config['site_url']}\">Return to Home</a>");
1891                 }else{
1892                         unset($_REQUEST[$value]);
1893                         unset($_POST[$value]);
1894                         unset($_GET[$value]);
1895                 }
1896         }
1897 }
1898
1899 function preprocess_param($value){
1900         if(is_string($value)){
1901                 if(get_magic_quotes_gpc() == 1){
1902                         $value = stripslashes($value);
1903                 }
1904
1905                 $value = securexss($value);
1906         }
1907
1908
1909         return $value;
1910
1911
1912 }
1913
1914 function set_register_value($category, $name, $value){
1915     return sugar_cache_put("{$category}:{$name}", $value);
1916 }
1917
1918 function get_register_value($category,$name){
1919     return sugar_cache_retrieve("{$category}:{$name}");
1920 }
1921
1922 // this function cleans id's when being imported
1923 function convert_id($string)
1924 {
1925         return preg_replace_callback( '|[^A-Za-z0-9\-]|',
1926         create_function(
1927         // single quotes are essential here,
1928         // or alternative escape all $ as \$
1929         '$matches',
1930         'return ord($matches[0]);'
1931          ) ,$string);
1932 }
1933
1934 /**
1935  * @deprecated use SugarTheme::getImage()
1936  */
1937 function get_image($image,$other_attributes,$width="",$height="")
1938 {
1939     return SugarThemeRegistry::current()->getImage(basename($image),
1940         $other_attributes,
1941         empty($width) ? null : $width,
1942         empty($height) ? null : $height
1943         );
1944 }
1945 /**
1946  * @deprecated use SugarTheme::getImageURL()
1947  */
1948 function getImagePath($image_name)
1949 {
1950     return SugarThemeRegistry::current()->getImageURL($image_name);
1951 }
1952
1953 function getWebPath($relative_path){
1954         //if it has  a :// then it isn't a relative path
1955         if(substr_count($relative_path, '://') > 0) return $relative_path;
1956         if(defined('TEMPLATE_URL'))$relative_path = SugarTemplateUtilities::getWebPath($relative_path);
1957         return $relative_path;
1958 }
1959
1960 function getJSPath($relative_path, $additional_attrs=''){
1961         if(defined('TEMPLATE_URL'))$relative_path = SugarTemplateUtilities::getWebPath($relative_path);
1962         if(empty($GLOBALS['sugar_config']['js_custom_version']))$GLOBALS['sugar_config']['js_custom_version'] = 1;
1963         $js_version_key = isset($GLOBALS['js_version_key'])?$GLOBALS['js_version_key']:'';
1964         $path = $relative_path . '?s=' . $js_version_key . '&c=' . $GLOBALS['sugar_config']['js_custom_version'] ;
1965         if ( inDeveloperMode() ) $path .= '&developerMode='.mt_rand();
1966         if(!empty($additonal_attrs)) $path .= '&' . $additional_attrs;
1967         return $path;
1968 }
1969
1970 function getSWFPath($relative_path, $additional_params=''){
1971         $path = $relative_path;
1972         if (!empty($additional_params)){
1973                 $path .= '?' . $additional_params;
1974         }
1975         if (defined('TEMPLATE_URL')){
1976                 $path = TEMPLATE_URL . '/' . $path;
1977         }
1978         return $path;
1979 }
1980
1981
1982
1983
1984
1985 function getSQLDate($date_str)
1986 {
1987         if (preg_match('/^(\d{1,2})-(\d{1,2})-(\d{4})$/',$date_str,$match))
1988         {
1989                 if ( strlen($match[2]) == 1)
1990                 {
1991                         $match[2] = "0".$match[2];
1992                 }
1993                 if ( strlen($match[1]) == 1)
1994                 {
1995                         $match[1] = "0".$match[1];
1996                 }
1997                 return "{$match[3]}-{$match[1]}-{$match[2]}";
1998         }
1999         else if (preg_match('/^(\d{1,2})\/(\d{1,2})\/(\d{4})$/',$date_str,$match))
2000         {
2001                 if ( strlen($match[2]) == 1)
2002                 {
2003                         $match[2] = "0".$match[2];
2004                 }
2005                 if ( strlen($match[1]) == 1)
2006                 {
2007                         $match[1] = "0".$match[1];
2008                 }
2009                 return "{$match[3]}-{$match[1]}-{$match[2]}";
2010         }
2011         else
2012         {
2013                 return "";
2014         }
2015 }
2016
2017 function clone_history(&$db, $from_id,$to_id, $to_type)
2018 {
2019         global $timedate;
2020         $old_note_id=null;
2021         $old_filename=null;
2022         require_once('include/upload_file.php');
2023         $tables = array('calls'=>'Call', 'meetings'=>'Meeting', 'notes'=>'Note', 'tasks'=>'Task');
2024
2025         $location=array('Email'=>"modules/Emails/Email.php",
2026         'Call'=>"modules/Calls/Call.php",
2027         'Meeting'=>"modules/Meetings/Meeting.php",
2028         'Note'=>"modules/Notes/Note.php",
2029         'Tasks'=>"modules/Tasks/Task.php",
2030         );
2031
2032
2033         foreach($tables as $table=>$bean_class)
2034         {
2035
2036                 if (!class_exists($bean_class))
2037                 {
2038                         require_once($location[$bean_class]);
2039                 }
2040
2041                 $bProcessingNotes=false;
2042                 if ($table=='notes')
2043                 {
2044                         $bProcessingNotes=true;
2045                 }
2046                 $query = "SELECT id FROM $table WHERE parent_id='$from_id'";
2047                 $results = $db->query($query);
2048                 while($row = $db->fetchByAssoc($results))
2049                 {
2050                         //retrieve existing record.
2051                         $bean= new $bean_class();
2052                         $bean->retrieve($row['id']);
2053                         //process for new instance.
2054                         if ($bProcessingNotes)
2055                         {
2056                                 $old_note_id=$row['id'];
2057                                 $old_filename=$bean->filename;
2058                         }
2059                         $bean->id=null;
2060                         $bean->parent_id=$to_id;
2061                         $bean->parent_type=$to_type;
2062                         if ($to_type=='Contacts' and in_array('contact_id',$bean->column_fields))
2063                         {
2064                                 $bean->contact_id=$to_id;
2065                         }
2066                         $bean->update_date_modified = false;
2067             $bean->update_modified_by = false;
2068             if(isset($bean->date_modified))
2069                 $bean->date_modified = $timedate->to_db($bean->date_modified);
2070             if(isset($bean->date_entered))
2071                 $bean->date_entered = $timedate->to_db($bean->date_entered);
2072                         //save
2073                         $new_id=$bean->save();
2074
2075                         //duplicate the file now. for notes.
2076                         if ($bProcessingNotes && !empty($old_filename))
2077                         {
2078                                 UploadFile::duplicate_file($old_note_id,$new_id,$old_filename);
2079                         }
2080                         //reset the values needed for attachment duplication.
2081                         $old_note_id=null;
2082                         $old_filename=null;
2083                 }
2084         }
2085 }
2086
2087 function values_to_keys($array)
2088 {
2089         $new_array = array();
2090         if(!is_array($array))
2091         {
2092                 return $new_array;
2093         }
2094         foreach($array as $arr){
2095                 $new_array[$arr] = $arr;
2096         }
2097         return $new_array;
2098 }
2099
2100 function clone_relationship(&$db, $tables = array(), $from_column, $from_id, $to_id)
2101 {
2102         foreach($tables as $table)
2103         {
2104
2105                 if ($table == 'emails_beans') {
2106                         $query = "SELECT * FROM $table WHERE $from_column='$from_id' and bean_module='Leads'";
2107                 } else {
2108                         $query = "SELECT * FROM $table WHERE $from_column='$from_id'";
2109                 }
2110                 $results = $db->query($query);
2111                 while($row = $db->fetchByAssoc($results))
2112                 {
2113                         $query = "INSERT INTO $table ";
2114                         $names = '';
2115                         $values = '';
2116                         $row[$from_column] = $to_id;
2117                         $row['id'] = create_guid();
2118                         if ($table=='emails_beans') {
2119                                 $row['bean_module'] =='Contacts';
2120                         }
2121
2122                         foreach($row as $name=>$value)
2123                         {
2124
2125                                 if(empty($names))
2126                                 {
2127                                         $names .= $name;
2128                                         $values .= "'$value'";
2129                                 } else
2130                                 {
2131                                         $names .= ', '. $name;
2132                                         $values .= ", '$value'";
2133                                 }
2134                         }
2135                         $query .= "($names)     VALUES ($values)";
2136                         $db->query($query);
2137                 }
2138         }
2139 }
2140
2141 function get_unlinked_email_query($type, $bean) {
2142     global $current_user;
2143
2144     $return_array['select']='SELECT emails.id ';
2145     $return_array['from']='FROM emails ';
2146     $return_array['where']="";
2147         $return_array['join'] = " JOIN (select distinct email_id from emails_email_addr_rel eear
2148
2149         join email_addr_bean_rel eabr on eabr.bean_id ='$bean->id' and eabr.bean_module = '$bean->module_dir' and
2150         eabr.email_address_id = eear.email_address_id and eabr.deleted=0
2151         where eear.deleted=0 and eear.email_id not in
2152         (select eb.email_id from emails_beans eb where eb.bean_module ='$bean->module_dir' and eb.bean_id = '$bean->id')
2153         ) derivedemails on derivedemails.email_id = emails.id";
2154     $return_array['join_tables'][0] = '';
2155
2156         if (isset($type) and isset($type['return_as_array']) and $type['return_as_array']==true) {
2157                 return $return_array;
2158         }
2159
2160         return $return_array['select'] . $return_array['from'] . $return_array['where'];
2161 } // fn
2162
2163 /**
2164  * Check to see if the number is empty or non-zero
2165  * @param $value
2166  * @return boolean
2167  **/
2168 function number_empty($value)
2169 {
2170         return empty($value) && $value != '0';
2171 }
2172
2173 function get_bean_select_array($add_blank=true, $bean_name, $display_columns, $where='', $order_by='', $blank_is_none=false)
2174 {
2175         global $beanFiles;
2176         require_once($beanFiles[$bean_name]);
2177         $focus = new $bean_name();
2178         $user_array = array();
2179         $user_array = get_register_value('select_array',$bean_name. $display_columns. $where . $order_by);
2180         if(!$user_array)
2181         {
2182
2183                 $db = DBManagerFactory::getInstance();
2184                 $temp_result = Array();
2185                 $query = "SELECT id, {$display_columns} as display from {$focus->table_name} where ";
2186                 if ( $where != '')
2187                 {
2188                         $query .= $where." AND ";
2189                 }
2190
2191                 $query .=  " deleted=0";
2192
2193                 if ( $order_by != '')
2194                 {
2195                         $query .= ' order by '.$order_by;
2196                 }
2197
2198                 $GLOBALS['log']->debug("get_user_array query: $query");
2199                 $result = $db->query($query, true, "Error filling in user array: ");
2200
2201                 if ($add_blank==true){
2202                         // Add in a blank row
2203                         if($blank_is_none == true) { // set 'blank row' to "--None--"
2204                                 global $app_strings;
2205                                 $temp_result[''] = $app_strings['LBL_NONE'];
2206                         } else {
2207                                 $temp_result[''] = '';
2208                         }
2209                 }
2210
2211                 // Get the id and the name.
2212                 while($row = $db->fetchByAssoc($result))
2213                 {
2214                         $temp_result[$row['id']] = $row['display'];
2215                 }
2216
2217                 $user_array = $temp_result;
2218                 set_register_value('select_array',$bean_name. $display_columns. $where . $order_by,$temp_result);
2219         }
2220
2221         return $user_array;
2222
2223 }
2224 /**
2225  *
2226  *
2227  * @param unknown_type $listArray
2228  */
2229 // function parse_list_modules
2230 // searches a list for items in a user's allowed tabs and returns an array that removes unallowed tabs from list
2231 function parse_list_modules(&$listArray)
2232 {
2233         global $modListHeader;
2234         $returnArray = array();
2235
2236         foreach($listArray as $optionName => $optionVal)
2237         {
2238                 if(array_key_exists($optionName, $modListHeader))
2239                 {
2240                         $returnArray[$optionName] = $optionVal;
2241                 }
2242
2243                 // special case for projects
2244                 if(array_key_exists('Project', $modListHeader))
2245                 {
2246                         $returnArray['ProjectTask'] = $listArray['ProjectTask'];
2247                 }
2248         }
2249         $acldenied = ACLController::disabledModuleList($listArray,false);
2250         foreach($acldenied as $denied){
2251                 unset($returnArray[$denied]);
2252         }
2253         asort($returnArray);
2254
2255         return $returnArray;
2256 }
2257
2258 function display_notice($msg = false){
2259         global $error_notice;
2260         //no error notice - lets just display the error to the user
2261         if(!isset($error_notice)){
2262                 echo '<br>'.$msg . '<br>';
2263         }else{
2264                 $error_notice .= $msg . '<br>';
2265         }
2266 }
2267
2268 /* checks if it is a number that atleast has the plus at the beggining
2269  */
2270 function skype_formatted($number){
2271         //kbrill - BUG #15375
2272         if(isset($_REQUEST['action']) && $_REQUEST['action']=="Popup") {
2273                 return false;
2274         } else {
2275                 return substr($number, 0, 1) == '+' || substr($number, 0, 2) == '00' || substr($number, 0, 3) == '011';
2276         }
2277 //      return substr($number, 0, 1) == '+' || substr($number, 0, 2) == '00' || substr($number, 0, 2) == '011';
2278 }
2279
2280 function format_skype($number) {
2281     return preg_replace('/[^\+0-9]/','',$number);
2282 }
2283
2284 function insert_charset_header() {
2285         header('Content-Type: text/html; charset=UTF-8');
2286 }
2287
2288 function getCurrentURL()
2289 {
2290         $href = "http:";
2291         if(!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on')
2292         {
2293                 $href = 'https:';
2294         }
2295
2296         $href.= "//".$_SERVER['HTTP_HOST'].$_SERVER['SCRIPT_NAME'].'?'.$_SERVER['QUERY_STRING'];
2297         return $href;
2298 }
2299
2300 function javascript_escape($str) {
2301         $new_str = '';
2302
2303         for($i = 0; $i < strlen($str); $i++) {
2304
2305                 if(ord(substr($str, $i, 1))==10){
2306                         $new_str .= '\n';
2307                 }elseif(ord(substr($str, $i, 1))==13){
2308                         $new_str .= '\r';
2309                 }
2310                 else {
2311                         $new_str .= $str{$i};
2312                 }
2313         }
2314
2315         $new_str = str_replace("'", "\\'", $new_str);
2316
2317         return $new_str;
2318 }
2319
2320 function js_escape($str, $keep=true){
2321         $str = html_entity_decode(str_replace("\\", "", $str), ENT_QUOTES);
2322
2323         if($keep){
2324                 $str = javascript_escape($str);
2325         }
2326         else {
2327                 $str = str_replace("'", " ", $str);
2328                 $str = str_replace('"', " ", $str);
2329         }
2330
2331         return $str;
2332
2333         //end function js_escape
2334 }
2335
2336 function br2nl($str) {
2337         $regex = "#<[^>]+br.+?>#";
2338         preg_match_all($regex, $str, $matches);
2339
2340         foreach($matches[0] as $match) {
2341                 $str = str_replace($match, "<br>", $str);
2342         }
2343
2344         $brs = array('<br>','<br/>', '<br />');
2345         $str = str_replace("\r\n", "\n", $str); // make from windows-returns, *nix-returns
2346         $str = str_replace("\n\r", "\n", $str); // make from windows-returns, *nix-returns
2347         $str = str_replace("\r", "\n", $str); // make from windows-returns, *nix-returns
2348         $str = str_replace($brs, "\n", $str); // to retrieve it
2349
2350         return $str;
2351 }
2352
2353 /**
2354  * Private helper function for displaying the contents of a given variable.
2355  * This function is only intended to be used for SugarCRM internal development.
2356  * The ppd stands for Pre Print Die.
2357  */
2358 function _ppd($mixed)
2359 {
2360 }
2361
2362
2363 /**
2364  * Private helper function for displaying the contents of a given variable in
2365  * the Logger. This function is only intended to be used for SugarCRM internal
2366  * development. The pp stands for Pre Print.
2367  * @param $mixed var to print_r()
2368  * @param $die boolean end script flow
2369  * @param $displayStackTrace also show stack trace
2370  */
2371 function _ppl($mixed, $die=false, $displayStackTrace=false, $loglevel="fatal") {
2372 }
2373
2374 /**
2375  * private helper function to quickly show the major, direct, field attributes of a given bean.
2376  * The ppf stands for Pre[formatted] Print Focus [object]
2377  * @param object bean The focus bean
2378  */
2379 function _ppf($bean, $die=false) {
2380 }
2381
2382
2383
2384 /**
2385  * Private helper function for displaying the contents of a given variable.
2386  * This function is only intended to be used for SugarCRM internal development.
2387  * The pp stands for Pre Print.
2388  */
2389 function _pp($mixed)
2390 {
2391 }
2392
2393 /**
2394  * Private helper function for displaying the contents of a given variable.
2395  * This function is only intended to be used for SugarCRM internal development.
2396  * The pp stands for Pre Print.
2397  */
2398 function _pstack_trace($mixed=NULL)
2399 {
2400 }
2401
2402 /**
2403  * Private helper function for displaying the contents of a given variable.
2404  * This function is only intended to be used for SugarCRM internal development.
2405  * The pp stands for Pre Print Trace.
2406  */
2407 function _ppt($mixed, $textOnly=false)
2408 {
2409 }
2410
2411 /**
2412  * Private helper function for displaying the contents of a given variable.
2413  * This function is only intended to be used for SugarCRM internal development.
2414  * The pp stands for Pre Print Trace Die.
2415  */
2416 function _pptd($mixed)
2417 {
2418 }
2419
2420 /**
2421  * Private helper function for decoding javascript UTF8
2422  * This function is only intended to be used for SugarCRM internal development.
2423  */
2424 function decodeJavascriptUTF8($str) {
2425 }
2426
2427 /**
2428  * Will check if a given PHP version string is supported (tested on this ver),
2429  * unsupported (results unknown), or invalid (something will break on this
2430  * ver).  Do not pass in any pararameter to default to a check against the
2431  * current environment's PHP version.
2432  *
2433  * @return 1 implies supported, 0 implies unsupported, -1 implies invalid
2434  */
2435 function check_php_version($sys_php_version = '') {
2436         $sys_php_version = empty($sys_php_version) ? constant('PHP_VERSION') : $sys_php_version;
2437         // versions below $min_considered_php_version considered invalid by default,
2438         // versions equal to or above this ver will be considered depending
2439         // on the rules that follow
2440         $min_considered_php_version = '5.2.1';
2441
2442         // only the supported versions,
2443         // should be mutually exclusive with $invalid_php_versions
2444         $supported_php_versions = array (
2445         '5.2.1', '5.2.2', '5.2.3', '5.2.4', '5.2.5', '5.2.6', '5.2.8', '5.3.0'
2446         );
2447         //Find out what Database the system is using.
2448         global $sugar_config;
2449         $dbType = '';
2450         if (isset($_REQUEST['setup_db_type'])) {
2451                 $dbType = $_REQUEST['setup_db_type'];
2452         } else if (isset ($sugar_config['dbconfig']) && isset ($sugar_config['dbconfig']['db_type'])) {
2453                 $dbType = $sugar_config['dbconfig']['db_type'];
2454         }
2455
2456         // invalid versions above the $min_considered_php_version,
2457         // should be mutually exclusive with $supported_php_versions
2458
2459         // SugarCRM prohibits install on PHP 5.2.7 on all platforms
2460         $invalid_php_versions = array('5.2.7');
2461
2462         // default unsupported
2463         $retval = 0;
2464
2465         // versions below $min_considered_php_version are invalid
2466         if(1 == version_compare($sys_php_version, $min_considered_php_version, '<')) {
2467                 $retval = -1;
2468         }
2469
2470         // supported version check overrides default unsupported
2471         foreach($supported_php_versions as $ver) {
2472                 if(1 == version_compare($sys_php_version, $ver, 'eq') || strpos($sys_php_version,$ver) !== false) {
2473                         $retval = 1;
2474                         break;
2475                 }
2476         }
2477
2478         // invalid version check overrides default unsupported
2479         foreach($invalid_php_versions as $ver) {
2480                 if(1 == version_compare($sys_php_version, $ver, 'eq') && strpos($sys_php_version,$ver) !== false) {
2481                         $retval = -1;
2482                         break;
2483                 }
2484         }
2485
2486     //allow a redhat distro to install, regardless of version.  We are assuming the redhat naming convention is followed
2487     //and the php version contains 'rh' characters
2488     if(strpos($sys_php_version, 'rh') !== false) {
2489         $retval = 1;
2490     }
2491
2492         return $retval;
2493 }
2494
2495 /**
2496  * Will check if a given IIS version string is supported (tested on this ver),
2497  * unsupported (results unknown), or invalid (something will break on this
2498  * ver).
2499  *
2500  * @return 1 implies supported, 0 implies unsupported, -1 implies invalid
2501  */
2502 function check_iis_version($sys_iis_version = '') {
2503
2504         $server_software = $_SERVER["SERVER_SOFTWARE"];
2505         $iis_version = '';
2506         if(strpos($server_software,'Microsoft-IIS') !== false && preg_match_all("/^.*\/(\d+\.?\d*)$/",  $server_software, $out))
2507             $iis_version = $out[1][0];
2508
2509     $sys_iis_version = empty($sys_iis_version) ? $iis_version : $sys_iis_version;
2510
2511     // versions below $min_considered_iis_version considered invalid by default,
2512     // versions equal to or above this ver will be considered depending
2513     // on the rules that follow
2514     $min_considered_iis_version = '6.0';
2515
2516     // only the supported versions,
2517     // should be mutually exclusive with $invalid_iis_versions
2518     $supported_iis_versions = array ('6.0', '7.0',);
2519     $unsupported_iis_versions = array();
2520     $invalid_iis_versions = array('5.0',);
2521
2522     // default unsupported
2523     $retval = 0;
2524
2525     // versions below $min_considered_iis_version are invalid
2526     if(1 == version_compare($sys_iis_version, $min_considered_iis_version, '<')) {
2527         $retval = -1;
2528     }
2529
2530     // supported version check overrides default unsupported
2531     foreach($supported_iis_versions as $ver) {
2532         if(1 == version_compare($sys_iis_version, $ver, 'eq') || strpos($sys_iis_version,$ver) !== false) {
2533             $retval = 1;
2534             break;
2535         }
2536     }
2537
2538     // unsupported version check overrides default unsupported
2539     foreach($unsupported_iis_versions as $ver) {
2540         if(1 == version_compare($sys_iis_version, $ver, 'eq') && strpos($sys_iis_version,$ver) !== false) {
2541             $retval = 0;
2542             break;
2543         }
2544     }
2545
2546     // invalid version check overrides default unsupported
2547     foreach($invalid_iis_versions as $ver) {
2548         if(1 == version_compare($sys_iis_version, $ver, 'eq') && strpos($sys_iis_version,$ver) !== false) {
2549             $retval = -1;
2550             break;
2551         }
2552     }
2553
2554     return $retval;
2555 }
2556
2557 function pre_login_check(){
2558         global $action, $login_error;
2559         if(!empty($action)&& $action == 'Login'){
2560
2561                 if(!empty($login_error)){
2562                         $login_error = htmlentities($login_error);
2563                         $login_error = str_replace(array("&lt;pre&gt;","&lt;/pre&gt;","\r\n", "\n"), "<br>", $login_error);
2564                         $_SESSION['login_error'] = $login_error;
2565                         echo '<script>
2566                                                 function set_focus() {}
2567                                                 if(document.getElementById("post_error")) {
2568                                                         document.getElementById("post_error").innerHTML="'. $login_error. '";
2569                                                         document.getElementById("cant_login").value=1;
2570                                                         document.getElementById("login_button").disabled = true;
2571                                                         document.getElementById("user_name").disabled = true;
2572                                                         //document.getElementById("user_password").disabled = true;
2573                                                 }
2574                                                 </script>';
2575                 }
2576         }
2577 }
2578
2579
2580
2581 function sugar_cleanup($exit = false) {
2582         static $called = false;
2583         if($called)return;
2584         $called = true;
2585         set_include_path(realpath(dirname(__FILE__) . '/..') . PATH_SEPARATOR . get_include_path());
2586         chdir(realpath(dirname(__FILE__) . '/..'));
2587         global $sugar_config;
2588         LogicHook::initialize();
2589         $GLOBALS['logic_hook']->call_custom_logic('', 'server_round_trip');
2590
2591         //added this check to avoid errors during install.
2592         if (empty($sugar_config['dbconfig'])) {
2593                 if ($exit) exit; else return;
2594         }
2595
2596     if (!class_exists('Tracker', true)) {
2597                 require_once 'modules/Trackers/Tracker.php';
2598         }
2599         Tracker::logPage();
2600         // Now write the cached tracker_queries
2601         if(!empty($GLOBALS['savePreferencesToDB']) && $GLOBALS['savePreferencesToDB']) {
2602             if ( isset($GLOBALS['current_user']) && $GLOBALS['current_user'] instanceOf User )
2603                 $GLOBALS['current_user']->savePreferencesToDB();
2604         }
2605
2606         //check to see if this is not an ajax call AND the user preference error flag is set
2607         if( 
2608                 (isset($_SESSION['USER_PREFRENCE_ERRORS']) && $_SESSION['USER_PREFRENCE_ERRORS'])
2609                 && ($_REQUEST['action']!='modulelistmenu' && $_REQUEST['action']!='DynamicAction') 
2610                 && (empty($_REQUEST['to_pdf']) || !$_REQUEST['to_pdf'] )  
2611                 && (empty($_REQUEST['sugar_body_only']) || !$_REQUEST['sugar_body_only'] ) 
2612                 
2613         ){
2614                 global $app_strings;
2615                 //this is not an ajax call and the user preference error flag is set, so reset the flag and print js to flash message
2616                 $err_mess = $app_strings['ERROR_USER_PREFS'];
2617                 $_SESSION['USER_PREFRENCE_ERRORS'] = false;
2618                 echo " 
2619                 <script>
2620                         ajaxStatus.flashStatus('$err_mess',7000);
2621                 </script>";                             
2622                 
2623         }       
2624         
2625         pre_login_check();
2626         if(class_exists('DBManagerFactory')) {
2627                 $db = DBManagerFactory::getInstance();
2628                 $db->disconnect();
2629                 if($exit) {
2630                         exit;
2631                 }
2632         }
2633 }
2634
2635 register_shutdown_function('sugar_cleanup');
2636
2637
2638 /*
2639  check_logic_hook - checks to see if your custom logic is in the logic file
2640  if not, it will add it. If the file isn't built yet, it will create the file
2641
2642  */
2643 function check_logic_hook_file($module_name, $event, $action_array){
2644         require_once('include/utils/logic_utils.php');
2645         $add_logic = false;
2646
2647         if(file_exists("custom/modules/$module_name/logic_hooks.php")){
2648
2649                 $hook_array = get_hook_array($module_name);
2650
2651                 if(check_existing_element($hook_array, $event, $action_array)==true){
2652                         //the hook at hand is present, so do nothing
2653                 } else {
2654                         $add_logic = true;
2655
2656                         $logic_count = count($hook_array[$event]);
2657                         if($action_array[0]==""){
2658                                 $action_array[0] = $logic_count  + 1;
2659                         }
2660                         $hook_array[$event][] = $action_array;
2661
2662                 }
2663                 //end if the file exists already
2664         } else {
2665                 $add_logic = true;
2666                 if($action_array[0]==""){
2667                         $action_array[0] = 1;
2668                 }
2669                 $hook_array = array();
2670                 $hook_array[$event][] = $action_array;
2671                 //end if else file exists already
2672         }
2673         if($add_logic == true){
2674
2675                 //reorder array by element[0]
2676                 //$hook_array = reorder_array($hook_array, $event);
2677                 //!!!Finish this above TODO
2678
2679                 $new_contents = replace_or_add_logic_type($hook_array);
2680                 write_logic_file($module_name, $new_contents);
2681
2682                 //end if add_element is true
2683         }
2684
2685         //end function check_logic_hook_file
2686 }
2687
2688 function remove_logic_hook($module_name, $event, $action_array) {
2689     require_once('include/utils/logic_utils.php');
2690         $add_logic = false;
2691
2692         if(file_exists("custom/modules/".$module_name."/logic_hooks.php")){
2693         // The file exists, let's make sure the hook is there
2694                 $hook_array = get_hook_array($module_name);
2695
2696                 if(check_existing_element($hook_array, $event, $action_array)==true){
2697             // The hook is there, time to take it out.
2698
2699             foreach ( $hook_array[$event] as $i => $hook ) {
2700                 // We don't do a full comparison below just in case the filename changes
2701                 if ( $hook[0] == $action_array[0]
2702                      && $hook[1] == $action_array[1]
2703                      && $hook[3] == $action_array[3]
2704                      && $hook[4] == $action_array[4] ) {
2705                     unset($hook_array[$event][$i]);
2706                 }
2707             }
2708
2709             $new_contents = replace_or_add_logic_type($hook_array);
2710             write_logic_file($module_name, $new_contents);
2711
2712         }
2713     }
2714 }
2715
2716 function display_stack_trace($textOnly=false){
2717
2718         $stack  = debug_backtrace();
2719
2720         echo "\n\n display_stack_trace caller, file: " . $stack[0]['file']. ' line#: ' .$stack[0]['line'];
2721
2722         if(!$textOnly)
2723         echo '<br>';
2724
2725         $first = true;
2726         $out = '';
2727
2728         foreach($stack as $item) {
2729                 $file  = '';
2730                 $class = '';
2731                 $line  = '';
2732                 $function  = '';
2733
2734                 if(isset($item['file']))
2735                 $file = $item['file'];
2736                 if(isset($item['class']))
2737                 $class = $item['class'];
2738                 if(isset($item['line']))
2739                 $line = $item['line'];
2740                 if(isset($item['function']))
2741                 $function = $item['function'];
2742
2743                 if(!$first) {
2744                         if(!$textOnly) {
2745                                 $out .= '<font color="black"><b>';
2746                         }
2747
2748                         $out .= $file;
2749
2750                         if(!$textOnly) {
2751                                 $out .= '</b></font><font color="blue">';
2752                         }
2753
2754                         $out .= "[L:{$line}]";
2755
2756                         if(!$textOnly) {
2757                                 $out .= '</font><font color="red">';
2758                         }
2759
2760                         $out .= "({$class}:{$function})";
2761
2762                         if(!$textOnly) {
2763                                 $out .= '</font><br>';
2764                         } else {
2765                                 $out .= "\n";
2766                         }
2767                 } else {
2768                         $first = false;
2769                 }
2770         }
2771
2772         echo $out;
2773 }
2774
2775 function StackTraceErrorHandler($errno, $errstr, $errfile,$errline, $errcontext) {
2776         $error_msg = " $errstr occured in <b>$errfile</b> on line $errline [" . date("Y-m-d H:i:s") . ']';
2777         $halt_script = true;
2778         switch($errno){
2779                 case 2048: return; //depricated we have lots of these ignore them
2780                 case E_USER_NOTICE:
2781                 case E_NOTICE:
2782                     if ( error_reporting() & E_NOTICE ) {
2783                         $halt_script = false;
2784                         $type = 'Notice';
2785                     }
2786                     else
2787                         return;
2788                         break;
2789                 case E_USER_WARNING:
2790                 case E_COMPILE_WARNING:
2791                 case E_CORE_WARNING:
2792                 case E_WARNING:
2793
2794                         $halt_script = false;
2795                         $type = "Warning";
2796                         break;
2797
2798                 case E_USER_ERROR:
2799                 case E_COMPILE_ERROR:
2800                 case E_CORE_ERROR:
2801                 case E_ERROR:
2802
2803                         $type = "Fatal Error";
2804                         break;
2805
2806                 case E_PARSE:
2807
2808                         $type = "Parse Error";
2809                         break;
2810
2811                 default:
2812                         //don't know what it is might not be so bad
2813                         $halt_script = false;
2814                         $type = "Unknown Error ($errno)";
2815                         break;
2816         }
2817         $error_msg = '<b>'.$type.'</b>:' . $error_msg;
2818         echo $error_msg;
2819         display_stack_trace();
2820         if($halt_script){
2821                 exit -1;
2822         }
2823
2824
2825
2826 }
2827
2828
2829 if(isset($sugar_config['stack_trace_errors']) && $sugar_config['stack_trace_errors']){
2830
2831         set_error_handler('StackTraceErrorHandler');
2832 }
2833 function get_sub_cookies($name){
2834         $cookies = array();
2835         if(isset($_COOKIE[$name])){
2836                 $subs = explode('#', $_COOKIE[$name]);
2837                 foreach($subs as $cookie){
2838                         if(!empty($cookie)){
2839                                 $cookie = explode('=', $cookie);
2840
2841                                 $cookies[$cookie[0]] = $cookie[1];
2842                         }
2843                 }
2844         }
2845         return $cookies;
2846
2847 }
2848
2849
2850 function mark_delete_components($sub_object_array, $run_second_level=false, $sub_sub_array=""){
2851
2852         if(!empty($sub_object_array)){
2853
2854                 foreach($sub_object_array as $sub_object){
2855
2856                         //run_second level is set to true if you need to remove sub-sub components
2857                         if($run_second_level==true){
2858
2859                                 mark_delete_components($sub_object->get_linked_beans($sub_sub_array['rel_field'],$sub_sub_array['rel_module']));
2860
2861                                 //end if run_second_level is true
2862                         }
2863                         $sub_object->mark_deleted($sub_object->id);
2864                         //end foreach sub component
2865                 }
2866                 //end if this is not empty
2867         }
2868
2869         //end function mark_delete_components
2870 }
2871
2872 /**
2873  * For translating the php.ini memory values into bytes.  e.g. input value of '8M' will return 8388608.
2874  */
2875 function return_bytes($val)
2876 {
2877         $val = trim($val);
2878         $last = strtolower($val{strlen($val)-1});
2879
2880         switch($last)
2881         {
2882                 // The 'G' modifier is available since PHP 5.1.0
2883                 case 'g':
2884                         $val *= 1024;
2885                 case 'm':
2886                         $val *= 1024;
2887                 case 'k':
2888                         $val *= 1024;
2889         }
2890
2891         return $val;
2892 }
2893
2894 /**
2895  * Adds the href HTML tags around any URL in the $string
2896  */
2897 function url2html($string) {
2898         //
2899         $return_string = preg_replace('/(\w+:\/\/)(\S+)/', ' <a href="\\1\\2" target="_new"  style="font-weight: normal;">\\1\\2</a>', $string);
2900         return $return_string;
2901 }
2902 // End customization by Julian
2903
2904 /**
2905  * tries to determine whether the Host machine is a Windows machine
2906  */
2907 function is_windows() {
2908     static $is_windows = null;
2909     if (!isset($is_windows)) {
2910         $is_windows = strtoupper(substr(PHP_OS, 0, 3)) == 'WIN';
2911     }
2912     return $is_windows;
2913 }
2914
2915 /**
2916  * equivalent for windows filesystem for PHP's is_writable()
2917  * @param string file Full path to the file/dir
2918  * @return bool true if writable
2919  */
2920 function is_writable_windows($file) {
2921         if($file{strlen($file)-1}=='/') {
2922                 return is_writable_windows($file.uniqid(mt_rand()).'.tmp');
2923         }
2924
2925         // the assumption here is that Windows has an inherited permissions scheme
2926         // any file that is a descendant of an unwritable directory will inherit
2927         // that property and will trigger a failure below.
2928         if(is_dir($file)) {
2929                 return true;
2930         }
2931
2932         $file = str_replace("/", '\\', $file);
2933
2934         if(file_exists($file)) {
2935                 if (!($f = @sugar_fopen($file, 'r+')))
2936                 return false;
2937                 fclose($f);
2938                 return true;
2939         }
2940
2941         if(!($f = @sugar_fopen($file, 'w')))
2942         return false;
2943         fclose($f);
2944         unlink($file);
2945         return true;
2946 }
2947
2948
2949 /**
2950  * best guesses Timezone based on webserver's TZ settings
2951  */
2952 function lookupTimezone($userOffset = 0){
2953         require_once('include/timezone/timezones.php');
2954
2955         $defaultZones= array('America/New_York'=>1, 'America/Los_Angeles'=>1,'America/Chicago'=>1, 'America/Denver'=>1,'America/Anchorage'=>1, 'America/Phoenix'=>1, 'Europe/Amsterdam'=>1,'Europe/Athens'=>1,'Europe/London'=>1, 'Australia/Sydney'=>1, 'Australia/Perth'=>1);
2956         global $timezones;
2957         $serverOffset = date('Z');
2958         if(date('I')) {
2959                 $serverOffset -= 3600;
2960         }
2961         if(!is_int($userOffset)) {
2962                 return '';
2963         }
2964         $gmtOffset = $serverOffset/60 + $userOffset * 60;
2965         $selectedZone = ' ';
2966         foreach($timezones as $zoneName=>$zone) {
2967
2968                 if($zone['gmtOffset'] == $gmtOffset) {
2969                         $selectedZone = $zoneName;
2970                 }
2971                 if(!empty($defaultZones[$selectedZone]) ) {
2972                         return $selectedZone;
2973                 }
2974         }
2975         return $selectedZone;
2976 }
2977
2978 function convert_module_to_singular($module_array){
2979         global $beanList;
2980
2981         foreach($module_array as $key => $value){
2982                 if(!empty($beanList[$value])) $module_array[$key] = $beanList[$value];
2983
2984                 if($value=="Cases") {
2985                         $module_array[$key] = "Case";
2986                 }
2987                 if($key=="projecttask"){
2988                         $module_array['ProjectTask'] = "Project Task";
2989                         unset($module_array[$key]);
2990                 }
2991         }
2992
2993         return $module_array;
2994
2995         //end function convert_module_to_singular
2996 }
2997
2998 /*
2999  * Given the bean_name which may be plural or singular return the singular
3000  * bean_name. This is important when you need to include files.
3001  */
3002 function get_singular_bean_name($bean_name){
3003         global $beanFiles, $beanList;
3004         if(array_key_exists($bean_name, $beanList)){
3005                 return $beanList[$bean_name];
3006         }
3007         else{
3008                 return $bean_name;
3009         }
3010 }
3011
3012 function get_label($label_tag, $temp_module_strings){
3013         global $app_strings;
3014         if(!empty($temp_module_strings[$label_tag])){
3015
3016                 $label_name = $temp_module_strings[$label_tag];
3017         } else {
3018                 if(!empty($app_strings[$label_tag])){
3019                         $label_name = $app_strings[$label_tag];
3020                 } else {
3021                         $label_name = $label_tag;
3022                 }
3023         }
3024         return $label_name;
3025
3026         //end function get_label
3027 }
3028
3029
3030 function search_filter_rel_info(& $focus, $tar_rel_module, $relationship_name){
3031
3032         $rel_list = array();
3033
3034         foreach($focus->relationship_fields as $rel_key => $rel_value){
3035                 if($rel_value == $relationship_name){
3036                         $temp_bean = get_module_info($tar_rel_module);
3037         //              echo $focus->$rel_key;
3038                         $temp_bean->retrieve($focus->$rel_key);
3039                         if($temp_bean->id!=""){
3040
3041                                 $rel_list[] = $temp_bean;
3042                                 return $rel_list;
3043                         }
3044                 }
3045         }
3046
3047         foreach($focus->field_defs as $field_name => $field_def){
3048                 //Check if the relationship_name matches a "relate" field
3049                 if(!empty($field_def['type']) && $field_def['type'] == 'relate'
3050                 && !empty($field_def['id_name']) && !empty($focus->field_defs[$field_def['id_name']])
3051                 && !empty($focus->field_defs[$field_def['id_name']]['relationship'])
3052                 && $focus->field_defs[$field_def['id_name']]['relationship'] == $relationship_name)
3053                 {
3054                         $temp_bean = get_module_info($tar_rel_module);
3055                 //      echo $focus->$field_def['id_name'];
3056                         $temp_bean->retrieve($focus->$field_def['id_name']);
3057                         if($temp_bean->id!=""){
3058
3059                                 $rel_list[] = $temp_bean;
3060                                 return $rel_list;
3061                         }
3062                 //Check if the relationship_name matches a "link" in a relate field
3063                 } else if(!empty($rel_value['link']) && !empty($rel_value['id_name']) && $rel_value['link'] == $relationship_name){
3064                         $temp_bean = get_module_info($tar_rel_module);
3065                 //      echo $focus->$rel_value['id_name'];
3066                         $temp_bean->retrieve($focus->$rel_value['id_name']);
3067                         if($temp_bean->id!=""){
3068
3069                                 $rel_list[] = $temp_bean;
3070                                 return $rel_list;
3071                         }
3072                 }
3073         }
3074
3075         // special case for unlisted parent-type relationships
3076         if($focus->parent_type == $tar_rel_module && !empty($focus->parent_id)) {
3077                 $temp_bean = get_module_info($tar_rel_module);
3078                 $temp_bean->retrieve($focus->parent_id);
3079                 if($temp_bean->id!=""){
3080                         $rel_list[] = $temp_bean;
3081                         return $rel_list;
3082                 }
3083         }
3084
3085         return $rel_list;
3086
3087         //end function search_filter_rel_info
3088 }
3089
3090 function get_module_info($module_name){
3091         global $beanList;
3092         global $dictionary;
3093
3094         //Get dictionary and focus data for module
3095         $vardef_name = $beanList[$module_name];
3096
3097         if($vardef_name=="aCase"){
3098                 $class_name = "Case";
3099         } else {
3100                 $class_name = $vardef_name;
3101         }
3102
3103         if(!file_exists('modules/'. $module_name . '/'.$class_name.'.php')){
3104                 return;
3105         }
3106
3107         include_once('modules/'. $module_name . '/'.$class_name.'.php');
3108
3109         $module_bean = new $vardef_name();
3110         return $module_bean;
3111         //end function get_module_table
3112 }
3113
3114 /**
3115  * In order to have one place to obtain the proper object name. aCase for example causes issues throughout the application.
3116  *
3117  * @param string $moduleName
3118  */
3119 function get_valid_bean_name($module_name){
3120         global $beanList;
3121
3122         $vardef_name = $beanList[$module_name];
3123         if($vardef_name=="aCase"){
3124                 $bean_name = "Case";
3125         } else {
3126                 $bean_name = $vardef_name;
3127         }
3128         return $bean_name;
3129 }
3130
3131
3132
3133 function  checkAuthUserStatus(){
3134
3135         //authUserStatus();
3136 }
3137
3138
3139 /**
3140  * This function returns an array of phpinfo() results that can be parsed and
3141  * used to figure out what version we run, what modules are compiled in, etc.
3142  * @param       $level                  int             info level constant (1,2,4,8...64);
3143  * @return      $returnInfo             array   array of info about the PHP environment
3144  * @author      original by "code at adspeed dot com" Fron php.net
3145  * @author      customized for Sugar by Chris N.
3146  */
3147 function getPhpInfo($level=-1) {
3148         /**     Name (constant)         Value   Description
3149                 INFO_GENERAL            1               The configuration line, php.ini location, build date, Web Server, System and more.
3150                 INFO_CREDITS            2               PHP Credits. See also phpcredits().
3151                 INFO_CONFIGURATION      4               Current Local and Master values for PHP directives. See also ini_get().
3152                 INFO_MODULES            8               Loaded modules and their respective settings. See also get_loaded_extensions().
3153                 INFO_ENVIRONMENT        16              Environment Variable information that's also available in $_ENV.
3154                 INFO_VARIABLES          32              Shows all predefined variables from EGPCS (Environment, GET, POST, Cookie, Server).
3155                 INFO_LICENSE            64              PHP License information. See also the license FAQ.
3156                 INFO_ALL                        -1              Shows all of the above. This is the default value.
3157          */
3158         ob_start();
3159         phpinfo($level);
3160         $phpinfo = ob_get_contents();
3161         ob_end_clean();
3162
3163         $phpinfo        = strip_tags($phpinfo,'<h1><h2><th><td>');
3164         $phpinfo        = preg_replace('/<th[^>]*>([^<]+)<\/th>/',"<info>\\1</info>",$phpinfo);
3165         $phpinfo        = preg_replace('/<td[^>]*>([^<]+)<\/td>/',"<info>\\1</info>",$phpinfo);
3166         $parsedInfo     = preg_split('/(<h.?>[^<]+<\/h.>)/', $phpinfo, -1, PREG_SPLIT_DELIM_CAPTURE);
3167         $match          = '';
3168         $version        = '';
3169         $returnInfo     = array();
3170
3171         if(preg_match('/<h1 class\=\"p\">PHP Version ([^<]+)<\/h1>/', $phpinfo, $version)) {
3172                 $returnInfo['PHP Version'] = $version[1];
3173         }
3174
3175
3176         for ($i=1; $i<count($parsedInfo); $i++) {
3177                 if (preg_match('/<h.>([^<]+)<\/h.>/', $parsedInfo[$i], $match)) {
3178                         $vName = trim($match[1]);
3179                         $parsedInfo2 = explode("\n",$parsedInfo[$i+1]);
3180
3181                         foreach ($parsedInfo2 AS $vOne) {
3182                                 $vPat   = '<info>([^<]+)<\/info>';
3183                                 $vPat3  = "/$vPat\s*$vPat\s*$vPat/";
3184                                 $vPat2  = "/$vPat\s*$vPat/";
3185
3186                                 if (preg_match($vPat3,$vOne,$match)) { // 3cols
3187                                         $returnInfo[$vName][trim($match[1])] = array(trim($match[2]),trim($match[3]));
3188                                 } elseif (preg_match($vPat2,$vOne,$match)) { // 2cols
3189                                         $returnInfo[$vName][trim($match[1])] = trim($match[2]);
3190                                 }
3191                         }
3192                 } elseif(true) {
3193
3194                 }
3195         }
3196
3197         return $returnInfo;
3198 }
3199
3200 /**
3201  * This function will take a string that has tokens like {0}, {1} and will replace
3202  * those tokens with the args provided
3203  * @param       $format string to format
3204  * @param       $args args to replace
3205  * @return      $result a formatted string
3206  */
3207 function string_format($format, $args){
3208         $result = $format;
3209         for($i = 0; $i < count($args); $i++){
3210                 $result = str_replace('{'.$i.'}', $args[$i], $result);
3211         }
3212         return $result;
3213 }
3214
3215 /**
3216  * Generate a string for displaying a unique identifier that is composed
3217  * of a system_id and number.  This is use to allow us to generate quote
3218  * numbers using a DB auto-increment key from offline clients and still
3219  * have the number be unique (since it is modified by the system_id.
3220  *
3221  * @param       $num of bean
3222  * @param       $system_id from system
3223  * @return      $result a formatted string
3224  */
3225 function format_number_display($num, $system_id){
3226         global $sugar_config;
3227         if(isset($num) && !empty($num)){
3228                 $num=unformat_number($num);
3229                 if(isset($system_id) && $system_id == 1){
3230                         return sprintf("%d", $num);
3231                 }
3232                 else{
3233                         return sprintf("%d-%d", $num, $system_id);
3234                 }
3235         }
3236 }
3237 function checkLoginUserStatus(){
3238 }
3239
3240 /**
3241  * This function will take a number and system_id and format
3242  * @param       $url URL containing host to append port
3243  * @param       $port the port number - if '' is passed, no change to url
3244  * @return      $resulturl the new URL with the port appended to the host
3245  */
3246 function appendPortToHost($url, $port)
3247 {
3248         $resulturl = $url;
3249
3250         // if no port, don't change the url
3251         if($port != '')
3252         {
3253                 $split = explode("/", $url);
3254                 //check if it starts with http, in case they didn't include that in url
3255                 if(str_begin($url, 'http'))
3256                 {
3257                         //third index ($split[2]) will be the host
3258                         $split[2] .= ":".$port;
3259                 }
3260                 else // otherwise assumed to start with host name
3261                 {
3262                         //first index ($split[0]) will be the host
3263                         $split[0] .= ":".$port;
3264                 }
3265
3266                 $resulturl = implode("/", $split);
3267         }
3268
3269         return $resulturl;
3270 }
3271
3272 /**
3273  * Singleton to return JSON object
3274  * @return      JSON object
3275  */
3276 function getJSONobj() {
3277         static $json = null;
3278         if(!isset($json)) {
3279                 require_once('include/JSON.php');
3280                 $json = new JSON(JSON_LOOSE_TYPE);
3281         }
3282         return $json;
3283 }
3284
3285 require_once('include/utils/db_utils.php');
3286 //check to see if custom utils exists
3287 if(file_exists('custom/include/custom_utils.php')){
3288         include_once('custom/include/custom_utils.php');
3289 }
3290
3291
3292 /**
3293  * Set default php.ini settings for entry points
3294  */
3295 function setPhpIniSettings() {
3296         // zlib module
3297         // Bug 37579 - Comment out force enabling zlib.output_compression, since it can cause problems on certain hosts
3298         /*
3299     if(function_exists('gzclose') && headers_sent() == false) {
3300                 ini_set('zlib.output_compression', 1);
3301         }
3302         */
3303         // mbstring module
3304         //nsingh: breaks zip/unzip functionality. Commenting out 4/23/08
3305
3306         /*if(function_exists('mb_strlen')) {
3307                 ini_set('mbstring.func_overload', 7);
3308                 ini_set('mbstring.internal_encoding', 'UTF-8');
3309         }*/
3310
3311
3312         // http://us3.php.net/manual/en/ref.pcre.php#ini.pcre.backtrack-limit
3313         // starting with 5.2.0, backtrack_limit breaks JSON decoding
3314         $backtrack_limit = ini_get('pcre.backtrack_limit');
3315         if(!empty($backtrack_limit)) {
3316                 ini_set('pcre.backtrack_limit', '-1');
3317         }
3318
3319         // mssql only
3320         if(ini_get("mssql.charset")) {
3321                 ini_set('mssql.charset', "UTF-8");
3322         }
3323 }
3324
3325 /**
3326  * like array_merge() but will handle array elements that are themselves arrays;
3327  * PHP's version just overwrites the element with the new one.
3328  *
3329  * @internal Note that this function deviates from the internal array_merge()
3330  *           functions in that it does does not treat numeric keys differently
3331  *           than string keys.  Additionally, it deviates from
3332  *           array_merge_recursive() by not creating an array when like values
3333  *           found.
3334  *
3335  * @param array gimp the array whose values will be overloaded
3336  * @param array dom the array whose values will pwn the gimp's
3337  * @return array beaten gimp
3338  */
3339 function sugarArrayMerge($gimp, $dom) {
3340         if(is_array($gimp) && is_array($dom)) {
3341                 foreach($dom as $domKey => $domVal) {
3342                         if(array_key_exists($domKey, $gimp)) {
3343                                 if(is_array($domVal)) {
3344                                         $tempArr = array();
3345                     foreach ( $domVal as $domArrKey => $domArrVal )
3346                         $tempArr[$domArrKey] = $domArrVal;
3347                     foreach ( $gimp[$domKey] as $gimpArrKey => $gimpArrVal )
3348                         if ( !array_key_exists($gimpArrKey, $tempArr) )
3349                             $tempArr[$gimpArrKey] = $gimpArrVal;
3350                     $gimp[$domKey] = $tempArr;
3351                                 } else {
3352                                         $gimp[$domKey] = $domVal;
3353                                 }
3354                         } else {
3355                                 $gimp[$domKey] = $domVal;
3356                         }
3357                 }
3358         }
3359     // if the passed value for gimp isn't an array, then return the $dom
3360     elseif(is_array($dom))
3361         return $dom;
3362
3363         return $gimp;
3364 }
3365
3366 /**
3367  * Similiar to sugarArrayMerge except arrays of N depth are merged.
3368  *
3369  * @param array gimp the array whose values will be overloaded
3370  * @param array dom the array whose values will pwn the gimp's
3371  * @return array beaten gimp
3372  */
3373 function sugarArrayMergeRecursive($gimp, $dom) {
3374         if(is_array($gimp) && is_array($dom)) {
3375                 foreach($dom as $domKey => $domVal) {
3376                         if(array_key_exists($domKey, $gimp)) {
3377                                 if(is_array($domVal) && is_array($gimp[$domKey])) {
3378                                         $gimp[$domKey] = sugarArrayMergeRecursive($gimp[$domKey], $domVal);
3379                                 } else {
3380                                         $gimp[$domKey] = $domVal;
3381                                 }
3382                         } else {
3383                                 $gimp[$domKey] = $domVal;
3384                         }
3385                 }
3386         }
3387     // if the passed value for gimp isn't an array, then return the $dom
3388     elseif(is_array($dom))
3389         return $dom;
3390
3391         return $gimp;
3392 }
3393
3394 /**
3395  * finds the correctly working versions of PHP-JSON
3396  * @return bool True if NOT found or WRONG version
3397  */
3398 function returnPhpJsonStatus() {
3399         $goodVersions = array('1.1.1',);
3400
3401         if(function_exists('json_encode')) {
3402                 $phpInfo = getPhpInfo(8);
3403
3404                 if(!in_array($phpInfo['json']['json version'], $goodVersions)) {
3405                         return true; // bad version found
3406                 } else {
3407                         return false; // all requirements met
3408                 }
3409         }
3410         return true; // not found
3411 }
3412
3413
3414 /**
3415  * getTrackerSubstring
3416  *
3417  * Returns a [number]-char or less string for the Tracker to display in the header
3418  * based on the tracker_max_display_length setting in config.php.  If not set,
3419  * or invalid length, then defaults to 15 for COM editions, 30 for others.
3420  *
3421  * @param string name field for a given Object
3422  * @return string [number]-char formatted string if length of string exceeds the max allowed
3423  */
3424 function getTrackerSubstring($name) {
3425         static $max_tracker_item_length;
3426
3427         //Trim the name
3428         $strlen = function_exists('mb_strlen') ? mb_strlen($name) : strlen($name);
3429
3430         global $sugar_config;
3431
3432         if(!isset($max_tracker_item_length)) {
3433                 if(isset($sugar_config['tracker_max_display_length'])) {
3434               $max_tracker_item_length = (is_int($sugar_config['tracker_max_display_length']) && $sugar_config['tracker_max_display_length'] > 0 && $sugar_config['tracker_max_display_length'] < 50) ? $sugar_config['tracker_max_display_length'] : 15;
3435                 } else {
3436               $max_tracker_item_length = 15;
3437                 }
3438         }
3439
3440         if($strlen > $max_tracker_item_length) {
3441                 $chopped = function_exists('mb_substr') ? mb_substr($name, 0, $max_tracker_item_length, "UTF-8") : substr($name, 0, $max_tracker_item_length, "UTF-8");
3442         } else {
3443                 $chopped = $name;
3444         }
3445
3446         return $chopped;
3447 }
3448 function generate_search_where ($field_list=array(),$values=array(),&$bean,$add_custom_fields=false,$module='') {
3449         $where_clauses= array();
3450         $like_char='%';
3451         $table_name=$bean->object_name;
3452         foreach ($field_list[$module] as $field=>$parms) {
3453                 if(isset($values[$field]) && $values[$field] != "") {
3454                         $operator='like';
3455                         if (!empty($parms['operator'])) {
3456                                 $operator=$parms['operator'];
3457                         }
3458                         if (is_array($values[$field])) {
3459                                 $operator='in';
3460                                 $field_value='';
3461                                 foreach ($values[$field] as $key => $val) {
3462                                         if ($val != ' ' and $val != '') {
3463                                                 if (!empty($field_value)) {
3464                                                         $field_value.=',';
3465                                                 }
3466                                                 $field_value .= "'".$GLOBALS['db']->quote($val)."'";
3467                                         }
3468                                 }
3469                         } else {
3470                                 $field_value=$GLOBALS['db']->quote($values[$field]);
3471                         }
3472                         //set db_fields array.
3473                         if (!isset($parms['db_field']) )  {
3474                                 $parms['db_field'] = array($field);
3475                         }
3476                         if (isset($parms['my_items']) and $parms['my_items'] == true) {
3477                                 global $current_user;
3478                                 $field_value = $GLOBALS['db']->quote($current_user->id);
3479                                 $operator='=';
3480                         }
3481
3482                         $where='';
3483                         $itr=0;
3484                         if ($field_value != '') {
3485
3486                                 foreach ($parms['db_field'] as $db_field) {
3487                                         if (strstr($db_field,'.')===false) {
3488                                                 $db_field=$bean->table_name.".".$db_field;
3489                                         }
3490                                         if ($GLOBALS['db']->dbType=='oci8' &&  isset($parms['query_type']) && $parms['query_type']=='case_insensitive') {
3491                                                 $db_field='upper('.$db_field.")";
3492                                                 $field_value=strtoupper($field_value);
3493                                         }
3494
3495                                         $itr++;
3496                                         if (!empty($where)) {
3497                                                 $where .= " OR ";
3498                                         }
3499                                         switch (strtolower($operator)) {
3500                                                 case 'like' :
3501                                                         $where .=  $db_field . " like '".$field_value.$like_char."'";
3502                                                         break;
3503                                                 case 'in':
3504                                                         $where .=  $db_field . " in (".$field_value.')';
3505                                                         break;
3506                                                 case '=':
3507                                                         $where .=  $db_field . " = '".$field_value ."'";
3508                                                         break;
3509                                         }
3510                                 }
3511                         }
3512                         if (!empty($where)) {
3513                                 if ($itr>1) {
3514                                         array_push($where_clauses, '( '.$where.' )');
3515                                 } else {
3516                                         array_push($where_clauses, $where);
3517                                 }
3518                         }
3519                 }
3520         }
3521         if ($add_custom_fields) {
3522                 require_once('modules/DynamicFields/DynamicField.php');
3523                 $bean->setupCustomFields($module);
3524                 $bean->custom_fields->setWhereClauses($where_clauses);
3525         }
3526         return $where_clauses;
3527 }
3528
3529 function add_quotes($str) {
3530         return "'{$str}'";
3531 }
3532
3533 /**
3534  * This function will rebuild the config file
3535  * @param       $sugar_config
3536  * @param       $sugar_version
3537  * @return      bool true if successful
3538  */
3539 function rebuildConfigFile($sugar_config, $sugar_version) {
3540         // add defaults to missing values of in-memory sugar_config
3541         $sugar_config = sugarArrayMerge(get_sugar_config_defaults(), $sugar_config );
3542         // need to override version with default no matter what
3543         $sugar_config['sugar_version'] = $sugar_version;
3544
3545         ksort( $sugar_config );
3546
3547         if( write_array_to_file( "sugar_config", $sugar_config, "config.php" ) ){
3548                 return true;
3549         }
3550         else {
3551                 return false;
3552         }
3553 }
3554
3555 /**
3556  * getJavascriptSiteURL
3557  * This function returns a URL for the client javascript calls to access
3558  * the site.  It uses $_SERVER['HTTP_REFERER'] in the event that Proxy servers
3559  * are used to access the site.  Thus, the hostname in the URL returned may
3560  * not always match that of $sugar_config['site_url'].  Basically, the
3561  * assumption is that however the user accessed the website is how they
3562  * will continue to with subsequent javascript requests.  If the variable
3563  * $_SERVER['HTTP_REFERER'] is not found then we default to old algorithm.
3564  * @return $site_url The url used to refer to the website
3565  */
3566 function getJavascriptSiteURL() {
3567         global $sugar_config;
3568         if(!empty($_SERVER['HTTP_REFERER'])) {
3569                 $url = parse_url($_SERVER['HTTP_REFERER']);
3570                 $replacement_url = $url['scheme']."://".$url['host'];
3571                 if(!empty($url['port']))
3572                 $replacement_url .= ':'.$url['port'];
3573                 $site_url = preg_replace('/^http[s]?\:\/\/[^\/]+/',$replacement_url,$sugar_config['site_url']);
3574         } else {
3575                 $site_url = preg_replace('/^http(s)?\:\/\/[^\/]+/',"http$1://".$_SERVER['HTTP_HOST'],$sugar_config['site_url']);
3576                 if(!empty($_SERVER['SERVER_PORT']) &&$_SERVER['SERVER_PORT'] == '443') {
3577                         $site_url = preg_replace('/^http\:/','https:',$site_url);
3578                 }
3579         }
3580         $GLOBALS['log']->debug("getJavascriptSiteURL(), site_url=".  $site_url);
3581         return $site_url;
3582 }
3583
3584 // works nicely with array_map() -- can be used to wrap single quotes around each element in an array
3585 function add_squotes($str) {
3586         return "'" . $str . "'";
3587 }
3588
3589
3590 // recursive function to count the number of levels within an array
3591 function array_depth($array, $depth_count=-1, $depth_array=array()){
3592         $depth_count++;
3593         if (is_array($array)){
3594                 foreach ($array as $key => $value){
3595                         $depth_array[] = array_depth($value, $depth_count);
3596                 }
3597         }
3598         else{
3599                 return $depth_count;
3600         }
3601         foreach ($depth_array as $value){
3602                 $depth_count = $value > $depth_count ? $value : $depth_count;
3603         }
3604         return $depth_count;
3605 }
3606
3607 /**
3608  * Creates a new Group User
3609  * @param string $name Name of Group User
3610  * @return string GUID of new Group User
3611  */
3612 function createGroupUser($name) {
3613
3614
3615         $group = new User();
3616         $group->user_name       = $name;
3617         $group->last_name       = $name;
3618         $group->is_group        = 1;
3619         $group->deleted         = 0;
3620         $group->status          = 'Active'; // cn: bug 6711
3621         $timezone = lookupTimezone();
3622         $group->setPreference('timezone', $timezone);
3623         $group->save();
3624
3625         return $group->id;
3626 }
3627
3628 /*
3629  * Helper function to locate an icon file given only a name
3630  * Searches through the various paths for the file
3631  * @param string iconFileName   The filename of the icon
3632  * @return string Relative pathname of the located icon, or '' if not found
3633  */
3634
3635 function _getIcon($iconFileName)
3636 {
3637     $iconPath = SugarThemeRegistry::current()->getImageURL("icon_{$iconFileName}.gif");
3638     //First try un-ucfirst-ing the icon name
3639     if ( empty($iconPath) )
3640         $iconPath = SugarThemeRegistry::current()->getImageURL(
3641             "icon_" . strtolower(substr($iconFileName,0,1)).substr($iconFileName,1) . ".gif");
3642     //Next try removing the icon prefix
3643     if ( empty($iconPath) )
3644         $iconPath = SugarThemeRegistry::current()->getImageURL("{$iconFileName}.gif");
3645
3646         return $iconPath;
3647 }
3648 /**
3649  * Function to grab the correct icon image for Studio
3650  * @param string $iconFileName Name of the icon file
3651  * @param string $altfilename Name of a fallback icon file (displayed if the imagefilename doesn't exist)
3652  * @param string $width Width of image
3653  * @param string $height Height of image
3654  * @param string $align Alignment of image
3655  * @return string $string <img> tag with corresponding image
3656  */
3657
3658 function getStudioIcon($iconFileName='', $altFileName='', $width='48', $height='48', $align='baseline' )
3659 {
3660         global $app_strings, $theme;
3661
3662     $iconPath = _getIcon($iconFileName);
3663         if(empty($iconPath)){
3664             $iconPath = _getIcon($altFileName);
3665             if (empty($iconPath))
3666             {
3667             return $app_strings['LBL_NO_IMAGE'];
3668             }
3669         }
3670         return '<img border="0" src="'.$iconPath.'" width="'.$width.'" height="'.$height.'" align="'.$align.'">';
3671 }
3672
3673 /**
3674  * Function to grab the correct icon image for Dashlets Dialog
3675  * @param string $filename Location of the icon file
3676  * @param string $module Name of the module to fall back onto if file does not exist
3677  * @param string $width Width of image
3678  * @param string $height Height of image
3679  * @param string $align Alignment of image
3680  * @return string $string <img> tag with corresponding image
3681  */
3682
3683 function get_dashlets_dialog_icon($module='', $width='32', $height='32', $align='absmiddle'){
3684         global $app_strings, $theme;
3685         $icon_path = _getIcon($module . "_32");
3686         if (empty($icon_path))
3687         {
3688                 $icon_path = _getIcon($module);
3689         }
3690         if(empty($icon_path)){
3691                 $icon = $app_strings['LBL_NO_IMAGE'];
3692         }
3693         else{
3694                 $icon = '<img border="0" src="'.$icon_path.'" width="'.$width.'" height="'.$height.'" align="'.$align.'">';
3695         }
3696         return $icon;
3697 }
3698
3699 // works nicely to change UTF8 strings that are html entities - good for PDF conversions
3700 function html_entity_decode_utf8($string)
3701 {
3702     static $trans_tbl;
3703     // replace numeric entities
3704     //php will have issues with numbers with leading zeros, so do not include them in what we send to code2utf.
3705     $string = preg_replace('~&#x0*([0-9a-f]+);~ei', 'code2utf(hexdec("\\1"))', $string);
3706     $string = preg_replace('~&#0*([0-9]+);~e', 'code2utf(\\1)', $string);
3707     // replace literal entities
3708     if (!isset($trans_tbl))
3709     {
3710         $trans_tbl = array();
3711         foreach (get_html_translation_table(HTML_ENTITIES) as $val=>$key)
3712             $trans_tbl[$key] = utf8_encode($val);
3713     }
3714     return strtr($string, $trans_tbl);
3715 }
3716
3717 // Returns the utf string corresponding to the unicode value
3718 function code2utf($num)
3719 {
3720     if ($num < 128) return chr($num);
3721     if ($num < 2048) return chr(($num >> 6) + 192) . chr(($num & 63) + 128);
3722     if ($num < 65536) return chr(($num >> 12) + 224) . chr((($num >> 6) & 63) + 128) . chr(($num & 63) + 128);
3723     if ($num < 2097152) return chr(($num >> 18) + 240) . chr((($num >> 12) & 63) + 128) . chr((($num >> 6) & 63) + 128) . chr(($num & 63) + 128);
3724     return '';
3725 }
3726
3727 function str_split_php4($string, $length = 1) {
3728         $string_length = strlen($string);
3729         $return = array();
3730         $cursor = 0;
3731         if ($length > $string_length) {
3732                 // use the string_length as the string is shorter than the length
3733                 $length = $string_length;
3734         }
3735         for ($cursor = 0; $cursor < $string_length; $cursor = $cursor + $length) {
3736                 $return[] = substr($string, $cursor, $length);
3737         }
3738         return $return;
3739 }
3740
3741 if (version_compare(phpversion(), '5.0.0', '<')) {
3742         function str_split($string, $length = 1) {
3743                 return str_split_php4($string, $length);
3744         }
3745 }
3746
3747 /*
3748  * Invoked when connected to mssql. checks if we have freetds version of mssql library.
3749  * the response is put into a global variable.
3750  */
3751 function is_freetds() {
3752
3753         $ret=false;
3754         if (isset($GLOBALS['mssql_library_version'])) {
3755                 if ($GLOBALS['mssql_library_version']=='freetds') {
3756                         $ret=true;
3757                 } else {
3758                         $ret=false;
3759                 }
3760         } else {
3761                 ob_start();
3762                 phpinfo();
3763                 $info=ob_get_contents();
3764                 ob_end_clean();
3765
3766                 if (strpos($info,'FreeTDS') !== false) {
3767                         $GLOBALS['mssql_library_version']='freetds';
3768                         $ret=true;
3769                 } else {
3770                         $GLOBALS['mssql_library_version']='regular';
3771                         $ret=false;
3772                 }
3773         }
3774         return $ret;
3775 }
3776
3777 /*
3778  *  stripos - Find position of first occurrence of a case-insensitive string
3779  *
3780  *  The function is being defined for systems with PHP version < 5.
3781  *
3782  */
3783 if (!function_exists("stripos")){
3784         function stripos($haystack,$needle,$offset=0){
3785       return strpos(strtolower($haystack),strtolower($needle),$offset);
3786         }
3787 }
3788
3789 /**
3790  * Chart dashlet helper function that returns the correct CSS file, dependent on the current theme.
3791  *
3792  * @todo this won't work completely right until we impliment css compression and combination
3793  *       for now, we'll just include the last css file found.
3794  *
3795  * @return chart.css file to use
3796  */
3797 function chartStyle()
3798 {
3799     return SugarThemeRegistry::current()->getCSSURL('chart.css');
3800 }
3801
3802 /**
3803  * Chart dashlet helper functions that returns the correct XML color file for charts,
3804  * dependent on the current theme.
3805  *
3806  * @return sugarColors.xml to use
3807  */
3808 function chartColors()
3809 {
3810         if (SugarThemeRegistry::current()->getCSSURL('sugarColors.xml')=='')
3811         return SugarThemeRegistry::current()->getImageURL('sugarColors.xml');
3812     return SugarThemeRegistry::current()->getCSSURL('sugarColors.xml');
3813 }
3814 /* End Chart Dashlet helper functions */
3815
3816 /**
3817  * This function is designed to set up the php enviroment
3818  * for AJAX requests.
3819  */
3820
3821 function ajaxInit() {
3822         ini_set('display_errors', 'false');
3823 }
3824
3825 /**
3826  * Returns an absolute path from the given path, determining if it is relative or absolute
3827  *
3828  * @param  string $path
3829  * @return string
3830  */
3831 function getAbsolutePath(
3832     $path,
3833     $currentServer = false
3834     )
3835 {
3836     $path = trim($path);
3837
3838     // try to match absolute paths like \\server\share, /directory or c:\
3839     if ( ( substr($path,0,2) == '\\\\' )
3840             || ( $path[0] == '/' )
3841             || preg_match('/^[A-z]:/i',$path)
3842             || $currentServer )
3843         return $path;
3844
3845     return getcwd().'/'.$path;
3846 }
3847
3848 /**
3849  * Returns the bean object of the given module
3850  *
3851  * @deprecated use SugarModule::loadBean() instead
3852  * @param  string $module
3853  * @return object
3854  */
3855 function loadBean(
3856     $module
3857     )
3858 {
3859     return SugarModule::get($module)->loadBean();
3860 }
3861
3862
3863 /**
3864  * Returns true if the application is being accessed on a touch screen interface ( like an iPad )
3865  */
3866 function isTouchScreen()
3867 {
3868     $ua = empty($_SERVER['HTTP_USER_AGENT']) ? "undefined" : strtolower($_SERVER['HTTP_USER_AGENT']);
3869
3870     // first check if we have forced use of the touch enhanced interface
3871     if ( isset($_COOKIE['touchscreen']) && $_COOKIE['touchscreen'] == '1' ) {
3872         return true;
3873     }
3874
3875     // next check if we should use the touch interface with our device
3876     if ( strpos($ua, 'ipad') !== false ) {
3877         return true;
3878     }
3879
3880     return false;
3881 }
3882
3883 /**
3884  * Returns the shortcut keys to access the shortcut links.  Shortcut
3885  * keys vary depending on browser versions and operating systems.
3886  * @return String value of the shortcut keys
3887  */
3888 function get_alt_hot_key() {
3889         $ua = '';
3890     if ( isset($_SERVER['HTTP_USER_AGENT']) )
3891         $ua = strtolower($_SERVER['HTTP_USER_AGENT']);
3892         $isMac = strpos($ua, 'mac') !== false;
3893         $isLinux = strpos($ua, 'linux') !== false;
3894
3895         if(!$isMac && !$isLinux && strpos($ua, 'mozilla') !== false) {
3896            if(preg_match('/firefox\/(\d)?\./', $ua, $matches)) {
3897                   return $matches[1] < 2 ? 'Alt+' : 'Alt+Shift+';
3898            }
3899         }
3900         return $isMac ? 'Ctrl+' : 'Alt+';
3901 }
3902
3903 function can_start_session(){
3904         if(!empty($_GET['PHPSESSID'])) {
3905            return true;
3906         }
3907         $session_id = session_id();
3908         return empty($session_id) ? true : false;
3909 }
3910
3911 function load_link_class($properties){
3912         $class = 'Link';
3913         if(!empty($properties['link_class']) && !empty($properties['link_file'])){
3914         require_once($properties['link_file']);
3915         $class = $properties['link_class'];
3916     }
3917     return $class;
3918 }
3919
3920
3921 function inDeveloperMode()
3922 {
3923     return isset($GLOBALS['sugar_config']['developerMode']) && $GLOBALS['sugar_config']['developerMode'];
3924 }
3925
3926 /**
3927  * Filter the protocol list for inbound email accounts.
3928  *
3929  * @param array $protocol
3930  */
3931 function filterInboundEmailPopSelection($protocol)
3932 {
3933     if ( !isset($GLOBALS['sugar_config']['allow_pop_inbound']) || ! $GLOBALS['sugar_config']['allow_pop_inbound'] )
3934     {
3935         if( isset($protocol['pop3']) )
3936                         unset($protocol['pop3']);
3937     }
3938     else
3939         $protocol['pop3'] = 'POP3';
3940
3941     return $protocol;
3942 }
3943
3944 /**
3945  * The function is used because currently we are not supporting mbstring.func_overload
3946  * For some user using mssql without FreeTDS, they may store multibyte charaters in varchar using latin_general collation. It cannot store so many mutilbyte characters, so we need to use strlen.
3947  * The varchar in MySQL, Orcale, and nvarchar in FreeTDS, we can store $length mutilbyte charaters in it. we need mb_substr to keep more info.
3948 * @returns the substred strings.
3949  */
3950 function sugar_substr($string, $length, $charset='UTF-8') {
3951     if($GLOBALS['db']->dbType == 'mssql' && empty($GLOBALS['db']->isFreeTDS)) {
3952         if(strlen($string) > $length) {
3953             $string = trim(substr(trim($string),0,$length));
3954         }
3955     }
3956     else {
3957         if(mb_strlen($string,$charset) > $length) {
3958             $string = trim(mb_substr(trim($string),0,$length,$charset));
3959         }
3960     }
3961     return $string;
3962 }
3963
3964 /**
3965  * The function is used because on FastCGI enviroment, the ucfirst(Chinese Characters) will produce bad charcters.
3966  * This will work even without setting the mbstring.*encoding
3967  */
3968 function sugar_ucfirst($string, $charset='UTF-8') {
3969     return mb_strtoupper(mb_substr($string, 0, 1, $charset), $charset) . mb_substr($string, 1, mb_strlen($string), $charset);
3970 }
3971
3972
3973 /**
3974  *
3975  */
3976 function unencodeMultienum($string) {
3977         if (is_array($string))
3978         {
3979            return $string;
3980         }
3981         if (substr($string, 0 ,1) == "^" && substr($string, -1) == "^") {
3982           $string = substr(substr($string, 1), 0, strlen($string) -2);
3983         }
3984
3985         return explode('^,^', $string);
3986 }
3987
3988 function encodeMultienumValue($arr) {
3989     if (!is_array($arr))
3990         return $arr;
3991
3992     if (empty($arr))
3993         return "";
3994
3995         $string = "^" . implode('^,^', $arr) . "^";
3996
3997     return $string;
3998 }
3999
4000 /**
4001  * create_export_query is used for export and massupdate
4002  * We haven't handle the these fields: $field['type'] == 'relate' && isset($field['link']
4003  * This function will correct the where clause and output necessary join condition for them
4004  * @param $module: the module name
4005  * @param $searchFields: searchFields which is got after $searchForm->populateFromArray()
4006  * @param $where: where clauses
4007  * @return $ret_array['where']: corrected where clause
4008  * @return $ret_array['join']: extra join condition
4009  */
4010 function create_export_query_relate_link_patch($module, $searchFields, $where){
4011         if(file_exists('modules/'.$module.'/SearchForm.html')){
4012                 $ret_array['where'] = $where;
4013                 return $ret_array;
4014         }
4015         $seed = loadBean($module);
4016     foreach($seed->field_defs as $name=>$field)
4017         {
4018
4019                 if( $field['type'] == 'relate' && isset($field['link']) && !empty($searchFields[$name]['value']) ){
4020                         $seed->load_relationship($field['link']);
4021                         $params = array();
4022                         if(empty($join_type))
4023                         {
4024                                 $params['join_type'] = ' LEFT JOIN ';
4025                         }
4026                         else
4027                         {
4028                                 $params['join_type'] = $join_type;
4029                         }
4030                         if(isset($data['join_name']))
4031                         {
4032                                 $params['join_table_alias'] = $field['join_name'];
4033                         }
4034                         else
4035                         {
4036                                 $params['join_table_alias']     = 'join_'.$field['name'];
4037
4038                         }
4039                         if(isset($data['join_link_name']))
4040                         {
4041                                 $params['join_table_link_alias'] = $field['join_link_name'];
4042                         }
4043                         else
4044                         {
4045                                 $params['join_table_link_alias'] = 'join_link_'.$field['name'];
4046                         }
4047                         $join = $seed->$field['link']->getJoin($params, true);
4048                         $join_table_alias = 'join_'.$field['name'];
4049                         if(isset($field['db_concat_fields'])){
4050                                 $db_field = db_concat($join_table_alias, $field['db_concat_fields']);
4051                                 $where = preg_replace('/'.$field['name'].'/', $db_field, $where);
4052                         }else{
4053                                 $where = preg_replace('/(^|[\s(])' . $field['name'] . '/', '${1}' . $join_table_alias . '.'.$field['rname'], $where);
4054                         }
4055                 }
4056         }
4057         $ret_array = array('where'=>$where, 'join'=>$join['join']);
4058         return $ret_array;
4059 }
4060
4061 /**
4062   * We need to clear all the js cache files, including the js language files  in serval places in MB. So I extract them into a util function here.
4063   * @Depends on QuickRepairAndRebuild.php
4064   * @Relate bug 30642  ,23177
4065   */
4066 function clearAllJsAndJsLangFilesWithoutOutput(){
4067                 global $current_language , $mod_strings;
4068                 $MBmodStrings = $mod_strings;
4069         $mod_strings = return_module_language ( $current_language, 'Administration' ) ;
4070         include_once ('modules/Administration/QuickRepairAndRebuild.php') ;
4071         $repair = new RepairAndClear();
4072         $repair->module_list = array();
4073                 $repair->show_output = false;
4074                 $repair->clearJsLangFiles();
4075                 $repair->clearJsFiles();
4076                 $mod_strings = $MBmodStrings;
4077 }
4078
4079 /**
4080  * This function will allow you to get a variable value from query string
4081  */
4082 function getVariableFromQueryString($variable, $string){
4083         $matches = array();
4084         $number = preg_match("/{$variable}=([a-zA-Z0-9_-]+)[&]?/", $string, $matches);
4085         if($number){
4086                 return $matches[1];
4087         }
4088         else{
4089                 return false;
4090         }
4091 }
4092
4093 /**
4094  * should_hide_iframes
4095  * This is a helper method to determine whether or not to show iframes (My Sites) related
4096  * information in the application.
4097  *
4098  * @return boolean flag indicating whether or not iframes module should be hidden
4099  */
4100 function should_hide_iframes() {
4101    //Remove the MySites module
4102    if(file_exists('modules/iFrames/iFrame.php')) {
4103         if(!class_exists("iFrame")) {
4104                 require_once('modules/iFrames/iFrame.php');
4105         }
4106         return false;
4107    }
4108    return true;
4109 }
4110
4111 /**
4112  * Given a version such as 5.5.0RC1 return RC. If we have a version such as: 5.5 then return GA
4113  *
4114  * @param string $version
4115  * @return string RC, BETA, GA
4116  */
4117 function getVersionStatus($version){
4118         if(preg_match('/^[\d\.]+?([a-zA-Z]+?)[\d]*?$/si', $version, $matches)) {
4119                 return strtoupper($matches[1]);
4120         }else{
4121                 return 'GA';
4122         }
4123 }
4124
4125 /**
4126  * Return the numeric portion of a version. For example if passed 5.5.0RC1 then return 5.5. If given
4127  * 5.5.1RC1 then return 5.5.1
4128  *
4129  * @param string $version
4130  * @return version
4131  */
4132 function getMajorMinorVersion($version){
4133         if(preg_match('/^([\d\.]+).*$/si', $version, $matches2)){
4134                 $version = $matches2[1];
4135                 $arr = explode('.', $version);
4136                 if(count($arr) > 2){
4137                         if($arr[2] == '0'){
4138                                 $version = substr($version, 0, 3);
4139                         }
4140                 }
4141         }
4142         return $version;
4143 }
4144
4145 /**
4146  * Return string composed of seconds & microseconds of current time, without dots
4147  * @return string
4148  */
4149 function sugar_microtime()
4150 {
4151         $now = explode(' ', microtime());
4152         $unique_id = $now[1].str_replace('.', '', $now[0]);
4153         return $unique_id;
4154 }
4155 ?>