view admajax.php @ 1082:571ad3639468

Fix file uploads.
author Matti Hamalainen <ccr@tnsp.org>
date Wed, 25 Jan 2017 12:29:27 +0200
parents 7da8bde9b7be
children c4b93729269d
line wrap: on
line source

<?php
//
// FAPWeb - Simple Web-based Demoparty Management System
// Party administration page AJAX backend module
// (C) Copyright 2012-2017 Tecnic Software productions (TNSP)
//
$sessionType = "admin";
require_once "mconfig.inc.php";
require_once "msite.inc.php";
require_once "msession.inc.php";


// Define modes for entry editing code
define("EEMODE_NORMAL", 0);
define("EEMODE_EDIT", 1);
define("EEMODE_ADD", 2);


function stValidateRequestCompoData($full, $ctype)
{
  global $previewTypeList;

  $res = TRUE;

  stChkRequestItemFail("name", $fake, $res,
    array(CHK_ISGT, VT_STR, 0, "Compo name is empty."),
    array(CHK_LTEQ, VT_STR, SET_LEN_COMPO_NAME, "Compo name too long (%1 chars, must be less than %2)."));

  stChkRequestItemFail("description", $fake, $res,
    array(CHK_ISGT, VT_STR, 10, "Compo description too short (%1 chars, must be more than %2)"),
    array(CHK_LTEQ, VT_STR, SET_LEN_COMPO_DESC, "Compo description too long (%1 chars, must be less than %2)."));

  // Not a full check?
  if (!$full)
    return $res;

  // Check by compo type
  switch ($ctype)
  {
    case COMPO_NORMAL:
      stChkRequestItemFail("voting", $fake, $res,
        array(CHK_TYPE, VT_BOOL, "Invalid data."));

      stChkRequestItemFail("show_authors", $fake, $res,
        array(CHK_TYPE, VT_BOOL, "Invalid data."));

      stChkRequestItemFail("preview_type", $fake, $res,
        array(CHK_TYPE, VT_INT, "Invalid data."),
        array(CHK_ARRAY_KEY, $previewTypeList, "Invalid preview type value."));

      stChkRequestItemFail("cpath", $fake, $res,
        array(CHK_LTEQ, VT_STR, SET_LEN_COMPO_PATH, "Compo file path too long (%1 chars, must be less than %2)."));
      break;
  }

  stChkRequestItemFail("visible", $fake, $res,
    array(CHK_TYPE, VT_BOOL, "Invalid data."));

  return $res;
}


function stValidateRequestEntryData(&$compo_id, $full, $ctype)
{
  $res = TRUE;

  // Things common for all compo types
  stChkRequestItemFail("name", $fake, $res,
    array(CHK_ISGT, VT_STR, 0, "Name is empty."),
    array(CHK_LTEQ, VT_STR, SET_LEN_ENTRY_NAME, "Name too long (%1 chars, must be less than %2)."));

  stChkRequestItemFail("notes", $fake, $res,
    array(CHK_TYPE, VT_TEXT, "Invalid data."),
    array(CHK_LTEQ, VT_STR, SET_LEN_ENTRY_NOTES, "Entry notes are too long (%1 chars, must be less than %2)."));

  // Check based on compo type
  switch ($ctype)
  {
    case COMPO_NORMAL:
      stChkRequestItemFail("compo_id", $compo_id, $res,
        array(CHK_TYPE, VT_INT, "Invalid compo ID."));

      stChkRequestItemFail("author", $fake, $res,
        array(CHK_ISGT, VT_STR, 0, "Author name not set."),
        array(CHK_LTEQ, VT_STR, SET_LEN_ENTRY_AUTHOR, "Entry author too long (%1 chars, must be less than %2)."));

      stChkRequestItemFail("info", $fake, $res,
        array(CHK_TYPE, VT_TEXT, "Invalid data."),
        array(CHK_LTEQ, VT_STR, SET_LEN_ENTRY_INFO, "Entry info text too long (%1 chars, must be less than %2)."));

      if ($full)
      {
        stChkRequestItemFail("preview_type", $fake, $res,
          array(CHK_TYPE, VT_INT, "Invalid data."),
          array(CHK_RANGE, VT_INT, array(EPREV_NONE, EPREV_AUDIO), "Invalid preview type value."));
      }
      break;
    
    case COMPO_POINTS:
      stChkRequestItemFail("evalue", $fake, $res,
        array(CHK_TYPE, VT_INT, "Invalid points value, must be a valid integer."));
      break;

    case COMPO_ASSIGN:
      stChkRequestItemFail("evalue", $fake, $res,
        array(CHK_TYPE, VT_INT, "Invalid position, must be a valid integer."),
        array(CHK_GTEQ, VT_INT, 1, "Invalid position, must be >= %2."));
      break;
  }

  return $res;
}


function stValidateRequestNewsData()
{
  $res = TRUE;

  stChkRequestItemFail("text", $fake, $res,
    array(CHK_ISGT, VT_STR, 0, "News text too short."),
    array(CHK_LTEQ, VT_STR, SET_LEN_NEWS_TEXT, "News text too long (%1 chars, must be less than %2)."));

  stChkRequestItemFail("author", $fake, $res,
    array(CHK_ISGT, VT_STR, 0, "News author name not set."),
    array(CHK_LTEQ, VT_STR, SET_LEN_NEWS_AUTHOR, "News author name too long (%1 chars, must be less than %2)."));

  stChkRequestItemFail("title", $fake, $res,
    array(CHK_ISGT, VT_STR, 0, "News title not set."),
    array(CHK_LTEQ, VT_STR, SET_LEN_NEWS_TITLE, "News title too long (%1 chars. must be less than %2)."));

  return $res;
}


function stGetCompoData($id, $item, $prefix)
{
  global $compoModeData, $previewTypeList;

  switch ($item["ctype"])
  {
    case COMPO_NORMAL:
      $str1 = 
        "  File path: ".stGetFormTextInput(40, SET_LEN_COMPO_PATH, "cpath", $id, $prefix, $item["cpath"])."<br />\n";

      $str2 =
        "  ".stGetFormCheckBoxInput("voting", $id, $prefix, $item["voting"],
            "Enable voting", "onChange=\"setCompoData(".$id.",'voting')\"").
        "  ".stGetFormCheckBoxInput("show_authors", $id, $prefix, $item["show_authors"], "Show authors")."\n".
        "  ".stGetFormOptionListFromArray($prefix."preview_type".$id, "  ", FALSE, $previewTypeList, $item["preview_type"], 0, 0)."\n";
      break;

    default:
      $str1 = $str2 = "";
      break;
  }

  return
    "  <h2>#".$id." - ".chentities($item["name"])."</h2>\n".
    "  Type: ".stGetFormOptionListFromArray($prefix."type".$id, "  ", FALSE, $compoModeData, $item["ctype"], 0, 0, "updateCompoType(".$id.")").
    " - ".$compoModeData[$item["ctype"]][1]."<br />\n".
    "  Name: ".stGetFormTextInput(40, SET_LEN_COMPO_NAME, "name", $id, $prefix, $item["name"])."<br />\n".
    $str1.
    "<div class=\"compoDesc\"><h3>Description</h3>".stGetFormTextArea(8, 60, "description", $id, $prefix, $item["description"])."</div>\n".
    "<div class=\"compoDesc\"><h3>Notes (shown in results)</h3>".stGetFormTextArea(8, 60, "notes", $id, $prefix, $item["notes"])."</div>\n".
    "<div>\n".
    "  ".stGetFormCheckBoxInput("visible", $id, $prefix, $item["visible"], "Visible")."\n".
    $str2."\n".
    "  ".stGetFormButtonInput("update", $id, $prefix, "Update", "updateCompo(".$id.")")."\n".
    "  ".stGetFormButtonInput("delete", $id, $prefix, "Delete", "deleteCompo(".$id.")")."\n".
    "</div>\n";
}


function stGetNewsItemData($id, $item, $prefix)
{
  return
    "  <h2>".chentities($item["title"])."</h2>\n".
    "  ".stGetFormTextInput(40, SET_LEN_NEWS_TITLE, "title", $id, $prefix, $item["title"]).
    " - posted ".date("d M Y / H:i", $item["utime"])."<br />\n".
    "  ".stGetFormTextArea(5, 60, "text", $id, $prefix, $item["text"])."<br />\n".
    "  ".stGetFormTextInput(20, SET_LEN_NEWS_AUTHOR, "author",  $id, $prefix, $item["author"])."\n".
    "  ".stGetFormButtonInput("", "upd".$id, $prefix, "Update", "updateNews(".$id.")")."\n".
    "  ".stGetFormButtonInput("", "del".$id, $prefix, "Delete", "deleteNews(".$id.")")."\n";
}


function stGetFileUploadAndSelector($mode, $entry, $type, $file_id, $title)
{
  if ($mode == 2)
    return "";

  $eid = $entry["id"];
  $str = "<div class=\"editControl\"><span class=\"editControlTitle\">".chentities($title)."</span>\n";

  // Show currently selected / active file
  if (($efile = stFetchSQL("SELECT * FROM files WHERE deleted=0 AND id=".$entry[$file_id])) !== false)
  {
    $str .=
      "<div>File: <b>".chentities($efile["filename"])."</b></div>\n".
      "<div>Orig: <b>".chentities($efile["origname"])."</b></div>\n";
  }
  else
  {
    $str .= "<div>No file stored OR selected</div>\n";
  }

  if ($mode == 1)
  {
    // Show active file selection
    // XXX TODO .. $sql = stPrepareSQL("SELECT * FROM files WHERE uploadtype=%s AND entry_id=%d", $type, $eid);

    // Show upload form
    $handler = "admajax.php";
    $str .=
    "     ".stGetFormStart($type."UploadForm".$eid, $handler, FALSE, "enctype=\"multipart/form-data\" id=\"".$type."UploadForm".$eid."\"").
    "      ".stGetFormHiddenInput("action", "upload")."\n".
    "      ".stGetFormHiddenInput("type", $type)."\n".
    "      ".stGetFormHiddenInput("entry_id", $eid)."\n".
    "      <input type=\"file\" name=\"".$type."ToUpload".$eid."\" id=\"".$type."ToUpload".$eid."\">\n".
    "      ".stGetFormButtonInput($type."UploadButton", $eid, "", "Upload",
    "jsStartFileUpload('".$type."UploadForm".$eid."','".$handler."','".$type."ToUpload".$eid.
    "',".stGetSetting($type."MaxSize").", function() { updateEntry(".$entry["compo_id"].",".$eid.", 1) })")."\n".
    "     </form>\n";
  }

  return $str."</div>\n";
}


function stGetCompoVoting($compo, $outer)
{
  return
    ($outer ? "<span id=\"covoting".$compo["id"]."\">" : "").
    stGetFormCheckBoxInput(
    "votingbutton", $compo["id"], "co", $compo["voting"], "Voting ".($compo["voting"] ? "IS ACTIVE" : "disabled"),
    "class=\"votingactive\" onChange=\"updateCompoVoting(".$compo["id"].")\"", "").
    ($outer ? "</span>" : "");
}


function stPrintEntryItemData($item, $row, $tr, $prefix, $compo, $mode)
{
  global $entryFlagsList, $previewTypeList, $compoModeData;

  // Fetch compo data if we don't have it already
  $eid = $item["id"];
  if ($compo === FALSE)
    $compo = stFetchSQL("SELECT * FROM compos WHERE id=".$item["compo_id"]);

  // Output wrapper div only if requested
  if ($tr)
  {
    echo
      "  <div class=\"entryRow ".($row % 2 == 1 ? "rodd" : "reven").
      "\"".($mode == EEMODE_NORMAL ? " id=\"entry".$eid."\" onClick=\"activateEntry(".$eid.", false)\"" : "").">\n";
  }

  // Only show show_id if this is a normal compo and we are not adding
  if ($mode != EEMODE_ADD && $compo["ctype"] == COMPO_NORMAL)
  {
    echo
      "   <div class=\"entryCell entryShowID\">".($item["show_id"] > 0 ? $item["show_id"] : "-")."</div>\n";
  }
  
  switch ($compo["ctype"])
  {
    case COMPO_NORMAL:
      echo
      "   <div class=\"entryCell entryBasic\">\n".
      "   ".stGetEditFormTextInput($mode, "Name", 20, SET_LEN_ENTRY_NAME, "name", $eid, $prefix, $item["name"])."\n".
      "   ".stGetEditFormTextInput($mode, "Author", 20, SET_LEN_ENTRY_AUTHOR, "author", $eid, $prefix, $item["author"])."\n".
      "   </div>\n".
      "   <div class=\"entryCell entryFiles\">\n".
      ($mode == 2 ? "Files can be uploaded after adding the entry" : "").
      stGetFileUploadAndSelector($mode, $item, "entry", "file_id", "Entry file").
      stGetFileUploadAndSelector($mode, $item, "preview", "preview_id", "Preview file").
      "   </div>\n".
      "   <div class=\"entryCell entryNotes\">\n".
      "    ".stGetEditFormTextArea($mode, "Info shown during compo", 2, 35, "info", $eid, $prefix, $item["info"])."\n".
      "    ".stGetEditFormTextArea($mode, "Notes for internal use", 2, 35, "notes", $eid, $prefix, $item["notes"])."\n".
      "   </div>\n".
      "   <div class=\"entryCell\">\n";

      if ($mode == EEMODE_NORMAL || $mode == EEMODE_EDIT)
      {
        echo "   <div class=\"editControl entryPreview\">".
          "<span class=\"editControlTitle\">Preview</span>";
          $previewTypeList[$compo["preview_type"]][0]." / ";

        if ($mode)
          echo stGetFormOptionListFromArray($prefix."preview_type".$eid, "    ", FALSE, $previewTypeList, $item["preview_type"], 0, 1);
        else
          echo $previewTypeList[$item["preview_type"]][1];

        stPrintPreviewElements($compo, $item);

        echo "</div>\n";
      }

      if ($mode == EEMODE_EDIT)
      {
        $sql =
          "SELECT compos.*, ".
          "COUNT(DISTINCT entries.id) AS nentries ".
          "FROM compos LEFT JOIN entries ON compos.id=entries.compo_id ".
          "GROUP BY compos.id ".
          "ORDER BY compos.id DESC";

        echo
          "   <div class=\"editControl entryCompoID\">".
          "<span class=\"editControlTitle\">Compo</span>".
          stGetFormOptionListStart($prefix."compo_id".$eid, "    ", TRUE, 0);

        foreach (stExecSQL($sql) as $cdata)
        {
          echo stGetFormOptionListItem("     ",
            $cdata["id"],
            ($cdata["id"] == $item["compo_id"]),
            sprintf("%-20s (%d)", substr($cdata["name"], 0, 20), $cdata["nentries"])
            );
        }

        echo
          stGetFormOptionListEnd("    ", TRUE).
          "</div>\n";
      }
      
      echo "</div>\n";
      break;
    
    case COMPO_POINTS:
    case COMPO_ASSIGN:
      echo
      "   <div class=\"entryCell entryBase\">".
      stGetEditFormTextInput($mode, "Name", 15, SET_LEN_ENTRY_AUTHOR, "name", $eid, $prefix, $item["name"]).
      "</div>\n".
      "   <div class=\"entryCell entryEvalue\">".
      stGetEditFormTextInput($mode, $compoModeData[$compo["ctype"]][2], 5, SET_LEN_ENTRY_AUTHOR, "evalue", $eid, $prefix, $item["evalue"]).
      "</div>\n".
      "   <div class=\"entryCell entryNotes\">\n".
      "    ".stGetEditFormTextArea($mode, "Notes", 2, 30, "notes", $eid, $prefix, $item["notes"])."\n".
      "   </div>\n";
      break;
  }

/* XXX TODO .. flags disabled for now
  if ($mode == EEMODE_NORMAL || $mode == EEMODE_EDIT)
  {
    echo "   <div class=\"entryCell\">";
    foreach ($entryFlagsList as $flag => $fdata)
    {
      echo "     ".stGetFormCheckBoxInput("eflag".$flag, $eid, $prefix, ($item["flags"] & $flag), $fdata[0],
        $mode ? "" : " disabled=\"disabled\" ")."\n";
    }
    echo "   </div>\n";
  }
*/

  if ($mode != EEMODE_NORMAL)
  {
    echo "<div class=\"entryCell entryActions\">\n";
    switch ($mode)
    {
      case EEMODE_EDIT:
        echo
          stGetFormButtonInput("update", $eid, $prefix, "Update", "updateEntry(".$item["compo_id"].",".$eid.", 0)").
          stGetFormButtonInput("delete", $eid, $prefix, "Delete", "deleteEntry(".$item["compo_id"].",".$eid.")");
        break;
      
      case EEMODE_ADD:
        echo
          stGetFormButtonInput("add", $item["compo_id"], $prefix, "Add new", "addEntry(".$item["compo_id"].")");
        break;
    }
    echo "</div>\n";
  }

  if ($tr)
    echo "  </div>\n";
}


function stGetVoteKeyClass($item)
{
  global $setVoteKeyMode;
  
  switch ($setVoteKeyMode)
  {
    case VOTE_FREELY:
      $cond = 0;
      break;

    case VOTE_ACTIVATE:
      $cond = $item["active"];
      break;

    case VOTE_ASSIGN:
      $cond = $item["key_id"] > 0;
      break;
  }

  return "votekey ".($cond ? "vkeyActive" : "vkeyInactive");
}


function stGetVoteKeyInfo()
{
  $nkeys = stFetchSQLColumn("SELECT COUNT(*) FROM votekeys WHERE active=1");
  $totalKeys = stFetchSQLColumn("SELECT COUNT(*) FROM votekeys");
  
  $nvoters = stFetchSQLColumn("SELECT COUNT(DISTINCT(key_id)) FROM votes");

  return
    "Info: <b>".$nkeys."</b> of <b>".$totalKeys."</b> votekeys are activated. ".
    "Also, <b>".$nvoters."</b> keys have been used for voting.";
}


function stGetVoteKeyItemData($id, $item, $prefix)
{
  global $setVoteKeyMode, $setVoteKeyLen;

  switch ($setVoteKeyMode)
  {
    case VOTE_FREELY:
    case VOTE_ACTIVATE:
      $klen = $setVoteKeyLen - strlen($item["key"]);
      $str = sprintf(
        "<span class=\"keyid\">%03d</span>&nbsp;:&nbsp;".
        "<span class=\"keycode\">%s</span>",
        $id,
        (($klen > 0) ? str_repeat("&nbsp;", $klen) : "").$item["key"]);

      if ($setVoteKeyMode == VOTE_ACTIVATE)
      {
        $str .= stGetFormCheckBoxInput("active", $id, $prefix, $item["active"], FALSE,
          "class=\"keyactive\" onChange=\"voteKeySetActive(".$id.")\"", "");
      }
      
      return $str;

    case VOTE_ASSIGN:
      $str =
        "  <td class=\"name\">".chentities($item["name"])."</td>\n".
        "  <td class=\"groups\">".chentities($item["groups"])."</td>\n".
        "  <td class=\"vkeynum\">".
          stGetFormTextInput(5, 5, "key_id", $id, $prefix, $item["key_id"]).
          stGetFormButtonInput("assign", $id, $prefix, "Set", "voteKeyAssign(".$id.",1)");

        if ($item["key_id"] != 0)
          $str .= stGetFormButtonInput("clear", $id, $prefix, "Clear", "voteKeyAssign(".$id.",0)");
        
      $str .=
        "</td>\n".
        "  <td class=\"vkey\">";

      if ($item["key_id"] > 0)
        $str .= sprintf("<span class=\"keyid\">%03d</span>".
          "&nbsp;:&nbsp;<span class=\"keycode\">%s</span>",
          $item["key_id"], chentities($item["key"]));

      $str .= "</td>\n";
      return $str;
  }
}


function stGetInfoEntryData($show_id, $compo_id, $showNotes)
{
  if ($show_id > 0)
  {
    $sql = stPrepareSQL("SELECT * FROM entries WHERE show_id=%d AND compo_id=%d",
      $show_id, $compo_id);

    if (($entry = stFetchSQL($sql)) !== false)
    {
      // Entry show#/title/author information
      $str =
        "<div class=\"entryInfo\">#".$entry["show_id"]." - ".
        "<span class=\"entryName\">".chentities($entry["name"])."</span>".
        "<span class=\"entryBy\"> by </span>".
        "<span class=\"entryAuthor\">".chentities($entry["author"])."</span>".
        "</div>";

      // File information for quick reference
      if (($efile = stFetchSQL("SELECT * FROM files WHERE deleted=0 AND id=".$entry["file_id"])) !== false)
      {
        foreach (array("S" => "filename", "O" => "origname") as $ftitle => $fid)
        {
          $str .=
            "<div class=\"entryFile\">".
            "<span class=\"entryFileTitle\">".$ftitle.": </span>".
            "<span class=\"entryFileName\">".chentities($efile[$fid])."</span>".
            "</div>";
        }
      }
      else
        $str .= "<div class=\"entryFile\"><span class=\"entryFileName\">No file!</span></div>";

      // Show entry notes here too
      if ($showNotes)
        $str .= "<div class=\"entryNotes\">".chentities($entry["notes"])."</div>";

      return $str;
    }
  }
  return "-";
}


function stGetInfoCurrCompoData($indent)
{
  $compoID = stGetDisplayVar("compoID");
  if ($compoID > 0)
  {
    $sql = stPrepareSQL("SELECT * FROM compos WHERE id=%d", $compoID);
    if (($entry = stFetchSQL($sql)) !== false)
      $strCompo = chentities($entry["name"]);

    $strCurrEntry = stGetInfoEntryData(stGetDisplayVar("compoCurrEntry"), $compoID, TRUE);
    $strPrevEntry = stGetInfoEntryData(stGetDisplayVar("compoPrevEntry"), $compoID, FALSE);
  }
  else
    $strCompo = $strCurrEntry = $strCurrEntryFile = $strPrevEntry = "-";

  return
    $indent."<div class=\"entryData\">Compo: <b>".$strCompo."</b></div>\n".
    $indent."<div class=\"entryData\"><div class=\"entryDataTitle\">Current entry:</div>".$strCurrEntry."</div>\n".
    $indent."<div class=\"entryData\"><div class=\"entryDataTitle\">Previous entry:</div>".$strPrevEntry."</div>\n";
}


function stGetInfoCurrEntryList($indent, $outer)
{
  $sql = stPrepareSQL(
    "SELECT * FROM entries WHERE compo_id=%d ORDER BY show_id ASC",
    stGetDisplayVar("compoID"));

  $currShowID = stGetDisplayVar("compoCurrEntry");
  if ($currShowID <= 0)
    $currShowID = -1;

  $str = stGetFormOptionListStart("ctrlEntryList", $indent, $outer);

  if (($res = stExecSQL($sql)) !== false)
  {
    foreach ($res as $item)
    {
      $str .= stGetFormOptionListItem($indent."  ", $item["show_id"],
        ($item["show_id"] == $currShowID),
        sprintf("%3d. %-25s by %-15s",
          $item["show_id"],
          substr($item["name"], 0, 25),
          substr($item["author"], 0, 15)));
    }
  }
  
  return $str.stGetFormOptionListEnd($indent, $outer);
}


function stGetInfoRotationLists($indent, $outer)
{
  $sql =
    "SELECT rot_list_data.*, ".
    "(SELECT COUNT(*) FROM rot_list_slides WHERE list_id=rot_list_data.id) AS nslides ".
    "FROM rot_list_data ".
    "ORDER BY id DESC";

  $str = stGetFormOptionListStart("ctrlRotationLists", $indent, $outer);
  $currListID = stGetDisplayVar("rotateList");

  if (($res = stExecSQL($sql)) !== false)
  {
    foreach ($res as $item)
    {
      $str .= stGetFormOptionListItem($indent."  ", $item["id"],
        ($currListID == $item["id"]),
        $item["name"]." (".$item["nslides"]." slides)");
    }
  }

  return $str.stGetFormOptionListEnd($indent, $outer);
}


function stGetInfoDisplaySlides($indent, $outer)
{
  $str = stGetFormOptionListStart("ctrlDisplaySlides", $indent, $outer);

  $sql = "SELECT * FROM display_slides ORDER BY id DESC";
  if (($res = stExecSQL($sql)) !== false)
  {
    foreach ($res as $item)
      $str .= stGetFormOptionListItem($indent."  ", $item["id"], FALSE, $item["title"]);
  }

  return $str.stGetFormOptionListEnd($indent, $outer);
}


function stGetInfoRotationListEditFull($indent, $outer, $list_id)
{
  $sql = stPrepareSQL("SELECT * FROM rot_list_data WHERE id=%d", $list_id);
  if (($data = stFetchSQL($sql)) === false)
    return "<p>No such rotation list ID #".intval($list_id)."</p>";
  
  $str =
    ($outer ? $indent."<div class=\"ctrlBox\" id=\"ctrlRotationListEdit\">\n" : "").
    $indent."  <div class=\"ctrlTitle\">Edit rotation list</div>\n".
    $indent."  ".stGetFormTextInput(30, SET_LEN_ROT_LIST_NAME, "", "ctrlEDRotationListName", "", $data["name"])."\n".
    $indent."  ".stGetFormButtonInput("updname", "", "", "Save", "updateRotationList(".$list_id.")")."\n".
    "<div>Available slides:</div>\n".
    stGetFormOptionListStart("ctrlEDDisplaySlides", $indent."  ", TRUE);

  $sql = "SELECT * FROM display_slides";
  if (($res = stExecSQL($sql)) !== false)
  {
    foreach ($res as $item)
      $str .= stGetFormOptionListItem($indent."    ", $item["id"], FALSE, $item["title"]);
  }

  $str .=
    stGetFormOptionListEnd($indent."  ", TRUE).
    "<div>List content:</div>\n".
    stGetInfoRotationListEditData($indent."  ", TRUE, $list_id).
    $indent."  <div class=\"ctrlButtons\">\n".
//    $indent."    ".stGetFormButtonInput("moveslideup", "", "", "Move Up", "moveRotationListSlide(".$list_id.", -1)")."\n".
//    $indent."    ".stGetFormButtonInput("moveslidedn", "", "", "Move Down", "moveRotationListSlide(".$list_id.", 1)")."\n".
    $indent."    ".stGetFormButtonInput("addslide", "", "", "Add slide", "addRotationListSlide(".$list_id.")")."\n".
    $indent."    ".stGetFormButtonInput("delslide", "", "", "Remove slide", "removeRotationListSlide(".$list_id.")")."\n".
    $indent."    ".stGetFormButtonInput("closeedit", "", "", "Close", "jsCloseAdminPopup()")."\n".
    $indent."  </div>\n".
    ($outer ? $indent."</div>\n" : "");

  return $str;
}


function stGetInfoRotationListEditData($indent, $outer, $list_id)
{
  $sql = stPrepareSQL(
    "SELECT display_slides.*,rot_list_slides.order_num FROM display_slides ".
    "LEFT JOIN rot_list_slides ON display_slides.id=rot_list_slides.slide_id ".
    "WHERE rot_list_slides.list_id=%d ".
    "ORDER BY rot_list_slides.order_num DESC",
    $list_id);

  $str = stGetFormOptionListStart("ctrlEDRotationList", $indent, $outer);

  if (($res = stExecSQL($sql)) !== false)
  {
    foreach ($res as $item)
    {
      $str .= stGetFormOptionListItem($indent."  ", $item["id"]."_".$item["order_num"], FALSE, $item["title"]);
    }
  }

  return $str.stGetFormOptionListEnd($indent, $outer);
}


function stGetInfoActiveRotationList($indent, $outer)
{
  $sql = stPrepareSQL("SELECT * FROM rot_list_data WHERE id=%d",
    stGetDisplayVar("rotateList"));
  
  $str = $indent.($outer ? "<div id=\"ctrlActiveRotationList\">" : "").
    "<b>Active list:</b> ";

  if (($slist = stFetchSQL($sql)) === false)
    $str .= "-";
  else
    $str .= chentities(substr($slist["name"], 0, 40));

  return $str.($outer ? "</div>\n" : "");
}


function stGetInfoDisplaySlideEdit($indent, $outer, $slide_id)
{
  $prefix = "ctrlDisplaySlide";

  $str =
    ($outer ? "<div class=\"ctrlBox\" id=\"".$prefix."Edit\">\n" : "").
    $indent."  <form method=\"post\" action=\"\" onsubmit=\"return updateDisplaySlide(".$slide_id.")\">\n".
    $indent."    <div class=\"ctrlTitle\">Edit display slide</div>\n";

  $sql = stPrepareSQL("SELECT * FROM display_slides WHERE id=%d", $slide_id);
  if (($slide = stFetchSQL($sql)) !== false)
  {
    $str .=
      "    ".stGetFormTextInput(40, SET_LEN_DISP_SLIDE_TITLE, "", "Title", $prefix, $slide["title"])."<br />\n".
      "    ".stGetFormTextArea(10, 80, "", "Text", $prefix, $slide["text"])."<br />\n";
  }

  $str .=
    "    <div class=\"ctrlButtons\">\n".
    "      ".stGetFormSubmitInput("createslide", "Save slide")."\n".
    "      ".stGetFormButtonInput("cancelslide", "", "", "Close / Cancel", "jsCloseAdminPopup()")."\n".
    "    </div>\n".
    "  </form>\n".
    ($outer ? "</div>\n" : "");
  
  return $str;
}


function stGetSaveButton()
{
  return "<input type=\"submit\" value=\" Save \" />\n";
}


function stGetShowModeButton($mode, $name, $cmode)
{
  return
    "<input type=\"radio\" id=\"showMode".$mode.
    "\" name=\"showMode\" value=\"".$mode."\" ".
    "onChange=\"setShowMode(".$mode.")\" ".
    ($cmode == $mode ? "checked=\"checked\" ": "")."/>".
    "<label for=\"showMode".$mode."\">".chentities($name)."</label>";
}


function stRandomizeCompoShowOrder($compo_id, $patch)
{
  $entries = stExecSQL("SELECT id,show_id FROM entries WHERE compo_id=".$compo_id);
  if ($entries !== FALSE)
  {
    $ncount = stFetchSQLColumn("SELECT COUNT(*) FROM entries WHERE compo_id=".$compo_id." AND show_id<>0");
    $final = array();

    if ($patch && $ncount > 0)
    {
      $index = -1;
      foreach ($entries as $entry)
      {
        if ($entry["show_id"] == 0)
          $final[] = $entry["id"];

        if ($entry["show_id"] > $index)
          $index = $entry["show_id"];
      }

      $index++;
    }
    else
    {
      foreach ($entries as $entry)
        $final[] = $entry["id"];

      shuffle($final);
      $index = 1;
    }

    stDBBeginTransaction();
    foreach ($final as $entry)
    {
      $sql = stPrepareSQL("UPDATE entries SET show_id=%d WHERE id=%d", $index, $entry);
      if (stExecSQL($sql) === false)
      {
        stError("Error updating entry show positions.");
        break;
      }
      $index++;
    }
    stDBCommitTransaction();
  }
}


//
// Check if we are allowed to execute
//
if (!stCheckHTTPS() || !stAdmSessionAuth(TRUE) || !stCSRFCheck())
{
  stSetStatus(903, "Session expired.");
  stSetupCacheControl();
  stDumpAJAXStatusErrors();

  stSessionEnd(SESS_ADMIN);

  echo
    "<h1>Session expired</h1>".
    "<div><a href=\"admin.php\">Click here to relogin</a>.</div>\n";

  exit;
}


//
// Initialize
//
ob_start();

stSetupCacheControl();

if (!stConnectSQLDB())
  die("Could not connect to SQL database.");

stReloadSettings();
stReloadDisplayVars();
stSessionExpire(SESS_ADMIN, FALSE);


$setVoteKeyMode = stGetSetting("voteKeyMode");
$setVoteKeyLen = stGetSetting("userKeyLength");
$type = stGetRequestItem("type", "");
switch (stGetRequestItem("action", ""))
{
  case "upload":
    //
    // File upload
    //
    if (stHandleGenericFileUpload(0))
    {
      echo "File upload successful!";
      stSetStatus(902, "File successfully uploaded.");
    }
    break;

  case "randomize":
    //
    // Randomize entries display order
    //
    $patch = intval(stGetRequestItem("patch", 1));
    if ($type == "all")
    {
      if (($compos = stExecSQL("SELECT id FROM compos")) === FALSE)
        stError("Eh? SQL error occured.");
      else
      foreach ($compos as $compo)
        stRandomizeCompoShowOrder($compo["id"], $patch);
    }
    else
    if ($type == "compo")
    {
      if (stChkRequestItem("id", $compo_id, array(CHK_TYPE, VT_INT, "Invalid data.")))
        stRandomizeCompoShowOrder($compo_id, $patch);
    }
    break;

  case "screencmd":
    if (stChkRequestItem("cmd", $stmp, array(CHK_TYPE, VT_STR, "Invalid data.")))
    {
      stSetDisplayVar("screenCmdSet", TRUE);
      stSetDisplayVarUpd("screenCmd", $stmp);
    }
    break;

  case "check":
    //
    // Perform systems check
    //
    $errors = 0;
    echo
      "<h1>Competitions / voting</h1>\n".
      "<ul>\n";
    
    echo "<li>".(stGetSetting("allowVoting") ? "Voting <b>IS ENABLED</b>." : "Voting is NOT enabled!")."</li>\n";

    if (($compos = stExecSQL("SELECT * FROM compos")) === FALSE)
      stError("Eh? SQL error occured.");
    else
    {
      foreach ($compos as $compo)
      {
        $nentries = stFetchSQLColumn("SELECT COUNT(*) FROM entries WHERE show_id=0 AND compo_id=".$compo["id"]);
        if ($nentries > 0)
        {
          echo "<li>Compo <b>#".$compo["id"]." - ".$compo["name"]."</b> has NO show order set for some entries.</li>\n";
          $errors++;
        }
      }
    }
    
    $nenabled = stFetchSQLColumn("SELECT COUNT(*) FROM compos WHERE visible<>0 AND voting<>0");
    if ($nenabled == 0)
      echo "<li>No competitions that are visible and enabled for voting.</li>\n";

    $nenabled = stFetchSQLColumn("SELECT COUNT(*) FROM compos WHERE visible=0 AND voting<>0");
    if ($nenabled > 0)
      echo "<li>".$nenabled." competitions that are NOT visible, but are enabled for voting?</li>\n";

    // Count entries and compos
    $nentries = $ncompos = 0;
    foreach (stExecSQL("SELECT * FROM compos WHERE ctype=".COMPO_NORMAL) as $compo)
    {
      if (($ne = stFetchSQLColumn("SELECT COUNT(*) FROM entries WHERE compo_id=".$compo["id"])) !== false && $ne > 0)
      {
        $nentries += $ne;
        $ncompos++;
      }
    }
    if ($ncompos > 0)
      echo "<li>VOTING COMPOS: <b>".$nentries."</b> entries in <b>".$ncompos."</b> compos.</li>\n";

    $nentries = $ncompos = 0;
    foreach (stExecSQL("SELECT * FROM compos WHERE ctype <> ".COMPO_NORMAL) as $compo)
    {
      if (($ne = stFetchSQLColumn("SELECT COUNT(*) FROM entries WHERE compo_id=".$compo["id"])) !== false && $ne > 0)
      {
        $nentries += $ne;
        $ncompos++;
      }
    }
    if ($ncompos > 0)
      echo "<li>NON-VOTING COMPOS: <b>".$nentries."</b> entries/participants in <b>".$ncompos."</b> compos.</li>\n";

    
    if ($errors == 0)
      echo "<li>No errors/warnings detected.</li>\n";

    echo "</ul>\n";
    
    break;

  case "ctrl":
    //
    // Party information system control
    //
    stDBBeginTransaction();
    switch ($type)
    {
      case "setRotateDuration":
        if (stChkRequestItem("duration", $duration,
          array(CHK_TYPE, VT_INT, "Invalid data."),
          array(CHK_RANGE, VT_INT, array(5, 60), "Invalid slide time value, must be 5 - 60 seconds.")))
        {
          stSetDisplayVarUpd("rotateDuration", $duration);
        }
        break;

      case "setActiveRotationList":
        if (stChkRequestItem("id", $list_id, array(CHK_TYPE, VT_INT, "Invalid data.")))
        {
          stSetDisplayVarUpd("rotateList", $list_id);
        }
        break;

      case "setShowMode":
        if (stChkRequestItem("mode", $mode,
          array(CHK_TYPE, VT_INT, "Invalid data."),
          array(CHK_RANGE, VT_INT, array(SMODE_DISABLED, SMODE_COMPO), "Invalid mode value.")))
        {
          stSetDisplayVarUpd("showMode", $mode);
        }
        break;

      case "setCompoID":
        if (stChkRequestItem("id", $compo_id, array(CHK_TYPE, VT_INT, "Invalid data.")))
        {
          if (stFetchSQL("SELECT id FROM compos WHERE id=".$compo_id) === false)
            stError("Invalid compo ID ".$compo_id);
          else
          {
            stSetDisplayVarUpd("compoID", $compo_id);
            stSetDisplayVar("compoCurrEntry", 0);
            stSetDisplayVar("compoPrevEntry", 0);
          }
        }
        break;

      case "setEntry":
      case "nextEntry":
      case "prevEntry":
        if (($compo_id = stGetDisplayVar("compoID")) > 0)
        {
          $prev = $curr = stGetDisplayVar("compoCurrEntry");
          $nentries = stFetchSQLColumn("SELECT COUNT(*) FROM entries WHERE compo_id=".$compo_id);
          switch ($type)
          {
            case "setEntry":
              if (stChkRequestItem("index", $tmp,
                array(CHK_TYPE, VT_INT, "Invalid index.")))
                $curr = $tmp;
              break;

            case "nextEntry":
              if ($curr < $nentries)
                $curr++;
              break;

            case "prevEntry":
              if ($curr > 1)
                $curr--;
              break;
          }

          if (!$errorSet)
          {
            stSetDisplayVar("compoCurrEntry", $curr);
            if ($curr != $prev)
              stSetDisplayVar("compoPrevEntry", $prev);
            stDisplayUpdated();
          }
        }
        else
          stError("No valid competition set.");
        break;

      case "setTempSlide":
        if (stChkRequestItem("id", $slide_id, array(CHK_TYPE, VT_INT, "Invalid data.")) &&
            stChkRequestItem("duration", $slide_dur, array(CHK_RANGE, VT_INT, array(1, 60), "Invalid duration range, should be 1-60 min.")))
        {
          $sql = stPrepareSQL("SELECT * FROM display_slides WHERE id=%d", $slide_id);
          if (($slide = stFetchSQL($sql)) !== false)
          {
            stSetDisplayVar("tempDuration", $slide_dur);
            stSetDisplayVar("tempSlide", $slide["id"]);
            stSetDisplayVar("tempSlideSet", TRUE);
            echo "Temporary slide '".chentities($slide["title"])."' set for <b>".$slide_dur."</b> minutes.";
            stDisplayUpdated();
          }
          else
            stError("No such slide ID #".$slide_id);
        }
        break;

      case "skipToNextSlide":
        if (stGetDisplayVar("activeSlideMode") == SMODE_ROTATE)
        {
          stSetDisplayVar("activeSlideExpire", 0);
          stDisplayUpdated();
        }
        break;

      case "copyDisplaySlide":
        if (stChkRequestItem("id", $slide_id, array(CHK_TYPE, VT_INT, "Invalid data.")))
        {
          $sql = stPrepareSQL("SELECT * FROM display_slides WHERE id=%d", $slide_id);
          if (($slide = stFetchSQL($sql)) !== false)
          {
            $sql = stPrepareSQL("INSERT INTO display_slides (title,text) VALUES (%s,%s)",
              $slide["title"]." (copy)", $slide["text"]);

            if (($new_id = stExecSQLInsert($sql)) !== false)
              echo stGetInfoDisplaySlideEdit("", TRUE, $new_id);
            else
              stError("Could not insert slide.");
          }
          else
            stError("No such slide ID #".$slide_id);
        }
        break;

      case "newDisplaySlide":
        $sql = stPrepareSQL("INSERT INTO display_slides (title) VALUES (%s)", "New slide");
        if (($slide_id = stExecSQLInsert($sql)) !== false)
          echo stGetInfoDisplaySlideEdit("", TRUE, $slide_id);
        break;

      case "updateDisplaySlide":
        if (stChkRequestItem("id", $slide_id, array(CHK_TYPE, VT_INT, "Invalid data.")) &&
            stChkRequestItem("title", $fake,
              array(CHK_GTEQ, VT_STR, 1, "Slide title too short."),
              array(CHK_LTEQ, VT_STR, SET_LEN_DISP_SLIDE_TITLE, "Slide title too long.")
            ) &&
            stChkRequestItem("text", $fake,
              array(CHK_LTEQ, VT_STR, SET_LEN_DISP_SLIDE_TEXT, "Slide content too long.")
            ))
        {
          $sql = stPrepareSQLUpdate("display_slides",
            "WHERE id=".$slide_id,
            array(
              "title" => "S",
              "text" => "S",
            ));

          if (stExecSQL($sql) !== false)
          {
            stSetStatus(200, "Slide updated.");
            stDisplayUpdated();
          }
        }
        break;

      case "deleteDisplaySlide":
        if (stChkRequestItem("id", $slide_id, array(CHK_TYPE, VT_INT, "Invalid data.")))
        {
          $sql = stPrepareSQL("DELETE FROM display_slides WHERE id=%d", $slide_id);
          stExecSQLCond($sql, "Slide deleted.");

          $sql = stPrepareSQL("DELETE FROM rot_list_slides WHERE slide_id=%d", $slide_id);
          stExecSQLCond($sql, "Slide list refs deleted.");
          stDisplayUpdated();
        }
        break;

      case "newRotationList":
        $sql = stPrepareSQL("INSERT INTO rot_list_data (name) VALUES (%s)", "New list #");
        if (($list_id = stExecSQLInsert($sql)) !== false)
        {
          $sql = stPrepareSQL("UPDATE rot_list_data SET name=%s WHERE id=%d",
            "New list #".$list_id, $list_id);

          if (stExecSQLCond($sql, "OK!") !== false)
            echo stGetInfoRotationListEditFull("", TRUE, $list_id);
        }
        break;

      case "updateRotationList":
        if (stChkRequestItem("id", $list_id, array(CHK_TYPE, VT_INT, "Invalid data.")) &&
            stChkRequestItem("name", $fake,
              array(CHK_GTEQ, VT_STR, 3, "Rotation list name too short."),
              array(CHK_LTEQ, VT_STR, SET_LEN_ROT_LIST_NAME, "Rotation list name too long.")))
        {
          $sql = stPrepareSQLUpdate("rot_list_data",
            "WHERE id=".$list_id,
            array(
              "name" => "S",
            ));

          stExecSQLCond($sql, "OK, list updated.");
          stDisplayUpdated();
        }
        stDisplayUpdated();
        break;

      case "deleteRotationList":
        if (stChkRequestItem("id", $list_id, array(CHK_TYPE, VT_INT, "Invalid data.")))
        {
          $sql = stPrepareSQL("DELETE FROM rot_list_data WHERE id=%d", $list_id);
          stExecSQLCond($sql, "List data deleted.");

          $sql = stPrepareSQL("DELETE FROM rot_list_slides WHERE list_id=%d", $list_id);
          stExecSQLCond($sql, "List slide refs deleted.");
          stDisplayUpdated();
        }
        break;

      case "moveRotationListSlide":
        if (stChkRequestItem("list_id", $list_id, array(CHK_TYPE, VT_INT, "Invalid data.")) &&
            stChkRequestItem("slide_id", $slide_id, array(CHK_TYPE, VT_INT, "Invalid data.")) &&
            stChkRequestItem("order_num", $order_num, array(CHK_TYPE, VT_INT, "Invalid data.")) &&
            stChkRequestItem("dir", $dir, array(CHK_TYPE, VT_INT, "Invalid data.")))
        {
        }
        break;

      case "addRotationListSlide":
        if (stChkRequestItem("list_id", $list_id, array(CHK_TYPE, VT_INT, "Invalid data.")) &&
            stChkRequestItem("slide_id", $slide_id, array(CHK_TYPE, VT_INT, "Invalid data.")))
        {
          $nslides = stFetchSQLColumn(stPrepareSQL("SELECT COUNT(*) FROM rot_list_slides WHERE list_id=%d", $list_id));
          $sql = stPrepareSQL(
            "INSERT INTO rot_list_slides (list_id,slide_id,order_num) VALUES (%d,%d,%d)",
            $list_id, $slide_id, $nslides+1);

          if (stExecSQLCond($sql, "Slide added to list."))
          {
            stNormalizeListSlideOrder($list_id);
            stDisplayUpdated();
          }
        }
        break;

      case "removeRotationListSlide":
        if (stChkRequestItem("list_id", $list_id, array(CHK_TYPE, VT_INT, "Invalid data.")) &&
            stChkRequestItem("slide_id", $slide_id, array(CHK_TYPE, VT_INT, "Invalid data.")) &&
            stChkRequestItem("order_num", $order_num, array(CHK_TYPE, VT_INT, "Invalid data.")))
        {
          $sql = stPrepareSQL("DELETE FROM rot_list_slides WHERE list_id=%d AND slide_id=%d AND order_num=%d",
            $list_id, $slide_id, $order_num);
          
          if (stExecSQLCond($sql, "List slide refs deleted."))
          {
            stNormalizeListSlideOrder($list_id);
            stDisplayUpdated();
          }
        }
        break;
    }
    stDBCommitTransaction();
    break;

  case "get":
    //
    // Get specific data
    //
    switch ($type)
    {
      case "infoCurrCompoData":
        echo stGetInfoCurrCompoData("", FALSE);
        break;

      case "infoCurrEntryList":
        echo stGetInfoCurrEntryList("", FALSE);
        break;
      
      case "infoRotationLists":
        echo stGetInfoRotationLists("", FALSE);
        break;
    
      case "infoDisplaySlides":
        echo stGetInfoDisplaySlides("", FALSE);
        break;

      case "infoRotationListEdit":
        if (stChkRequestItem("id", $list_id, array(CHK_TYPE, VT_INT, "Invalid data.")))
          echo stGetInfoRotationListEditFull("", stGetRequestItem("full", TRUE), $list_id);
        break;

      case "infoRotationListEditData":
        if (stChkRequestItem("id", $list_id, array(CHK_TYPE, VT_INT, "Invalid data.")))
          echo stGetInfoRotationListEditData("", FALSE, $list_id);
        break;

      case "infoDisplaySlideEdit":
        if (stChkRequestItem("id", $slide_id, array(CHK_TYPE, VT_INT, "Invalid data.")))
          echo stGetInfoDisplaySlideEdit("", TRUE, $slide_id);
        break;

      case "infoActiveRotationList":
        echo stGetInfoActiveRotationList("", FALSE);
        break;

      case "infoMain":
        //
        // Main information control screen
        //
        $showMode = stGetDisplayVar("showMode");
        echo
          "<div id=\"ctrlModeControls\" class=\"ctrlModeControls\">\n".
          "Active mode:\n".
          stGetShowModeButton(SMODE_DISABLED, "Off/disabled", $showMode)."\n".
          stGetShowModeButton(SMODE_ROTATE, "Slide rotation", $showMode)."\n".
          stGetShowModeButton(SMODE_COMPO, "Compo mode", $showMode)."\n".
          stGetFormButtonInput("openShowScreen", "", "", "Showscreen window", "window.open('show.php')")."\n".
          stGetFormButtonInput("reloadShowScreen", "", "", "Showscreen reload", "showScreenCmd('reload')")."\n".
          //"</div>\n".
          //"<div id=\"ctrlSystemControls\">\n".
          stGetFormButtonInput("systemCheck", "", "", "System check", "performSystemCheck()")."\n".
          stGetFormButtonInput("generateShowPositions", "", "", "Add show positions", "generateEntryPositions(0, 1)")."\n".
          // XXX: disable this button for now
          // stGetFormButtonInput("regenerate", "", "", "RESET show positions", "generateEntryPositions(0, 0)")."\n".
          "</div>\n";

        echo
          "<div class=\"ctrlBox\" id=\"ctrlListRotationLists\">\n".
          "  <div class=\"ctrlTitle\">Rotation lists:</div>\n".
          "  <div class=\"ctrlInfo\">Lists of slides, that are shown for X seconds and 'rotated' to next one.</div>\n".
          stGetInfoRotationLists("    ", TRUE).
          "  <div class=\"ctrlButtons\">\n".
          "    ".stGetFormButtonInput("setdur", "", "", "Set", "setRotateDuration()")."\n".
          "    ".stGetFormTextInput(3, 5, "", "ctrlRotSlideDuration", "", stGetDisplayVar("rotateDuration"))." sec\n".
          " - ".
          "    ".stGetFormButtonInput("actlist", "", "", "Set Active", "setActiveRotationList()")."\n".
          "    ".stGetFormButtonInput("editlist", "", "", "Edit", "editRotationList()")."\n".
          "    ".stGetFormButtonInput("newlist", "", "", "New", "newRotationList()")."\n".
          "    ".stGetFormButtonInput("dellist", "", "", "Delete", "deleteRotationList()")."\n".
          "  </div>\n".
          stGetInfoActiveRotationList("  ", TRUE).
          "</div>\n";

        echo
          "<div class=\"ctrlBox\" id=\"ctrlListDisplaySlides\">\n".
          "<div class=\"ctrlTitle\">Display slides:</div>\n".
          "  <div class=\"ctrlInfo\">Editable slides (think 'powerpoint') for information/announcements. ".
          "Can be collected into slide rotations or set to display as 'temp slide' at any given time.</div>\n".
          stGetInfoDisplaySlides("  ", TRUE).
          "  <div class=\"ctrlButtons\">\n".
          "    ".stGetFormButtonInput("editslide", "", "", "Edit", "editDisplaySlide()")."\n".
          "    ".stGetFormButtonInput("copyslide", "", "", "Copy", "copyDisplaySlide()")."\n".
          "    ".stGetFormButtonInput("newslide", "", "", "New", "newDisplaySlide()")."\n".
          "    ".stGetFormButtonInput("delslide", "", "", "Delete", "deleteDisplaySlide()")."\n".
          "  </div>\n".
          "  <div class=\"ctrlButtons\">\n".
          "    ".stGetFormTextInput(3, 5, "", "ctrlTempSlideDuration", "", stGetDisplayVar("tempDuration"))." min\n".
          "    ".stGetFormButtonInput("setslide", "", "", "Set Temp", "activateTempSlide()")."\n".
          "    ".stGetFormButtonInput("nextslide", "", "", "Skip to next", "skipToNextSlide()")."\n".
          "  </div>\n".
          "</div>\n".
          "<div class=\"ctrlBox\" id=\"ctrlCompoControl\">\n".
          "  <div class=\"ctrlTitle\">Competition control:</div>\n".
          "  <div class=\"ctrlInfo\">Controls for competition showing mode. Select and activate desired compo, then ".
          "hit 'Next entry' to activate the first entry to show. <b>Notice! You need to have generated 'show positions' ".
          "before starting compos!</b></div>\n".
          "  <div class=\"ctrlDBox1\">\n".
          stGetFormOptionListStart("ctrlCompoList", "    ", TRUE);

        $sql =
          "SELECT compos.*, ".
          "COUNT(DISTINCT entries.id) AS nentries ".
          "FROM compos LEFT JOIN entries ON compos.id=entries.compo_id ".
          "GROUP BY compos.id ".
          "HAVING COUNT(DISTINCT entries.id) > 0 AND compos.ctype=".COMPO_NORMAL." ".
          "ORDER BY compos.id DESC";

        $currCompoID = stGetDisplayVar("compoID");
        if (($res = stExecSQL($sql)) !== false)
        {
          foreach ($res as $item)
          {
            echo stGetFormOptionListItem("     ", $item["id"],
              ($item["id"] == $currCompoID),
              sprintf("%-20s (%d entries)", substr($item["name"], 0, 20), $item["nentries"]));
          }
        }

        echo
          stGetFormOptionListEnd("    ", TRUE).
          "    <div class=\"ctrlButtons\">\n".
          "      ".stGetFormButtonInput("setcompo", "", "", "Change compo", "activateCompo()")."\n".
          "    </div>\n".
          "  </div>\n".
          "  <div class=\"ctrlDBox1\">\n".
          stGetInfoCurrEntryList("    ", TRUE).
          "    <div class=\"ctrlButtons\">\n".
          "      ".stGetFormButtonInput("setentry", "", "", "Set selected entry", "setSelectedEntry()")."\n".
          "      ".stGetFormButtonInput("preventry", "", "", "Prev entry", "switchEntry(-1)")."\n".
          "      ".stGetFormButtonInput("nextentry", "", "", "Next entry", "switchEntry(1)")."\n".
          "    </div>\n".
          "  </div>\n".
          "  <div class=\"ctrlDBox2\" id=\"ctrlCurrCompoData\">\n".
          stGetInfoCurrCompoData("    ").
          "  </div>\n".
          "</div>\n";
          stGetInfoRotationListEditFull("", TRUE, 0);
        break;

      case "news":
        echo
          "<form method=\"post\" action=\"\" onsubmit=\"return addNews()\">\n".
          "  ".stGetFormTextInput(40, SET_LEN_NEWS_TITLE, "", "nntitle", "", "")."<br />\n".
          "  ".stGetFormTextArea(5, 60, "", "nntext", "", "")."<br />\n".
          "  ".stGetFormTextInput(20, SET_LEN_NEWS_AUTHOR, "", "nnauthor", "", "orgaz")."\n".
          "  ".stGetFormSubmitInput("nnadd", "Add post")."\n".
          "  ".stGetFormButtonInput("", "", "", "Clear", "this.form.reset()")."\n".
          "</form>\n".
          "<hr />\n";

        $sql = "SELECT * FROM news ORDER BY utime DESC";
        foreach (stExecSQL($sql) as $item)
        {
          echo
            "<div id=\"news".$item["id"]."\" class=\"newsItem\">\n".
            stGetNewsItemData($item["id"], $item, "ne").
            "</div>\n";
        }
        break;

      case "newsitem":
        $res = stFetchSQL(stPrepareSQL("SELECT * FROM news WHERE id=%D", "id"));
        if ($res !== FALSE)
          echo stGetNewsItemData($res["id"], $res, "ne");
        break;

      case "attendees":
        echo
          "<div class=\"tabHeadersSub\">\n".
          "<a href=\"print.php?type=emails\" target=\"_blank\">Show plain list of e-mails</a>\n".
          "</div>\n";

        // For adding a new one
        $prefix = "ne";
        echo
          "<table>\n".
          " <tr>\n".
          "  <th>Name</th>\n".
          "  <th>Groups</th>\n".
          "  <th>Oneliner</th>\n".
          "  <th>E-mail</th>\n".
          "  <th>Actions</th>\n".
          " </tr>\n".
          " <tr>\n".
          "  <td>".stGetFormTextInput(20, SET_LEN_USERNAME, "name", "x", $prefix, "")."</td>\n".
          "  <td>".stGetFormTextInput(20, SET_LEN_GROUPS,   "groups", "x", $prefix, "")."</td>\n".
          "  <td>".stGetFormTextInput(30, SET_LEN_ONELINER, "oneliner", "x", $prefix, "")."</td>\n".
          "  <td>".stGetFormTextInput(20, SET_LEN_EMAIL,    "email", "x", $prefix, "")."</td>\n".
          "  <td>".stGetFormButtonInput("add", "", $prefix, " Add new ", "addAttendee()")."</td>\n".
          " </tr>\n".
          "</table>\n".
          "<hr />\n";

        // List of attendees
        echo
          "<table class=\"attendees\">\n".
          " <tr>\n".
          "  <th class=\"name\">Name</th>\n".
          "  <th class=\"groups\">Groups</th>\n".
          "  <th class=\"regtime\">Registered</th>\n".
          "  <th class=\"oneliner\">Oneliner</th>\n".
          "  <th class=\"email\">E-mail</th>\n".
          "  <th class=\"reghost\">RegHost</th>\n".
          "  <th>Actions</th>\n".
          " </tr>\n";

        $sql = "SELECT * FROM attendees ORDER BY regtime DESC";
        $row = 0;
        foreach (stExecSQL($sql) as $item)
          stPrintAttendee($item, $row++, TRUE, TRUE, FALSE);

        echo
          "</table>\n";
        break;

      case "attendee":
        $res = stFetchSQL(stPrepareSQL("SELECT * FROM attendees WHERE id=%D", "id"));
        if ($res !== FALSE)
          stPrintAttendee($res, -1, FALSE, TRUE, stGetRequestItem("edit", FALSE));
        else
          stError("No such attendee ID!");
        break;

      case "votekeyinfo":
        echo stGetVoteKeyInfo();
        break;

      case "votekey":
      case "votekeyclass":
        switch ($setVoteKeyMode)
        {
          case VOTE_FREELY:
          case VOTE_ACTIVATE:
            $sql = stPrepareSQL("SELECT * FROM votekeys WHERE id=%D", "id");
            break;

          case VOTE_ASSIGN:
            $sql = stPrepareSQL("SELECT votekeys.key,attendees.* FROM attendees ".
              "LEFT JOIN votekeys ON votekeys.id=attendees.key_id ".
              "WHERE attendees.id=%D", "id");
              break;
        }
        if (($res = stFetchSQL($sql)) !== FALSE)
        {
          if ($type == "votekeyclass")
            echo stGetVoteKeyClass($res);
          else
            echo stGetVoteKeyItemData($res["id"], $res, "vk");
        }
        break;

      case "voters":
        // Generate vote keys, if needed
        $numVKeys = stFetchSQLColumn("SELECT COUNT(*) FROM votekeys");
        $numUsers = stFetchSQLColumn("SELECT COUNT(*) FROM attendees");
        if (($tmp = stGetSetting("maxAttendeesHard")) > $numUsers)
          $numUsers = $tmp;
        else
        if (($tmp = stGetSetting("maxAttendeesSoft")) > $numUsers)
          $numUsers = $tmp;

        while ($numVKeys <= $numUsers)
        {
          if (($key = stGenerateUserKey()) !== false)
          {
            if (stExecSQL(stPrepareSQL("INSERT INTO votekeys (key) VALUES (%s)", $key)) !== false)
              $numVKeys++;
          }
        }

        // Some information
        echo
          "<div class=\"tabHeadersSub\">\n".
          " <a href=\"print.php?type=votekeys\" target=\"_blank\">Show printable key list</a>\n".
          " <a href=\"print.php?type=results&flags=".(RFLAG_NORMAL)."\" target=\"_blank\">Printable results</a>\n".
          " <a href=\"print.php?type=results&flags=".(RFLAG_DISQUALIFIED)."\" target=\"_blank\">Printable full results</a> (shows also disqualified entries)\n".
          " <a href=\"print.php?type=results&flags=".(RFLAG_DISQUALIFIED | RFLAG_HIDDEN_COMPOS)."\" target=\"_blank\">Printable FULL results</a> (shows also hidden and empty compos)\n".
          " <div id=\"vkeyInfo\">".stGetVoteKeyInfo()."</div>\n".
          "</div>\n";

        echo
          "<div class=\"info\"><b>Voting mode: ";
        
        if (isset($voteModeData[$setVoteKeyMode]))
          echo $voteModeData[$setVoteKeyMode][0]."</b>. ".$voteModeData[$setVoteKeyMode][1];
        else
          echo "VOTE MODE NOT SET! CHECK CONFIGURATION!</b>";

        echo "</div>\n";

        // List of votekeys
        switch ($setVoteKeyMode)
        {
          case VOTE_FREELY:
          case VOTE_ACTIVATE:
            $sql = "SELECT * FROM votekeys ORDER BY votekeys.id ASC";

            foreach (stExecSQL($sql) as $item)
            {
              echo
                "<div class=\"".stGetVoteKeyClass($item).
                "\" id=\"vkey".$item["id"]."\">".
                stGetVoteKeyItemData($item["id"], $item, "vk").
                "</div>\n";
            }
            break;

          case VOTE_ASSIGN:
            $sql = "SELECT votekeys.key,attendees.* FROM attendees ".
              "LEFT JOIN votekeys ON votekeys.id=attendees.key_id ".
              "ORDER BY attendees.regtime DESC";

            echo
              "<table class=\"attendees\">\n".
              " <tr>\n".
              "  <th class=\"name\">Name</th>\n".
              "  <th class=\"groups\">Groups</th>\n".
              "  <th class=\"vkeynum\">Key #</th>\n".
              "  <th class=\"vkey\">Votekey</th>\n".
              " </tr>\n";

            $index = 0;
            foreach (stExecSQL($sql) as $item)
            {
              echo
                " <tr class=\"".stGetVoteKeyClass($item).
                "\" id=\"vkey".$item["id"]."\">\n".
                stGetVoteKeyItemData($item["id"], $item, "vk").
                " </tr>\n";
            }

            echo
              "</table>\n";
            break;
        }
        break;

      case "compos":
        echo
          "<form method=\"post\" action=\"\" onsubmit=\"return addCompo()\">\n".
          "<b>Name:<b>".
          "  ".stGetFormTextInput(64, SET_LEN_COMPO_NAME, "", "ncname", "", "")."<br />\n".
          "<b>Description:</b>".
          "  ".stGetFormTextArea(5, 60, "", "ncdescription", "", "")."<br />\n".
          "  ".stGetFormSubmitInput("nccompo", "Add compo")."\n".
          "  ".stGetFormButtonInput("", "", "", "Clear", "this.form.reset()")."\n".
          "</form>\n".
          "<hr />\n";

        $sql = "SELECT * FROM compos ORDER BY id DESC";
        foreach (stExecSQL($sql) as $item)
        {
          echo
            "<div id=\"compo".$item["id"]."\" class=\"compoItem\">\n".
            stGetCompoData($item["id"], $item, "co").
            "</div>\n";
        }
        break;

      case "compo":
        $res = stFetchSQL(stPrepareSQL("SELECT * FROM compos WHERE id=%D", "id"));
        if ($res !== FALSE)
          echo stGetCompoData($res["id"], $res, "co");
        else
          stError("No such compo ID!");
        break;

      case "settingslist":
        $index = 0;
        foreach (stExecSQL("SELECT * FROM settings_groups") as $group)
        {
          if ($index++ > 0) echo ",";
          echo "\"".$group["id"]."\":\"".chentities($group["name"])."\"";
        }
        break;

      case "settings":
        $group = stFetchSQL(stPrepareSQL("SELECT * FROM settings_groups WHERE id=%D", "id"));
        if ($group !== FALSE)
        {
          $prefix = "st";
          $first = TRUE;
          echo
            "<h1>".chentities($group["description"])."</h1>\n".
            "<form method=\"post\" action=\"\" onsubmit=\"return jsUpdateSettings(".$group["id"].")\">\n";

          foreach (stExecSQL("SELECT * FROM settings WHERE vtype<>".VT_TEXT." AND vgroup=".$group["id"]." ORDER BY vtype ASC") as $item)
          {
            if ($first)
            {
              echo "<table>\n";
              $first = FALSE;
            }

            echo
              " <tr>\n".
              "  <td>";

            $id = $item["key"];
            switch ($item["vtype"])
            {
              case VT_INT:
                echo stGetFormTextInput(10, 10, "", $id, $prefix, $item["vint"]);
                break;
              case VT_STR:
                echo stGetFormTextInput(40, 128, "", $id, $prefix, $item["vstr"]);
                break;
              case VT_BOOL:
                echo stGetFormCheckBoxInput("", $id, $prefix, $item["vint"], "");
                break;
            }
            echo
              "</td>\n".
              "  <td><label for=\"".$prefix.$id."\">".chentities($item["sdesc"])."</label></td>\n".
              " </tr>\n";
          }
          if (!$first)
            echo "</table>\n".stGetSaveButton();

          foreach (stExecSQL("SELECT * FROM settings WHERE vtype=".VT_TEXT." AND vgroup=".$group["id"]." ORDER BY key DESC") as $item)
          {
            echo
              "<h2>".chentities($item["sdesc"])."</h2>\n".
              stGetFormTextArea(12, 80, "", $item["key"], $prefix, $item["vtext"]).
              "\n<br />\n".
              stGetSaveButton();
          }
          echo "</form>\n";
        }
        break;
      
      case "compolist":
        $index = 0;
        foreach (stExecSQL("SELECT * FROM compos") as $compo)
        {
          $ne = stFetchSQLColumn("SELECT COUNT(*) FROM entries WHERE compo_id=".$compo["id"]);
          if ($index++ > 0) echo ",";
          echo
            "\"".$compo["id"]."\":\"".chentities($compo["name"]).
            (($ne !== false && $ne > 0) ? " <span class='cnotice'>(".$ne.")</span>" : "")."\"";
        }
        break;

      case "compovoting":
        $id = intval(stGetRequestItem("id", 0));
        if (($compo = stFetchSQL("SELECT * FROM compos WHERE id=".$id)) !== false)
          echo stGetCompoVoting($compo, FALSE);
        break;

      case "entries":
        $id = intval(stGetRequestItem("id", 0));
        if (($compo = stFetchSQL("SELECT * FROM compos WHERE id=".$id)) !== false)
        {
          $nentries = stFetchSQLColumn("SELECT COUNT(*) FROM entries WHERE compo_id=".$id);
          $prefix = "ne";
          echo
            "<h1>#".$id." - ".chentities($compo["name"])." (".$nentries." entries)</h1>\n";

          if ($nentries > 0 && $compo["ctype"] == COMPO_NORMAL)
          {
            echo
              stGetFormButtonInput("generate", "", "", " Add missing show positions ", "generateEntryPositions(".$id.", 1)")."\n".
              stGetFormButtonInput("regenerate", "", "", " ReGenerate show positions ", "generateEntryPositions(".$id.", 0)")."\n".
              stGetCompoVoting($compo, TRUE)."\n";
          }

          stPrintEntryItemData(array(
            "id" => $id,
            "show_id" => 0,
            "name" => "",
            "author" => "",
            "compo_id" => $id,
            "info" => "",
            "notes" => "",
            "preview_type" => 0,
            "flags" => 0,
            "evalue" => "",
            "utime" => 0,
            ),
            0, TRUE, "ne", $compo, EEMODE_ADD);

          echo
            "<hr />\n".
            "<div class=\"entries\">\n";

          $row = 0;
          foreach (stExecSQL("SELECT * FROM entries WHERE compo_id=".$id." ORDER BY id DESC") as $entry)
            stPrintEntryItemData($entry, $row++, TRUE, "en", $compo, EEMODE_NORMAL);

          echo "</div>\n";
        }
        break;

      case "entry":
        $res = stFetchSQL(stPrepareSQL("SELECT * FROM entries WHERE id=%D", "id"));
        if ($res !== FALSE)
        {
          stPrintEntryItemData($res, -1, FALSE, "en", FALSE,
            stGetRequestItem("edit", FALSE) ? EEMODE_EDIT : EEMODE_NORMAL);
        }
        else
          stError("No such entry ID!");
        break;
    }
    break;

  case "delete":
    //
    // Delete entry
    //
    stDBBeginTransaction();
    if (stChkRequestItem("id", $id, array(CHK_TYPE, VT_INT, "Invalid data.")))
    {
      if ($type == "news")
      {
        $sql = stPrepareSQL("DELETE FROM news WHERE id=%d AND persist=0", $id);
        stExecSQLCond($sql, "OK, news item ".$id." deleted.");
      }
      else
      if ($type == "attendees")
      {
        // Attendees require some more work
        $sql = stPrepareSQL("SELECT * FROM attendees WHERE id=%d", $id);
        if (($attn = stFetchSQL($sql)) !== false)
        {
          $sql = stPrepareSQL("DELETE FROM attendees WHERE id=%d", $id);
          stExecSQLCond($sql, "OK, attendee ".$id." deleted.");

          // If assigned votekey mode, delete the key and votes as well
          if ($setVoteKeyMode == VOTE_ASSIGN && $attn["key_id"] != 0)
          {
            $sql = stPrepareSQL("DELETE FROM votekeys WHERE id=%d", $attn["key_id"]);
            stExecSQLCond($sql, "OK, attendee ".$id." votekey deleted.");

            $sql = stPrepareSQL("DELETE FROM votes WHERE key_id=%d", $attn["key_id"]);
            stExecSQLCond($sql, "OK, attendee ".$id." votes deleted.");
          }
        }
        else
          stError("No such attendee ID #".$id);
      }
      else
      if ($type == "entries")
      {
        stDeleteCompoEntry($id);
      }
      else
      if ($type == "compo")
      {
        // Delete entries for the compo
        foreach (stExecSQL("SELECT * FROM entries WHERE compo_id=".$id) as $sentry)
          stDeleteCompoEntry($sentry["id"]);

        // Delete the compo itself
        stExecSQLCond(
          "DELETE FROM compos WHERE id=".$id,
          "OK, compo ".$id." deleted.");
      }
    }
    else
    if ($type == "votekeys")
    {
      $sql = stPrepareSQL("DELETE FROM votekeys");
      stExecSQLCond($sql, "OK, all votekeys purged");
    }

    stDBCommitTransaction();
    break;

  case "add":
    //
    // Add new entry
    //
    stDBBeginTransaction();
    if ($type == "news" && stValidateRequestNewsData())
    {
      $sql = stPrepareSQL(
        "INSERT INTO news (utime,title,text,author) VALUES (%d,%S,%Q,%S)",
        time(), "title", "text", "author");

      stExecSQLCond($sql, "OK, news item added.");
    }
    else
    if ($type == "compo" && stValidateRequestCompoData(FALSE, 0))
    {
      $sql = stPrepareSQL(
        "INSERT INTO compos (name,description,visible,voting,show_authors,preview_type) VALUES (%S,%Q,0,0,0,0)",
        "name", "description");

      stExecSQLCond($sql, "OK, compo added.");
    }
    else
    if ($type == "attendees" && stValidateRequestUserData(TRUE, FALSE))
    {
      $sql = stGetAttendeeRegistrationSQL();
      stExecSQLCond($sql, "OK, attendee added.");
    }
    else
    if ($type == "entry")
    {
      if (($compo = stFetchSQL(stPrepareSQL("SELECT * FROM compos WHERE id=%D", "compo_id"))) === FALSE)
        stError("No such compo ID.");
      else
      if (stValidateRequestEntryData($cfake, FALSE, $compo["ctype"]))
      {
        // The function gets most of its data from request parameters
        stAddCompoEntry($compo, 0); // User ID = 0 for admin
      }
    }
    stDBCommitTransaction();
    break;

  case "update":
    //
    // Update existing entry
    //
    stDBBeginTransaction();
    if (stChkRequestItem("id", $id, array(CHK_TYPE, VT_INT, "Invalid data.")))
    {
      if ($type == "settings")
      {
        foreach (stExecSQL("SELECT * FROM settings WHERE vgroup=".$id) as $item)
        if (($val = stGetRequestItem($item["key"], FALSE)) !== FALSE)
        {
          $sql = "UPDATE settings SET ".stGetSettingSQL($item, $val)." WHERE key=".$db->quote($item["key"]);
          stExecSQL($sql);
        }
        stSetStatus(200, "Updated settings.");
      }
      else
      if ($type == "attendees" && stValidateRequestUserData(TRUE, $id))
      {
        $sql = stPrepareSQLUpdate("attendees",
          "WHERE id=".$id,
          array(
            "name" => "S",
            "groups" => "S",
            "email" => "S",
            "oneliner" => "S",
            "reghost" => "S",
          ));

        stExecSQLCond($sql, "OK, attendee updated.");
      }
      else
      if ($type == "news" && stValidateRequestNewsData())
      {
        $sql = stPrepareSQLUpdate("news",
          "WHERE id=".$id,
          array(
            "title" => "S",
            "text" => "Q",
            "author" => "S"
          ));

        stExecSQLCond($sql, "OK, news item updated.");
      }
      else
      if ($type == "compotype" &&
        stChkRequestItem("ctype", $compotype,
          array(CHK_RANGE, VT_INT, array(COMPO_NORMAL, COMPO_ASSIGN), "Invalid compo type.")
        ))
      {
        $sql = stPrepareSQL("UPDATE compos SET ctype=%d WHERE id=%d", $compotype, $id);
        stExecSQLCond($sql, "OK, compo updated.");
      }
      else
      if ($type == "compovoting" &&
        stChkRequestItem("voting", $compovoting, $qres,
          array(CHK_TYPE, VT_BOOL, "Invalid data.")
        ))
      {
        $sql = stPrepareSQL("UPDATE compos SET voting=%b WHERE id=%d", $compovoting, $id);
        stExecSQLCond($sql, "OK, compo updated.");
      }
      else
      if ($type == "compo")
      {
        // Check if compo ID exists
        if (($compo = stFetchSQL("SELECT * FROM compos WHERE id=".$id)) === false)
          stError("No such compo ID.");
        else
        if (stValidateRequestCompoData(TRUE, $compo["ctype"]))
        {
          switch ($compo["ctype"])
          {
            case COMPO_NORMAL:
              $cdata = array(
                "voting" => "B",
                "show_authors" => "B",
                "preview_type" => "D",
                "cpath" => "S",
              );
              break;
            
            default:
              $cdata = array();
              break;
          }
          
          $sql = stPrepareSQLUpdate("compos",
            "WHERE id=".$id,
            array_merge(array(
              "name" => "S",
              "description" => "Q",
              "notes" => "Q",
              "visible" => "B",
            ), $cdata));

          stExecSQLCond($sql, "OK, compo updated.");
        }
      }
      else
      if ($type == "entry")
      {
        if (($compo = stFetchSQL(stPrepareSQL("SELECT * FROM compos WHERE id=%D", "compo_id"))) === FALSE)
          stError("No such compo ID.");
        else
        if (stValidateRequestEntryData($compo_id, TRUE, $compo["ctype"]))
        {
          switch ($compo["ctype"])
          {
            case COMPO_NORMAL:
              $cdata = array(
                "author" => "S",
                "info" => "Q",
                "compo_id" => "D",
              );
              break;
            
            case COMPO_POINTS:
            case COMPO_ASSIGN:
              $cdata = array(
                "evalue" => "D",
              );
              break;
          }

          $sql = stPrepareSQLUpdate("entries",
            "WHERE id=".$id,
            array_merge(array(
              "name" => "S",
              "notes" => "Q",
            ), $cdata));

          stExecSQLCond($sql, "OK, entry updated.");
        }
      }
    }
    stDBCommitTransaction();
    break;

  case "votekey":
    //
    // Votekey activation/deactivation handling
    //
    stDBBeginTransaction();
    if (stChkRequestItem("id", $id, array(CHK_TYPE, VT_INT, "Invalid data.")))
    {
      switch ($type)
      {
        case "assign":
          // Check if already assigned to someone ..
          $key_id = intval(stGetRequestItem("key_id", 0));
          $sql = stPrepareSQL("SELECT * FROM votekeys WHERE id=%d", $key_id);
          if (stFetchSQL($sql) === false)
            stError("Invalid key ID #.");
          else
          {
            $sql = stPrepareSQL("SELECT * FROM attendees WHERE key_id=%d", $key_id);
            if (($attn = stFetchSQL($sql)) !== false && $attn["id"] != $id)
              stError("That key has already been assigned to another attendee!");
            else
            {
              // Assign ..
              $sql = stPrepareSQL("UPDATE attendees SET key_id=%d WHERE id=%d", $key_id, $id);
              stExecSQLCond($sql, "Assigned key updated.");
            }
          }
          break;

        case "clear":
          $sql = stPrepareSQL("UPDATE attendees SET key_id=NULL WHERE id=%d", $id);
          stExecSQLCond($sql, "Assigned key cleared.");
          break;
        
        case "active":
          // Autobots activate!
          $sql = stPrepareSQL("UPDATE votekeys SET active=%B WHERE id=%d", "active", $id);
          stExecSQLCond($sql, "Votekey status changed.");
          break;
      }
    }
    stDBCommitTransaction();
    break;

  default:
    stSetStatus(903, "Not Found");
    break;
}

if (!$errorSet)
  stSaveDisplayVars();


if ($errorSet)
{
  ob_clean();
  stDumpAJAXStatusErrors();
}

ob_end_flush();
?>