<?php

# PLUGIN PREVIEW BY TEXTPATTERN.INFO

/**
 * smd_ebook
 *
 * A Textpattern CMS plugin for creating e-books (Kindle) from Txp content
 *  -> Content can be in one article or across many
 *  -> Article image of one of the articles is used as cover art
 *  -> Automatic TOC generation and page breaks from Textiled markup
 *  -> Support for book description
 *
 * @author Stef Dawson
 * @link   http://stefdawson.com/
 */

global $smd_ebook_prefs;
smd_ebook_get_prefs();

if(@
txpinterface == 'admin') {
    global 
$smd_ebook_event$smd_ebook_styles;
    
$smd_ebook_event 'smd_ebook';

    
$smd_ebook_styles = array(
        
'cpanel' =>
         
'.smd_hidden { display:none; }
         .smd_active { font-weight:bold; }
         .smd_clear { clear:both; }
         .smd_preselected { opacity:0.6; font-style:italic; }
         .smd_selected { border-top:solid #444; border-bottom:solid #444; }
         .smd_important { color:red; }
         .smd_inline { display:inline; }
         .txp-container, .txp-control-panel { text-align:center; }
         #smd_ebook_preview { display:none; position:absolute; top:1em; left:1em; margin:0 auto; text-align:left; border:2px ridge #999; background:#ececec; max-width:640px; min-width:300px; box-shadow: 8px 8px 15px #b9b9b9; }
         #smd_ebook_preview_close { float:right; cursor:pointer; margin-left:1em;}
         #smd_ebook_preview_content { padding:1em; }
         #smd_ebook_preview_titlebar { padding:5px; border-bottom:1px solid black; font-size:120%; background:#ccc;;}
         #smd_ebook_form { margin:0 auto; width:80%; }
         #smd_ebook_form label, #smd_ebook_create { display:block; }
         #smd_ebook_prefs input[type="text"] { width:250px }
         .smd_ebook_manager { position:relative; margin:0 auto; width:80% }
         .smd_ebook_buttons { display:inline-block; margin:0 2em; }
         .smd_ebook_report textarea { width:80%; }
         #smd_ebook_editor { display:block; width:75%}
         .smd_ebook_files { float:left; width:25% }
         .smd_ebook_mobi_options { text-align:right; }
         .smd_ebook_entity { float:left; margin:1em; }
         #smd_ebook_form label, .smd_ebook_report, .smd_ebook_manager { margin-top:1.5em; }
         .smd_ebook_file { display:block; line-height:1.5; }'
,
    );

    
$pub_prv get_pref('smd_ebook_privs'$smd_ebook_prefs['smd_ebook_privs']['default']);
    
add_privs($smd_ebook_event'1'. (($pub_prv) ? ','.$pub_prv'') );
    
add_privs('plugin_prefs.'.$smd_ebook_event'1');

    
register_tab('content'$smd_ebook_eventsmd_ebook_gTxt('smd_ebook_tab_name'));
    
register_callback('smd_ebook_dispatcher'$smd_ebook_event);
    
register_callback('smd_ebook_dispatcher''plugin_prefs.'.$smd_ebook_event);
    
register_callback('smd_ebook_welcome''plugin_lifecycle.'.$smd_ebook_event);
}

// ********************
// ADMIN SIDE INTERFACE
// ********************
// Plugin jump off point
function smd_ebook_dispatcher($evt$stp) {
    global 
$smd_ebook_event;

    
$available_steps = array(
        
'smd_ebook'               => false,
        
'smd_ebook_prefs'         => true,
        
'smd_ebook_create'        => true,
        
'smd_ebook_generate'      => true,
        
'smd_ebook_loadfile'      => true,
        
'smd_ebook_savefile'      => true,
        
'smd_ebook_viewfile'      => true,
        
'smd_ebook_test'          => true,
        
'smd_ebook_tidy'          => true,
        
'save_pane_state'         => true,
    );

    if (
$stp == 'save_pane_state') {
        
smd_ebook_save_pane_state();
    } else if (!
$stp or !bouncer($stp$available_steps)) {
        
$stp $smd_ebook_event;
    }
    
$stp();
}

// ------------------------
function smd_ebook_welcome($evt$stp) {
    
$msg '';
    switch (
$stp) {
        case 
'installed':
            
$msg 'Go publish!';
            break;
        case 
'deleted':
            
smd_ebook_prefs_remove(0);
            break;
    }
    return 
$msg;
}

// ------------------------
// Stub with correct signature for being called via Txp
function smd_ebook($evt=''$stp='') {
    
smd_ebook_ui();
}

// ------------------------
// Interface for compiling the book
function smd_ebook_ui($msg=''$listfile=''$report ''$retval='') {
    global 
$smd_ebook_event$smd_ebook_prefs$smd_ebook_styles$prefs;

    
pagetop(smd_ebook_gTxt('smd_ebook_tab_name'), $msg);
    
extract(smd_ebook_buttons('mgr'));

    
$btnbar = (has_privs('plugin_prefs.'.$smd_ebook_event))? '<span class="smd_ebook_buttons">'.$btnMgr.$btnPrf.$btnCln.'</span>' '';

    
// Inject styles
    
echo n.'<style type="text/css">' $smd_ebook_styles['cpanel'] . '</style>';
    echo 
n.'<div id="'.$smd_ebook_event.'_control" class="txp-control-panel">' $btnbar '</div>';

    if (!
$listfile) {
        
// Stage 1: Gather the info and create the content

        // Figure out if the various fields are coming from CFs or from user-supplied text areas
        
$fields = array(
            
'description' => array(
                
'html' => 'textarea',
            ),
            
'authornote' => array(
                
'html' => 'textarea',
            ),
            
'title' => array(
                
'html'     => 'text_input',
                
'required' => true,
            ),
            
'chaptitle' => array(
                
'html'       => 'text_input',
                
'hide_empty' => true,
            ),
            
'author' => array(
                
'html' => 'text_input',
            ),
            
'publisher' => array(
                
'html' => 'text_input',
            ),
            
'subject' => array(
                
'html' => 'text_input',
            ),
            
'srp' => array(
                
'html' => 'text_input',
            ),
        );

        
$cfs getCustomFields();

        foreach (
$fields as $field => $data) {
            
$data['value'] = get_pref('smd_ebook_fld_'.$field$smd_ebook_prefs['smd_ebook_fld_'.$field]['default']);
            
$data['column'] = is_numeric($data['value']) ? 'custom_'.$data['value'] : $data['value'];
            
$data['name'] = (is_numeric($data['value']) && isset($cfs[$data['value']])) ? $cfs[$data['value']] : $data['value'];
            
$data['content'] = ($data['value'] == 'SMD_FIXED') ? get_pref('smd_ebook_fld_'.$field.'_fixed''') : '';
            
$data['required'] = isset($data['required']) ? $data['required'] : false;
            
$data['hide_empty'] = isset($data['hide_empty']) ? $data['hide_empty'] : false;
            ${
'ip_'.$field} = '<div class="smd_ebook_entity">' . ( ($data['content'] || ($data['name']=='' && $data['hide_empty']))
                ? 
hInput('smd_ebook_fld_'.$fieldhtmlspecialchars($data['content']))
                : 
'<label for="smd_ebook_fld_'.$field.'">' smd_ebook_gTxt('smd_ebook_lbl_'.$field) . '</label>'
                    
. ( ($data['column'])
                        ? 
hInput('smd_ebook_fld_'.$field'SMD_FLD_'.$data['column'])
                            . 
'<span class="smd_preselected">' smd_ebook_gTxt('smd_ebook_from').' '.str_replace('SMD_FLD_'''$data['name']) . '</span>'
                        
: ( ($data['html'] == 'textarea')
                            ? 
text_area('smd_ebook_fld_'.$field'150''250''''smd_ebook_fld_'.$field)
                            : 
fInput('text''smd_ebook_fld_'.$field'''''''''''''smd_ebook_fld_'.$field''$data['required'])
                        )
                    )
            ) . 
'</div>';
        }

        
$where = array('1=1');
        
$sec get_pref('smd_ebook_section'$smd_ebook_prefs['smd_ebook_section']['default']);
        if (
$sec) {
            
$where[] = "Section='" doSlash($sec) . "'";
        }

        
$articles safe_rows('*''textpattern'join(' AND '$where). ' ORDER BY url_title');

        
// Build dropdown list of articles: not using selectInput() because it doesn't support multiples
        
$alist = array();
        
$alist[] = '<select name="smd_ebook_articles[]" id="smd_ebook_articles" class="list multiple" multiple="multiple" size="12" required="">';
        foreach (
$articles as $row) {
            
$alist[] = '<option value="smd_ebook_article_'.htmlspecialchars($row['ID']).'">' htmlspecialchars($row['Title']) . '</option>';
        }
        
$alist[] = '</select>';

        echo 
n.'<div id="'.$smd_ebook_event.'_container" class="txp-container">';
        echo 
n.'<form id="smd_ebook_form" action="index.php" method="post">';
        echo 
n.'<div class="smd_ebook_entity"><label for="smd_ebook_articles">' smd_ebook_gTxt('smd_ebook_lbl_articles') . '</label>';
        echo 
join(n$alist);
        echo 
n.'</div>';
        echo 
n$ip_description .n$ip_authornote .n$ip_title .n$ip_chaptitle .n$ip_author .n$ip_publisher .n.$ip_subject .n$ip_srp;
        echo 
n.'<div class="smd_clear"></div>';
        echo 
n.fInput('submit''smd_ebook_create'smd_ebook_gTxt('smd_ebook_lbl_create'), 'publish''''''''''smd_ebook_create');
        echo 
n.eInput($smd_ebook_event);
        echo 
n.sInput('smd_ebook_create');
        echo 
n.tInput();
        echo 
'</form>';
        echo 
'</div>';

    } else {
        
// Stage 2: Edit the content and generate the kindle file
        
$titlePrefix smd_ebook_gTxt('smd_ebook_preview_prefix');

        
$qs = array(
            
"event" => $smd_ebook_event,
        );
        
$qsVars "index.php".join_qs($qs);

        echo <<<EOJS
<script type="text/javascript">
var smd_ebook_currfile;

jQuery(function() {
    // Load a file into the editor
    jQuery('.smd_ebook_files .smd_ebook_file').click(function(ev) {
        ev.preventDefault();

        // Spinner and user feedback
        var form = jQuery(this).closest('form');
        form.addClass('busy');
        s = jQuery(ev.currentTarget);
        s.after('<span class="spinner"></span>')

        var me = jQuery(this);
        var name = me.text();
        smd_ebook_currfile = name;

        jQuery.post('
{$qsVars}',
            {
                step: 'smd_ebook_loadfile',
                name: name,
                _txp_token: textpattern._txp_token
            },
            function(data) {
                jQuery('.smd_ebook_files .smd_ebook_file').removeClass('smd_selected');
                me.toggleClass('smd_selected');
                jQuery('#smd_ebook_editor').val(jQuery(data).find('smd_ebook_filedata').attr('value'));
                form.removeClass('busy');
                jQuery('span.spinner').remove();
            }
        );
    });

    // Save the current file back to the file system
    jQuery('.smd_ebook_filesave').click(function(ev) {
        ev.preventDefault();

        // Spinner and user feedback
        var form = jQuery(this).closest('form');
        form.addClass('busy');
        s = jQuery(ev.currentTarget);
        s.after('<span class="spinner"></span>')

        var content = jQuery('#smd_ebook_editor').val();

        jQuery.post('
{$qsVars}',
            {
                step: 'smd_ebook_savefile',
                name: smd_ebook_currfile,
                data: content,
                _txp_token: textpattern._txp_token
            },
            function(data) {
                jQuery('.smd_ebook_files .smd_ebook_file').removeClass('smd_selected');
                jQuery('#smd_ebook_editor').val('');
                form.removeClass('busy');
                jQuery('span.spinner').remove();
            }
        );
    });

    // Preview an html file in its own popup window
    var smd_ebook_previewing = 0;
    jQuery('.smd_ebook_files .smd_ebook_view').click(function(ev) {
        ev.preventDefault();

        // Spinner and user feedback
        var form = jQuery(this).closest('form');
        form.addClass('busy');
        s = jQuery(ev.currentTarget);
        s.after('<span class="spinner"></span>')

        var me = jQuery(this).prev();
        var name = me.text();

        jQuery.post('
{$qsVars}',
            {
                step: 'smd_ebook_viewfile',
                name: name,
                _txp_token: textpattern._txp_token
            },
            function(data) {
                // Grab body text and inject it into the preview container
                jQuery('#smd_ebook_preview_content').empty().append(jQuery(data).find('smd_ebook_filedata').attr('value'));
                jQuery('#smd_ebook_preview_title').text('
{$titlePrefix} ' + name);
                if ((jQuery(ev.target).hasClass('smd_ebook_view')) && !smd_ebook_previewing) {
                    smd_ebook_prevu();
                }
                form.removeClass('busy');
                jQuery('span.spinner').remove();
            }
        );
    });

    function smd_ebook_prevu() {
        jQuery('#smd_ebook_preview').toggle('fast');
        smd_ebook_previewing = !smd_ebook_previewing;
    }

    function smd_ebook_prevu_bind() {
        jQuery('#smd_ebook_preview_close').click(function(){
            smd_ebook_prevu();
        });
        jQuery(document).keypress(function(e){
            if(e.keyCode==27 && smd_ebook_previewing) {
                smd_ebook_prevu();
            }
        });
    }
    smd_ebook_prevu_bind();
});
</script>
EOJS;
        echo 
n.'<div id="'.$smd_ebook_event.'_container" class="txp-container">';
        echo 
n.'<form id="smd_ebook_form" action="index.php" method="post">';

        echo 
n.'<div class="smd_ebook_report">'
            
hed(smd_ebook_gTxt('smd_ebook_lbl_report'), 2)
            . 
'<textarea id="smd_ebook_report" cols=80 rows="6">'.$report.'</textarea>'
            
'</div>';

        echo 
n.'<div class="smd_ebook_manager">';

        
// 'Generate book' and 'download' buttons
        
echo '<div class="smd_ebook_mobi_options">';
        echo 
n.fInput('submit''smd_ebook_generate'smd_ebook_gTxt('smd_ebook_lbl_generate'), 'publish smd_ebook_mobi');
        if (
$retval <= 1) {
            
$info explode ('.',$listfile);
            
$basepart array_slice($info0count($info)-1);
            
$mobifile join(''$basepart) . '.mobi';
            echo 
n.hInput('smd_ebook_mobifile'$mobifile);
            echo 
n.fInput('submit''smd_ebook_to_files'smd_ebook_gTxt('smd_ebook_lbl_to_files'), 'publish smd_ebook_mobi');;
            echo 
n.fInput('submit''smd_ebook_download'smd_ebook_gTxt('smd_ebook_lbl_download'), 'publish smd_ebook_mobi');;
        }
        echo 
'</div>';

        echo 
n.hed(smd_ebook_gTxt('smd_ebook_lbl_files'), 2);
        echo 
n.'<div class="smd_ebook_files">';

        
$opf_edit get_pref('smd_ebook_opf_edit'$smd_ebook_prefs['smd_ebook_opf_edit']['default']);
        
$opf_allowed do_list($opf_edit);
        
$opf_allowed[] = '1'// Publishers can always edit .opf
        
$can_opf in_array($GLOBALS['privs'], $opf_allowed);

        
$files file($prefs['tempdir'] . DS $listfile);

        foreach (
$files as $file) {
            
$info explode ('.',$file);
            
$lastpart count($info)-1;
            
$ext trim($info[$lastpart]);
            if (
$ext == 'opf') {
                echo 
n.hInput('smd_ebook_opf_file'$file);
            }
            if (
$ext != 'opf' || ($ext == 'opf' && $can_opf)) {
                echo 
n.'<a href="#" class="smd_ebook_file">'.trim($file).'</a>';
                if (
$ext == 'html') {
                    echo 
n.'<a href="#" class="smd_ebook_view">'.smd_ebook_gTxt('smd_ebook_lbl_view').'</a>';
                }
            }
        }

        echo 
n.'<button class="smd_ebook_filesave smallerbox">'.gTxt('save').'</button>';
        echo 
n.'</div>';

        echo 
n.'<div class="smd_ebook_editor">';
        echo 
n.'<textarea id="smd_ebook_editor" cols="60" rows="25"></textarea>';
        echo 
n.'</div>';
        echo 
n.'<div id="smd_ebook_preview">
            <div id="smd_ebook_preview_titlebar">
                <span id="smd_ebook_preview_title"></span>
                <a id="smd_ebook_preview_close">X</a>
            </div>
            <div id="smd_ebook_preview_content"></div>
            </div>'
;

        echo 
n.hInput('smd_ebook_listfile'$listfile);
        echo 
n.eInput($smd_ebook_event);
        echo 
n.sInput('smd_ebook_generate');
        echo 
n.tInput();
        echo 
n.'</div>';
        echo 
n.'</form>';
        echo 
n.'<div class="smd_clear"></div>';
        echo 
n.'</div>';
    }
}

// ------------------------
function smd_ebook_loadfile() {
    global 
$prefs;

    
$name sanitizeForFile(ps('name'));
    
$file file($prefs['tempdir'] . DS $name);
    if (
$file) {
        
send_xml_response(array('smd_ebook_filedata' => str_replace(array("'"), array('&#039;'), join(''$file)) ));
    } else {
        
send_xml_response(array('http-status' => '400 Bad Request'));
    }
    exit; 
// Don't display page_end
}

// ------------------------
function smd_ebook_savefile() {
    global 
$prefs;

    
$name sanitizeForFile(ps('name'));
    
$content ps('data');
    
$fp fopen($prefs['tempdir'] . DS $name"wb");
    
fwrite($fptrim($content));
    
fclose($fp);
    if (
$fp) {
        
send_xml_response();
    } else {
        
send_xml_response(array('http-status' => '400 Bad Request'));
    }
    exit; 
// Don't display page_end
}

// ------------------------
// Extract a subset of the HTML file for display
function smd_ebook_viewfile() {
    global 
$prefs$path_to_site;

    
$name sanitizeForFile(ps('name'));
    
$file file_get_contents($prefs['tempdir'] . DS $name);

    if (
$file) {
        
$doc = new DOMDocument();
        
$doc->loadHTML($file);
        
$domxpath = new DOMXpath($doc);
        
$newDoc = new DOMDocument('1.0','UTF-8');

        
$nodeStyle $domxpath->query('//style');
        
$nodeList $domxpath->query('//body');

        
// Create a new document and import the document subsets
        
$newDoc->appendChild($newDoc->importNode($nodeStyle->item(0), true));
        
$newDoc->appendChild($newDoc->importNode($nodeList->item(0), true));
        
$out $newDoc->saveHTML();

        
send_xml_response(array('smd_ebook_filedata' => str_replace(array("'"$path_to_site.DS), array('&#039;'ihu), $out) ));
    } else {
        
send_xml_response(array('http-status' => '400 Bad Request'));
    }
    exit; 
// Don't display page_end
}

// ------------------------
function smd_ebook_templates() {
    
// .opf file template
    
$template['opf'] = <<<EOOPF
<?xml version="1.0" encoding="{smd_ebook_encoding}"?>
<package xmlns="http://www.idpf.org/2007/opf" version="2.0" {smd_ebook_uid_ref}>
    <metadata xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:opf="http://www.idpf.org/2007/opf">
        {smd_ebook_md_uid}
        {smd_ebook_md_title}
        {smd_ebook_md_lang}
        {smd_ebook_md_creator}
        {smd_ebook_md_date}
        {smd_ebook_md_description}
        {smd_ebook_md_subject}
        {smd_ebook_md_publisher}
        {smd_ebook_md_cover}
        <x-metadata>
            <output encoding="{smd_ebook_encoding}" content-type="text/x-oeb1-document"></output>
            {smd_ebook_md_srp}
        </x-metadata>
    </metadata>

    <manifest>
        {smd_ebook_manifest_ncx}
        {smd_ebook_manifest_cover}
        {smd_ebook_manifest_authornote}
        {smd_ebook_manifest_toc}
        {smd_ebook_manifest_items}
    </manifest>

    <spine {smd_ebook_spine_ncx_ref}>
        {smd_ebook_spine_ncx}
        {smd_ebook_spine_authornote}
        {smd_ebook_spine_toc}
        {smd_ebook_spine_items}
    </spine>

    <guide>
        {smd_ebook_guide_toc}
        {smd_ebook_guide_start}
    </guide>
</package>
EOOPF;

    
// .ncx file template
    
$template['ncx'] = <<<EONCX
<?xml version="1.0" encoding="{smd_ebook_encoding}"?>
<!DOCTYPE ncx PUBLIC "-//NISO//DTD ncx 2005-1//EN"
"http://www.daisy.org/z3986/2005/ncx-2005-1.dtd">
<ncx xmlns="http://www.daisy.org/z3986/2005/ncx/" version="2005-1" xml:lang="{smd_ebook_lang}">
    <head>
        {smd_ebook_dtb_uid}
    </head>

    <docTitle><text>{smd_ebook_title}</text></docTitle>
    <docAuthor><text>{smd_ebook_creator}</text></docAuthor>
    <navMap>
        {smd_ebook_ncx_map}
    </navMap>
</ncx>
EONCX;

    
// navPoint template (a portion of the .ncx file)
    
$template['nav'] = <<<EONAV
        <navPoint class="titlepage" id="{smd_ebook_nav_hash}" playOrder="{smd_ebook_nav_idx}">
            <navLabel><text>{smd_ebook_nav_label}</text></navLabel>
            <content src="{smd_ebook_file_name}#{smd_ebook_nav_hash}" />
        </navPoint>
EONAV;

    
// TOC template
    
$template['toc'] = <<<EOTOC
<html>
<head>
    <title>Table of Contents</title>
    {smd_ebook_stylesheet}
</head>
<body>
    {smd_ebook_toc_list}
</body>
</html>
EOTOC;

    
// HTML template
    
$template['doc'] = <<<EOTOC
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset={smd_ebook_encoding}" />
    <title>{smd_ebook_title}</title>
    {smd_ebook_stylesheet}
</head>
<body>
    {smd_ebook_chaptitle}
    {smd_ebook_contents}
</body>
</html>
EOTOC;

    return 
$template;
}

// ------------------------
// Stage 1: create the files necessary for generation of the book.
// The actual generation via kindlegen is a separate step.
function smd_ebook_create() {
    global 
$smd_ebook_prefs$prefs$img_dir;

    @include_once 
txpath.'/lib/classTextile.php';
    @include_once 
txpath.'/publish.php'// for parse()
    
$textile = new Textile();

    
$template smd_ebook_templates();
    
$msg '';
    
$report $toc $ncx $reps = array();

    
// Get Textile and encoding options
    
$encoding get_pref('smd_ebook_encoding'$smd_ebook_prefs['smd_ebook_encoding']['default']);
    
$which get_pref('smd_ebook_textile'$smd_ebook_prefs['smd_ebook_textile']['default']);
    
$txt_description in_list('description'$which);
    
$txt_authornote in_list('authornote'$which);

    
// Build up a giant replacement table which is then substituted into
    // the various templates before passing to kindlegen

    // Populate the unique ID entries direcly into the .opf template as they're only used once each
    
$uid get_pref('smd_ebook_uid'$smd_ebook_prefs['smd_ebook_uid']['default']);

    
$template['opf'] = str_replace('{smd_ebook_uid_ref}', (($uid) ? 'unique-identifier="uid"' ''), $template['opf']);
    
$template['opf'] = str_replace('{smd_ebook_md_uid}', (($uid) ? '<dc:identifier id="uid">' $uid '</dc:identifier>' ''), $template['opf']);
    
$template['ncx'] = str_replace('{smd_ebook_dtb_uid}', (($uid) ? '<meta name="dtb:uid" content="uid"/>' ''), $template['ncx']);

    
// Set up the TOC wrappers
    
$toc_wrap get_pref('smd_ebook_toc_wraptag'$smd_ebook_prefs['smd_ebook_toc_wraptag']['default']);
    
$toc_class get_pref('smd_ebook_toc_class'$smd_ebook_prefs['smd_ebook_toc_class']['default']);
    
$wrapit = ($toc_wrap == 'ol') ? '#' '*';

    
$article_cnt $ncx_cnt $elem_cnt 0;
    
$article_refs $article_spines = array();

    
// Page break, stylesheet and heading references
    
$pbr get_pref('smd_ebook_page_break'$smd_ebook_prefs['smd_ebook_page_break']['default']);
    
$css get_pref('smd_ebook_stylesheet'$smd_ebook_prefs['smd_ebook_stylesheet']['default']);
    
$hdg get_pref('smd_ebook_heading_level'$smd_ebook_prefs['smd_ebook_heading_level']['default']);

    if (
$css) {
        
$sheet safe_field('css''txp_css'"name='" doSlash($css) . "'");
    }
    
$sheet = ($sheet) ? '<style type="text/css">' $sheet '</style>' '';


    
// Loop for each article in the collection
    
foreach (ps('smd_ebook_articles') as $artid) {
        
$article_cnt++;

        
$id str_replace('smd_ebook_article_'''$artid);
        
$row safe_row('*''textpattern'"ID = '" doSlash($id) . "'");

        if (
$row) {
            
// Initialize a few things
            
$note_content '';
            
$reps['{smd_ebook_file_name}'] = $row['url_title'] . '.html';
            
$reps['{smd_ebook_encoding}'] = $encoding;
            
$cur_file $row['url_title'] . '.html';

            
// Each of the items starting !isset() are only ever loaded _once_ from the
            // first article in which they are found.
            // Begin by setting up the file names
            
if (!isset($firstfile)) {
                
$firstfile $row['url_title'] . '.html';
                
$listfile $row['url_title'] . '.smd';
                
$notefile $row['url_title'] . '_notes.html';
                
$toc_file $row['url_title'] . '_toc.html';
                
$ncx_file $row['url_title'] . '.ncx';
                
$opf_file $row['url_title'] . '.opf';
            }
            
// Language
            
if (!isset($reps['{smd_ebook_md_lang}'])) {
                
$reps['{smd_ebook_md_lang}'] = '<dc:language>'.$prefs['language'].'</dc:language>';
                
$reps['{smd_ebook_lang}'] = $prefs['language'];
            }
            
// Author can come from:
            //  1) an article field
            //  2) the current logged in user
            //  3) user-supplied at book creation time
            //  4) hard-coded in plugin settings
            
if (!isset($reps['{smd_ebook_md_creator}'])) {
                
$val ps('smd_ebook_fld_author');
                if (
strpos($val'SMD_FLD_') !== false) {
                    
$valfld str_replace('SMD_FLD_'''$val);
                    
$val = isset($row[$valfld]) ? ( ($valfld == 'AuthorID') ? get_author_name($row[$valfld]) : $row[$valfld] ) : '';
                }
                if (
$val) {
                    
$reps['{smd_ebook_md_creator}'] = '<dc:creator>'.$val.'</dc:creator>';
                    
$reps['{smd_ebook_creator}'] = $val;
                }
            }
            
// Publication date
            // TODO: reformat?
            
if (!isset($reps['{smd_ebook_md_date}'])) {
                
$reps['{smd_ebook_md_date}'] = '<dc:date>'.($row['Posted']).'</dc:date>';
            }

            
// Cover image
            
if (!isset($reps['{smd_ebook_md_cover}'])) {
                if (isset(
$row['Image'])) {
                    
$img safe_row('*''txp_image'"id='" intval($row['Image']) . "'");

                    
// Only GIFs and JPGs need apply
                    
$mime_type = (($img['ext'] == '.jpg') ? 'image/jpeg' : (($img['ext'] == '.gif') ? 'image/gif' ''));
                    if (
$mime_type) {
                        
$reps['{smd_ebook_md_cover}'] = '<meta name="cover" content="cover-image" />';
                        
$reps['{smd_ebook_manifest_cover}'] = '<item id="cover-image" media-type="'.$mime_type.'" href="' $prefs['path_to_site'] . DS $img_dir DS $img['id'] . $img['ext'] . '" />';
                    }
                }
            }

            
// The following values can either come from the given field or be used verbatim
            // Firstly the title, description, subject, publisher and chapter title
            
$setMany = array('chaptitle');
            foreach (array(
'title''description''subject''publisher''chaptitle') as $thingy) {
                if (
in_array($thingy$setMany) || !isset($reps['{smd_ebook_md_'.$thingy.'}'])) {
                    
$val ps('smd_ebook_fld_'.$thingy);
                    if (
strpos($val'SMD_FLD_') !== false) {
                        
$valfld str_replace('SMD_FLD_'''$val);
                        
$val = isset($row[$valfld]) ? $row[$valfld] : '';
                    }
                    if (
$val) {
                        
// Textile the content?
                        
$content = (isset($txt_{$thingy}) && $txt_{$thingy}) ? trim($textile->TextileThis($val)) : trim($val);
                        if (!
in_array($thingy$setMany)) {
                            
$reps['{smd_ebook_md_'.$thingy.'}'] = '<dc:'.$thingy.'>' $content '</dc:'.$thingy.'>';
                        }

                        
// There are two titles: one for the metadata and one raw so if the title
                        // has just been found, populate the raw title too
                        
if ($thingy == 'title') {
                            
$reps['{smd_ebook_title}'] = $content;
                        } else if (
$thingy == 'chaptitle') {
                            
// Chapter title has an associated heading level
                            
$reps['{smd_ebook_chaptitle}'] = '<h'.$hdg.'>'.$content.'</h'.$hdg.'>';
                        }
                    }
                }
            }

            
// Price (SRP) can also come from a field but it needs some special jiggery pokery
            
if (!isset($reps['{smd_ebook_md_srp}'])) {
                
$val ps('smd_ebook_fld_srp');
                if (
strpos($val'SMD_FLD_') !== false) {
                    
$valfld str_replace('SMD_FLD_'''$val);
                    
$val = isset($row[$valfld]) ? $row[$valfld] : '';
                }
                if (
$val) {
                    
$parts do_list($val'|');
                    
$parts[0] = $parts[0] ? $parts[0] : '0.00';
                    
$parts[1] = (isset($parts[1]) && $parts[1]) ? $parts[1] : get_pref('smd_ebook_currency'$smd_ebook_prefs['smd_ebook_currency']['default']);
                    
$reps['{smd_ebook_md_srp}'] = '<SRP Currency="'.$parts[1].'">'.$parts[0].'</SRP>';
                }
            }

            
// Authornote is slightly different because it needs storing as a file,
            // and needs adding to the .ncx (but not to the TOC)
            
if (!isset($reps['{smd_ebook_manifest_authornote}'])) {
                
$val ps('smd_ebook_fld_authornote');
                if (
strpos($val'SMD_FLD_') !== false) {
                    
$valfld str_replace('SMD_FLD_'''$val);
                    
$val = isset($row[$valfld]) ? $row[$valfld] : '';
                }
                if (
$val) {
                    
$reps['{smd_ebook_manifest_authornote}'] = '<item id="smd_ebook_notes" media-type="text/html" href="'.$notefile.'" />';
                    
$reps['{smd_ebook_spine_authornote}'] = '<itemref idref="smd_ebook_notes" />';
                    
$note_content '<span id="smd_ebook_notes"></span>' . (($txt_authornote) ? $textile->TextileThis($val) : $val);

                    
// While it's 99% likely the actual title used for the eventual book has been found,
                    // there's a slim chance it hasn't. In that case, the current row's title is used as a fallback
                    
$note_title = isset($reps['{smd_ebook_title}']) ? $reps['{smd_ebook_title}'] : $row['Title'];
                    
$note_content str_replace(array('{smd_ebook_encoding}''{smd_ebook_title}''{smd_ebook_chaptitle}''{smd_ebook_stylesheet}''{smd_ebook_contents}'), array($encoding$note_title''$sheet$note_content), $template['doc']);

                    
$fp fopen($prefs['tempdir'].DS.$notefile"wb");
                    
fwrite($fptrim($note_content));
                    
fclose($fp);
                    
$lfout[] = $notefile;

                    
// Add it to the .ncx
                    
$ncx_cnt++;
                    
$from = array('{smd_ebook_file_name}''{smd_ebook_nav_label}''{smd_ebook_nav_hash}''{smd_ebook_nav_idx}');
                    
$to = array($notefilesmd_ebook_gTxt('smd_ebook_lbl_authornote'), 'smd_ebook_notes'$ncx_cnt);
                    
$ncx[] = str_replace($from$to$template['nav']);
                }
            }

            
// Note:
            //  1) a full (well-formed, hopefully) HTML file (from <html>...</html>) is generated
            //     here so the loadHTML() method is happy. The body will need reinjecting into
            //     the template after the ToC has been generated.
            //  2) The current HTML file's title is used instead of the overall book title.
            //  3) parse() is called twice to simulate secondpass.
            
$chap_title = isset($reps['{smd_ebook_chaptitle}']) ? $reps['{smd_ebook_chaptitle}'] : '';
            
article_format_info($row); // Load article context
            
$html_content str_replace(array('{smd_ebook_encoding}''{smd_ebook_title}''{smd_ebook_chaptitle}''{smd_ebook_stylesheet}''{smd_ebook_contents}'), array($encoding$row['Title'], $chap_title$sheetparse(parse($row['Body_html']))), $template['doc']);

            
// Trawl through the HTML content, either:
            //  a) pulling out the ToC entries.
            //  b) creating ToC entries if the pref allows
            
$autotoc get_pref('smd_ebook_auto_toc'$smd_ebook_prefs['smd_ebook_auto_toc']['default']);
            
$doc = new DOMDocument();
            
$dom_ok $doc->loadHTML($html_content);
            if (
$dom_ok) {
                
$items $doc->getElementsByTagName('*');
                
$offset $toc_cnt 0;
                foreach (
$items as $item) {
                    if (
$autotoc && !$item->hasAttribute('id') && preg_match('/h([1-6])/i'$item->nodeName$matches)) {
                        
// It's a heading. Make the anchor chain based on the heading level
                        
$anchor_parts array_fill(0$matches[1], 'sub');
                        
$anchor join('-'$anchor_parts). ++$elem_cnt;
                        
$item->setAttribute('id'$anchor);
                    }

                    if (
$item->hasAttribute('id')) {
                        
$ncx_cnt++;
                        
$toc_cnt++;
                        
$hashval $item->getAttribute('id');
                        if ( (!isset(
$reps['{smd_ebook_guide_start}'])) && ($toc_cnt == 1) ) {
                            
$reps['{smd_ebook_guide_start}'] = '<reference type="text" title="'.smd_ebook_gTxt('smd_ebook_lbl_start').'" href="'.$firstfile.'#'.$hashval.'"></reference>';
                        }

                        
// mb_convert_encoding() seems to bypass the odd behaviour where apostrophes
                        // would appear in the TOC as Ã¢â‚¬â„¢. This may actually be a band-aid to circumvent
                        // problems with the encoding in DOMDocument: perhaps if appropriate encoding is
                        // used there, this hack won't be necessary
                        
$node mb_convert_encoding($item->nodeValue'HTML-ENTITIES''utf-8');
                        
$from = array('{smd_ebook_file_name}''{smd_ebook_nav_label}''{smd_ebook_nav_hash}''{smd_ebook_nav_idx}');
                        
$to = array($cur_file$node$hashval$ncx_cnt);
                        
$ncx[] = str_replace($from$to$template['nav']);

                        
// Now it's the turn of the HTML TOC. Utilise Textile here to
                        // create the toc list from ul or ol syntax
                        
$hashBits do_list($hashval'-');
                        
$indent count($hashBits);

                        if ( (
$toc_cnt == 1) && ($indent 1) ) {
                            
// Doesn't start with h1 (begins h2, maybe) so scale back the indent.
                            // Without this, Textile produces invalid markup
                            
$offset $indent 1;
                        }

                        
$toc_cls = (($toc_cnt == 1) && $toc_class) ? '('.$toc_class.')' '';
                        
$toc[] = str_pad(''max(1$indent-$offset), $wrapit) . $toc_cls.' ' href($node$cur_file.'#'.$hashval);
                    }
                }

                
// Grab any changes just made to the DOM tree in case anchors have been added.
                // Note _only_ the <body> is extracted since the XML headers that come with a full
                // saveXML() get in the way. Also note that saveHTML() is not being used because its
                // 'node' parameter wasn't added until PHP 5.3.6 which would affect the plugin's
                // base requirements.
                // Hackish: remove the body tag wrapper with substr() so when the html_content
                // is shoved back into the template (which has a body tag already) there's no
                // tag duplication
                
$html_content substr($doc->saveXML($doc->getElementsByTagName('body')->item(0)), 6, -7);

                
// Swap out any line break placeholders. Note that the line break is replaced twice:
                // once to get rid of any surrounding <p> tags that Textile may have introduced around
                // the marker, and again in case a few of them didn't get paragraph tags.
                
$html_content str_replace('<p>'.$pbr.'</p>''<mbp:pagebreak />'$html_content);
                
$html_content str_replace($pbr'<mbp:pagebreak />'$html_content);

                
// Pass the extracted <body> tree into the doc template again so it regenerates
                // the full <html>...</html> document.
                
$html_content str_replace(array('{smd_ebook_encoding}''{smd_ebook_title}''{smd_ebook_chaptitle}''{smd_ebook_stylesheet}''{smd_ebook_contents}'), array($encoding$row['Title'], ''$sheet$html_content), $template['doc']);
            } else {
                
trigger_error(smd_ebook_gTxt('smd_ebook_malformed'), E_WARNING);
            }

            
// Write the final HTML document to the file system
            
$fp fopen($prefs['tempdir'].DS.$cur_file"wb");
            
fwrite($fptrim($html_content));
            
fclose($fp);

            
$lfout[] = $cur_file;
            
$article_refs[] = '<item id="smd_ebook_item_'.$article_cnt.'" media-type="text/html" href="'.$row['url_title'].'.html" />';
            
$article_spines[] = '<itemref idref="smd_ebook_item_' $article_cnt '" />';

        }
    }

    
// Ensure any NULL replacements are cleared or throw errors
    
$reps['{smd_ebook_chaptitle}'] = (!isset($reps['{smd_ebook_chaptitle}'])) ? '' $reps['{smd_ebook_chaptitle}'];
    
$reps['{smd_ebook_creator}'] = (!isset($reps['{smd_ebook_creator}'])) ? '' $reps['{smd_ebook_creator}'];
    
$reps['{smd_ebook_md_creator}'] = (!isset($reps['{smd_ebook_md_creator}'])) ? '' $reps['{smd_ebook_md_creator}'];
    
$reps['{smd_ebook_md_description}'] = (!isset($reps['{smd_ebook_md_description}'])) ? '' $reps['{smd_ebook_md_description}'];
    
$reps['{smd_ebook_md_subject}'] = (!isset($reps['{smd_ebook_md_subject}'])) ? '' $reps['{smd_ebook_md_subject}'];
    
$reps['{smd_ebook_md_publisher}'] = (!isset($reps['{smd_ebook_md_publisher}'])) ? '' $reps['{smd_ebook_md_publisher}'];
    
$reps['{smd_ebook_md_srp}'] = (!isset($reps['{smd_ebook_md_srp}'])) ? '' $reps['{smd_ebook_md_srp}'];
    
$reps['{smd_ebook_guide_start}'] = (!isset($reps['{smd_ebook_guide_start}'])) ? '' $reps['{smd_ebook_guide_start}'];
    if (!isset(
$reps['{smd_ebook_md_cover}'])) {
        
$reps['{smd_ebook_md_cover}'] = '';
        
$reps['{smd_ebook_manifest_cover}'] = '';
    }
    if (!isset(
$reps['{smd_ebook_manifest_authornote}'])) {
        
$reps['{smd_ebook_manifest_authornote}'] =  '';
        
$reps['{smd_ebook_spine_authornote}'] =  '';
    }

    
// All the replacements are set up so prepare for kindlegen
    // First, create the TOC and write it to the filesystem
    
if ($toc_cnt 0) {
        
$reps['{smd_ebook_manifest_toc}'] = '<item id="toc" media-type="text/html" href="'.$toc_file.'" />';
        
$reps['{smd_ebook_spine_toc}'] = '<itemref idref="toc" />';
        
$reps['{smd_ebook_guide_toc}'] = '<reference type="toc" title="' smd_ebook_gTxt('smd_ebook_toc') . '" href="'.$toc_file.'"></reference>';
        
$html_toc $textile->TextileThis(join(n$toc));
        
$html_toc str_replace(array('{smd_ebook_toc_list}''{smd_ebook_stylesheet}'), array($html_toc$sheet), $template['toc']);
        
$fp fopen($prefs['tempdir'] . DS $toc_file"wb");
        
fwrite($fptrim($html_toc));
        
fclose($fp);
        
$lfout[] = $toc_file;
    } else {
        
$reps['{smd_ebook_manifest_toc}'] = '';
        
$reps['{smd_ebook_spine_toc}'] = '';
        
$reps['{smd_ebook_guide_toc}'] = '';
    }

    
// Add the ncx waypoints to the reps array and generate the .ncx file
    
if ($ncx_cnt 0) {
        
$reps['{smd_ebook_ncx_map}'] = join(n$ncx);
        
$reps['{smd_ebook_manifest_ncx}'] = '<item id="ncx" media-type="application/x-dtbncx+xml" href="'.$ncx_file.'" />';
        
$reps['{smd_ebook_spine_ncx}'] = '<itemref idref="ncx" />';
        
$reps['{smd_ebook_spine_ncx_ref}'] = 'toc="ncx"';
        
$ncx_file_content strtr($template['ncx'], $reps);
        
$fp fopen($prefs['tempdir'] . DS $ncx_file"wb");
        
fwrite($fptrim($ncx_file_content));
        
fclose($fp);
        
$lfout[] = $ncx_file;
    } else {
        
$reps['{smd_ebook_manifest_ncx}'] = '';
        
$reps['{smd_ebook_spine_ncx}'] = '';
        
$reps['{smd_ebook_spine_ncx_ref}'] = '';
    }

    
// Build the remaining manifest replacements and generate the OPF
    
$reps['{smd_ebook_manifest_items}'] = join(n$article_refs);
    
$reps['{smd_ebook_spine_items}'] = join(n$article_spines);

    
$opf_file_content strtr($template['opf'], $reps);
    
$fp fopen($prefs['tempdir'] . DS $opf_file"wb");
    
fwrite($fptrim($opf_file_content));
    
fclose($fp);
    
$lfout[] = $opf_file;

    
// Write the listfile, which contains a list of all the files used in this stage
    
$fp fopen($prefs['tempdir'] . DS $listfile"wb");
    
fwrite($fpjoin(n$lfout));
    
fclose($fp);

    
// Hand off to Stage 2 to do the deed
    
smd_ebook_generate($listfile$opf_file);
}

// ------------------------
// Stage 2 only: Pre-requisites are that the necessary files (toc, .html, ncx + opf)
// have already been generated by the previous stage. If called directly via the
// GUI, the hidden form value containing the OPF file is read.
function smd_ebook_generate($listfile=''$opf_file='') {
    global 
$prefs$smd_ebook_prefs;

    
$report = array();
    
$retval NULL;

    
// Use passed in values in lieu of the one in the form
    
$opf_file = ($opf_file) ? $opf_file ps('smd_ebook_opf_file');
    
$listfile = ($listfile) ? $listfile ps('smd_ebook_listfile');

    
// .mobifile credentials
    
$mobifile ps('smd_ebook_mobifile');
    
$fullpath $prefs['tempdir'] . DS $mobifile;
    
$filesize filesize($fullpath);

    
$downloadit ps('smd_ebook_download');
    
$fileit ps('smd_ebook_to_files');

    if (
$downloadit) {
        
ob_clean();
        
header('Content-Description: File Download');
        
header('Content-Type: application/octet-stream');
        
header('Content-Disposition: attachment; filename="'.$mobifile.'"; size = "'.$filesize.'"');
        
header("Content-Transfer-Encoding: binary");
        
header("Cache-Control: no-cache, must-revalidate, max-age=60");
        
header("Expires: Sat, 01 Jan 2000 12:00:00 GMT");
        
header('Cache-Control: private');
        @
set_time_limit(0);
        if (
$file fopen($fullpath'rb')) {
            while(!
feof($file) and (connection_status()==0)) {
                echo 
fread($file1024*64);
                
ob_flush();
                
flush();
            }
            
fclose($file);
        }
        exit;

    } else if (
$fileit) {

        @include_once 
txpath.'/include/txp_file.php';

        
// Copy the file to the files area
        
$destpath $prefs['file_base_path'] . DS $mobifile;
        
copy($fullpath$destpath);

        
// Get the file category
        
$filecat get_pref('smd_ebook_file_cat'$smd_ebook_prefs['smd_ebook_file_cat']['default']);

        
// Read description and title from .opf
        
$doc = new DOMDocument();
        
$content file_get_contents($prefs['tempdir'] . DS $opf_file);
        
$dom_ok $doc->loadXML($content);

        
$description $title '';
        if (
$dom_ok) {
            
$items $doc->getElementsByTagName('*');
            foreach (
$items as $item) {
                if (
$item->nodeName == 'dc:title') {
                    
$title $item->nodeValue;
                }
                if (
$item->nodeName == 'dc:description') {
                    
$description $item->nodeValue;
                }
            }
        }

        
$curid safe_field('id''txp_file'"filename='".doSlash($mobifile)."'");

        if (
$curid) {
            
// Update existing database entry
            
$ret safe_update('txp_file',
                
"
                    title='" 
doSlash($title) . "',
                    category='" 
doSlash($filecat) . "',
                    description='" 
doSlash($description) . "',
                    size='" 
doSlash($filesize) . "',
                    modified= now()
                "
,
                
"id='".doSlash($curid)."'"
            
);
            if (
$ret) {
                
$msg smd_ebook_gTxt('smd_ebook_updated', array('{id}' => $curid));
            } else {
                
$msg smd_ebook_gTxt('smd_ebook_not_filed');
            }

        } else {
            
// Make a new entry in the database for it
            
$newid file_db_add(doSlash($mobifile), doSlash($filecat), ''doSlash($description), doSlash($filesize), doSlash($title));
            if (
$newid) {
                
$msg smd_ebook_gTxt('smd_ebook_filed', array('{id}' => $newid));
            } else {
                
$msg smd_ebook_gTxt('smd_ebook_not_filed');
            }
        }

    } else {

        
// (Re)generate the book
        
list($report$retval) = smd_ebook_kindlegen($opf_file);

        if (
$retval 1) {
            
$msg smd_ebook_gTxt('smd_ebook_generate_failed', array('{code}' => $retval));
        } else {
            
$msg smd_ebook_gTxt('smd_ebook_generate_ok');
        }
    }
    
smd_ebook_ui($msg$listfilejoin(n$report), $retval);
}

// ------------------------
// Interface with kindlegen to generate the .mobi file.
function smd_ebook_kindlegen($opf) {
    global 
$prefs$smd_ebook_prefs;    

    
$kgen get_pref('smd_ebook_kindlegen_path'$smd_ebook_prefs['smd_ebook_kindlegen_path']['default']);
    
$command $kgen ' ' $prefs['tempdir'] . DS $opf;
    
exec($command$output$result);

    return array(
$output$result);
}

// ------------------------
// Common buttons for the interface
function smd_ebook_buttons($curr='mgr') {
    global 
$smd_ebook_event;

    
$ret = array (
        
'btnMgr' => '<form method="post" action="?event='.$smd_ebook_event.'" class="smd_inline">'.fInput('submit''submit'smd_ebook_gTxt('smd_ebook_lbl_mgr'), 'smallerbox'.($curr=='mgr'?' smd_active':'')).tInput().'</form>',
        
'btnPrf' => '<form method="post" action="?event='.$smd_ebook_event.a.'step=smd_ebook_prefs" class="smd_inline">'.fInput('submit''submit'smd_ebook_gTxt('smd_ebook_lbl_prf'), 'smallerbox'.($curr=='prf'?' smd_active':'')).tInput().'</form>',
        
'btnCln' => '<form method="post" action="?event='.$smd_ebook_event.a.'step=smd_ebook_tidy" class="smd_inline">'.fInput('submit''submit'smd_ebook_gTxt('smd_ebook_lbl_cln'), 'smallerbox'.($curr=='cln'?' smd_active':'')).tInput().'</form>',
        
'btnTst' => '<a href="?event='.$smd_ebook_event.a.'step=smd_ebook_test'.a.'_txp_token='.form_token().'" class="smd_inline">'.smd_ebook_gTxt('smd_ebook_lbl_tst').'</a>',
    );
    return 
$ret;
}

// ------------------------
// Tidy up the temp dir
function smd_ebook_tidy($msg='') {
    global 
$prefs$smd_ebook_event$smd_ebook_styles;

    
require_privs('plugin_prefs.'.$smd_ebook_event);

    if (
ps('smd_ebook_cleanup')) {
        
$to_delete ps('smd_ebook_files');
        foreach(
$to_delete as $del) {
            
$path realpath($prefs['tempdir'] . DS $del);
            
unlink($path);
        }
        
$msg smd_ebook_gTxt('smd_ebook_deleted');
    }

    
pagetop(smd_ebook_gTxt('smd_ebook_tab_name'), $msg);
    
extract(smd_ebook_buttons('cln'));

    
$btnbar = (has_privs('plugin_prefs.'.$smd_ebook_event))? '<span class="smd_ebook_buttons">'.$btnMgr.$btnPrf.$btnCln.'</span>' '';

    
$filelist = array();
    
$valid = array('mobi''html''ncx''opf''smd');
    
$tmp $prefs['tempdir'] . DS;

    
// Grab all files then remove unnecessary ones: faster than multiple globs
    // for each file type and more robust than relying on GLOB_BRACE support
    
$allfiles glob($tmp.'*.*');

    foreach (
$allfiles as $file) {
        
$info explode ('.',$file);
        
$lastpart count($info)-1;
        
$ext trim($info[$lastpart]);
        if (
in_array($ext$valid)) {
            
$filelist[] = $file;
        }
    }

    
// Inject styles
    
echo '<style type="text/css">' $smd_ebook_styles['cpanel'] . '</style>';

    echo 
'<div id="'.$smd_ebook_event.'_control" class="txp-control-panel">' $btnbar '</div>';

    
$filesel '';
    if (
$filelist) {
        
$filez = array();
        foreach(
$filelist as $val) {
            
$val basename($val);
            
$key sanitizeForFile($val);
            
$filez[$key] = $val;
       }
        
$selout[] = '<select id="smd_ebook_files" name="smd_ebook_files[]" class="list" size="20" multiple="multiple">';
        foreach (
$filez as $key => $leaf) {
            
$selout[] = t.'<option value="'.$key.'">'.htmlspecialchars($leaf).'</option>'.n;
        }
        
$selout[] = '</select>';
        
$filesel join(n$selout);
    }

    echo 
'<div class="txp-list">';
    echo 
startTable('list');
    echo 
'<form method="post" action="?event='.$smd_ebook_event.'">';
    echo 
tr(tda(strong(smd_ebook_gTxt('smd_ebook_tidy'))));
    echo (
$filesel) ? tr(tda($filesel)) : tr(tda(smd_ebook_gTxt('smd_ebook_no_files')));
    echo 
tr(tda(fInput('submit''smd_ebook_cleanup'gTxt('delete'), 'publish'), ' class="noline"'));
    echo 
sInput('smd_ebook_tidy');
    echo 
tInput();
    echo 
'</form>';
    echo 
endTable();
    echo 
'</div>';
}

// ------------------------
// List of current stylesheets
function smd_ebook_style_list($name$val='') {
    
$styles safe_column('name''txp_css''1=1');
    return 
selectInput($name$styles$valtrue);
}

// ------------------------
// List of current file categories
function smd_ebook_file_cat_list($name$val='') {
    
$rs getTree('root''file');
    if (
$rs) {
        return 
treeSelectInput($name$rs$val$name);
    }
}

// ------------------------
// List of numbers for heading levels
function smd_ebook_number($name$val='') {
    
// Can't use range() since it creates indices starting at 0
    
$nums = array();
    for (
$idx 1$idx <= 6$idx++) {
        
$nums[$idx] = $idx;
    }
    return 
selectInput($name$nums$valfalse);
}

// ------------------------
// List of current sections
// TODO: multiple select?
function smd_ebook_section_list($name$val='') {
    
$secs safe_column('name''txp_section''1=1');
    return 
selectInput($name$secs$valtrue);
}

// ------------------------
// List of custom fields
function smd_ebook_fld_list($name$val='') {
    
$cfs getCustomFields();
    
$cfs['Title'] = gTxt('title');
    
$cfs['Excerpt_html'] = gTxt('excerpt');
    
$cfs['SMD_FIXED'] = smd_ebook_gTxt('smd_ebook_fixed');
    return 
selectInput($name$cfs$valtrue);
}

// ------------------------
// List of custom fields with a few extras
function smd_ebook_fld_list_plus($name$val='') {
    
$cfs getCustomFields();
    
$cfs['Title'] = gTxt('title');
    
$cfs['Excerpt_html'] = gTxt('excerpt');
    
$cfs['Category1'] = gTxt('category1');
    
$cfs['Category2'] = gTxt('category2');
    
$cfs['Section'] = gTxt('section');
    
$cfs['SMD_FIXED'] = smd_ebook_gTxt('smd_ebook_fixed');
    return 
selectInput($name$cfs$valtrue);
}

// ------------------------
// List of custom fields
function smd_ebook_fld_list_author($name$val='') {
    
$cfs getCustomFields();
    
$cfs['Title'] = gTxt('title');
    
$cfs['Excerpt_html'] = gTxt('excerpt');
    
$cfs['AuthorID'] = gTxt('author');
    
$cfs['SMD_FIXED'] = smd_ebook_gTxt('smd_ebook_fixed');
    return 
selectInput($name$cfs$valtrue);
}

// ------------------------
// Multi-select list of privilege levels
function smd_ebook_priv_list($name$val='') {
    
$grps get_groups();
    unset(
$grps['0']); // Remove 'none'
    
unset($grps['1']); // Remove publishers -- they get access to everything already

    
$sels do_list($val);

    
$ulist = array();
    
$ulist[] = '<select name="'.$name.'[]" id="'.$name.'" class="list multiple" multiple="multiple" size="6">';
    foreach (
$grps as $lvl => $grp) {
        
$selected in_array($lvl$sels) ? ' selected="selected"' '';
        
$ulist[] = '<option value="'.$lvl.'"'.$selected.'>' htmlspecialchars($grp) . '</option>';
    }
    
$ulist[] = '</select>';

    return 
join(n$ulist);
}

// ------------------------
// Mini diagnostics to see if the kindlegen program can be run on this host.
function smd_ebook_test() {
    global 
$smd_ebook_event$smd_ebook_prefs;

    
require_privs('plugin_prefs.'.$smd_ebook_event);

    
$out '';
    
$kgen get_pref('smd_ebook_kindlegen_path'$smd_ebook_prefs['smd_ebook_kindlegen_path']['default']);
    
exec($kgen$output$retval);

    if (
$retval != 0) {
        switch (
$retval) {
            case 
126:
                
$out smd_ebook_gTxt('smd_ebook_permissions_issue');
            break;
            case 
127:
                
$out smd_ebook_gTxt('smd_ebook_not_found');
            break;
            default:
                
$out smd_ebook_gTxt('smd_ebook_error_code', array('{code}' => $retval));
            break;
        }
        
$out print_r($outputtrue);
    } else {
        
$out smd_ebook_gTxt('smd_ebook_ok');
    }
    
$_POST['smd_ebook_test_output'] = $out;
    
$msg smd_ebook_gTxt('smd_ebook_test_complete');
    
smd_ebook_prefs($msg);
}

// ------------------------
// Handle the prefs panel
function smd_ebook_prefs($msg='') {
    global 
$smd_ebook_event$smd_ebook_prefs$smd_ebook_styles$step;

    
require_privs('plugin_prefs.'.$smd_ebook_event);

    if (
ps('smd_ebook_pref_save')) {
        foreach (
$smd_ebook_prefs as $idx => $prefobj) {
            
$val ps($idx);
            
$val = (is_array($val)) ? join(', '$val) : $val;
            
set_pref($idxdoSlash($val), 'smd_ebook'$prefobj['type'], $prefobj['html'], $prefobj['position']);
        }

        
$msg gTxt('preferences_saved');
    }

    
pagetop(smd_ebook_gTxt('smd_ebook_tab_name'), $msg);
    
extract(smd_ebook_buttons('prf'));

    
$btnbar = (has_privs('plugin_prefs.'.$smd_ebook_event))? '<span class="smd_ebook_buttons">'.$btnMgr.$btnPrf.$btnCln.'</span>' '';

    
// Inject styles
    
echo '<style type="text/css">' $smd_ebook_styles['cpanel'] . '</style>';

    echo <<<EOJS
<script type="text/javascript">
jQuery(function() {
    jQuery("select[name='smd_ebook_fld_title'], select[name='smd_ebook_fld_chaptitle'], select[name='smd_ebook_fld_author'], select[name='smd_ebook_fld_description'], select[name='smd_ebook_fld_authornote'], select[name='smd_ebook_fld_subject'], select[name='smd_ebook_fld_publisher'], select[name='smd_ebook_fld_srp']").change(function() {
        var xtra = jQuery(this).attr('name') + '_fixed';
        if (jQuery('option:selected', this).val() == 'SMD_FIXED') {
            jQuery("input[name='"+xtra+"']").parent().parent().show('normal');
        } else {
            jQuery("input[name='"+xtra+"']").parent().parent().hide('fast');
        }
    }).change();
});
</script>
EOJS;
    echo 
'<div id="'.$smd_ebook_event.'_control" class="txp-control-panel">' $btnbar '</div>';

    
$out = array();
    
$out[] = n.'<div class="txp-list">';
    
$out[] = '<form name="smd_ebook_prefs" id="smd_ebook_prefs" action="index.php" method="post">';
    
$out[] = eInput($smd_ebook_event).sInput('smd_ebook_prefs');
    
$out[] = startTable('list');
    
$last_grp '';
    foreach (
$smd_ebook_prefs as $idx => $prefobj) {
        if (
$last_grp != $prefobj['group']) {
            
$out[] = tr(tdcs(strong(smd_ebook_gTxt($prefobj['group'])), 2));
        }
        
$last_grp $prefobj['group'];
        
$subout = array();
        
$subout[] = tda('<label for="'.$idx.'">'.smd_ebook_gTxt($idx).'</label>'' class="noline" style="text-align: right; vertical-align: middle;"');
        
$val get_pref($idx$prefobj['default'], 1);
        
$vis = (isset($prefobj['visible']) && !$prefobj['visible']) ? 'smd_hidden' '';
        switch (
$prefobj['html']) {
            case 
'text_input':
                
$subout[] = tda(fInput('text'$idx$val''''''''''$idx),' class="noline"');
            break;
            case 
'yesnoradio':
                
$subout[] = tda(yesnoRadio($idx$val),' class="noline"');
            break;
            case 
'radioset':
                
$subout[] = tda(radioSet($prefobj['content'], $idx$val),' class="noline"');
            break;
            case 
'checkboxset':
                
$vals do_list($val);
                
$lclout = array();
                foreach (
$prefobj['content'] as $cb => $val) {
                    
$checked in_array($cb$vals);
                    
$lclout[] = checkbox($idx.'[]'$cb$checked). smd_ebook_gTxt($val);
                }
                
$subout[] = tda(join(n$lclout),' class="noline"');
            break;
            case 
'selectlist':
                
$subout[] = tda(selectInput($idx$prefobj['content'][0], $val$prefobj['content'][1]),' class="noline"');
            break;
            default:
                if ( 
strpos($prefobj['html'], 'smd_ebook_') !== false && is_callable($prefobj['html']) ) {
                    
$subout[] = tda($prefobj['html']($idx$val),' class="noline"');
                }
            break;
        }
        
$out[] = tr(join(,$subout), ' class="'.$vis.'"');
    }
    
$out[] = tr(tda('&nbsp;'' class="noline"') . tda($btnTst' class="noline"'));

    if (
$step == 'smd_ebook_test') {
        
$out[] = tr(tda('&nbsp;'' class="noline"') . tda(text_area('smd_ebook_test_results'150200ps('smd_ebook_test_output')), ' class="noline"'));
    }

    
$out[] = tr(tda('&nbsp;'' class="noline"') . tda(fInput('submit''smd_ebook_pref_save'gTxt('save'), 'publish'), ' class="noline"'));
    
$out[] = endTable().tInput();
    
$out[] = '</form></div>';

    echo 
join(n$out);
}

// ------------------------
// Delete plugin prefs
function smd_ebook_prefs_remove($showpane=1) {
    
$message '';

    
safe_delete('txp_prefs'"name like 'smd_ebook_%'");

    if (
$showpane) {
        
$message smd_ebook_gTxt('smd_ebook_prefs_deleted');
        
smd_ebook($message);
    }
}

// ------------------------
// Set up the global prefs for the plugin
function smd_ebook_get_prefs() {
    global 
$smd_ebook_prefs$prefs;

    
$smd_ebook_prefs = array(
        
'smd_ebook_uid' => array(
            
'html'     => 'text_input',
            
'type'     => PREF_HIDDEN,
            
'position' => 20,
            
'default'  => '',
            
'group'    => 'smd_ebook_settings',
        ),
        
'smd_ebook_page_break' => array(
            
'html'     => 'text_input',
            
'type'     => PREF_HIDDEN,
            
'position' => 30,
            
'default'  => '~~~~~',
            
'group'    => 'smd_ebook_settings',
        ),
        
'smd_ebook_toc_wraptag' => array(
            
'html'     => 'radioset',
            
'type'     => PREF_HIDDEN,
            
'position' => 40,
            
'content'  => array('ul' => smd_ebook_gTxt('smd_ebook_lbl_ul'), 'ol' => smd_ebook_gTxt('smd_ebook_lbl_ol')),
            
'default'  => 'ul',
            
'group'    => 'smd_ebook_settings',
        ),
        
'smd_ebook_toc_class' => array(
            
'html'     => 'text_input',
            
'type'     => PREF_HIDDEN,
            
'position' => 60,
            
'default'  => 'smd_ebook_toc',
            
'group'    => 'smd_ebook_settings',
        ),
        
'smd_ebook_section' => array(
            
'html'     => 'smd_ebook_section_list',
            
'type'     => PREF_HIDDEN,
            
'position' => 70,
            
'default'  => '',
            
'group'    => 'smd_ebook_settings',
        ),
        
'smd_ebook_stylesheet' => array(
            
'html'     => 'smd_ebook_style_list',
            
'type'     => PREF_HIDDEN,
            
'position' => 80,
            
'default'  => '',
            
'group'    => 'smd_ebook_settings',
        ),
        
'smd_ebook_textile' => array(
            
'html'     => 'checkboxset',
            
'type'     => PREF_HIDDEN,
            
'position' => 90,
            
'content'  => array('description' => 'smd_ebook_lbl_description''authornote' => 'smd_ebook_lbl_authornote'),
            
'default'  => '',
            
'group'    => 'smd_ebook_settings',
        ),
        
'smd_ebook_encoding' => array(
            
'html'     => 'text_input',
            
'type'     => PREF_HIDDEN,
            
'position' => 100,
            
'default'  => 'utf-8',
            
'group'    => 'smd_ebook_settings',
        ),
        
'smd_ebook_kindlegen_path' => array(
            
'html'     => 'text_input',
            
'type'     => PREF_HIDDEN,
            
'position' => 200,
            
'default'  => $prefs['path_to_site'].DS.'kindle'.DS.'kindlegen',
            
'group'    => 'smd_ebook_settings',
        ),
        
'smd_ebook_auto_toc' => array(
            
'html'     => 'yesnoradio',
            
'type'     => PREF_HIDDEN,
            
'position' => 10,
            
'default'  => '1',
            
'group'    => 'smd_ebook_pubset',
        ),
        
'smd_ebook_fld_title' => array(
            
'html'     => 'smd_ebook_fld_list',
            
'type'     => PREF_HIDDEN,
            
'position' => 20,
            
'default'  => 'Title',
            
'group'    => 'smd_ebook_pubset',
        ),
        
'smd_ebook_fld_title_fixed' => array(
            
'html'     => 'text_input',
            
'type'     => PREF_HIDDEN,
            
'position' => 25,
            
'default'  => '',
            
'group'    => 'smd_ebook_pubset',
            
'visible'  => false,
        ),
        
'smd_ebook_fld_chaptitle' => array(
            
'html'     => 'smd_ebook_fld_list',
            
'type'     => PREF_HIDDEN,
            
'position' => 30,
            
'default'  => '',
            
'group'    => 'smd_ebook_pubset',
        ),
        
'smd_ebook_fld_chaptitle_fixed' => array(
            
'html'     => 'text_input',
            
'type'     => PREF_HIDDEN,
            
'position' => 35,
            
'default'  => '',
            
'group'    => 'smd_ebook_pubset',
            
'visible'  => false,
        ),
        
'smd_ebook_fld_author' => array(
            
'html'     => 'smd_ebook_fld_list_author',
            
'type'     => PREF_HIDDEN,
            
'position' => 40,
            
'default'  => 'AuthorID',
            
'group'    => 'smd_ebook_pubset',
        ),
        
'smd_ebook_fld_author_fixed' => array(
            
'html'     => 'text_input',
            
'type'     => PREF_HIDDEN,
            
'position' => 45,
            
'default'  => '',
            
'group'    => 'smd_ebook_pubset',
            
'visible'  => false,
        ),
        
'smd_ebook_fld_description' => array(
            
'html'     => 'smd_ebook_fld_list',
            
'type'     => PREF_HIDDEN,
            
'position' => 50,
            
'default'  => '',
            
'group'    => 'smd_ebook_pubset',
        ),
        
'smd_ebook_fld_description_fixed' => array(
            
'html'     => 'text_input',
            
'type'     => PREF_HIDDEN,
            
'position' => 55,
            
'default'  => '',
            
'group'    => 'smd_ebook_pubset',
            
'visible'  => false,
        ),
        
'smd_ebook_fld_authornote' => array(
            
'html'     => 'smd_ebook_fld_list',
            
'type'     => PREF_HIDDEN,
            
'position' => 60,
            
'default'  => '',
            
'group'    => 'smd_ebook_pubset',
        ),
        
'smd_ebook_fld_authornote_fixed' => array(
            
'html'     => 'text_input',
            
'type'     => PREF_HIDDEN,
            
'position' => 65,
            
'default'  => '',
            
'group'    => 'smd_ebook_pubset',
            
'visible'  => false,
        ),
        
'smd_ebook_fld_subject' => array(
            
'html'     => 'smd_ebook_fld_list_plus',
            
'type'     => PREF_HIDDEN,
            
'position' => 70,
            
'default'  => '',
            
'group'    => 'smd_ebook_pubset',
        ),
        
'smd_ebook_fld_subject_fixed' => array(
            
'html'     => 'text_input',
            
'type'     => PREF_HIDDEN,
            
'position' => 75,
            
'default'  => '',
            
'group'    => 'smd_ebook_pubset',
            
'visible'  => false,
        ),
        
'smd_ebook_fld_publisher' => array(
            
'html'     => 'smd_ebook_fld_list_plus',
            
'type'     => PREF_HIDDEN,
            
'position' => 80,
            
'default'  => '',
            
'group'    => 'smd_ebook_pubset',
        ),
        
'smd_ebook_fld_publisher_fixed' => array(
            
'html'     => 'text_input',
            
'type'     => PREF_HIDDEN,
            
'position' => 85,
            
'default'  => '',
            
'group'    => 'smd_ebook_pubset',
            
'visible'  => false,
        ),
        
'smd_ebook_fld_srp' => array(
            
'html'     => 'smd_ebook_fld_list',
            
'type'     => PREF_HIDDEN,
            
'position' => 90,
            
'default'  => '',
            
'group'    => 'smd_ebook_pubset',
        ),
        
'smd_ebook_fld_srp_fixed' => array(
            
'html'     => 'text_input',
            
'type'     => PREF_HIDDEN,
            
'position' => 95,
            
'default'  => '',
            
'group'    => 'smd_ebook_pubset',
            
'visible'  => false,
        ),
        
'smd_ebook_currency' => array(
            
'html'     => 'text_input',
            
'type'     => PREF_HIDDEN,
            
'position' => 100,
            
'default'  => 'EUR',
            
'group'    => 'smd_ebook_pubset',
        ),
        
'smd_ebook_heading_level' => array(
            
'html'     => 'smd_ebook_number',
            
'type'     => PREF_HIDDEN,
            
'position' => 110,
            
'default'  => '2',
            
'group'    => 'smd_ebook_pubset',
        ),
        
'smd_ebook_file_cat' => array(
            
'html'     => 'smd_ebook_file_cat_list',
            
'type'     => PREF_HIDDEN,
            
'position' => 120,
            
'default'  => '',
            
'group'    => 'smd_ebook_pubset',
        ),
        
'smd_ebook_privs' => array(
            
'html'     => 'smd_ebook_priv_list',
            
'type'     => PREF_HIDDEN,
            
'position' => 10,
            
'default'  => '',
            
'group'    => 'smd_ebook_usrset',
        ),
        
'smd_ebook_opf_edit' => array(
            
'html'     => 'smd_ebook_priv_list',
            
'type'     => PREF_HIDDEN,
            
'position' => 20,
            
'default'  => '',
            
'group'    => 'smd_ebook_usrset',
        ),
    );
}

// ------------------------
function smd_ebook_gTxt($what$atts = array()) {
    
$lang = array(
        
'en-gb' => array(
            
'smd_ebook_auto_toc'              => 'Automatically create ToC anchors on headings',
            
'smd_ebook_currency'              => 'Default three-letter currency code',
            
'smd_ebook_deleted'               => 'Temporary files deleted',
            
'smd_ebook_encoding'              => 'Character set of document',
            
'smd_ebook_error_code'            => 'Status code {code} returned. Ensure the program was uploaded as Binary',
            
'smd_ebook_file_cat'              => 'Store files in category',
            
'smd_ebook_filed'                 => 'E-book filed as ID {id}',
            
'smd_ebook_fixed'                 => 'Static text',
            
'smd_ebook_fld_author'            => 'Get author from field',
            
'smd_ebook_fld_author_fixed'      => '&lfloor;_ Text',
            
'smd_ebook_fld_authornote'        => 'Get author notes from field',
            
'smd_ebook_fld_authornote_fixed'  => '&lfloor;_ Text',
            
'smd_ebook_fld_chaptitle'         => 'Get chapter titles from field',
            
'smd_ebook_fld_chaptitle_fixed'   => '&lfloor;_ Text',
            
'smd_ebook_fld_description'       => 'Get description from field',
            
'smd_ebook_fld_description_fixed' => '&lfloor;_ Text',
            
'smd_ebook_fld_publisher'         => 'Get publisher from field',
            
'smd_ebook_fld_publisher_fixed'   => '&lfloor;_ Text',
            
'smd_ebook_fld_srp'               => 'Get SRP (price) from field',
            
'smd_ebook_fld_srp_fixed'         => '&lfloor;_ Text',
            
'smd_ebook_fld_subject'           => 'Get subject (genre) from field',
            
'smd_ebook_fld_subject_fixed'     => '&lfloor;_ Text',
            
'smd_ebook_fld_title'             => 'Get book title from field',
            
'smd_ebook_fld_title_fixed'       => '&lfloor;_ Text',
            
'smd_ebook_from'                  => 'From',
            
'smd_ebook_heading_level'         => 'Chapter heading level',
            
'smd_ebook_generate_failed'       => 'E-book generation failed (exit status {code})',
            
'smd_ebook_generate_ok'           => 'E-book generation successful',
            
'smd_ebook_kindlegen_path'        => 'Path to kindlegen executable',
            
'smd_ebook_lbl_articles'          => 'Choose book article(s)',
            
'smd_ebook_lbl_author'            => 'Author',
            
'smd_ebook_lbl_authornote'        => 'Author notes',
            
'smd_ebook_lbl_chaptitle'         => 'Chapter titles',
            
'smd_ebook_lbl_cln'               => 'Tidy up',
            
'smd_ebook_lbl_create'            => 'Create',
            
'smd_ebook_lbl_description'       => 'Book description',
            
'smd_ebook_lbl_download'          => 'Download',
            
'smd_ebook_lbl_files'             => 'File manager',
            
'smd_ebook_lbl_generate'          => '(Re)generate',
            
'smd_ebook_lbl_mgr'               => 'E-book',
            
'smd_ebook_lbl_ol'                => 'Numeric list',
            
'smd_ebook_lbl_prf'               => 'Settings',
            
'smd_ebook_lbl_publisher'         => 'Publisher',
            
'smd_ebook_lbl_report'            => 'Build report',
            
'smd_ebook_lbl_srp'               => 'Price|Currency',
            
'smd_ebook_lbl_start'             => 'Welcome',
            
'smd_ebook_lbl_subject'           => 'Subject (genre)',
            
'smd_ebook_lbl_title'             => 'Book title',
            
'smd_ebook_lbl_to_files'          => 'Store file',
            
'smd_ebook_lbl_tst'               => 'Test kindlegen program',
            
'smd_ebook_lbl_ul'                => 'Standard list',
            
'smd_ebook_lbl_view'              => '[Preview]',
            
'smd_ebook_malformed'             => 'Could not process HTML from {file}. Malformed?',
            
'smd_ebook_no_files'              => 'No e-book files found',
            
'smd_ebook_not_filed'             => 'E-book NOT filed',
            
'smd_ebook_not_found'             => 'File not found. Check path?',
            
'smd_ebook_ok'                    => 'Everything looks OK',
            
'smd_ebook_opf_edit'              => 'Groups that can edit .opf',
            
'smd_ebook_page_break'            => 'Page break character sequence',
            
'smd_ebook_permissions_issue'     => 'Permissions problem. Is the file executable?',
            
'smd_ebook_prefs_deleted'         => 'Settings deleted',
            
'smd_ebook_preview_prefix'        => 'Preview of',
            
'smd_ebook_privs'                 => 'Groups that can publish',
            
'smd_ebook_pubset'                => 'Publishing',
            
'smd_ebook_stylesheet'            => 'Stylesheet to include with the book',
            
'smd_ebook_section'               => 'List articles from section',
            
'smd_ebook_settings'              => 'Plugin configuration',
            
'smd_ebook_tab_name'              => 'E-books',
            
'smd_ebook_test_complete'         => 'Test complete',
            
'smd_ebook_textile'               => 'Apply Textile to',
            
'smd_ebook_tidy'                  => 'Tidy up temporary e-book files',
            
'smd_ebook_toc'                   => 'Table of Contents',
            
'smd_ebook_toc_class'             => 'ToC CSS class name',
            
'smd_ebook_toc_wraptag'           => 'Render ToC as',
            
'smd_ebook_uid'                   => 'Unique ID',
            
'smd_ebook_updated'               => 'E-book info for file ID {id} updated',
            
'smd_ebook_usrset'                => 'Rights',
        ),
    );

    
$thislang get_pref('language''en-gb');
    
$exists = (isset($lang[$thislang][$what]));
    
$thislang $exists $thislang 'en-gb';
    return (
$exists) ? strtr($lang[$thislang][$what], $atts) : $what;
}