<?php

# PLUGIN PREVIEW BY TEXTPATTERN.INFO

/**
 * smd_admin_themes
 *
 * A Textpattern CMS plugin for creating, editing, testing, installing and distributing admin-side themes
 *  -> Employ images, CSS, JS, HTML/PHP in your theme
 *  -> Use constants in your CSS files
 *  -> Base your theme on an existing theme to tweak it to your taste
 *  -> Export a theme package for distribution to the community in either .tar, .tgz, .bz2 or .zip format (requires smd_crunchers plugin)
 *  -> Import / install other themes from the "community repository":http://textgarden.org/administration-themes
 *  -> Administrator can set a default theme for all users, or enable per-user / per-role themes
 *
 * @author Stef Dawson
 * @link   http://stefdawson.com/
 * @todo : Remove these strings
 *  -> smd_at_list_title
 *  -> smd_at_one_theme
 */

// TODO:
//  * Verify that files can't be uploaded/created outside of the theme's dir
//  * 'empty_info' message shouldn't fire for bad file upload
// TOFIX:
//  * rawurlencode/decode for files with spaces in them. Currently can't edit contents of file with spaces in it as they get encoded as %20. If encoded, with each save they get %2520 added and it gets longer and longer....

use \Textpattern\Admin\Theme;

if (
txpinterface === 'admin') {

    
// Silence warnings because, although the plugin requires smd_crunchers for the
    // import/export features, it'll function in a reduced capacity without it
    
@require_plugin('smd_crunchers');

    global 
$smd_at_event$smd_at_fullev$smd_at_adm_event$smd_at_privs,
        
$smd_core_themes$prefs$smd_at_feedurl$smd_at_theme_repo;

    
$smd_at_event 'smd_at';
    
$smd_at_fullev 'smd_admin_themes';
    
$smd_at_adm_event 'smd_admat';
    
$smd_at_privs '1';
    
$smd_at_feedurl '';
    
$smd_at_theme_repo '';

    
$smd_core_themes = array('hive''hiveneutral');

    
add_privs($smd_at_event$smd_at_privs);
    
add_privs('plugin_prefs.'.$smd_at_fullev$smd_at_privs);
    
register_tab("extensions"$smd_at_eventgTxt('smd_adth_tab_name'));
    
register_callback('smd_at_options''plugin_prefs.'.$smd_at_fullev);
    
register_callback('smd_at_welcome''plugin_lifecycle.'.$smd_at_fullev);
    
register_callback('smd_at'$smd_at_event);
    
register_callback('smd_at_per''admin_side''theme_name');
    
register_callback('smd_at_link''prefs_ui''theme_name');
    
register_callback('smd_at_inject_css''admin_side''head_end');

    if (isset(
$prefs['smd_at_system']) && $prefs['smd_at_system'] == 2) {
        
add_privs($smd_at_adm_event'2,3,4,5,6');
        
register_tab("admin"$smd_at_adm_eventgTxt('smd_adth_skinner'));
        
register_callback('smd_admat'$smd_at_adm_event);
    }
}

// -------------------------------------------------------------
// CSS definitions: hopefully kind to themers
function smd_at_get_style_rules()
{
    
$smd_at_styles = array(
        
'smd_at' =>'
.smd_at_btn { float: right }
.smd-at-list-name { display:block; padding:.38461538461538em 2.5em .38461538461538em 1em; text-overflow:ellipsis; white-space:nowrap; overflow:hidden; }
.switcher-action + .smd-at-list-name { padding-right:1em; padding-left:2.5em; }
.smd_at_update { font-weight:bold; color:#900; }
#smd_at_images { margin:0px 6px -4px 0; }
.smd_skin_filetypes { margin:12px 0; }
smd_fakebtn { color:#555; cursor:pointer; }
'
    
);

    return 
$smd_at_styles;
}

// -------------------------------------------------------------
function smd_at_inject_css($evt$stp)
{
    global 
$smd_at_event$event;

    if (
$event == $smd_at_event) {
        
$smd_at_styles smd_at_get_style_rules();
        echo 
'<style type="text/css">'$smd_at_styles['smd_at'], '</style>';
    }

    return;
}

// ------------------------
// Plugin jumpoff point
function smd_at($evt$stp)
{
    
$available_steps = array(
        
'smd_at_clone'         => true,
        
'smd_at_delete'        => true,
        
'smd_at_delete_folder' => true,
        
'smd_at_edit'          => false,
        
'smd_at_multi_edit'    => true,
        
'smd_at_export'        => true,
        
'smd_at_import'        => true,
        
'smd_at_newfile'       => false,
        
'smd_at_prefs_install' => false,
        
'smd_at_prefs_remove'  => false,
        
'smd_at_prefs_update'  => true,
        
'smd_at_preview'       => true,
        
'smd_at_rename'        => true,
        
'smd_at_save'          => true,
        
'smd_at_setup'         => false,
        
'smd_at_switch'        => true,
        
'smd_at_upload'        => true,
        
'smd_at_change_pageby' => true,
        
'save_pane_state'      => true,
    );

    if (
$stp == 'save_pane_state') {
        
smd_at_save_pane_state();
    } else if (
$stp && bouncer($stp$available_steps)) {
        
$stp();
    } else {
        
smd_at_list();
    }
}

// -------------------------------------------------------------
function smd_at_welcome($event$step)
{
    
$msg '';
    switch (
$step) {
        case 
'installed':
            
smd_at_prefs_install(0);
            break;
        case 
'deleted':
            
smd_at_prefs_remove(0);
            break;
    }
    return 
$msg;
}

// -------------------------------------------------------------
function smd_at_link()
{
    global 
$smd_at_event;
    return 
href(gTxt('smd_adth_manage_lbl'), '?event='.$smd_at_event);
}

// ------------------------
function smd_at_list($message '')
{
    global 
$smd_at_event$prefs$theme$smd_core_themes$smd_at_fullev$smd_at_feedurl$smd_at_theme_repo;

    
$smd_at_styles smd_at_get_style_rules();
    
$at_prefs smd_at_get_prefs();

    
extract(gpsa(array('step''page''crit''search_method''skin')));
    
$message = ($message) ? $message gps('message');
    
$layout $at_prefs['smd_at_layout'];
    
$stylerule = ($layout==0) ? 'list' 'grid';
    
$tw $at_prefs['smd_at_tw'] + 10;
    
$th $at_prefs['smd_at_th'] + 80;
    
$helpLink "?event=plugin&step=plugin_help&name=$smd_at_fullev#usage";

    
$pageby = (gps('qty')) ? gps('qty') : ((cs('smd_at_pageby')) ? cs('smd_at_pageby') : 15);
    
$max_theme_size $at_prefs['smd_at_max_theme_size'];

    
$curr_skin = (smd_at_exists($theme->name)) ? $theme->name 'hive';
    
$skin_list smd_at_read_skins();
    
$crushers smd_at_crush_options('compress');
    
$uncrushers smd_at_crush_options('decompress');
    
$bases = array();

    
// Get a list of ancestor themes (i.e. dependencies)
    
foreach ($skin_list as $skina) {
        
$manifest smd_at_read_skinfo($skina);
        if (
$manifest) {
            if (
$manifest['based_on']) {
                
$bases[] = $manifest['based_on'];
            }
        }
    }

    
$bases array_unique($bases);

    
pagetop(gTxt('smd_adth_manage_lbl'), $message);

    
// Handle paging.
    // @todo Why does plugin not have its own pageby?
    
$total count($skin_list);
    
$limit max(@$pageby15);

    list(
$page$offset$numPages) = pager($total$limit$page);
    
$skin_list array_slice($skin_list$offset$limit);

    
$qs = array(
        
"event" => $smd_at_event,
        
"page" => $page,
    );

    echo 
script_js(<<<EOJS
function smd_getcrush(skin) {
    skinHandle = "crush_"+skin;
    jQuery('.smd_popup').each(function() {
        box = jQuery(this);
        if (box.attr("id") == skinHandle) {
            if (box.css("display") == "none") {
                box.slideDown('fast');
            } else {
                box.slideUp('fast');
            }
        } else {
            box.slideUp('fast');
        }
    });
    jQuery('#'+skinHandle+' a').click(function() {
        jQuery(this).attr("href", "?event=
{$smd_at_event}&skin="+skin+"&step=smd_at_export&crush="+jQuery('#'+skinHandle+' input[type=\'radio\']:checked').val()+"&page="+{$page}+"&_txp_token="+textpattern._txp_token);
    });
    return false;
}

function smd_getval(skin, step) {
    skinHandle = "pop_"+skin;
    jQuery('.smd_popup').each(function() {
        box = jQuery(this);
        if (box.attr("id") == skinHandle) {
            if (box.css("display") == "none") {
                box.slideDown('fast');
                jQuery('#'+skinHandle+' input').focus();
            } else {
                box.slideUp('fast');
            }
        } else {
            box.slideUp('fast');
        }
    });
    jQuery('#'+skinHandle+' a').click(function() {
        jQuery(this).attr("href", "?event=
{$smd_at_event}&skin="+((skin=='new')? '' : skin)+"&step="+step+"&new_skin="+jQuery('#'+skinHandle+' input').val()+"&page="+{$page}+"&_txp_token="+textpattern._txp_token);
    });

    jQuery('#'+skinHandle+' input').keyup(function () {
        this.value = this.value.replace(/[^a-zA-Z0-9_]/g,'');
        while (this.value.length > 0 && this.value.substring(0,1).match(/[0-9]/)) {
            this.value = this.value.substring(1);
        }
    });

    return false;
}
EOJS
    );

    
// List the available skins.
    
echo '<div class="txp-layout">'
        
.n'<div class="txp-layout-2col">'
        
.nhed(gTxt('smd_adth_tab_name'), 1, array('class' => 'txp-heading'))
        .
n'</div>'
        
.n'<div class="txp-layout-2col">'
        
.ngraf(
            
n'<a href="?event='$smd_at_eventa'step=smd_at_setup">'gTxt('smd_adth_setup'). '</a>'
            
.ngTxt('smd_adth_help_link', array('{link}' => $helpLink))
        .
n'<a href="#" onclick="return smd_getval(\'new\', \'smd_at_clone\');"><span class="ui-icon ui-extra-icon-new-document"></span> '.gTxt('smd_adth_new').'</a>'
        
.n'<p id="pop_new" class="smd_popup txp-list-options" hidden>'
        
.n'<span>'gTxt('smd_adth_new_skin'). '</span>'.n'<input type="text" name="smd_text_name" value="" size="'INPUT_REGULAR'" /> <a class="navlink" href="#">'gTxt('smd_adth_confirm'). '</a>'
        
.n'</p>'
            
, array('class' => 'txp-actions txp-actions-inline')
        )
        .
n'</div>'

        
.n'<div class="smd_at_layout_grid">'
        
.n'<div id="smd_control" class="txp-control-panel">'
        
.n. (($uncrushers)
            ? 
upload_form(gTxt('smd_adth_install_skin'), '''smd_at_import'$smd_at_event''$max_theme_size)
            .
ntag(gTxt('smd_adth_supported_import', array('{types}' => (($uncrushers) ? join(', '$uncrushers) : gTxt('none')))), 'div', array('class' => 'txp-form-field-instructions'))
            : 
''
            
)
        .
n'</div>';

    echo 
'<div class="txp-layout-1col"><form method="post" name="longform" action="' join_qs($qs) . '">';

    if (
$layout=="0") {
        echo 
'<div class="txp-listtables">'.
            
startTable('''''txp-list'5).
            
assHead(
                
gTxt('smd_adth_skin_gbl'),
                
'author',
                
gTxt('version'),
                
'description',
                
gTxt('smd_adth_actions')
            );
    } else {
        echo 
'<div class="txp-grid">';
    }

    if (
is_callable('fsockopen')) {
        
$transport 'fsock';
    } elseif (
is_callable('curl_init')) {
        
$transport 'curl';
    } else {
        
$transport '';
    }

    
$feed '';
    switch (
$transport) {
        case 
'curl':
            
$c curl_init();
            
curl_setopt($cCURLOPT_URL$smd_at_feedurl);
            
curl_setopt($cCURLOPT_REFERERhu);
            
curl_setopt($cCURLOPT_RETURNTRANSFERtrue);
            
curl_setopt($cCURLOPT_VERBOSEfalse);
            
curl_setopt($cCURLOPT_TIMEOUT10);
            
$feed curl_exec($c);
            break;
        case 
'fsock':
            
$url parse_url($smd_at_feedurl);
            
$fp = @fsockopen ($url['host'], 80$errno$errstr5);
            if (
$fp) {
                
$qry 'GET '.$smd_at_feedurl;
                
$qry .= " HTTP/1.0\r\n\r\n";

                
fputs($fp$qry);
                
stream_set_timeout($fp10);
                
$info stream_get_meta_data($fp);

                
$hdrs true;
                while ((!
feof($fp)) && (!$info['timed_out'])) {
                    
$line fgets($fp8192);
                    
$line preg_replace("[\r\n]"""$line);
                    if (
$hdrs == false) {
                        
$feed .= $line."\n";
                    }
                    if (
strlen($line) == 0$hdrs false;
                }
                if (
$info['timed_out']) {
                    
$feed '';
                }
                
fclose($fp);
            } else {
                
$feed '';
            }
            break;
        default:
            
$feed '';
    }

    
$smd_at_vlast '';
    
$feeds = array();

    if (isset(
$prefs['smd_at_versions']) && isset($prefs['smd_at_vlast'])) {
        if (
time() - $prefs['smd_at_vlast'] < 86400) {
            
// Last updated within the last day, so read the cached version numbers
            
$feeds unserialize($prefs['smd_at_versions']);
        }
    }
    if (!
$feeds || gps('read_versions')) {
        
$feeds smd_at_feed($feed);
        
$installed_feed = array();
        
$feeds = (is_array($feeds)) ? $feeds : array();

        
// Only record the version info from themes that are installed
        
foreach($skin_list as $skin_name) {
            
$feed_skin_name str_replace('_''-'$skin_name); // Unsanitize the url_title
            
if (array_key_exists($feed_skin_name$feeds)) {
                
$installed_feed[$feed_skin_name] = $feeds[$feed_skin_name];
            }
        }
        
set_pref('smd_at_vlast'time(), $smd_at_eventPREF_HIDDEN'text_input');
        
set_pref('smd_at_versions'serialize($installed_feed), $smd_at_eventPREF_HIDDEN'text_input');
    }

    foreach (
$skin_list as $skin_name) {
        
// Read each manifest and set up the labels
        
$skinfo smd_at_read_skinfo($skin_name);
        
$feed_skin_name str_replace('_''-'$skin_name); // Unsanitize for url_title matching

        
$thumbnail smd_at_get_thumb($skinfo1);
        
$this_skin = ($skinfo) ? $skinfo['dname'] : $skin_name;
        
$is_gbl = ($skin_name == $at_prefs['smd_at_global_skin']) ? gTxt('smd_adth_is_global') : '';
        
$switch_link '?event='.$smd_at_event.a.'step=smd_at_switch'.a.'nextstep=smd_at_list'.a.'skin='.$skin_name.a.'page='.$page.a.'_txp_token='.form_token();
        
$skintext $this_skin .n$is_gbl .n. (($skinfo && $skinfo['based_on']) ? n.gTxt('smd_adth_based_on', array('{skin}' => $skinfo['based_on'])) : '');
        
$thumblock = ($layout==0)
                        ? 
'<a href="'.$switch_link.'" title="'.gTxt('smd_adth_apply_skin').'">'.$skintext.(($thumbnail) ? br.$thumbnail '').'</a>'
                        
'<a href="'.$switch_link.'" title="'.gTxt('smd_adth_apply_skin').'">'.(($thumbnail) ? $thumbnail gTxt('smd_adth_apply_skin')).'</a>';
        
$authblock = (($skinfo && strpos($skinfo['author_uri'], "http://") === 0) ? '<a href="'.$skinfo['author_uri'].'">'.$skinfo['author'].'</a>' : (($skinfo) ? $skinfo['author'] : '-'));
        
$actblock '<p class="txp-actions"><a href="?event='.$smd_at_event.a.'step=smd_at_edit'.a.'skin='.$skin_name.'"><span class="ui-icon ui-icon-pencil"></span> '.gTxt('edit').'</a>'
            
. (($skinfo) ? '<a href="#" onclick="return smd_getval(\''.$skin_name.'\', \'smd_at_clone\');"><span class="ui-icon ui-icon-copy"></span> '.gTxt('smd_adth_clone').'</a>' '')
            . ((
$skinfo && $crushers) ? '<a href="#" onclick="return smd_getcrush(\''.$skin_name.'\');"><span class="ui-icon ui-icon-extlink"></span> '.gTxt('smd_adth_export').'</a>' '')
            . ((
in_array($skin_name$smd_core_themes) || in_array($skin_name$bases)) ? '' '<a href="?event='.$smd_at_event.a.'step=smd_at_delete'.a.'skin='.$skin_name.a.'page='.$page.a.'_txp_token='.form_token().'" onclick="return confirm(\''.gTxt('smd_adth_delete_confirm', array('{skin}' => $skin_name)).'\');"><span class="ui-icon ui-icon-close"></span> '.gTxt('delete').'</a></p>');
        
$cloneblock '<p id="pop_'.$skin_name.'" class="smd_popup" hidden><span>'.gTxt('smd_adth_new_cloneskin').'</span>'.n.'<input type="text" name="smd_text_name" value="" size="'.INPUT_MEDIUM.'" class="input-medium" />'.n.'<a class="navlink" href="#">'.strong(gTxt('smd_adth_confirm')).'</a></p>';
        
$crushblock = (($crushers) ? '<p id="crush_'.$skin_name.'" class="smd_popup" hidden><span>'.gTxt('smd_adth_crush_format').'</span>'.radioSet($crushers$skin_name.'_crush'$at_prefs['smd_at_crush']).n.'<a class="navlink" href="#">'.strong(gTxt('smd_adth_confirm')).'</a></p>' '');
        
$verblock = ($skinfo) ? ((isset($feeds[$feed_skin_name]) && isset($feeds[$feed_skin_name]['summary']) && version_compare($feeds[$feed_skin_name]['summary'],$skinfo['version'])===1) ? '<a href="'.$feeds[$feed_skin_name]['link'].'" class="smd_at_update">'.gTxt('smd_adth_version').$skinfo['version'].'</a>' gTxt('smd_adth_version').$skinfo['version']) : '';

        if (
$layout==0) {
            echo 
tr(
                
n.td($thumblock)
                .
n.td($authblock)
                .
n.td($verblock)
                .
n.td((($skinfo)? $skinfo['description'] : '-').(($skinfo && $skinfo['help']) ? ' '.href('['.gTxt('help').']'$skinfo['help']) : ''))
                .
n.td($actblock .n$cloneblock .n$crushblock)
            , ((
$skin_name == $curr_skin) ? ' class="highlight"' '')
            );
        } else {
            echo 
'<div class="txp-grid-cell', (($skin_name == $curr_skin) ? ' highlight' ''), '">',
                    
nhed($skintext3),
                    
n'<p>'$thumblock'</p>',
                    
n'<p>'$verblockngTxt('smd_adth_by'), n$authblock'</p>',
                    
n'<p>'$actblock'</p>',
                    
n$cloneblock,
                    
n$crushblock,
                
n'</div>';
        }
    }

    if (
$layout=="0") {
        echo 
nendTable();
    }

    echo 
n'</div>',
        
ntInput(),
        
n'</form></div>',
        
n'<div id="list_navigation" class="txp-navigation">',
        
nnav_form($smd_at_event$page$numPagesNULLNULLNULLNULL),
        
npageby_form($smd_at_event$pageby),
        
n'</div>',
        
n'</div>';
}

function 
smd_at_feed($feed)
{
    global 
$feeds;

    
$feed=preg_replace("/>"."[[:space:]]+"."</i""><"$feed); // Kill whitespace in feed
    
$xmlparser xml_parser_create();
    
xml_set_element_handler($xmlparser"smd_at_feed_start_tag""smd_at_feed_end_tag");
    
xml_set_character_data_handler($xmlparser"smd_at_feed_tag_contents");
    
xml_parse($xmlparser$feed);
    
xml_parser_free($xmlparser);

    return 
$feeds;
}

function 
smd_at_feed_start_tag($parser$name$attribs)
{
    global 
$smd_at_feedin$smd_at_feedtag;
    if (
$name == "ENTRY") {
        
$smd_at_feedin true;
    }
    if (
$smd_at_feedin) {
        
$smd_at_feedtag $name;
    }
}

function 
smd_at_feed_end_tag($parser$name)
{
    global 
$smd_at_feedin$smd_at_feedtag$smd_at_feedname;
    if (
$name == "ENTRY") {
        
$smd_at_feedin false;
        
$smd_at_feedname '';
    }
}

function 
smd_at_feed_tag_contents($parser$data)
{
    global 
$smd_at_feedin$smd_at_feedtag$smd_at_feedname$feeds;
    if (
$smd_at_feedin) {
        if (
$smd_at_feedtag == "NAME") {
            
$feeds[$data] = '';
            
$smd_at_feedname $data;
        }
        if (isset(
$feeds[$smd_at_feedname])) {
            if (
$smd_at_feedtag == "TITLE" || $smd_at_feedtag == "SUMMARY" || $smd_at_feedtag == "UPDATED" || $smd_at_feedtag == "ID" || $smd_at_feedtag == "LINK") {
                
$feeds[$smd_at_feedname][strtolower($smd_at_feedtag)] = $data;
            }
        }
    }
}

// ------------------------
function smd_at_valid_types()
{
    
$editable = array('ssc''scss''css''js''php''txt''textile');
    
$imagable = array('jpg''jpeg''gif''png''svg');
    return array(
$editable$imagable);
}

// ------------------------
function smd_at_edit($message '')
{
    global 
$smd_at_event$file_max_upload_size$step;

    
extract(doSlash(gpsa(array('skin''new_skin''new_skin_dir''file''dir'))));

    
$smd_at_styles smd_at_get_style_rules();
    
$at_prefs smd_at_get_prefs();
    
$layout $at_prefs['smd_at_layout'];

    list(
$editable$imagable) = smd_at_valid_types();

    
$skinfo smd_at_read_skinfo($skin);
    
$file = (empty($new_skin)) ? $file $new_skin;
    
$dir = (empty($new_skin_dir)) ? $dir $new_skin_dir;
    
$files smd_at_listdir(THEME.$skin);
    
sort($files);

    
// Split the list into its directory groups
    
$allfiles = array();

    foreach (
$files as $currfile) {
        
$file_info pathinfo($currfile);
        
// Ignore any rogue Subversion files
        
if (strpos($file_info['dirname'], '/.svn') === false) {
            
$file_type strtolower((isset($file_info['extension'])) ? $file_info['extension'] : 'other');
            
$allfiles[$file_type][] = $currfile;
        }
    }

    if (
gps('smd_at_edits')) {
        
$contents str_replace('\r\n','
'
,gps('smd_at_edits')); // newline workaround
    
} else {
        
$contents '';

        if (
$file && file_exists(THEME.$skin.DS.$dir.DS.$file)) {
            
$contents file(THEME.$skin.DS.$dir.DS.$file);
            
$contents join(""$contents);
        }
    }

    
$info explode ('.',$file);
    
$lastpart count($info)-1;
    
$ext strtolower(trim($info[$lastpart]));
    
$is_textile = ($ext == 'textile');
    
$is_svg = ($ext == 'svg');

    
// Begin rendering the page
    
pagetop(gTxt('smd_adth_edit_lbl', array('{theme}' => $skin)), $message);

    
$skin_list smd_at_read_skins();

    
// selectInput needs both index and value to be the same in this case
    
$skinsel = array();

    foreach (
$skin_list as $key1 => $value1) {
        
$skinsel[$value1] = $skin_list[$key1];
    }

    
$skinChange '<form name="skinchange" action="index.php">'
        
eInput($smd_at_event)
        . 
sInput('smd_at_edit')
        . 
tInput()
        . 
selectInput('skin'$skinsel$skin01)
        . 
'</form>';

    
$listActions graf(
        
href('<span class="ui-icon ui-icon-arrowthickstop-1-s"></span> '.gTxt('expand_all'), '#', array(
            
'class'         => 'txp-expand-all',
            
'aria-controls' => 'allforms_form',
        )).
        
href('<span class="ui-icon ui-icon-arrowthickstop-1-n"></span> '.gTxt('collapse_all'), '#', array(
            
'class'         => 'txp-collapse-all',
            
'aria-controls' => 'allforms_form',
        )), array(
'class' => 'txp-actions')
    );

    
$fileList = array();
    
$fileList[] = '<div id="content_switcher" class="txp-layout-4col-alt" role="region">'
        
.nhed(gTxt('smd_adth_skin_files'), 2)
        .
n$skinChange
        
.$listActions
//      .n. upload_form(gTxt('upload_file'), '', 'smd_at_upload', $smd_at_event, $skin, $file_max_upload_size, '', '')
        
.n'<form id="smd_at_allfiles" action="index.php" method="post">';

    
$dirs $dirout $out = array();
    
$methods = array(
        
'delete'     => gTxt('delete'),
    );

    foreach (
$allfiles as $ftype => $filerec) {
        foreach (
$filerec as $idx => $currfile) {
            
$justfile basename($currfile);
            
$dirs[] = $theDir dirname($currfile);
            
$justdir trim(str_replace(THEME.$skin''$theDir), DS);
            
$parts explode('.'$justfile);
            
$basefile array_shift($parts);
            
$showfile = ($file == $justfile) ? strong($justfile) : $justfile;
            
$is_img smd_at_is_image($currfile);
            
$is_bin smd_at_is_binary($currfile);

            
$edit $is_img '<a href="'.$currfile.'" title="'.gTxt('smd_adth_preview_image').'">'.$showfile.'</a>' : ($is_bin '<span class="smd-at-list-name">' $showfile '</span>' '<a href="?event='.$smd_at_event.a.'step=smd_at_edit'.a.'skin='.$skin.a.'file='.$justfile.a.'dir='.$justdir.'">'.$showfile.'</a>');
            
$modbox = ($basefile == $skin)
                ?   
''
                
:   '<input type="checkbox" name="selected_files[]" value="'.$justdir.DS.$justfile.'" />';

            
$group_name in_array($ftype$imagable) ? 'image_files' : (in_array($ftype$editable) ? $ftype 'other');

            
$out[$group_name][] = '<li>'.n.'<span class="switcher-action">'.$modbox.'</span>'.$edit.'</li>';
        }
    }

    
$combined array_merge($editable, array('image_files''other'));

    foreach (
$combined as $group_name) {
        if (isset(
$out[$group_name])) {
            
$content '<ul class="switcher-list">' .njoin(n$out[$group_name]) .n'</ul>';
            
$fileList[] = wrapRegion($group_name.'_group'$content$group_name'smd_at_'.$group_name'smd_at_pane_'.$group_name.'_visible');
        }
    }

    
$fileList[] = multi_edit($methods$smd_at_event'smd_at_multi_edit'''''''$skin);
    
$fileList[] = tInput().n.'</form>';

    
$dirs array_unique($dirs);
    unset(
$dirs[array_search(THEME.$skin$dirs)]);

    foreach (
$dirs as $thisdir) {
        
$dirout[] = '<li class="smd-at-list-name">'.str_replace(THEME.$skin.'/'''$thisdir).'</td><td>'.dLink($smd_at_event'smd_at_delete_folder''delfolder'$thisdir1'skin'$skin).'</li>';
    }

    
$folderList = ($dirout)
        ? 
wrapRegion('smd_at_folders_group''<ul class="switcher-list">' .njoin(n$dirout) .n'</ul>''folders''smd_at_folders''smd_at_pane_folders_visible')
        : 
'';

    
$qs = array(
        
"event" => $smd_at_event,
    );

    
$qsVars "index.php".join_qs($qs);

    
// Render the rest of the page.
    
echo '<div class="txp-layout">'
        
.'<div class="txp-layout-2col">'
        
.hed(gTxt('smd_adth_edit_lbl', array('{theme}' => (($skinfo) ? $skinfo['dname'] : $skin))), 1)
        .
'</div>'
        
.n'<div class="txp-layout-2col">'
        
.graf(
            
href(gTxt('smd_adth_all_themes'), '?event=' $smd_at_event, array('class' => 'smd_at_btn'))
            , array(
'class' => 'txp-actions txp-actions-inline')
        )
        .
n'</div>'

        
.n'<div class="txp-layout-1col">'
        
.n'<div class="txp-control-panel">'
        
.n'<form action="index.php" method="post" enctype="multipart/form-data">'
        
.nhInput('MAX_FILE_SIZE'$file_max_upload_size)
        .
nhInput('id'$skin)
        .
neInput($smd_at_event)
        .
nsInput('smd_at_upload')
        .
ntInput()
        .
n'<input type="file" name="smd_at_file[]" multiple="true" />'.sp.fInput('submit'''gTxt('upload'))
        .
ngraf('<label for="smd_at_folder">'.gTxt('smd_adth_folder').'</label>' .nfInput('text''smd_at_folder'ps('smd_at_folder'), ''''''INPUT_MEDIUM'''smd_at_folder'))
        .
n'</form>'
        
.n'</div>'
        
.n'</div>'

        
.join(n$fileList).n.$folderList.'</div>'
        
.'<div class="txp-layout-4col-3span" role="region">'
        
.form(
            
n'<p class="txp-actions txp-actions-inline">'
            
.n'<a href="?event='.$smd_at_event.a.'step=smd_at_newfile'.a.'skin='.$skin.'"><span class="ui-icon ui-extra-icon-new-document"></span> '.gTxt('smd_adth_new_file').'</a>'
            
.n'</p>'
            
.n.'<div class="txp-form-field">'
            
.n.'<div class="txp-form-field-label">'
            
.n.'<label for="new_skin">' gTxt('smd_adth_file_name') . '</label>'
            
.n.'</div>'
            
.n.'<div class="txp-form-field-value">'
            
.n.'<input type="text" id="new_skin" name="new_skin" value="'.txpspecialchars($file).'" size="'.INPUT_REGULAR.'" />'
            
.n.($is_textile '<a class="smd_at_preview" href="?event=' $smd_at_event .a'step=smd_at_preview' .a'skin='.$skin.a.'dir='.$dir.a.'file='.$file.a.'type=textile'.a.'_txp_token='.form_token().'">'.gTxt('preview').'</a>' '')
            .
n.($is_svg '<a class="smd_at_preview" href="'THEME $skin.'/' . (($dir) ? $dir.'/' '') . $file .'">'.gTxt('preview').'</a>' '')
            .
n.'</div>'
            
.n.'</div>'
            
.($step == 'smd_at_newfile'
                
n.'<div class="txp-form-field">'
                    
.n.'<div class="txp-form-field-label">'
                    
.n.'<label for="new_skin_dir">' gTxt('smd_adth_folder_name') . '</label>'
                    
.n.'</div>'
                    
.n.'<div class="txp-form-field-value">'
                    
.n.'<input type="text" id="new_skin_dir" name="new_skin_dir" value="'.txpspecialchars($dir).'" size="'.INPUT_REGULAR.'" />'
                    
.n.'</div>'
                    
.n.'</div>'
                
''
            
)
            .
n.graf(
                
'<textarea id="smd_at_edits" class="code" name="smd_at_edits" cols="'.INPUT_XLARGE.'" rows="'.INPUT_REGULAR.'">'.txpspecialchars($contents).'</textarea>'
                
)
            .
n.graf(
                
fInput('submit','',gTxt('save'),'publish')
            )
            .
n.eInput($smd_at_event)
            .
n.sInput('smd_at_save')
            .
n.hInput('skin',$skin)
            .
n.hInput('file',$file)
            .
n.hInput('dir',$dir)
        )
        .
'</div>'
        
.script_js( <<<EOS
jQuery(document).ready(function() {
    jQuery('#smd_at_allfiles').txpMultiEditForm({
        'checkbox' : 'input[name="selected_files[]"][type=checkbox]',
        'row' : '.switcher-list li',
        'highlighted' : '.switcher-list li'
    });
});
jQuery('#smd_at_edits').keyup(function() {
    jQuery('.smd_at_preview').hide();
});
EOS
        )
        .
'</div></div>';
}

// ------------------------
// Just clear out the var so the save function treats the content as a new file
function smd_at_newfile()
{
    
$_POST['file'] = '';
    
$message='';
    
smd_at_edit($message);
}

// ------------------------
function smd_at_preview()
{
    
extract(doSlash(gpsa(array('skin''file''dir''type'))));

    
$fp $skin.DS.(($dir) ? $dir.DS '').$file;

    
$path THEME.$fp;
    
$out '';

    switch (
$type) {
        case 
'textile':
            @include_once 
txpath.'/lib/classTextile.php';

            if (
class_exists('Textile') && file_exists($path)) {
                
$textile = new Textile();
                
$contents file_get_contents($path);
                
$out $textile->TextileThis($contents);
            }
        break;
    }

    
pagetop(gTxt('smd_adth_preview', array('{name}' => $fp)));
    echo 
n,'<div id="smd_at_container" class="txp-container txp-view">',
        
n,'<div class="text-column">' $out '</div>',
        
n,'</div>';

    
//TODO: back to smd_at_edit() button?
}

// ------------------------
// Do the first 512 bytes contain a disproportionate quantity of non-ascii chars?
// Hacked from http://stackoverflow.com/questions/3872877/how-to-check-if-uploaded-file-is-binary-file, thanks
function smd_at_is_binary($path)
{
    if (
file_exists($path)) {
        if (!
is_file($path)) return 0;

        
$fh  fopen($path"r");
        
$blk fread($fh512);
        
fclose($fh);
        
clearstatcache();

        return (
            
or substr_count($blk"\x00") > 0
        
);
    }
    return 
0;
}

// ------------------------
// Hacked from http://www.binarytides.com/blog/php-best-way-to-check-if-file-is-an-image/, thanks
function smd_at_is_image($path)
{
    
// Silence warnings in case file is not readable due to spaces or something
    
$a = @getimagesize($path);
    
$image_type $a[2];

    if(
in_array($image_type , array(IMAGETYPE_GIFIMAGETYPE_JPEGIMAGETYPE_PNG))) {
        return 
true;
    }
    return 
false;
}

// ------------------------
function smd_at_clone()
{
    global 
$txp_user;

    
extract(doSlash(gpsa(array('skin''new_skin'))));
    
$msg='';

    
$new_skin trim($new_skin);
    
$new_skin rawurlencode($new_skin);

    if (empty(
$new_skin)) {
        
$msg = array(gTxt('smd_adth_name_empty'), E_WARNING);
    }

    
// Check the new name isn't already in use
    
$themes smd_at_read_skins();

    if (
in_array($new_skin$themes)) {
        
$msg = array(gTxt('smd_adth_skin_exists', array('{name}' => $new_skin)), E_ERROR);
    }

    
// No errors, so make a new dir and create the PHP file
    
if ($msg=='') {
        
$content '';
        
$destdir THEME.$new_skin.DS;
        
$res mkdir($destdir);
        
$based '';

        if (
$skin) {
            
// Based on an existing theme. No need for any functions other than manifest()
            
$based "Theme::based_on('".$skin."');";
            
$extends $skin.'_theme';
            
$srcss THEME.$skin.DS.'textpattern.css';
            if (
file_exists($srcss) && filesize($srcss) > 0) {
                
$import join(''file($srcss));
            } else {
                
$import '@import url("../hive/assets/css/textpattern.css");';
            }
            
$content '{';
        } else {
            
// Brand spanking new theme. Clone 'hive' functions then add new manifest()
            
$extends 'Theme';
            
$import '';
            
$src txpath.DS.THEME.'hive'.DS.'hive.php';
            
$grab false;
            
$fp file($src);

            foreach(
$fp as $line) {
                
$line rtrim($line);
                if (
strpos($line'function manifest()') !== false) {
                    
$grab false// unnecessary?
                    
break;
                }
                if (
$grab) {
                    
$content .= $line.n;
                }
                if (
strpos($line'class hive_theme extends') !== false) {
                    
$grab true;
                }
            }
        }

        
// manifest fields
        
$manuser doSlash(get_author_name($txp_user));
        
$mantitle doSlash(ucwords($new_skin));

        
// Write the new PHP file
        
$buf = <<<EOF
<?php

use \Textpattern\Admin\Theme;

if (!defined('txpinterface')) die('txpinterface is undefined.');

{$based}

class 
{$new_skin}_theme extends {$extends}
{$content}

    function manifest()
    {
        return array(
            'title'         => '
{$mantitle}',
            'author'        => '
{$manuser}',
            'author_uri'    => '',
            'version'       => '1.0',
            'description'   => '',
            'help'          => '',
        );
    }
}
?>
EOF;

        
$fp fopen($destdir.$new_skin.'.php'"wb");
        
fwrite($fp$buf);
        
fclose($fp);

        
// Create the CSS file
        
$fp fopen($destdir.'textpattern.css'"wb");
        
fwrite($fp$import);
        
fclose($fp);

        if (
$skin) {
            
$msg gTxt('smd_adth_skin_cloned', array('{name}' => $new_skin));;
        } else {
            
$msg gTxt('smd_adth_skin_created', array('{name}' => $new_skin));;
        }

//  $msg = gTxt('skin_not_created', array('{name}' => $new_skin));;

    
}

    
smd_at_list($msg);
}

// ------------------------
function smd_at_crush_options($type 'compress')
{
    global 
$plugins;

    
$smd_crushers = array();

    if (
is_array($plugins) && in_array('smd_crunchers'$plugins)) {
        
$crunchers smd_crunch_capabilities($type);
        foreach (array(
'tar''gzip''zip''bzip2') as $cm) {
            if (
in_array($cm$crunchers)) {
                
$smd_crushers[$cm] = gTxt('smd_adth_c_'.$cm);
            }
        }
    }

    return 
$smd_crushers;
}

// ------------------------
function smd_at_export()
{
    
extract(doSlash(gpsa(array('skin','crush'))));

    
$at_prefs smd_at_get_prefs();

    
$message='';
    
chdir(THEME);
    
$skinfo smd_at_read_skinfo($skin);
    
$reps = array(
        
'{theme}' => $skin,
        
'{version}' => $skinfo['version'],
    );
    
$out strtr($at_prefs['smd_at_filename_format'], $reps);

    
// Check the passed compression format is valid
    
$crushers smd_at_crush_options('compress');
    if (
$crush=='' || $crush=='undefined' || !array_key_exists($crush$crushers)) {
        
$msg = array(gTxt('smd_adth_unsupported_compressiontype', array('{crush}' => $crush)), E_WARNING);
        
smd_at_list($message);
        return;
    }

    switch(
$crush) {
        case 
'zip':
            
$zip = new smd_crunch_zip_file($out.'.zip');
            break;
        case 
'bzip2':
            
$zip = new smd_crunch_bzip_file($out.'.tbz2');
            break;
        case 
'tar':
            
$zip = new smd_crunch_tar_file($out.'.tar');
            break;
        case 
'gzip':
            
$zip = new smd_crunch_gzip_file($out.'.tgz');
            break;
    }

    
$zip->set_options(array('basedir' => txpath.DS.THEME'overwrite' => 1'inmemory' => 1));
    
$zip->add_files($skin.DS.'*.*');
    
$zip->exclude_files($skin.DS.'*.svn*');
    
$zip->create_archive();
    
$zip->download_file();
}

// ------------------------
function smd_at_import()
{
    
$name $_FILES['thefile']['name'];
    
$file get_uploaded_file($_FILES['thefile']['tmp_name'], txpath.DS.THEME.basename($_FILES['thefile']['tmp_name']));
    
$basedir txpath.DS.THEME;
    
$uncrushers smd_at_crush_options('decompress');
    
$message='';
    
$info explode ('.',$name);
    
$lastpart count($info)-1;
    
$ext $info[$lastpart];

    if (
$name && $file) {
        if (
$ext == 'zip' && array_key_exists('zip'$uncrushers)) {
            
$zip = new smd_crunch_dUnzip2($file);
//          $zip->debug = true;
            
$zip->getList();
            
$validArchive smd_at_check_archive($zip->compressedList$ext);
            if (
$validArchive) {
                
$zip->unzipAll($basedir''true0755);
                
$zip->close();
                
$message gTxt('smd_adth_import_ok');
            } else {
                
$message = array(gTxt('smd_adth_import_failed'), E_ERROR);
            }
        } else if (
$ext == 'tgz' && array_key_exists('gzip'$uncrushers)) {
            
$zip = new smd_crunch_gzip_file(basename($file));
            
$zip->set_options(array('basedir' => $basedir'overwrite' => 1));
            
$zip->extract_files();
            
$message gTxt('smd_adth_import_ok');
        } else if (
$ext == 'tbz2' && array_key_exists('bzip2'$uncrushers)) {
            
$zip = new smd_crunch_bzip_file(basename($file));
            
$zip->set_options(array('basedir' => $basedir'overwrite' => 1));
            
$zip->extract_files();
            
$message gTxt('smd_adth_import_ok');
        } else if (
$ext == 'tar') {
            
$zip = new smd_crunch_tar_file(basename($file));
            
$zip->set_options(array('basedir' => $basedir'overwrite' => 1));
            
$zip->extract_files();
            
$message gTxt('smd_adth_import_ok');
        } else {
            
$message = array(gTxt('smd_adth_unsupported_compressiontype', array('{crush}' => $ext)), E_WARNING);
        }

        
// Remove the temporary file
        
unlink($file);
    } else {
        
$message = array(gTxt('smd_adth_empty_info'), E_WARNING);
    }

    
smd_at_list($message);
}

// Check the directory structure of the archive for various items/attributes.
// Each time one of the conditions is met, the vcnt is incrememented.
// Once the whole archive has been read, if the vcnt matches the expectedCounts for
// that type, the archive is valid.
function smd_at_check_archive($struct$type 'zip')
{
    
$expectedCounts = array('zip' => 1'tgz' => 0'tbz2' => 0'tar' => 0);
    switch (
$type) {
        case 
"zip":
            
$vcnt 0;
            foreach (
$struct as $entry => $info) {
                
$parts pathinfo($info['file_name']);
                if (isset(
$parts['extension']) && $parts['extension'] == 'php') {
                    
$dirbits explode(DS$parts['dirname']);
                    
$numdirs count($dirbits);
                    if ((
$parts['filename'] == $dirbits[$numdirs-1]) && $numdirs==1) {
                        
$vcnt++;
                    }
                }
            }
            break;
    }

    return (
$expectedCounts[$type] == $vcnt) ? true false;
}

// ------------------------
function smd_at_sanitize_folder($text)
{
    
// Remove control characters and " * \ : < > ? |
    
$text preg_replace('/[\x00-\x1f\x22\x2a\x3a\x3c\x3e\x3f\x5c\x7c\x7f]+/'''$text);
    
// Remove duplicate dots and any leading or trailing dots/spaces
    
$text preg_replace('/[.]{2,}/''.'trim($text'. '));
    
// Remove any leading or trailing slash
    
$text trim($text'/');
    return 
$text;
}

// ------------------------
function smd_at_rrmdir($dir)
{
    foreach(
glob($dir '/*') as $file) {
        if(
is_dir($file))
            
smd_at_rrmdir($file);
        else
            
unlink($file);
    }
    
rmdir($dir);
}

// ------------------------
function smd_at_upload()
{
    global 
$file_max_upload_size;

    
extract(doSlash(gpsa(array('id''smd_at_folder'))));

    
$_POST['skin'] = $skin $id;
    
$folder smd_at_sanitize_folder($smd_at_folder);

    
$filelist $_FILES['smd_at_file']['name'];
    
$name $pos NULL;
    
$message='';
    
$up_count $fail_count 0;
    
$uploaded = array();

    
$skinfo smd_at_read_skinfo($skin);
    
$new_skin $skinfo['name'];

    if (
$new_skin) {
        
$newpath $skinfo['path'] . (($folder) ? $folder.'/' '');

        if (!
file_exists($newpath)) {
            
mkdir($newpath0755true);
        }

        foreach (
$filelist as $pos => $name) {
            if (
$name == '') continue;

            
$file get_uploaded_file($_FILES['smd_at_file']['tmp_name'][$pos]);

            
// Skip files that are too big
            
$size filesize($file);
            if (
$file_max_upload_size $size) {
                
unlink($file);
                
$fail_count++;
                continue;
            }

            if (
$name && $file) {
                if(
shift_uploaded_file($file$newpath.$name)) {
                    
chmod($newpath.$name0755);
                    
$up_count++;
                    
$uploaded[] = $name;
                } else {
                    
unlink($file);
                    
$fail_count++;
                }
            }
        }
        
$message gTxt('smd_adth_upload_report', array('{num_success}' => $up_count'{num_fail}' => $fail_count'{uploaded}' => join(', '$uploaded)));
    } else {
        
$message = array(gTxt('smd_adth_empty_info'), E_WARNING);
    }

    
smd_at_edit($message);
}

// ------------------------
function smd_at_delete()
{
    global 
$smd_core_themes$smd_at_event;
dmp('running');
    if (!
has_privs($smd_at_event)) {
        
smd_at_edit();
    }

    
extract(doSlash(gpsa(array('skin'))));

    
$message '';

    if (
in_array($skin$smd_core_themes)) {
        
$message = array(gTxt('smd_adth_core_theme', array('{skin}' => $skin)), E_ERROR);
dmp('iscore'$skin$message);
        
smd_at_list($message);
    } else {
        
$skindir THEME.$skin;
        if (!
smd_rmdir_recursive($skindir)) {
            
$message = array(gTxt('smd_adth_delete_failed'), E_ERROR);
        } else {
            
$message gTxt('smd_adth_skin_deleted', array('{name}' => $skin));
        }

        
// Handle situations if current skin has been deleted
        
if (!file_exists(txpath.DS.THEME.$skin)) {
            
$at_prefs smd_at_get_prefs();

            
// Reset the global skin in case it's been deleted
            
$gbl_skin $at_prefs['smd_at_global_skin'];
            
$gbl_skin = ($gbl_skin != '' && file_exists(txpath.DS.THEME.$gbl_skin)) ? $gbl_skin 'hive';
            
set_pref('smd_at_global_skin'$gbl_skin$smd_at_eventPREF_HIDDEN'text_input');
            
set_pref('theme_name'$gbl_skin);

            
$skin get_pref('smd_skin');
            if (!
file_exists(txpath.DS.THEME.$skin)) {
                
$skin $gbl_skin;
            }
            
set_pref('smd_skin'$skin'smd_at'PREF_HIDDEN'text_input'0PREF_PRIVATE);
        }
        
$_GET['skin'] = $skin;
        
$_GET['nextstep'] = 'smd_at_list';
        
smd_at_switch($message);
    }
}

// ------------------------
function smd_at_delete_file($skin$delfile)
{
    global 
$smd_core_themes$smd_at_event;

    if (!
has_privs($smd_at_event)) {
        
smd_at_edit();
    }

    
$ret false;
    
$path THEME.$skin.DS.$delfile;
    if (
file_exists($path) && !in_array($skin$smd_core_themes)) {
        
$ret unlink($path);
    }
    return 
$ret;
}

// ------------------------
function smd_at_delete_folder()
{
    global 
$smd_core_themes$smd_at_event;

    if (!
has_privs($smd_at_event)) {
        
smd_at_edit();
    }

    
extract(doSlash(gpsa(array('skin''delfolder'))));
    
$message '';

    
$_POST['skin'] = $skin;

    if (
file_exists($delfolder) && !in_array($skin$smd_core_themes)) {
        
smd_at_rrmdir($delfolder);
        
$message gTxt('smd_adth_folder_deleted', array('{name}' => $delfolder));
    }

    
smd_at_edit($message);
}

// ------------------------
function smd_at_multi_edit()
{
    global 
$smd_core_themes$smd_at_event;

    if (!
has_privs($smd_at_event)) {
        
smd_at_edit();
    }

    
$message '';
    
$method ps('edit_method');
    
$files ps('selected_files');
    
$skin ps('crit'); // bit of a hack, but multi_edit() has a fixed param set
    
$affected = array();
    
$_POST['skin'] = $skin;

    if (
$files and is_array($files)) {
        if (
$method == 'delete') {
            foreach (
$files as $name) {
                if (
smd_at_delete_file($skin$name)) {
                    
$affected[] = $name;
                }
            }

            if (
$affected) {
                
$message gTxt('smd_adth_files_deleted', array('{list}' => join(', '$affected)));
            }

            
smd_at_edit($message);
        }
    } else {
        
smd_at_edit();
    }
}

// ------------------------
function smd_at_save()
{
    
extract(doSlash(gpsa(array('skin','new_skin','new_skin_dir','file','dir','smd_at_edits'))));

    list(
$editable$imagable) = smd_at_valid_types();
    
$message $extraMsg '';
    
$file trim($file);
    
$new_skin trim($new_skin);
    
$trimDir trim($new_skin_dir);
    
$new_skin_dir trim($trimDirDS);
    
$msglev 0;

    
// New file
    
if (!$file && $new_skin) {
        
$file $new_skin;
        
$dir $new_skin_dir;
        
$ext pathinfo($filePATHINFO_EXTENSION);

        if (
strtolower($file) != 'readme' && ($ext == '' || !in_array($ext$editable))) {
            
$message gTxt('smd_adth_unsupported_filetype').gTxt('smd_adth_unsupported_fudge');
            
$msglev E_WARNING;
            
$_POST['file'] = $file;
            
$_POST['dir'] = $dir;
        }
    }

    if (
$message == '') {
        
$fname sanitizeForFile($file);
        
$new_skin rawurlencode($new_skin);
        
$_POST['new_skin'] = $new_skin;

        
$smd_at_edits doStrip(str_replace('\r\n','
'
,$smd_at_edits)); // newline workaround

        
if ($fname) {
            
$filepath THEME.$skin.DS.$dir.DS;
            if (!
file_exists($filepath.$fname)) {
                if (!
file_exists($filepath)) {
                    
mkdir($filepath0755true);
                }

                
$ret touch($filepath.$fname);
                if (
$ret === false) {
                    
$message gTxt('smd_adth_mkdir_failed', array('{name}' => $fname));
                }
            }

            
// Assuming no errors so far...
            
if ($message == '') {
                
$fh fopen($filepath.$fname'wb');
                
fwrite($fh$smd_at_edits);
                
fclose($fh);

                if (
$fname != $new_skin) {
                    
// Rename the file
                    
$res rename($filepath.$fname$filepath.$new_skin);

                    
// If the renamed file is the theme's PHP file, try to rename the main skin dir too
                    
$filebits explode('.'$new_skin);
                    
$oldfilebits explode('.'$fname);
                    
$ext array_pop($filebits);
                    if (
$res && $ext == 'php' && ($oldfilebits[0] == $skin)) {
                        
$new_filepath THEME.$filebits[0].DS;
                        
$ren rename($filepath$new_filepath);
                        
$filepath = ($ren) ? $new_filepath $filepath;
                        
$_POST['skin'] = $filebits[0];
                    }
                    
$extraMsg = ($res) ? gTxt('smd_adth_renamed', array('{name}' => $new_skin)) : gTxt('smd_adth_rename_failed');
                }

                
// Process any css replacements
                
$filebits explode('.',(($fname==$new_skin)? $fname $new_skin));
                
$cssfile $filebits[0];
                
$ext array_pop($filebits);
                if (
$ext == 'ssc') {
                    
$replacements = array();
                    
$num_rep1 preg_match_all('/(\@[A-Za-z0-9_]+):\s*(.*);/'$smd_at_edits$matches1);
                    
$num_rep2 preg_match_all('/(\@[A-Za-z0-9_]+):\s*\{(.*?)\}/s'$smd_at_edits$matches2);

                    
// Simple replacements
                    
foreach($matches1 as $idx => $reparr) {
                        if (
$idx == 0) {
                            
// Remove the var definitions
                            
foreach ($reparr as $rep) {
                                
$smd_at_edits str_replace($rep'',$smd_at_edits);
                            }
                        }
                        if (
$idx == 1) {
                            foreach (
$reparr as $jdx => $rep) {
                                
$replacements[$rep] = $matches1[2][$jdx];
                            }
                        }
                    }

                    
// Multi-line replacements
                    
foreach($matches2 as $idx => $reparr) {
                        if (
$idx == 0) {
                            
// Remove the var definitions
                            
foreach ($reparr as $rep) {
                                
$smd_at_edits str_replace($rep'',$smd_at_edits);
                            }
                        }
                        if (
$idx == 1) {
                            foreach (
$reparr as $jdx => $rep) {
                                
$replacements[$rep.';'] = trim($matches2[2][$jdx]);
                            }
                        }
                    }

                    
// Generate and write the new css file
                    
$repDone strtr($smd_at_edits$replacements);
                    
$smd_at_edits trim($repDone);
                    
$fh fopen($filepath.$cssfile.'.css''wb');
                    
fwrite($fh$smd_at_edits);
                    
fclose($fh);
                    if (
$fname != $new_skin) {
                        
$oldfname explode('.'$fname);
                        
$oldfname $oldfname[0].'.css';
                        
$res = @unlink($filepath.$oldfname);
                    }
                }

                
$message gTxt('smd_adth_file_saved', array('{name}' => $fname)).br.$extraMsg;
            }
        }
    }
    
smd_at_edit(array($message$msglev));
}


// ------------------------
// PREFS
// ------------------------
// Get current pref value or default for each known pref
function smd_at_get_prefs($force 0)
{
    global 
$prefs;

    
$smd_at_prefs = array(
        
'smd_at_case_sort' => array(
            
'html'     => 'yesnoradio',
            
'position' => 10,
            
'default'  => '1',
            
'group'    => 'smd_at_settings',
        ),
        
'smd_at_crush' => array(
            
'html'     => 'radioset',
            
'position' => 20,
            
'default'  => 'zip',
            
'group'    => 'smd_at_settings',
        ),
        
'smd_at_tw' => array(
            
'html'     => 'text_input',
            
'position' => 30,
            
'default'  => '260',
            
'group'    => 'smd_at_settings',
        ),
        
'smd_at_th' => array(
            
'html'     => 'text_input',
            
'position' => 40,
            
'default'  => '150',
            
'group'    => 'smd_at_settings',
        ),
        
'smd_at_filename_format' => array(
            
'html'     => 'text_input',
            
'position' => 60,
            
'default'  => '{theme}',
            
'group'    => 'smd_at_settings',
        ),
        
'smd_at_max_theme_size' => array(
            
'html'     => 'text_input',
            
'position' => 70,
            
'default'  => (500 1024),
            
'group'    => 'smd_at_settings',
        ),
        
'smd_at_layout' => array(
            
'html'     => 'radioset',
            
'position' => 80,
            
'default'  => '1',
            
'group'    => 'smd_at_settings',
        ),
        
'smd_at_system' => array(
            
'html'     => 'radioset',
            
'position' => 90,
            
'default'  => '0',
            
'group'    => 'smd_at_settings',
        ),
        
'smd_at_global_skin' => array(
            
'html'     => 'selectlist',
            
'position' => 100,
            
'default'  => '',
            
'group'    => 'smd_at_settings',
        ),
        
'smd_at_group_list' => array(
            
'html'     => 'list',
            
'position' => 110,
            
'default'  => '',
            
'group'    => 'smd_at_settings',
        ),
        
'smd_at_user_list' => array(
            
'html'     => 'list',
            
'position' => 120,
            
'default'  => '',
            
'group'    => 'smd_at_settings',
        ),
    );

    
$at_prefs = array();
    foreach (
$smd_at_prefs as $key => $prefarr) {
        
$at_prefs[$key] = get_pref($key''$force);
        if (
$at_prefs[$key] == '') {
            
$at_prefs[$key] = $prefarr['default'];
        }
    }
    return 
$at_prefs;
}

// ------------------------
function smd_at_options($event$step$message '')
{
    
smd_at_setup($message);
}

// ------------------------
function smd_at_setup($message '')
{
    global 
$smd_at_event$theme$smd_core_themes;

    
$smd_at_styles smd_at_get_style_rules();
    
$at_prefs smd_at_get_prefs(1);

    
pagetop(gTxt('smd_adth_prefs_title'),$message);

    
$levels get_groups();
    unset(
$levels[1]); // Publishers get special privs apart from the masses
    
$numLevs count($levels);

    
// Split the user skin list
    
$uskins explode(','$at_prefs['smd_at_user_list']);

    
$layout $at_prefs['smd_at_layout'];
    
$clrBtn ' [<span id="smd_clr" class="smd_fakebtn">'.gTxt('smd_adth_clear').'</span>]';
    
$btnSet fInput('submit''submit'gTxt('smd_adth_set'), 'publish');
    
$btnSave graf(fInput('submit''submit'gTxt('save'), 'publish'));
    
$btnList graf(
        
href(gTxt('smd_adth_all_themes'), '?event=' $smd_at_event, array('class' => 'smd_at_btn'))
        , array(
'class' => 'txp-actions txp-actions-inline')
    );
    
$radBtns = array(
        
gTxt('smd_adth_per_site'),
        
gTxt('smd_adth_per_group'),
        
gTxt('smd_adth_per_user'),
    );

    
$skin_list smd_at_read_skins();

    
// selectInput needs both index and value to be the same in this case
    
$skinsel = array();

    foreach(
$skin_list as $key1 => $value1) {
        if (
smd_at_exists($value1)) {
            
$skinsel[$value1] = $skin_list[$key1];
        }
    }

    
$gbl_skin = ($at_prefs['smd_at_global_skin'] != '') ? $at_prefs['smd_at_global_skin'] : $theme->name;
    
$crushers smd_at_crush_options('compress');

    echo 
n'<div class="txp-layout">'
            
.n'<div class="txp-layout-2col">'
            
.n'<h1 class="txp-heading">'.gTxt('smd_adth_prefs_title').'</h1>'
            
.n'</div>'
            
.n'<div class="txp-layout-2col">'
            
.n$btnList
            
.n'</div>'
        
.n'<div class="txp-layout-1col">'
        
.n'<form method="post" class="txp-edit" action="?event='$smd_at_eventa'step=smd_at_prefs_update" onsubmit="return smd_presub();">'
        
.ninputLabel('smd_at_case_sort'yesnoRadio('smd_at_case_sort'$at_prefs['smd_at_case_sort']), 'smd_at_case_sort');

    if (
$crushers) {
        echo 
ninputLabel('smd_at_crush'radioSet($crushers'smd_at_crush'$at_prefs['smd_at_crush']), 'smd_at_crush_type');
    }

    echo 
ninputLabel('smd_at_layout'radioSet(array(gTxt('smd_adth_layout_list'), gTxt('smd_adth_layout_grid')), 'smd_at_layout'$at_prefs['smd_at_layout']), 'smd_at_layout')
        .
ninputLabel('smd_at_thumbsize'fInput('text''smd_at_tw'$at_prefs['smd_at_tw'],'input-xsmall','','',4).n.gTxt('smd_adth_times').n.fInput('text''smd_at_th'$at_prefs['smd_at_th'],'input-xsmall','','',4), 'smd_at_thumbsize')
        .
ninputLabel('smd_at_filename_format'fInput('text''smd_at_filename_format'$at_prefs['smd_at_filename_format']), 'smd_at_filename_format')
        .
ninputLabel('smd_at_max_theme_size'fInput('text''smd_at_max_theme_size'$at_prefs['smd_at_max_theme_size']), 'smd_at_max_theme_size')
        .
ninputLabel('smd_at_global_skin'selectInput('smd_at_global_skin'$skinsel$gbl_skin00'smd_at_global_skin'), 'smd_at_global_skin')
        .
ninputLabel('smd_at_skin_system'radioSet($radBtns'smd_at_system'$at_prefs['smd_at_system']), 'smd_at_skin_system');

    
// Option 1
    
$priv_list '<select id="smd_at_privs" name="smd_at_privs[]" class="list" size="'.$numLevs.'" multiple="multiple">';

    foreach (
$levels as $levid => $levname) {
        
$priv_list .= '<option value="'.$levid.'">'.$levname.'</option>';
    }

    
$priv_list .= '</select>';

    
// Note the hidden skin group box; jQuery keeps track of any list changes and keeps it updated
    
$sela '<div class="txp-form-field-label"><label>' gTxt('smd_adth_skin_groups') . '</label></div>';
    
$selb hInput('smd_at_group_list'$at_prefs['smd_at_group_list']);
    
$selb .= '<select id="smd_at_grps" name="smd_at_grps" class="list" size="'.$numLevs.'">';

    foreach (
$skin_list as $askin) {
        if (
smd_at_exists($askin)) {
            
$selb .= '<option value="'.$askin.'">'.$askin.'</option>';
        }
    }

    
$selb .= '</select>';

    echo 
n'<div class="txp-form-field smd_at_sel1">' .$sela.'<div class="txp-form-field-value">'.$selb.$priv_list.'</div></div>';

    
// Option 2
    
$sela '<div class="txp-form-field-label"><label>' gTxt('smd_adth_allowed_skins') . '</label></div>';
    
$selb '<select id="smd_at_user_list" name="smd_at_user_list[]" class="list" size="8" multiple="multiple">';

    foreach (
$skin_list as $askin) {
        if (
smd_at_exists($askin)) {
            
$selb .= '<option value="'.$askin.'"'.((in_array($askin$uskins)) ? ' selected="selected"' '').'>'.$askin.'</option>';
        }
    }

    
$selb .= '</select>'.$clrBtn;

    echo 
n'<div class="txp-form-field smd_at_sel2">' .$sela.'<div class="txp-form-field-value">'.$selb.'</div></div>'
        
.n$btnSave
        
.ntInput()
        .
n'</form>'
        
.n'</div></div>';

    echo 
script_js(<<<EOJS
// Handle show/hide of pref widgets based on radio selection
function smd_at_prefswap(selValue) {
    for (idx=0; idx < 3; idx++) {
        if (idx==selValue) {
            jQuery(".smd_at_sel"+idx).show();
        } else {
            jQuery(".smd_at_sel"+idx).hide();
        }
    }
}

jQuery(function() {
    jQuery("input[name='smd_at_system']").change(function() {
        smd_at_prefswap(this.value);
    });

    jQuery('#smd_clr').click(function() {
        jQuery('#smd_at_user_list option').prop("selected", "");
    });

    jQuery("#smd_at_grps").change(function() {
        selskin = jQuery(this).val();

        // Clear the old privs list and grab the current list from the hidden field
        jQuery("#smd_at_privs option").prop("selected",false);
        var grplist = jQuery("input[name='smd_at_group_list']").val();
        var grps = grplist.split(',');
        var cnt = grps.length;
        for (var idx = 0; idx < cnt; idx++) {
            privs = grps[idx].split(':');
            skinid = privs.shift();
            if (skinid == selskin) {
                numPrivs = privs.length;
                for (jdx = 0; jdx < numPrivs; jdx++) {
                    jQuery("#smd_at_privs option[value='"+privs[jdx]+"']").prop("selected", true);
                }
            }
        }
    });

    jQuery("#smd_at_privs").change(function() {
        selskin = jQuery("#smd_at_grps option:selected").val();
        var out = [];
        var privs = [];
        privs.push(selskin);
        jQuery("#smd_at_privs option:selected").each(function() {
            privs.push(jQuery(this).val());
        });
        if (privs.length == 1) {
            privs.pop();
        } else {
            out.push(privs.join(":"));
        }
        var hidlist = jQuery("input[name='smd_at_group_list']").val();
        var prevlist = hidlist.split(',');
        var prevcnt = prevlist.length;

        jQuery("#smd_at_grps option").each(function() {
            currskin = jQuery(this).val();
            if (currskin != selskin) {
                for (var idx = 0; idx < prevcnt; idx++) {
                    prevprivs = prevlist[idx].split(':');
                    skinid = prevprivs.shift();
                    // Generate the priv list for the currently selected skin, removing any duplicate privs set elsewhere
                    if (skinid == currskin) {
                        tmpout = [];
                        tmpout.push(skinid);
                        for (thispriv in prevprivs) {
                            if (jQuery.inArray(prevprivs[thispriv], privs) < 0) {
                                tmpout.push(prevprivs[thispriv]);
                            }
                        }
                        if (tmpout.length > 1) {
                            out.push(tmpout.join(":"));
                        }
                    }
                }
            }
        });
        jQuery("input[name='smd_at_group_list']").val(out);
    });

    // Display a tooltip showing the currently-assigned skin when hovering over a privilege level
    jQuery("#smd_at_privs option").hover(function() {
        hovitem = jQuery(this).val();
        grps = jQuery("input[name='smd_at_group_list']").val();
        items = grps.split(",");
        for (idx = 0; idx < items.length; idx++) {
            skinz = items[idx].split(":");
            for (jdx = 1; jdx < skinz.length; jdx++) {
                if (skinz[jdx] == hovitem) {
                    jQuery(this).attr("title", skinz[0]);
                    break;
                }
            }
        }
    },
    function() {
        jQuery(this).attr("title", "");
    });
    smd_at_prefswap(jQuery("input[name='smd_at_system']:checked").val());
    jQuery("#smd_at_privs").change();
});
EOJS
    );
}

// ------------------------
// Split a multi-char preference value into an array of keys/values.
// Note: value is passed in and not read directly from the prefs array in this function - intentionally
function smd_at_pref_explode($val)
{
    
$order array_values(array(gTxt('smd_adth_c_gzip'),gTxt('smd_adth_c_bzip2'),gTxt('smd_adth_c_zip')));
    
$onoff array_values(preg_split('//'$val, -1PREG_SPLIT_NO_EMPTY));
    
$out = array();
    foreach(
$order as $key1 => $value1) {
        
$out[(string)$value1] = $onoff[$key1];
    }
    return 
$out;
}

// -------------------------------------------------------------
function smd_at_prefs_install($showpane '1')
{
    
$at_prefs smd_at_get_prefs();

    
$message '';
    foreach (
$at_prefs as $pref => $dflt) {
        if (!
fetch('name','txp_prefs','name',$pref)) {
            
$id safe_insert('txp_prefs','prefs_id=1, name='.doQuote(doSlash($pref)).', val='.doQuote(doSlash($dflt)).', event="smd_at", type='.PREF_HIDDEN);
        }
    }
    if (
$showpane) {
        
$message gTxt('smd_adth_prefs_installed');
        
smd_at_setup($message);
    }
}

// -------------------------------------------------------------
function smd_at_prefs_remove($showpane '1')
{
    
$at_prefs smd_at_get_prefs();

    
$message '';
    foreach (
$at_prefs as $pref => $dflt) {
        if (
fetch('name','txp_prefs','name',$pref)) {
            
$id safe_delete('txp_prefs','name='.doQuote(doSlash($pref)));
        }
    }
    if (
$showpane) {
        
$message gTxt('smd_adth_prefs_deleted');
        
smd_at_setup($message);
    }
}

// -------------------------------------------------------------
function smd_at_prefs_update()
{
    global 
$smd_plugin_prefs$smd_at_event;

    
$at_prefs smd_at_get_prefs();

    
$message '';
    
$post = array();

    foreach (
$at_prefs as $pref => $prefobj) {
        
$post[$pref] = ps($pref);
    }

    
// Handle list options separately and only update them if they're set
    // (they've already been set in the foreach above, so need unsetting)
    
if (ps('smd_at_user_list')) {
        
$post['smd_at_user_list'] = join(','ps('smd_at_user_list'));
    } else {
        
$post['smd_at_user_list'] = '';
    }
    if (
ps('smd_at_group_list')) {
        
$post['smd_at_group_list'] = ps('smd_at_group_list');
    } else {
        unset(
$post['smd_at_group_list']);
    }
    if (
ps('smd_at_crush')) {
        
$post['smd_at_crush'] = ps('smd_at_crush');
    } else {
        unset(
$post['smd_at_crush']);
    }

    
// Set the system-wide theme to the global theme
    
if ($post['smd_at_global_skin']) {
        
set_pref('theme_name'$post['smd_at_global_skin']);
    }

    foreach (
$at_prefs as $pref => $dflt) {
        if (isset(
$post[$pref])) {
            
set_pref($pref$post[$pref], $smd_at_eventPREF_HIDDEN);
        }
    }
    
$message gTxt('preferences_saved');
    
smd_at_setup($message);
}

// ------------------------
// UTILITY FUNCTIONS
// ------------------------
function smd_at_get_privs($user '')
{
    global 
$txp_user;
    
$user = ($user) ? $user $txp_user;
    
$privs safe_field("privs""txp_users""name='".doSlash($user)."'");
    return 
$privs;
}

// ------------------------
function smd_at_exists($name)
{
    
$instance Theme::factory($name);
    return 
$instance;
}

// If per-user skin support is OFF, the global skin wins.
// One exception: if the user is an admin, allow the current skin to prevail so they may switch skins with impunity
// and not affect the global skin
function smd_at_per()
{
    global 
$smd_at_privs$theme$txp_user;

    
$at_prefs smd_at_get_prefs();
    
$skinSys $at_prefs['smd_at_system'];
    
$privs smd_at_get_privs();
    
$gbl_skin = ($at_prefs['smd_at_global_skin'] != '') ? $at_prefs['smd_at_global_skin'] : '';
    
$gbl_skin = (smd_at_exists($gbl_skin)) ? $gbl_skin 'hive';

    switch (
$skinSys) {
        case 
0:
            
// Global forced skin (except admins)
            
if (!in_array($privsexplode(','$smd_at_privs))) {
                return 
$gbl_skin;
            } else {
                
// Admins
                
$adm_skin get_pref('smd_skin', (($gbl_skin) ? $gbl_skin $theme->name));
                return (
smd_at_exists($adm_skin)) ? $adm_skin 'hive';
            }
            break;
        case 
1:
            
// Group-level forced skins
            
if (!in_array($privsexplode(','$smd_at_privs))) {
                
$forceSkins = ($at_prefs['smd_at_group_list'] != '') ? $at_prefs['smd_at_group_list'] : (($gbl_skin) ? $gbl_skin $theme->name);

                
// Split the group skin list
                
$gskins = array();
                
$gopts explode(','$forceSkins);
                foreach (
$gopts as $grpdef) {
                    if (
$grpdef == '') continue;
                    
$privgrp explode(":"$grpdef);
                    
$skinid array_shift($privgrp);
                    if (
in_array($privs$privgrp)) {
                        return (
smd_at_exists($skinid)) ? $skinid 'hive';;
                    }
                }
                return (
$gbl_skin) ? $gbl_skin $theme->name;
            } else {
                
// Admins
                
$adm_skin get_pref('smd_skin', (($gbl_skin) ? $gbl_skin $theme->name));
                return (
smd_at_exists($adm_skin)) ? $adm_skin 'hive';
            }
            break;
        case 
2:
            
// Per-user skin. If user is non-admin, check the skin is in the allowed list
            
if (!in_array($privsexplode(','$smd_at_privs))) {
                
$validSkins = ($at_prefs['smd_at_user_list']) ? $at_prefs['smd_at_user_list'] : (($gbl_skin) ? $gbl_skin $theme->name);
                
$validSkins do_list($validSkins);
                
$the_skin get_pref('smd_skin', (($gbl_skin) ? $gbl_skin $theme->name));
                return (
in_array($the_skin$validSkins) && smd_at_exists($the_skin)) ? $the_skin '';
            } else {
                
// Admins
                
$adm_skin get_pref('smd_skin', (($gbl_skin) ? $gbl_skin $theme->name));
                return (
smd_at_exists($adm_skin)) ? $adm_skin 'hive';
            }
            break;
    }
}

// ------------------------
// Read and return the manifest, if it exists and add a few other niceties to the array for later
function smd_at_read_skinfo($skin)
{
    global 
$smd_core_themes;

    
$this_theme Theme::factory($skin);
    
$skinfo = array();
    if (
$this_theme) {
        
$skinfo $this_theme->manifest();
        
$skinfo['dname'] = empty($skinfo['title']) ? ucwords($this_theme->name) : $skinfo['title'];
        
$skinfo['name'] = $this_theme->name;
        
$skinfo['path'] = $this_theme->url;
        
$skinfo['phpfile'] = $this_theme->path($skin);
        
$skinfo['based_on'] = '';
        
$contents file_get_contents($skinfo['phpfile']);
        if ((
$pos strpos($contents'Theme::based_on')) !== false) {
            
$begpos strpos($contents"'"$pos)+1;
            
$endpos strpos($contents"'"$begpos);
            
$base substr($contents$begpos$endpos-$begpos);
            
$skinfo['based_on'] = (in_array($base$smd_core_themes)) ? '' $base;
        }
        unset(
$this_theme);
    }
    return 
$skinfo;
}

// ------------------------
// Grab the thumbnail filename if it exists, optionally return a formatted img tag
function smd_at_get_thumb($skin$img 0)
{
    
$at_prefs smd_at_get_prefs();
    
$tw $at_prefs['smd_at_tw'];
    
$th $at_prefs['smd_at_th'];
    
$use_thumb = ($tw == || $th == 0) ? false true;
    
$dflt_thumb 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAQQAAACWCAMAAAAPDwbEAAAAwFBMVEX2vTf51WnT09P09PT62XX4zFP4y033wTw3NjP3w0Dr6+v4zVj73YHftE74xUPf39/74Ir4yETIxsD86Lvh1bTSxJ3m4dT3xUj8/PzDuZri2sb4x0j4z13hyYe9u7X50WLnyHfqxmf3yVK2lkTtwlecgTzVqD11ZDrhzJbk0qHxyl74yE3w1YTyxU/GoEHVu3Lruj/u0HnbnBb13aPm5ubwv0nx8fHu6+HuxlnssjD4yUjYnyjlqB/u7u75+fn39/e8SXn6AAANTklEQVR42u3de3PaRhcG8GAhFBAWweWSAApgbHMziWmE4tBXzvf/Vj1nd6VHqy03/7W80XGn0860ndmfnj1nV4Tmw++yfpcIJUKJUCKUCCVCiVAilAglQolQIpQItiO8OX86wtvb589Q+CMRSIDqLfkDERACVY2L/10njp2rRwABV3LJ8p04aUS9zjK5fgTnc65i57zVi+UPOovJZFXze87/F8Lv6Izl0+qX4WS6orq/r+3vO/HVIzTyCG/R0ezzww+nDw+boF4P2qJqNXeZXD1C9JZXaB3e+uHk4WG323k7r06lEPb7mvscOc61J0HbD1Gsrx7L9z6k5VHV27L2tZq/bTlQuE6ERNsPSZQtXzS+hx2V98ICMBBRSA1cd9SKoXClI7KVR3Bu1NYX2cfKNQRtN9T80aARXz3Cm2qKTvzzZ28WTne0+p2Hh49CEtp1ZUAIfidKoHClCPFbnNDye72/qML/fThenoEwWrQaV4iAzpdEre8dWn5WP/4+A6HtkQIQwlYjia8OAVN/Mt39E4KA6umUAZKwZwTXH21vsB+uASE98S7D6aYut/2v7xrC7VnbgQwCQpBJqNxEjetAEA8/Eife102fGh+3PsHwpCEsjwEQAVfQBoJLCHe0H2xGwPI5+32qgJ6jx8UEXP9oCD9+nUSgf58Ugmw6VLpoClYhYOu3+OlvX1cbBgiYQBmk9fdf5+0HJUcG3BIEQk0clsbdGysRss63Xfm+e39/v14PMwMEQTaFpYYwOYwgHEjBqyMJrutXQjQFmxCSwXJZ3VbGo9HI94XBmgyIIKAVgEDWRN8Px3aCGg1BrjG6/nhrJYLzs9msVtnAp1IGfRUDBEHVbU6g0j8UAxRRBmQAhMpd1EjsS0L0iQwq4zHngHaDNMghQCCH0BwfOytrSQCCm46H2DqExlIkQQZBIgSUBBjkk/CLI1DtH58KMOA9VdcRuq3IQoSEECoCwZVBoEJPLD7wZ0TgcAyAQJFK75BU9iLEnbQluOgIJsLp4sAUDASDNNhLhDHGg1UIA5EEbTySwMUEZg68QBAwgtwO9iI4vWdKAiNwDnBQfLcBgmAg0GmpivFg04kxYoSRr3Igg6Ba4rsN6p7aC3itJBFGYkbGFiJUBIIKQp0N3ksAASZQCMP0mOD6fFBoRRYiNJYiCWwwHMqmiIvje1KQVsDFBsN8Euj2gKZgDUKyrI4ZQRgQgndhDvifPWCgkqAhoDPahBB3+LwoOwKa4tkA+vnIMNCS4BPC1k6EwZaGAyGgKVK9IwZ1w4AQWAEIPsaDXQhOT/ZFORkumo7Hc8A1JAIdAbcHCxBQva1oCURwWRA89QOEgsEwaCuEmoYQWYgQEYIrEeqXIMDgafb4+ASDXA5MBHV7cGxDeB7JJMDgEoHZ/KOoeZGgHzCAiYDOaBFCYzGi4YAgXJKDl8ePWX3zdARhYCKEViLEy5EvES4KAv9zs4+5eswTDOmPrNZMIM8J4/EzxoNNCJ2xQEAQztwJ3+Q2mL14L3P+C0WAsQAEVlBJoBkZ2ZcEZ7ASLeFCgw+iF8zqPBaEx2NK0JcpgEGGQEnAeLALobXl4XDmZsgmgtgBQToa+W+8eorQzgkwgjIQScB4sAABFQHhzCBIg/mv7JjISZgFhgED0B8ZwogRFuiMFiE0ttQSgHC2wctLPY/wUlcGegqEgZshYDzYhZAs1CmBCbyzDXLXBe+R/h4ExRQQQrobKAliPMTWISx9Qji7I3jeizBQMRA1p5YABJmBXAokgtwOcjxYhxB3uCVcgDDnvZC7MHm3vBukQV8hrFXdM4E0UEmoYjxYhOAMgHBOR5jx8fBD/tY4I5VCO1AlCVQOOAiE0G2hKdiD0APCOR8t8DgEARWflW5lDGAg2wEIeC+IIFS7N/YgoFqrdf8cA5wQnggBdcvbgxH0kVDDToABKfCMTKxDaExVEI4DqAsD35k8IMjZ8E1rBxgKMABCyAixdQiTYXDSQP6otkgEqBcOQp8IYJAT0A0Y4fmuZSFCEvZPIqQG8rKUIQT0w0HoKwQWwPEI7SAXhCrGg1UIyw0jnNEPZBL4yePlAYKQPxsgB4qAJoNCwHiwCSHubOonEDwgyBt0SlDvyyBgKhgdkQm4Ksqg2b2xEMEZvJ7RErJ65CgELBBkQZAxUMdk5MA0oMJ4sAAB1QPCaQWeB/Uge6U8V0FQW+EeMTBzUBUITdwebEKIpucmAbNRXRWeKAi7PjoiGmKGIAiQg2a1SbcH+xAak5NJMD51lwY12hq3MMBeQD8AQUUZNOV4cOxCSEJCOHMv5A363BUfd9l96d4k0A2A0LAPYXEMwYMCYiCvjDsKwo5zkPUDwwDtIDPAeLAJIV7WT3YEbAXkoM/vETYwQA6UQm4qwEAiJLYhOB1a4gkDsyf2108cBJNAIRzKASPg4GwPQm93NAkGgQzCUAQhM8BWMAxAIGpx04psQUAB4UAOsBVUEcF+poJwDwMDITcaofCM8WARQvRwcjjqo5FzwEGY65cFnJHoxwgCFRAa1iE0pt45CGiJbMBvFme4LGg3Z5wQQJAqfCKEGxsRwoMI/3VGkhdnvkOYOZAIonI5EAJAwHiwCCFZ7I4b6HOBDfYu36N0AsRAbwhsAIJPnwihZR9CvNwdMwBC7nXq+iOVW6s9zFxsBaQg9xIlL8AGNCMxHuxBcAZHEfIpwDskRpjPqTuCgAoE2AwAkNVcYDxYhNB7OJ4DICgCRlD1OFIEMJBVNJBFf4HxYBVC9HB6OOoEa/ebMvBzBAWEagUGULANATPyIIKZg7VQoIb47dvj4+2r6wMBm0HvCGr1QMBrd4sRTAOuwptE957WnwLAQBLAwFBoVr+2WvYhJOE5CP22QtDfnriHDIDwqYiA8WAPQrwwCYoIfS0IksDMgdoKSIK5HcQ9Ek3BHoSOcW0yDdpAgAE6IvrBqSA0q19sRHAGBYO0jBwM858z+vk7o7kZhMJhhMQ2hN5xAzRFGHDhyqgdkpTBgSAQQvcOndEOBK6Wd+DVMiYDDIz3aBqBQkBHMBEqISFE1iFEDwc+YzAN9Hvzw/zjbIyNgJ54xKBKCDcWIjSmxz5iQE9EDoiADfilAmKg9QMd4UfOoDK5Q2e0ByEJPWM2wmDYhoE+F+aEsGIEMwf6bAABfy95+tVGhHixO5WD9dD4iGkk7g8jA6GKj5vUnQEG4vvpEiGxDaEjETyUORjMl0iPjDBbZccDTAbt/giCpjBwX7/c4PZgBwLeKHgfjiHUCgjudC7ukSoIQEAOuBQBG8gc+IyA8WAFAt4oFL/4LxHUZkBDyLcEqtU4S4IsNAQVBPpTZlAhg9rmixoPjhUImJEIgo7Qlgb7momw4l/G+ZprCYqgks8B/4BgzAa1vkBo2IOAGfmfBKor1mCQS4JYvL4bEAMgaAaMsPluJ8JEJAHnRCCo73dCwTwwIwZ4xa5aInJQVQZuba8QEssQkvBADhihSOAbl4bcdIQBFyPAgDcDI/S/f6XxgM5oC8JSbYdCDtpZDqDgIwj5y2NxNKrSDFIEPii0rEOIOyoJyIEKAgwwH403KUdeqKEhKAT6L+0fKAn2ITgD/K/zZBBUDnQERMFFFgwEJkDlEXyFsEkRHKsQers0BzAwEVBGEs4xkAhcXzEeLEKINhIBfbGd7oa9YYDxYCJAAdtBjUfVEri+3NiDgIpe5Rc99SRoXVH8HEpCZWy+VPyhJ2GUJcH17URoTPrZZOBiAzke0yAgD0A4kITCdsBuIASu6Rc5HWxDSBaEoGLQFgKF+Wh0R2wIJMGYj/ohgUoSUF/EW0Z7EOLlhhGwE7L5eEgB8+FUTyADIHwngrsb3g0WInQYQSqoHMDgMIL5q1LMJOCktFoJAmlg0y0Sv+CfDNoBF3LAVQOErqBvBygcQvCnLCAIuCM0LEToEULQ5n4QoCEIA1PhiEETCNpsWE3VPmABIoCBFQiYkZSETIAN2owABxOBFYBQPDXjkLDdkgBHAARsYB9CY1oXSUAO0u1gbAnjO15GEpoZwfN2uw1ZAACSAAY2IUyQBBmFtkqCoij2BH00mK/VJEHYzQlEnAESYAIYWISQLNQJAQhDEAABXdEwAAEtnypcdAFABKkACGxDiJdpDlB7dAXEAAQFA2wHIlh0u5gEABACILAOoRNwSzARYIBP4ACA9+yi+Plj/S0ubAIGgICNCM5gGBwnKHzb0fzYrfD4kQBEAAJ2IvQ2bQOhLQyQArF+oxNsn8Mulp97/FyJAWAzQrTSDdAP0QiK3/XchtT979Tq8fTzzz8DuIrfKjGarvMEmAg6QIWLF99NF9/Cw8fysX4AXAFCI1znU5DvAlkH2G45+HjyWDqv3lg+1n8tCMliXxTIvtO2neSevLb0hqokOWf59iMsN/KMmPs/ZE3CEA++R2tPy1g6lo/1XyFCPNiQgQBYicUj82rdJ5eO5V8rgtNb0eIX3U5h8RFWbi7dXPyVI8RRLu0nHrq59CtHAIP4zV+pLn/o148ABa53L/36EcCgV/kb7lOVCCVCiVAilAglQolQIpQIJcJV17/IIfDRd0nPlQAAAABJRU5ErkJggg==';

    
// An array means the manifest has already been read and is being passed into this function
    
if (!is_array($skin)) {
        
$skin smd_at_read_skinfo($skin);
    }
    if (
$skin) {
        
$skindir $skin['path'];
        
$thumbname glob($skindir.'screenshot.*');
        return (
$img && $use_thumb) ? '<img class="content-image" src="'.(($thumbname && file_exists($thumbname[0])) ? $thumbname[0] : $dflt_thumb).'" alt="'.((isset($skin['name'])) ? $skin['name'] : '').' thumbnail" width="'.$tw.'" height="'.$th.'" />' '';
    } else {
        return 
'';
    }
}

// ------------------------
function smd_at_read_skins()
{
    
$skin_list Theme::names();
    
$skin_list smd_at_sort($skin_list);
    return 
$skin_list;
}

// ------------------------
// Sort the skins, keeping core themes at the top
function smd_at_sort($skin_list)
{
    global 
$prefs$smd_core_themes;

    
$caseSense = isset($prefs['smd_at_case_sort']) ? $prefs['smd_at_case_sort'] : 1;

    if(
$caseSense) {
        
natsort($skin_list);
    } else {
        
natcasesort($skin_list);
    }
    
$dflt_found = array();
    foreach (
$skin_list as $skin_idx => $skin_name) {
        if (
in_array($skin_name$smd_core_themes)) {
            unset(
$skin_list[$skin_idx]);
            
$dflt_found[] = $skin_name;
        }
    }

    
$dflts array_reverse($dflt_found); // So they go in alphabetical order
    
foreach ($dflts as $coretheme) {
        
array_unshift($skin_list$coretheme);
    }

    return 
$skin_list;
}

// ------------------------
function smd_at_listdir($start_dir '.')
{
    
$files = array();

    if (
is_dir($start_dir)) {
        
$fh opendir($start_dir);
        while ((
$file readdir($fh)) !== false) {
            
// loop through the files, skipping . and .., and recursing if necessary
            
if (strcmp($file'.')==|| strcmp($file'..')==0) continue;
            
$filepath $start_dir '/' $file;
            if ( 
is_dir($filepath) ) {
                
$files array_merge($filessmd_at_listdir($filepath));
            } else {
                
array_push($files$filepath);
            }
        }
        
closedir($fh);
    } else {

        
// false if the function was called with an invalid non-directory argument
        
$files false;
    }

    return 
$files;
}

// ------------------------
// Recursive rmdir() courtesy of the php manual user comments
function smd_rmdir_recursive($filepath)
{
    if (
is_dir($filepath) && !is_link($filepath)) {
        if (
$dh opendir($filepath)) {
            while ((
$sf readdir($dh)) !== false) {
                if (
$sf == '.' || $sf == '..') continue;
                if (!
smd_rmdir_recursive($filepath.'/'.$sf)) {
                    break; 
// Doh, can't delete
                
}
            }
            
closedir($dh);
        }
        return 
rmdir($filepath);
    }
    return 
unlink($filepath);
}

// ------------------------
// From PHP manual comments. Thanks puremango
function smd_at_is_dir($dir)
{
    
// bypasses open_basedir restrictions of is_dir and fileperms
    
$tmp_cmd = `ls -dl $dir`;
    
$dir_flag $tmp_cmd[0];
    if(
$dir_flag!="d") {
        
// not d; use next char (first char might be 's' and is still directory)
        
$dir_flag $tmp_cmd[1];
    }
    return (
$dir_flag=="d");
}

// ------------------------
function smd_at_change_pageby()
{
    
setcookie('smd_at_pageby'gps('qty'));
    
smd_at_list();
}

// ------------------------
function smd_at_switch($message '')
{
    global 
$smd_at_privs;

    
extract(doSlash(gpsa(array('skin''event''nextstep'))));
    
$url "?event=".$event."&step=".$nextstep;

    if (
$skin && smd_at_exists($skin)) {
        
set_pref('smd_skin'$skin$eventPREF_HIDDEN'text_input'0PREF_PRIVATE);
        
$url .= '&message=' . (($message) ? $message gTxt('smd_adth_skin_switched', array('{skin}' => $skin)));
    } else {
        
$url .= '&message=' $message;
    }

    
// Since the headers have been sent, double-declutch in order to show the skin this first time
    
echo <<<EOS
<script type="text/javascript">
window.location.href="
{$url}";
</script>
<noscript>
<meta http-equiv="refresh" content="0;url=
{$url}" />
</noscript>
EOS;
    exit;
}

// All-user skin chooser
function smd_admat($event$step)
{
    if(!
$step or !in_array($step, array(
            
'smd_at_switch',
        ))) {
        
smd_at_chooser('');
    } else 
$step();
}

// ------------------------
function smd_at_chooser($message '')
{
    global 
$prefs$smd_at_adm_event$theme;

    
$smd_at_styles smd_at_get_style_rules();
    
$at_prefs smd_at_get_prefs();
    
$layout $at_prefs['smd_at_layout'];
    
$tw $at_prefs['smd_at_tw'] + 10;
    
$th $at_prefs['smd_at_th'] + 80;

    
$message = ($message) ? $message gps('message');
    
pagetop(gTxt('smd_adth_skinner'),$message);

    
$curr_skin $theme->name;

    
$allowed '';
    if (isset(
$prefs['smd_at_user_list'])) {
        
$allowed explode(",",$prefs['smd_at_user_list']);
        foreach (
$allowed as $idx => $valid) {
            if (
$valid == '') {
                unset(
$allowed[$idx]);
            }
        }
    }
    
$allowed smd_at_sort($allowed);
    
$hdrow hed(gTxt('smd_adth_avail_title'), 2);

    echo 
'<div class="txp-container">';

    if (
$layout==0) {
        echo 
'<div class="txp-listtables">',
            
startTable('''''txp-list'),
            
tr(
                
tda($hdrow' colspan="3"')
            ),
            
assHead(
                
gTxt('smd_adth_skin_gbl'),
                
'author',
                
'description'
            
);
    } else {
        echo 
$hdrow'<div class="txp-grid">';
    }
    foreach (
$allowed as $skin_name) {
        
$skinfo smd_at_read_skinfo($skin_name);
        if (
$skinfo) {
            
$thumbnail smd_at_get_thumb($skinfo1);
            
$switch_link '?event='.$smd_at_adm_event.a.'step=smd_at_switch'.a.'nextstep=smd_admat'.a.'skin='.$skin_name;
            
$thumblock = ($layout==0)
                        ? 
'<a href="'.$switch_link.'" title="'.gTxt('smd_adth_apply_skin').'">'.$skinfo['dname'].(($thumbnail) ? br.$thumbnail '').'</a>'
                        
'<a href="'.$switch_link.'" title="'.gTxt('smd_adth_apply_skin').'">'.(($thumbnail) ? $thumbnail gTxt('smd_adth_apply_skin')).'</a>';
            
$authblock = (strpos($skinfo['author_uri'], "http://") === 0) ? '<a href="'.$skinfo['author_uri'].'">'.$skinfo['author'].'</a>' $skinfo['author'];

            if (
$layout==0) {
                echo 
tr(
                    
n.td($thumblock)
                    .
n.td($authblock)
                    .
n.td($skinfo['description'])
                    , ((
$skin_name == $curr_skin) ? ' class="highlight"' '')
                );
            } else {
                echo 
n'<div class="txp-grid-cell'.(($skin_name == $curr_skin) ? ' highlight' '').'">',
                        
nhed($skinfo['dname'], 3),
                        
n'<p>'$thumblock'</p>',
                        
n'<p>'ngTxt('smd_adth_by'), n$authblock.'</p>',
                    
n'</div>';
            }
        }
    }

    if (
$layout == 0) {
        echo 
nendTable(),
            
n'</div>';
    } else {
        echo 
n'</div>';
    }
    echo 
n'</div>';
}

// -------------------------------------------------------------
function smd_at_save_pane_state()
{
    list(
$p1$p2) = smd_at_valid_types();

    
$panes array_merge($p1$p2, array('folders''image_files''other'));
    
$pane gps('pane');

    if (
in_array($pane$panes))
    {
        
set_pref("smd_at_pane_{$pane}_visible", (gps('visible') == 'true' '1' '0'), 'smd_at'PREF_HIDDEN'yesnoradio'0PREF_PRIVATE);
        
send_xml_response();
    } else {
        
send_xml_response(array('http-status' => '400 Bad Request'));
    }
}