function disc_client_file_sync($soapclient, $session, $verbose = false, $attempts = 0)
{
    $max_attempts = 3;
    global $sugar_config;
    // files might be big
    ini_set("memory_limit", "-1");
    $return_str = "";
    $tempdir_parent = create_cache_directory("disc_client");
    $temp_dir = tempnam($tempdir_parent, "sug");
    sugar_mkdir($temp_dir, 0775);
    if (!is_dir($temp_dir)) {
        die("Could not create a temp dir.");
    }
    // get pattern file
    $result = $soapclient->call('get_encoded_file', array('session' => $session, 'filename' => "install/data/disc_client.php"));
    if (!empty($soapclient->error_str)) {
        if ($attempts < $max_attempts && substr_count($soapclient->error_str, 'HTTP Error: socket read of headers timed out') > 0) {
            echo "Could not retrieve file patterns list.  Error was: " . $soapclient->error_str;
            $attempts++;
            echo "<BR> {$attempts} of {$max_attempts} attempts trying again<br>";
            flush();
            ob_flush();
            return disc_client_file_sync($soapclient, $session, $verbose, $attempts);
        }
        die("Failed: Could not retrieve file patterns list.  Error was: " . $soapclient->error_str);
    }
    if ($result['error']['number'] != 0) {
        die("Failed: Could not retrieve file patterns list.  Error was: " . $result['error']['name'] . ' - ' . $result['description']);
    }
    $newfile = write_encoded_file($result, $temp_dir);
    if (!copy($newfile, $result['filename'])) {
        die("Could not copy {$newfile} to new location.");
    }
    // get array definitions: $disc_client_ignore
    require "install/data/disc_client.php";
    // get file list/md5s, write as temp file, then require_once from tmp location
    $result = $soapclient->call('get_disc_client_file_list', array('session' => $session));
    if (!empty($soapclient->error_str)) {
        if ($attempts < $max_attempts && substr_count($soapclient->error_str, 'HTTP Error: socket read of headers timed out') > 0) {
            echo "Could not retrieve file patterns list.  Error was: " . $soapclient->error_str;
            $attempts++;
            echo "<BR> {$attempts} of {$max_attempts} attempts trying again<br>";
            flush();
            ob_flush();
            return disc_client_file_sync($soapclient, $session, $verbose, $attempts);
        }
        die("Failed: Could not retrieve file  list.  Error was: " . $soapclient->error_str);
    }
    if ($result['error']['number'] != 0) {
        die("Failed: Could not retrieve file  list.  Error was: " . $result['error']['name'] . ' - ' . $result['description']);
    }
    $temp_file = tempnam($temp_dir, "sug");
    write_encoded_file($result, $temp_dir, $temp_file);
    require_once $temp_file;
    // determine which files are needed locally
    $needed_file_list = array();
    $server_files = array();
    // used later for removing unneeded local files
    foreach ($server_file_list as $result) {
        $server_filename = $result['filename'];
        $server_md5 = $result['md5'];
        $server_files[] = $server_filename;
        $ignore = false;
        foreach ($disc_client_ignore as $ignore_pattern) {
            if (preg_match("#" . $ignore_pattern . "#", $server_filename)) {
                $ignore = true;
            }
        }
        if (file_exists($server_filename)) {
            if (!$ignore && md5_file($server_filename) != $server_md5) {
                // not on the ignore list and the client's md5sum does not match the server's
                $needed_file_list[] = $server_filename;
            }
        } else {
            if (!$ignore) {
                $return_str .= disc_client_utils_print("File missing from client : {$temp_dir}/{$server_filename}<br>", $verbose);
                $needed_file_list[] = $server_filename;
            }
        }
    }
    if (sizeof($server_files) < 100) {
        if ($attempts < $max_attempts && substr_count($soapclient->error_str, 'HTTP Error: socket read of headers timed out') > 0) {
            echo "Could not retrieve file patterns list.  Error was: " . $soapclient->error_str;
            $attempts++;
            echo "<BR> {$attempts} of {$max_attempts} attempts trying again<br>";
            flush();
            ob_flush();
            return disc_client_file_sync($soapclient, $session, $verbose, $attempts);
        }
        die("Failed: Empty file list returned from server.  Please try again.");
    }
    // get needed files
    foreach ($needed_file_list as $needed_file) {
        $result = $soapclient->call('get_encoded_file', array('session' => $session, 'filename' => "{$needed_file}"));
        write_encoded_file($result, $temp_dir);
    }
    // all files recieved, copy them into place
    foreach ($needed_file_list as $needed_file) {
        if (file_exists("{$temp_dir}/{$needed_file}")) {
            mkdir_recursive(dirname($needed_file), true);
            copy("{$temp_dir}/{$needed_file}", $needed_file);
            $return_str .= disc_client_utils_print("Updated file: {$needed_file} <br>", $verbose);
        } else {
            $return_str .= disc_client_utils_print("File missing from client : {$temp_dir}/{$needed_file}<br>", $verbose);
        }
    }
    if (sizeof($needed_file_list) == 0) {
        $return_str .= disc_client_utils_print("No files needed to be synchronized.<br>", $verbose);
    }
    // scrub local files that are not part of client application
    $local_file_list = findAllFiles(".", array());
    $removed_file_count = 0;
    foreach ($local_file_list as $local_file) {
        $ignore = false;
        foreach ($disc_client_ignore as $ignore_pattern) {
            if (preg_match("#" . $ignore_pattern . "#", $local_file)) {
                $ignore = true;
            }
        }
        if (!$ignore && !in_array($local_file, $server_files)) {
            // not on the ignore list and the server does not know about it
            unlink($local_file);
            $return_str .= disc_client_utils_print("Removed file: {$local_file} <br>", $verbose);
            $removed_file_count++;
        }
    }
    if ($removed_file_count == 0) {
        $return_str .= disc_client_utils_print("No files needed to be removed.<br>", $verbose);
    }
    return $return_str;
}
function ConvertDiscClient()
{
    global $sugar_config;
    global $app_strings;
    global $app_list_strings;
    global $mod_strings;
    $xtpl = new XTemplate('modules/Administration/ConvertDiscClient.html');
    $xtpl->assign("MOD", $mod_strings);
    $xtpl->assign("APP", $app_strings);
    echo getClassicModuleTitle($mod_strings['LBL_MODULE_NAME'], array($mod_strings['LBL_MODULE_NAME'], $mod_strings['LBL_UPGRADE_CONVERT_DISC_CLIENT_TITLE']), false);
    require_once 'vendor/nusoap//nusoap.php';
    $errors = array();
    $server_url = "http://";
    $user_name = "";
    $admin_name = "";
    $password = "";
    // run options are: convert, sync
    // default behavior of this page
    $run = "convert";
    if (isset($_REQUEST['run'])) {
        $run = $_REQUEST['run'];
    }
    if ($run == "convert") {
        if (isset($_REQUEST['server_url'])) {
            $server_url = $_REQUEST['server_url'];
            if ($server_url == "") {
                $errors[] = $mod_strings['LBL_CONVERT_DISC_CLIENT_SERVER_URL_EMPTY_ERROR'];
            }
        }
    } else {
        if ($run == "sync") {
            $server_url = $sugar_config['sync_site_url'];
        }
    }
    if (isset($_REQUEST['user_name'])) {
        $user_name = $_REQUEST['user_name'];
        if ($user_name == "") {
            $errors[] = $mod_strings['LBL_CONVERT_DISC_CLIENT_USER_NAME_EMPTY_ERROR'];
        }
    }
    if (isset($_REQUEST['password'])) {
        if ($_REQUEST['password'] == "") {
            $errors[] = $mod_strings['LBL_CONVERT_DISC_CLIENT_PASSWORD_EMPTY_ERROR'];
        }
    }
    if (isset($_REQUEST['admin_name'])) {
        $admin_name = $_REQUEST['admin_name'];
        if ($_REQUEST['admin_name'] == "") {
            $errors[] = $mod_strings['LBL_CONVERT_DISC_CLIENT_ADMIN_NAME_EMPTY'];
        }
    }
    if ($run == "convert") {
        if (!is_writable("config.php")) {
            $errors[] = $mod_strings['LBL_CONVERT_DISC_CLIENT_CONFIG_WRITABLE_ERROR'];
        }
    }
    if (isset($_REQUEST['submitted']) && sizeof($errors) == 0) {
        if (empty($server_url) || $server_url == 'http://') {
            $errors[] = $mod_strings['LBL_CONVERT_DISC_CLIENT_SERVER_URL_REQUIRED'];
        } else {
            $soapclient = new nusoapclient("{$server_url}/soap.php");
            $soapclient->response_timeout = 360;
            if ($soapclient->call('is_loopback', array())) {
                $errors[] = $mod_strings['LBL_CONVERT_DISC_CLIENT_SERVER_CLIENT_IP_ERROR'];
            }
            if (!$soapclient->call('offline_client_available', array())) {
                $errors[] = $mod_strings['LBL_CONVERT_DISC_CLIENT_NO_LICENSE'];
            }
            $result = $soapclient->call('login', array('user_auth' => array('user_name' => $admin_name, 'password' => md5($_REQUEST['password']), 'version' => '.01'), 'application_name' => 'Disconnected Client Setup'));
            if ($soapclient->error_str) {
                $errors[] = $mod_strings['LBL_CONVERT_DISC_CLIENT_LOGIN_FAILED_ERROR'] . $soapclient->error_str;
            }
            if ($result['error']['number'] != 0) {
                $errors[] = $mod_strings['LBL_CONVERT_DISC_CLIENT_LOGIN_FAILED_ERROR'] . $result['error']['name'] . ' ' . $result['error']['description'];
            }
            $session = $result['id'];
            if (empty($errors)) {
                $data = array($user_name);
                $result = $soapclient->call('sudo_user', array('session' => $session, 'user_name' => $user_name));
                if ($soapclient->error_str) {
                    $errors[] = string_format($mod_strings['LBL_CONVERT_DISC_CLIENT_SWITCH_TO_USER_ERROR'], $data) . $soapclient->error_str;
                }
                if (isset($result['error']) && $result['error']['number'] != 0) {
                    $errors[] = string_format($mod_strings['LBL_CONVERT_DISC_CLIENT_SWITCH_TO_USER_ERROR'], $data) . $result['error']['name'] . ' ' . $result['error']['description'];
                }
            }
        }
        $errorString = "";
        if (!empty($errors)) {
            foreach ($errors as $error) {
                $errorString .= $error . "<br>";
            }
        }
        echo '<font color="red"> ' . $errorString . '</font>';
        if ($session && empty($errors)) {
            if ($run == "convert") {
                // register this client/user with server
                // update local config.php file
                $sugar_config['disc_client'] = true;
                $sugar_config['sync_site_url'] = $server_url;
                //attempt to obtain the system_id from the server
                $result = $soapclient->call('get_unique_system_id', array('session' => $session, 'unique_key' => $sugar_config['unique_key']));
                if ($soapclient->error_str) {
                    $errors[] = $mod_strings['LBL_CONVERT_DISC_CLIENT_UNIQUE_SYSTEM_ID_ERROR'] . $soapclient->error_str;
                } else {
                    $admin = BeanFactory::getBean('Administration');
                    $system_id = $result['id'];
                    if (!isset($system_id)) {
                        $system_id = 1;
                    }
                    $admin->saveSetting('system', 'system_id', $system_id);
                }
            }
            // run the file sync
            require_once "include/utils/disc_client_utils.php";
            disc_client_file_sync($soapclient, $session, true);
            // data sync triggers
            require_once "modules/Sync/SyncHelper.php";
            sync_users($soapclient, $session, true);
            ksort($sugar_config);
            echo $mod_strings['LBL_CONVERT_DISC_CLIENT_UPDATE_LOCAL_INFO'];
            if (!write_array_to_file("sugar_config", $sugar_config, "config.php")) {
                $xtpl->assign("COMPLETED_MESSAGE", $mod_strings['LBL_CONVERT_DISC_CLIENT_CONFIG_WRITABLE_AGAIN_ERROR']);
                $xtpl->parse("main.complete");
                return;
            }
            echo $mod_strings['LBL_CONVERT_DISC_CLIENT_DONE_LOGOUT'] . '<script> function logout_countdown(left){document.getElementById("seconds_left").innerHTML = left; if(left == 0){document.location.href = "index.php?module=Users&action=Logout";}else{left--; setTimeout("logout_countdown("+ left+")", 1000)}};setTimeout("logout_countdown(10)", 1000)</script>';
            // done with soap calls
            $result = $soapclient->call('logout', array('session' => $session));
            $xtpl->assign("COMPLETED_MESSAGE", $mod_strings['LBL_CONVERT_DISC_CLIENT_SYNC_COMPLETE']);
            $xtpl->parse("main.complete");
            return;
        }
    }
    $errorString = "";
    foreach ($errors as $error) {
        $errorString .= $error . "<br>";
    }
    if (!empty($errorString)) {
        $xtpl->assign("COMPLETED_MESSAGE", $errorString);
        $xtpl->parse("main.complete");
    }
    if ($run == "convert" && isset($sugar_config['disc_client']) && $sugar_config['disc_client'] == true) {
        $xtpl->parse("main.existing");
    } else {
        if ($run == "convert") {
            $xtpl->assign("SERVER_URL", $server_url);
        }
        $xtpl->assign("USER_NAME", $user_name);
        $xtpl->assign("ADMIN_NAME", $admin_name);
        $xtpl->assign("SUBMITTTED", "true");
        $xtpl->assign("RUN", $run);
        if ($run == "convert") {
            $xtpl->assign("SUBMIT_MESSAGE", $mod_strings['LBL_CONVERT_DISC_CLIENT_SUBMIT']);
        } else {
            if ($run == "sync") {
                $xtpl->assign("SUBMIT_MESSAGE", $mod_strings['LBL_CONVERT_DISC_CLIENT_SYNC_SUBMIT']);
            }
        }
        $xtpl->parse("main.convert");
    }
    $xtpl->parse("main");
    $xtpl->out("main");
}