<?php

// diese Seite stellt Orga-Funktionen für die eh2007-Seite zur Verfügung
// (Topics: ~ heißt geplant, - heißt im Bau, + heißt implementiert.)
// + diese Seite liegt im öffentlichen Serverbereich, dieser darf *.php nicht als plain/text ausliefern ;)
// + diese Seite verlangt zwingend https
// + diese Seite fragt ein Authentifikationspasswort ab
// + die Authentifikation läuft nach einer gewissen Zeitspanne (Konstante) ab
// + es dürfen von dieser Seite aus keine anderen orga-spezifischen Seiten aufgerufen werden,
//   da dies eventuell eine Umgehungsmöglichkeit der Authentifizierung zur Folge haben könnte

/*
  Struktur dieser Seite:
  + write HTTP header
  + recall session
  + check, defuse and shorten input variables
  + Prüfung auf https
    = OK => continue
    = FAIL => Session-Zwangslogout, Abbruchmeldung und Schlußverarbeitung
  + Prüfung auf gültigen Loginstatus, inkl. Timeout
    = OK => continue
    = FAIL => Authentifizierungsformular, Abbruchmeldung und Schlußverarbeitung
  + Prüfung auf Wartungsstatus
    = OK => continue
    = FAIL => Abbruchmeldung und Schlußverarbeitung
  + Login
    = OK => continue
    = FAIL => Authentifizierungsformular, Abbruchmeldung und Schlußverarbeitung
  + Verarbeitung der Submit-Aktionen (POST), Anzeige der einzelnen Orga-Formulare
*/


/*
  known bugs / todo
  
  - Script rennt in einen Loop-of-Death, wenn man auf einen Button klickt,
    während die Seite (z.B. wegen dem Fahrplan-Editor) noch nicht fertig aufgebaut war
    -> Session hängt sich auf.
    
    Dieses Problem taucht auf webtest.hamburg.ccc.de auf,
    ist aber lokal (auf Rainers Notebook) nicht reproduzierbar.
    -> php-Version oder "nur" Config-Problem? (deadlock-timeout?)
  
*/




// this script needs following additional server modules for PHP
// - Database: (e.g. pgsql)


// write HTTP header (anti-cache)
header('Expires: Sun,	31 Dec 1989	23:59:59 GMT');
header('Last-Modified: ' . gmdate('D,	d	M	Y	H:i:s')	.	'	GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0');
header('Pragma:	no-cache');


// recall session
session_cache_limiter('nocache');
session_cache_expire (1);
session_start();


// include library files
// ja genau, die ist hier jetzt auch direkt aus dem htdocs abrufbar;
// ist aber egal, denn da steht nix kritisches drin und die Seite ist auch rein passiv
require("inc_db.php");

// define general server constants
define( "SERVER_SITE_MAINTENANCE", false );               // maintenance state, set to TRUE to lock this page temporarily
define( "SERVER_LOCALHOST_IP", "127.0.0.1" );             // localhost IP, which does not need authentication
define( "SERVER_PROTOCOL_HTTPS", "HTTPS" );               // HTTPS protocol name


// define server file constants
define( "SERVER_FILE_MYSELF", "orga.php" );               // submit target of forms = this file itself
define( "SERVER_FILE_TEMPLATE", "template.shtml" );       // template file
define( "SERVER_FILE_WORKSHOPS", "workshops.shtml" );     // workshops file
define( "SERVER_FILE_FAHRPLAN", "fahrplan.shtml" );       // fahrplan file
define( "SERVER_FILE_HEADER", "ssi_site_header.html" );   // SSI file for site header
define( "SERVER_FILE_INTRO", "ssi_site_intro.html" );     // SSI file for site intro
define( "SERVER_FILE_EXTRO", "ssi_site_extro.html" );     // SSI file for site extro
define( "SERVER_FILE_AUTOGEN", "ssi_site_autogen.html" ); // SSI file for site autogeneration warning

// define display constants
define( "DISPLAY_TEXT_NONE", " " );
define( "DISPLAY_VALUE_SEPARATOR", chr(9));

// define auth constants
define( "AUTH_TIMEOUT_MINUTES", 10 );                     // idle timeout for login session
define( "AUTH_SERVER_PASS", "?AdminOsterhase#2007" );     // login password, [todo:] should be outsourced to an external, secured data file

// define constants for database data
define( "DB_ID_NONE", 0 );
define( "DB_ID_NEW", -1 );

// define constants for database access
// define SERVER_DB_TYPE as supported type in library db.php
define( "SERVER_DB_TYPE", constant("DB_TYPE_POSTGRESQL") );
define( "SERVER_DB_HOST", "localhost" );
define( "SERVER_DB_PORT", 5432 );
define( "SERVER_DB_NAME", "eh2007" );
define( "SERVER_DB_USER", "eh2007" );
define( "SERVER_DB_PASS", "Osterhase2007" );    //



// init references to $_SESSION variables ($sxxx)
$sbolauthloggedin = & $_SESSION['bolauthloginok'];
$sintauthprevtime = & $_SESSION['intauthprevtime'];

// init session variables
if ( !isset($sbolauthloggedin) ) $sbolauthloggedin = false;
if ( !isset($sintauthprevtime) ) $sintauthprevtime = time();


// init references to $_POST variables ($pxxx)
$pstrauth = & $_POST['txtauth'];
$pbollogin = & $_POST['cmdlogin'];
$pbollogout = & $_POST['cmdlogout'];
$pbolmakeworkshops = & $_POST['cmdmakeworkshops'];
$pbolmakefahrplan = & $_POST['cmdmakefahrplan'];
$pbolrunsql = & $_POST['cmdrunsql'];
$pbolwsupdate = & $_POST['cmdwsupdate'];
$pbolsdactivate = & $_POST['cmdsdactivate'];
$pbolsdupdate = & $_POST['cmdsdupdate'];
$plstschedule = & $_POST['cboschedule'];

$pintwsid = & $_POST['txtwsid'];
if ( !isset( $pintwsid ) ) { $pintwsid = & $_POST['cboworkshop']; }
$pstrwsname = & $_POST['txtwsname'];
$pstrwsspeakers = & $_POST['txtwsspeakers'];
$pintwsduration = & $_POST['txtwsduration'];
$pstrwscontent = & $_POST['txtwscontent'];
$pstrwscomment = & $_POST['txtwscomment'];
$pstrsql = & $_POST['txtsql'];

// init post variables (only for mandatory variables, ignore variables submitted by special forms!)
if ( !isset($pstrauth) ) $pstrauth = '';
if ( !isset($pintwsid) ) $pintwsid = constant("DB_ID_NONE");
if ( !isset($pstrwsname) ) $pstrwsname = '';
if ( !isset($pstrwsspeakers) ) $pstrwsspeakers = '';
if ( !isset($pintwsduration) ) $pintwsduration = 0;
if ( !isset($pstrwscontent) ) $pstrwscontent = '';
if ( !isset($pstrwscomment) ) $pstrwscomment = '';
if ( !isset($pstrsql) ) $pstrsql = '';
if ( !isset($plstschedule) ) $plstschedule = array();


// init instance variables
$intnow = time();

$strmsg = '';                     // (status/error/etc.) message to user
$bolauthabort = false;            // auth check will be aborted: show authentication page
$bolauthlogoutnow = false;        // user will be logged out

$intdbconnid = 0;
$intdbresult = 0;
$lngdbrows = 0;
$strdbfields = array();
$strdberror = '';
$strdbsql = '';
$strdbrow = '';
$strdbsql2 = '';

$strweekdayname = array (0 => 'Sonntag',
                         1 => 'Montag',
                         2 => 'Dienstag',
                         3 => 'Mittwoch',
                         4 => 'Donnerstag',
                         5 => 'Freitag',
                         6 => 'Samstag');

$strvalue = '';
$intindex = 0;
$intcolrotate = 1;
$strinput = '';
$stroutput = '';
$intfileid = 0;
$intcount = 0;

$strauth = '';
$bollogin = false;
$bollogout = false;
$bolmakefahrplan = false;
$bolmakeworkshops = false;
$bolrunsql = false;
$bolwsupdate = false;
$bolsdactivate = false;
$bolsdupdate = false;

$strtablehead = '';
$intcolrot = 0;
$intsdyear = 0;
$intsdmonth = 0;
$intsdday = 0;
$intsdhour = 0;
$strroname = '';
$boleof = false;
$strworkshoplist = '';
$intwsid = constant("DB_ID_NONE");
$strwsname = '';
$strwsspeakers = '';
$intwsduration = 0;
$strwscontent = '';
$strwscomment = '';
$strsql= '';
$strdbfields = '';
$lstschedule = array();
$strscheduleindex = '';
$intscheduleindex = constant("DB_ID_NONE");
$intschedulevalue = constant("DB_ID_NONE");

$bolok = false;                   // action feedback, triggers confirmation if true or warning if false


// function library

function addmsg ($straddmsg)
{
  // adds $straddmsg to $strmsg
  global $strmsg;
  if ( $straddmsg != '' )
  {
    $strmsg = $strmsg . '<li>' . $straddmsg . '</li>';
  }
}

function showmsg ()
{
  // shows messages in $strmsg if available
  global $strmsg, $bolok;
  if ( $strmsg != '' )
  {
    echo
    '
    <div class="announcement">
    <h3 class="';
    if ( $bolok )
    {
      echo 'confirmation';
    }
    else
    {
      echo 'warning';
    }
    echo '">Feedback</h3>
    <ul>' . $strmsg . '</ul>
    </div>
    ';
    $strmsg = '';
    $bolok = false;
  }
}

function selectws ( $intwsid )
{
  // selects workshop with $intwsid of $strworkshoplist
  global $strworkshoplist;
  
  return str_replace( '<option value="' . $intwsid . '">', '<option value="' . $intwsid . '" selected="selected">', $strworkshoplist );
}

// check input variables
//$bollogin = isset( $pbollogin ); // does not work in IE when submitted from within a text field by pressing Return key, reason unknown
$bollogin = ( isset( $pbollogin ) || $pstrauth != '' );  //workaround for IE problem, see line above
$bollogout = ( isset( $pbollogout ) || $bollogin ); //also fire a logout before (re-)login
$bolmakefahrplan = ( isset( $pbolmakefahrplan ) );
$bolmakeworkshops = ( isset( $pbolmakeworkshops ) );
$bolrunsql = ( isset( $pbolrunsql ) );
$bolwsupdate = ( isset( $pbolwsupdate ) );
$bolsdactivate = ( isset( $pbolsdactivate ) );
$bolsdupdate = ( isset( $pbolsdupdate ) );

$intwsid = $pintwsid;
$strwsname = $pstrwsname;
$strwsspeakers = $pstrwsspeakers;
$intwsduration = $pintwsduration;
$strwscontent = $pstrwscontent;
$strwscomment = $pstrwscomment;
$strsql = $pstrsql;

// todo: check control lists for invalid values!
$lstschedule = $plstschedule;

// defuse input variables
$strauth = trim( htmlentities( $pstrauth, ENT_QUOTES ));
$intwsid = intval( $intwsid );
$strwsname = trim( htmlentities( $strwsname, ENT_QUOTES ));
$strwsspeakers = trim( htmlentities( $strwsspeakers, ENT_QUOTES ));
$intwsduration = intval( $intwsduration );
$strwscontent = trim( htmlentities( $strwscontent, ENT_QUOTES ));
$strwscomment = trim( htmlentities( $strwscomment, ENT_QUOTES ));
$strsql = trim( htmlentities( $strsql, ENT_QUOTES ));

// shorten input variables
if ( strlen( $strauth ) > 255 ) $strauth = substr( $strauth, 0, 255 ); //cut it, do not modify
if ( strlen( $strwsname ) > 255 ) $strwsname = substr( $strwsname, 0, 252 ) . "...";
if ( strlen( $strwsspeakers ) > 255 ) $strwsspeakers = substr( $strwsspeakers, 0, 252 ) . "...";
if ( strlen( $strwscontent ) > 4095 ) $strwscontent = substr( $strwscontent, 0, 4092 ) . "...";
if ( strlen( $strwscomment ) > 4095 ) $strwscomment = substr( $strwscomment, 0, 4092 ) . "...";
if ( strlen( $strsql ) > 4095 ) $strsql = substr( $strsql, 0, 4095 ); //cut it, do not modify


if
(
  // localhost access
  (
    // direkter Aufruf von localhost
    htmlspecialchars( $_SERVER['HTTP_X_FORWARDED_FOR'], ENT_QUOTES ) == ''
    &&
    htmlspecialchars( $_SERVER['REMOTE_ADDR'], ENT_QUOTES ) == constant("SERVER_LOCALHOST_IP")
  )
  ||
  (
    // indirekter Aufruf (z.B. transparenter SSL-Proxy) mit übergebenem localhost
    htmlspecialchars( $_SERVER['HTTP_X_FORWARDED_FOR'], ENT_QUOTES ) == constant("SERVER_LOCALHOST_IP")
  )
)
{
  // localhost ist immer eingeloggt
  $sbolauthloggedin = true;
}
else
{
  // check protocol and timeout



  // check secure connection
  // possible results:
  // - secure => continue
  // - insecure => force logout ($bolauthlogoutnow), show error page and prepare message ($strmsg)
  if
  (
    (
      // direct connection without HTTPS
      $_SERVER['HTTPS'] == ''
      &&
      $_SERVER['HTTP_X_FORWARDED_PROTO'] == ''
    )
    ||
    (
      // indirect connection without local HTTPS proxy, e.g. orenosp
      strtolower($_SERVER['HTTP_X_FORWARDED_PROTO']) != strtolower(constant("SERVER_PROTOCOL_HTTPS"))
      && $_SERVER['HTTP_X_FORWARDED_PROTO'] != ''
    )
  )
  {
    // insecure connection -> abort
    if ( !$bolauthlogoutnow && $sbolauthloggedin )
    {
      // active login over insecure connection -> force logout
      $bolauthlogoutnow = true;
      addmsg ( 'Du wirst ausgeloggt, da Deine Verbindung unsicher (unverschlüsselt) geworden ist.' );
    }
    addmsg ( 'Dein Verbindungsprotokoll ist HTTP. Bitte verwende für die Orga-Seite Verschlüsselung mittels HTTPS.' );
    $bolauthabort = true;
  }


  // check auth timeout
  // possible results:
  // - auth active => continue
  // - auth timeout => force logout ($bolauthlogoutnow), prepare message ($strmsg) and continue
  if ( $sbolauthloggedin && !$bolauthlogoutnow && ( $intnow > ( $sintauthprevtime + 60 * constant("AUTH_TIMEOUT_MINUTES") )))
  {
    // write message on user authentication expired -> also fire a logout ($bolauthlogoutnow)
    // echo '<div class="warning">Du wurdest ausgeloggt wegen mehr als ' . constant("AUTH_TIMEOUT_MINUTES") . ' Minuten Inaktivit&auml;t.</div><br>';
    $bolauthlogoutnow = true;
    addmsg ( 'Du wirst ausgeloggt wegen mehr als ' . constant("AUTH_TIMEOUT_MINUTES") . ' Minuten Inaktivit&auml;t.' );
  }
  // restart timeout
  $sintauthprevtime = $intnow;

}

if ( $bolauthlogoutnow || $bollogout )
{
  // logout
  if ( $bolauthlogoutnow )
  {
    addmsg ( 'Du wurdest automatisch ausgeloggt. Bitte gegebenenfalls erneut einloggen.' );
  }
  $sbolauthloggedin = false;
}

// check maintenance state
if ( constant("SERVER_SITE_MAINTENANCE") )
{
  // cancel because of maintenance
  addmsg ( 'Die Orga-Seite ist zurzeit wegen Wartungsarbeiten deaktiviert. Bitte sp&auml;ter wiederkommen. Danke.' );
  $bolauthabort = true;
}

// Well, Checkpoint.
// Now a defined and normal state of checking has been reached.
// Possible states are now:
// - $sbolauthloggedin = true: user has successfully authenticated and is still logged in
// - $sbolauthloggedin = false: user is either not (yet) authenticated or authentication has been expired
// If there were any messages on the way up to here, they are stored as list items (<li>) in variable $strmsg.


// check auth phrase if user tries to login
if ( !$bolauthabort && $bollogin && $strauth > '' )
{
  if ( $strauth == constant("AUTH_SERVER_PASS") )
  {
    // login accepted
    $sbolauthloggedin = true;
  }
  else
  {
    // login failed
    $sbolauthloggedin = false;
    addmsg ( 'Das klappt so nicht. Vermutlich hast Du Dich vertippt.' );
  }
}

// prepare orga page
// assume that all ssi files are there. No, I won't check _that_ explicitely.
// If they ain't there, the user gets a partial page. ...so what? ;o)
readfile( constant("SERVER_FILE_HEADER") );
echo
'
<!-- begin of specific page header -->

<title>Easterhegg 2007 - Orga</title>

<!-- end of specific page header -->

';
readfile( constant("SERVER_FILE_INTRO") );
echo
'
<!-- begin of specific page content -->

';

echo
'
<div class="announcement">
<h3 class="announcement">interne Orga</h3>
</div>

';

// show msg, if available
if ( $strmsg != '' )
{
  echo
  '
  <div class="announcement">
  <h3 class="warning">Authentifizierungshinweis:</h3>
  <ul>' . $strmsg . '</ul>
  </div>
  ';
  $strmsg = '';
}

if ( !$sbolauthloggedin )
{
  // show authentication page and then die

  if ( !$bolauthabort )
  {
    // show login form
    echo
    '
    <div class="chapter">
    <h4>*knock-knock*</h4>
    <form	id="loginform" name="loginform" action="' . constant("SERVER_FILE_MYSELF") . '" method="post">
      <input name="txtauth" type="password">
      <input name="cmdlogin" type="submit" value="Lass mich rein!">
    </form>
    </div>
    ';
  }

  // close page and stoprun.
  echo
  '
  
  <!-- end of specific page content -->

  ';
  readfile( constant("SERVER_FILE_EXTRO") );

  die();
}





// Well, Checkpoint.
// Now the user is proofed to be successfully logged in. (All others are wiped out.)
// From here on the user is authorized to enjoy all the following features.
// default sequence within each chapter:
// 1. headline
// 2. submit action
// 3. showmsg();
// 4. user forms
// 5. showmsg();
// 6. five empty rows to separate from next chapter ;)





// show logout chapter
echo
'
<div class="chapter">
<h4>Logout</h4>
</div>';
showmsg();
echo '
<div>
<form	id="logoutform" name="logoutform" action="' . constant("SERVER_FILE_MYSELF") . '" method="post">
<p>
<input name="cmdlogout" type="submit" value="Bin fertig!" />
</p>
</form>
</div>
';
showmsg();





// show make workshops chapter
echo
'
<div class="chapter">
<h4>make install Workshops</h4>
</div>
';

if ( $bolmakeworkshops )
{
  //make workshops

  $bolok = false;

  $stroutput = '';

  // read workshops
  $strdbsql = " select ws_id, ws_name, ws_speakers, ws_content" .
              " from tbl_workshops ws" .
              " order by ws_name";
  addmsg ( 'Running SQL: ' . $strdbsql );
  if ( db_sql( $intdbconnid, $strdbsql, $intdbresult, $lngdbrows, $strdberror ) )
  {
    if ( $lngdbrows > 0 )
    {
      // workshops found
      // -> use them

      while ( db_row ( $intdbresult, $strdbrow, constant("DB_ROW_NEXT"), $strdberror ))
      {
        // for each workshop:
        $stroutput = $stroutput .
        '
          <div class="chapter">
          <a id="ws' . $strdbrow['ws_id'] .  '" class="linktarget">&nbsp;</a>
          <h4>' . $strdbrow['ws_name'] . '</h4>
          <p>
          <span class="topic">' . $strdbrow['ws_speakers'] . '</span>
          </p>
          <div class="chaptercontent">
          ' . html_entity_decode( $strdbrow['ws_content'], ENT_QUOTES ) . '
          </div>
          </div>
        ';
      }
      // don't allow to finish properly until finished developing!
       $bolok = true;
    }
    else
    {
      // no workshops found
      // -> hmm, that should not happen, but even then there should be no data anyway...
    }
  }
  else
  {
    // error accessing database
    addmsg ( 'Sorry, die Datenbank ist momentan nicht für die Abfrage der Workshops verfügbar.<br />Die Datenbank sagt: ' . $strdberror );
  }

  if ( $bolok )
  {
    // operation has succeeded -> now generate workshop file

    $stroutput = '
    <div class="announcement">
    <h3 class="announcement">Workshops</h3>
    Stand: ' . date( "d.m.Y H:i:s", $intnow ) . '
    </div>
    <div>
    ' . $stroutput .
    '
    </div>
    ';

    // add autogeneration-warning
    $stroutput = file_get_contents( constant("SERVER_FILE_AUTOGEN") ) . $stroutput;
    $strinput = file_get_contents( constant("SERVER_FILE_TEMPLATE") );
    $strinput = str_replace( "[%title%]", "Workshops", $strinput );
    $stroutput = str_replace( "[%content%]", $stroutput, $strinput );

    if ( is_writable( constant("SERVER_FILE_WORKSHOPS") ))
    {
      // file_put_contents does not work with PHP 4.x, so use instead: fopen, fwrite, fclose
      // file_put_contents( constant("SERVER_FILE_WORKSHOPS"), $stroutput );
      $intfileid = fopen( constant("SERVER_FILE_WORKSHOPS"), "w" );
      fwrite( $intfileid, $stroutput );
      fclose( $intfileid );
      $bolok = true;
    }
    else
    {
      addmsg ( 'Die Workshopdatei &quot;' . constant("SERVER_FILE_WORKSHOPS") . '&quot; konnte nicht geschrieben werden. (Rechteproblem?)');
      $bolok = false;
    }
  }

  // write result
  if ( $bolok )
  {
    addmsg ( 'Die Workshopdatei wurde erfolgreich aktualisiert.' );
  }
  else
  {
    addmsg ( 'Die Workshopdatei wurde nicht aktualisiert.' );
  }
}
showmsg();

echo
'
<div>
<form id="makeworkshopsform" name="makeworkshopsform" action="' . constant("SERVER_FILE_MYSELF") . '" method="post">
<p>
Hier wird die (statische) Workshopseite auf Basis der aktuellen Datenbank neu erstellt. <br />
Achtung: Die alte Workshopseite wird dabei unwiderruflich überschrieben!
</p>
<p>
<input name="cmdmakeworkshops" type="submit" value="Workshopdatei jetzt erstellen!" />
</p>
</form>
</div>
';
showmsg();





// show make fahrplan chapter
echo
'
<div class="chapter">
<h4>make install Fahrplan</h4>
</div>
';

if ( $bolmakefahrplan )
{
  //make fahrplan

  $bolok = false;

  $stroutput = '';

  // prepare table header with room names
  // read rooms
  $strdbsql = " select ro_name" .
              " from tbl_rooms ro" .
              " order by ro_schedpos";
  addmsg ( 'Running SQL: ' . $strdbsql );
  if ( db_sql( $intdbconnid, $strdbsql, $intdbresult, $lngdbrows, $strdberror ) )
  {
    if ( $lngdbrows > 0 )
    {
      // rooms found
      // -> use them

      $strtablehead = '';

      while ( db_row ( $intdbresult, $strdbrow, constant("DB_ROW_NEXT"), $strdberror ))
      {
        // for each room:
        $strtablehead = $strtablehead .
        '
                <td class="db">' . $strdbrow['ro_name'] . '</td>
        ';
      }
      $bolok = true;
    }
    else
    {
      // no rooms found
      // -> hmm, that should not happen, but even then there should be no data anyway...
    }
  }
  else
  {
    // error accessing database
    addmsg ( 'Sorry, die Datenbank ist momentan nicht für die Abfrage der Raumliste verfügbar.<br />Die Datenbank sagt: ' . $strdberror );
  }

  if ( $bolok )
  {
    // read schedule slots with workshops
    $strdbsql = " select extract(hour from sd_begintime) as sd_begintime_hour, extract(day from sd_begintime) as sd_begintime_day," .
                " extract(month from sd_begintime) as sd_begintime_month, extract(year from sd_begintime) as sd_begintime_year," .
                " extract(dow from sd_begintime) as sd_begintime_weekday, sd_begintime," .
                " ws_id, ws_name, ws_speakers,".
                " ro_name" .
                " from tbl_schedule sd" .
                " left join tbl_workshops ws on sd.sd_ws_id = ws.ws_id" .
                " left join tbl_rooms ro on sd.sd_ro_id = ro.ro_id" .
                " order by sd_begintime, ro_schedpos";
    addmsg ( 'Running SQL: ' . $strdbsql );
    if ( db_sql( $intdbconnid, $strdbsql, $intdbresult, $lngdbrows, $strdberror ) )
    {
      if ( $lngdbrows > 0 )
      {
        // scheduled events found
        // -> use them

        // es folgt: Gruppenwechsel über Tag, Timeslot, Raum, Schedule-Event

        // Gesamtvorlauf
        $intsdyear = 0;
        $intsdmonth = 0;
        $intsdday = 0;
        $intsdhour = 0;
        $strroname = '';
        $boleof = false;

        $boleof = !db_row ( $intdbresult, $strdbrow, constant("DB_ROW_NEXT"), $strdberror );

        while ( !$boleof )
        {
          // Gruppenvorlauf Tag
          $intsdyear = $strdbrow['sd_begintime_year'];
          $intsdmonth = $strdbrow['sd_begintime_month'];
          $intsdday = $strdbrow['sd_begintime_day'];
          // neue Tabelle initialisieren
          $intcolrot = 1;
          $stroutput = $stroutput .
          '
            <div class="chapter">
              <table class="db">
                <tr class="dbhead">
                  <td class="db">
                    ' . $strweekdayname[ $strdbrow['sd_begintime_weekday'] ] . '<br />
                    ' . $intsdday . '.' . $intsdmonth . '.
                  </td>
          ';
          $stroutput = $stroutput . $strtablehead;
          $stroutput = $stroutput .
          '
                </tr>
          ';

          while
          (
            !$boleof
            &&
            (
              $intsdyear == $strdbrow['sd_begintime_year']
              &&
              $intsdmonth == $strdbrow['sd_begintime_month']
              &&
              $intsdday == $strdbrow['sd_begintime_day']
            )
          )
          {
            // Gruppenvorlauf Timeslot
            $intsdhour = $strdbrow['sd_begintime_hour'];
            // neue Tabellenzeile initialisieren
            $intcolrot = abs( $intcolrot - 1 );
            $stroutput = $stroutput .
            '
                <tr class="db' . $intcolrot . '">
                  <td class="db">
                    ' . $intsdhour . '<span class="small">:00</span>
                  </td>
            ';

            while
            (
              !$boleof
              &&
              (
                $intsdyear == $strdbrow['sd_begintime_year']
                &&
                $intsdmonth == $strdbrow['sd_begintime_month']
                &&
                $intsdday == $strdbrow['sd_begintime_day']
              )
              &&
              (
                $intsdhour == $strdbrow['sd_begintime_hour']
              )
            )
            {

              // Gruppenvorlauf Schedule-Event
              $strroname = $strdbrow['ro_name'];
              // neue Tabellenzelle initialisieren
              $stroutput = $stroutput .
              '
                  <td class="db">
              ';

              while
              (
                !$boleof
                &&
                (
                  $intsdyear == $strdbrow['sd_begintime_year']
                  &&
                  $intsdmonth == $strdbrow['sd_begintime_month']
                  &&
                  $intsdday == $strdbrow['sd_begintime_day']
                )
                &&
                (
                  $intsdhour == $strdbrow['sd_begintime_hour']
                )
                &&
                (
                  $strroname == $strdbrow['ro_name']
                )
              )
              {
                // Datensatz (Schedule-Event) verarbeiten
                if ( $strdbrow['ws_name'] > '')
                {
                  $stroutput = $stroutput . '<a class="db" href="' . constant("SERVER_FILE_WORKSHOPS") . '#ws' . $strdbrow['ws_id'] . '">' . $strdbrow['ws_name'];
                  if ( $strdbrow['ws_speakers'] > '')
                  {
                    $stroutput = $stroutput . '<span class="line small"> (' . $strdbrow['ws_speakers'] . ')</span>';
                  }
                  $stroutput = $stroutput . '</a>';
                }

                // neuen Datensatz lesen
                $boleof = !db_row ( $intdbresult, $strdbrow, constant("DB_ROW_NEXT"), $strdberror );
              }
              // Gruppennachlauf Schedule-Event
              // Tabellenzelle finalisieren
              $stroutput = $stroutput .
              '
                  </td>
              ';

            }
            // Gruppennachlauf Timeslot
            // Tabellenzeile finalisieren
            $stroutput = $stroutput .
            '
                </tr>
            ';

          }

          // Gruppennachlauf Tag
          // Tabelle finalisieren
          $stroutput = $stroutput .
          '
              </table>
            </div>
          ';
        }

        // Gesamtnachlauf
        // Gesamtausgabe finalisieren

        addmsg ( 'Die Fahrplandaten wurden erfolgreich zusammengestellt. Die Fahrplandatei kann jetzt geschrieben werden.' );
        $bolok = true;
      }
      else
      {
        // no scheduled events found
        // -> hmm, that should not happen, but even then there should be no data anyway...
      }
    }
    else
    {
      // error accessing database
      addmsg ( 'Sorry, die Datenbank ist momentan nicht für die Abfrage des Fahrplans verfügbar.<br />Die Datenbank sagt: ' . $strdberror );
    }
  }

  if ( $bolok )
  {
    // operation has succeeded -> now generate schedule file

    $stroutput = '
    <div class="announcement">
    <h3 class="announcement">Fahrplan</h3>
    Stand: ' . date( "d.m.Y H:i:s", $intnow ) . '
    </div>
    
    ' . $stroutput .
    '
    <div class="chapter">
    <h4>feste Einrichtungen</h4>
    <p>
    <span class="topic">Projektleitung:</span>
    NOC (OG), POC (OG)
    </p>
    <p>
    <span class="topic">CERT (Rot-Kreuz):</span>
    Flur (OG)
    </p>
    <p>
    <span class="topic"><a href="workshops.shtml#ws3">CAcert</a>:</span>
    Work3 (OG), bei den Funkamateuren
    </p>
    <p>
    <span class="topic">Freifunker:</span>
    Werkstatt (OG), hinter Work3
    </p>
    <p>
    <span class="topic">Fest- und Flüssignahrung:</span>
    Cafe, vorderer Teil (EG)
    </p>
    </div>
    ';

    // add autogeneration-warning
    $stroutput = file_get_contents( constant("SERVER_FILE_AUTOGEN") ) . $stroutput;
    $strinput = file_get_contents( constant("SERVER_FILE_TEMPLATE") );
    $strinput = str_replace( "[%title%]", "Fahrplan", $strinput );
    $stroutput = str_replace( "[%content%]", $stroutput, $strinput );

    if ( is_writable( constant("SERVER_FILE_FAHRPLAN") ))
    {
      // file_put_contents does not work with PHP 4.x, so use instead: fopen, fwrite, fclose
      // file_put_contents( constant("SERVER_FILE_FAHRPLAN"), $stroutput );
      $intfileid = fopen( constant("SERVER_FILE_FAHRPLAN"), "w" );
      fwrite( $intfileid, $stroutput );
      fclose( $intfileid );
      $bolok = true;
    }
    else
    {
      addmsg ( 'Die Fahrplandatei &quot;' . constant("SERVER_FILE_FAHRPLAN") . '&quot; konnte nicht geschrieben werden. (Rechteproblem?)');
      $bolok = false;
    }
  }

  // write result
  if ( $bolok )
  {
    addmsg ( 'Die Fahrplandatei wurde erfolgreich aktualisiert.' );
  }
  else
  {
    addmsg ( 'Die Fahrplandatei wurde nicht aktualisiert.' );
  }
}
showmsg();

echo
'
<div>
<form id="makefahrplanform" name="makefahrplanform" action="' . constant("SERVER_FILE_MYSELF") . '" method="post">
<p>
Hier wird die (statische) Fahrplanseite auf Basis der aktuellen Datenbank neu erstellt. <br />
Achtung: Die alte Fahrplanseite wird dabei unwiderruflich überschrieben!
</p>
<p>
<input name="cmdmakefahrplan" type="submit" value="Fahrplandatei jetzt erstellen!" />
</p>
</form>
</div>
';
showmsg();





// show workshop editor chapter

echo '
<div class="chapter">
<h4>Workshop Editor</h4>
</div>
<a id="wseditor"';
if ( $intwsid != constant("DB_ID_NONE") ) { echo ' class="linktarget" '; }
echo '><!-- space to avoid anchor being displayed below topbars --></a>
';

if ( $bolwsupdate && $intwsid != constant("DB_ID_NONE") )
{
  // update workshop
  // if $intwsid == constant("DB_ID_NEW") create new workshop else update existing
  
  $bolok = false;

  if ( $intwsid != constant("DB_ID_NEW") )
  {
    // update existing workshop

    $strdbsql = " ws_name = '" . $strwsname . "'," .
                " ws_speakers = '" . $strwsspeakers . "'," .
                " ws_content = '" . $strwscontent . "'," .
                " ws_comment = '" . $strwscomment . "',";
    if ( $intwsduration != '' )
    {
      $strdbsql = $strdbsql . " ws_duration = " . $intwsduration . ",";
    }
    else
    {
      $strdbsql = $strdbsql . " ws_duration = NULL,";
    }
    
    $strdbsql = " update tbl_workshops set " .
                substr( $strdbsql, 0, strlen( $strdbsql ) - 1 ) .
                " where ws_id = " . $intwsid;
  
    addmsg ( 'Running SQL: ' . $strdbsql );
    if ( db_sql( $intdbconnid, $strdbsql, $intdbresult, $lngdbrows, $strdberror ) )
    {
      if ( $lngdbrows > 0 )
      {
        // update successful
        addmsg ( 'Erfolgreich aktualisiert: ' . $lngdbrows . ' Workshop(s).' );
        $bolok = true;
      }
      else
      {
        // update failed
        addmsg ( 'Aktualisierung fehlgeschlagen!<br />Die Datenbank sagt: ' . $strdberror );
      }
    }
    else
    {
      // error accessing database
      addmsg ( 'Sorry, die Datenbank ist momentan nicht für die Workshop-Aktualisierung verfügbar.<br />Die Datenbank sagt: ' . $strdberror );
    }
  }
  else
  {
    // insert new workshop

    $strdbsql = '';
    if ( $strwsname != '' )
    {
      $strdbfields = $strdbfields . " ws_name,";
      $strdbsql = $strdbsql . " '" . $strwsname . "',";
    }
    if ( $intwsduration != '' )
    {
      $strdbfields = $strdbfields . " ws_duration,";
      $strdbsql = $strdbsql . " " . $intwsduration . ",";
    }
    if ( $strwsspeakers != '' )
    {
      $strdbfields = $strdbfields . " ws_speakers,";
      $strdbsql = $strdbsql . " '" . $strwsspeakers . "',";
    }
    if ( $strwscontent != '' )
    {
      $strdbfields = $strdbfields . " ws_content,";
      $strdbsql = $strdbsql . " '" . $strwscontent . "',";
    }
    if ( $strwscomment != '' )
    {
      $strdbfields = $strdbfields . " ws_comment,";
      $strdbsql = $strdbsql . " '" . $strwscomment . "',";
    }

    if ( $strdbsql != '' )
    {
      // get nextval
      $strdbsql2 = "select nextval('seq_ws_id')";
      addmsg ( 'Running SQL: ' . $strdbsql2 );
      if ( db_sql( $intdbconnid, $strdbsql2, $intdbresult, $lngdbrows, $strdberror ) )
      {
        if ( $lngdbrows > 0 )
        {
          if ( db_row ( $intdbresult, $strdbrow, constant("DB_ROW_FIRST"), $strdberror ))
          {
            // nextval succeeded
            addmsg ( 'Nextval erhalten: ' . $strdbrow['nextval'] );
            $intwsid = $strdbrow['nextval'];
            
            $strdbfields = " ws_id," . $strdbfields;
            $strdbsql = " " . $intwsid . "," . $strdbsql;
          }
          else
          {
            // this should never happen, at all
            addmsg ( 'Keinen Nextval erhalten!<br />Die Datenbank sagt: ' . $strdberror );
          }
        }
        else
        {
          // nextval failed
          addmsg ( 'Keinen Nextval erhalten!<br />Die Datenbank sagt: ' . $strdberror );
        }
      }
      else
      {
        // error accessing database
        addmsg ( 'Sorry, die Datenbank ist momentan nicht für die Workshop-Erstellung verfügbar.<br />Die Datenbank sagt: ' . $strdberror );
      }
      
      if ( $intwsid != constant("DB_ID_NEW") )
      {
        // nextval available

        $strdbsql = " insert into tbl_workshops (" .
                    substr( $strdbfields, 0, strlen( $strdbfields ) - 1 ) .
                    ") values ("
                    . substr( $strdbsql, 0, strlen( $strdbsql ) - 1 ) .
                    ")";

        addmsg ( 'Running SQL: ' . $strdbsql );
        if ( db_sql( $intdbconnid, $strdbsql, $intdbresult, $lngdbrows, $strdberror ) )
        {
          if ( $lngdbrows > 0 )
          {
            // insert successful
            addmsg ( 'Erfolgreich erstellt: ' . $lngdbrows . ' Workshop(s).' );
            $bolok = true;
          }
          else
          {
            // insert failed
            addmsg ( 'Erstellung fehlgeschlagen!<br />Die Datenbank sagt: ' . $strdberror );
          }
        }
        else
        {
          // error accessing database
          addmsg ( 'Sorry, die Datenbank ist momentan nicht für die Workshop-Erstellung verfügbar.<br />Die Datenbank sagt: ' . $strdberror );
        }
        if ( !$bolok )
        {
          $intwsid = constant("DB_ID_NEW");
        }
      }
    }
    else
    {
      // no fields filled
      addmsg ( 'Wenn Du einen neuen Workshop anlegen willst, wäre es geschickt, zumindest schonmal den Namen auszufüllen. ;o) ' );
    }
  }
}





showmsg();

echo '
<div>
<p>
Hier können Workshops manuell bearbeitet - oder eben auch kaputtgemacht - werden, bitte also aufpassen ;)
</p>
';

echo '
<form	id="wsselectform " ';
echo ' name="wsselectform" action="' . constant("SERVER_FILE_MYSELF") . '#wseditor" method="post">
<div>
';

$bolok = false;

// read workshops
$strdbsql = " select *" .
            " from tbl_workshops ws" .
            " order by ws_name";
if ( db_sql( $intdbconnid, $strdbsql, $intdbresult, $lngdbrows, $strdberror ) )
{
  if ( $lngdbrows > 0 )
  {
    // workshops found
    // -> use them

    $strworkshoplist = '<option value="' . constant("DB_ID_NONE") . '"';
    if ( $intwsid == constant("DB_ID_NONE") || $intwsid == constant("DB_ID_NEW") )
    {
      // extracted to function "selectws": $strworkshoplist = $strworkshoplist . ' selected="selected"';
      if ( !$bolwsupdate )
      {
        // clear workshop fields, except user tried to update
        $strwsname = '';
        $strwsspeakers = '';
        $intwsduration = 0;
        $strwscontent = '';
        $strwscomment = '';
      }
    }
    $strworkshoplist = $strworkshoplist . '>' . constant("DISPLAY_TEXT_NONE") . '</option>';

    while ( db_row ( $intdbresult, $strdbrow, constant("DB_ROW_NEXT"), $strdberror ))
    {
      // for each workshop:
      $strworkshoplist = $strworkshoplist . '<option value="' . $strdbrow["ws_id"] . '"';
      if ( $intwsid == $strdbrow["ws_id"] )
      {
        // extracted to function "selectws": $strworkshoplist = $strworkshoplist . ' selected="selected"';
        // init workshop fields
        $intwsid = $strdbrow["ws_id"];
        $strwsname = $strdbrow["ws_name"];
        $strwsspeakers = $strdbrow["ws_speakers"];
        $intwsduration = $strdbrow["ws_duration"];
        $strwscontent = $strdbrow["ws_content"];
        $strwscomment = $strdbrow["ws_comment"];
      }
      $strworkshoplist = $strworkshoplist . '>' . $strdbrow["ws_name"] . '</option>';
    }
    echo
    '
      <span class="topic">Auswahl:</span><select name="cboworkshop" onchange="document.wsselectform.submit();">' . selectws( $intwsid ) . '</select>
    ';
    $bolok = true;
  }
  else
  {
    // no workshops found
    // -> hmm, that should not happen, but even then there should be no data anyway...
  }
}
else
{
  // error accessing database
  addmsg ( 'Sorry, die Datenbank ist momentan nicht für die Abfrage der Workshopliste verfügbar.<br />Die Datenbank sagt: ' . $strdberror );
}

echo
'
    </div>
  </form>
  <form	id="wscreateform" name="wscreateform" action="' . constant("SERVER_FILE_MYSELF") . '#wseditor" method="post">
    <div>
      <input name="txtwsid" type="hidden" value="' . constant("DB_ID_NEW") . '" />
      <input name="cmdwscreate" type="submit" value="Neuen Workshop erstellen..." />
    </div>
  </form>
';

if ( $intwsid != constant("DB_ID_NONE") )
{
  // show workshop update form with selected workshop
  
  echo
  '
  <form	id="wsupdateform" name="wsupdateform" action="' . constant("SERVER_FILE_MYSELF") . '#wseditor" method="post">
    <div class="box">

    <input name="txtwsid" type="hidden" value="' . $intwsid . '" />
    <span class="topic">Name:</span><input class="db" name="txtwsname" type="text" value="' . $strwsname . '" />
    <span class="topic">Referenten:</span><input class="db" name="txtwsspeakers" type="text" value="' . $strwsspeakers .'" />
    <span class="topic">Dauer (Min.):</span><input class="db" name="txtwsduration" type="text" value="' . $intwsduration .'" />
    <span class="topic">Inhalt:</span><textarea class="db verybig" name="txtwscontent">'. $strwscontent .'</textarea>
    <span class="topic">Bemerkung:</span><textarea class="db" name="txtwscomment">'. $strwscomment .'</textarea>
    <input name="cmdwsupdate" type="submit" value="Workshop jetzt aktualisieren!" />

    </div>
  </form>
  ';
}

echo
'
</div>
';
showmsg();





// show fahrplan editor chapter
echo
'
<div class="chapter">
<h4>Fahrplan Editor</h4>
</div>
';

// update fahrplan

if ( $bolsdupdate )
{
  // save all selected workshops (from downlists) into schedule

  $bolok = true;
  $intcount = 0;

  reset( $lstschedule );
  foreach ( $lstschedule as $strscheduleindex => $intschedulevalue)
  {
    $intscheduleindex = intval( substr( $strscheduleindex, 0, strpos( $strscheduleindex . constant("DISPLAY_VALUE_SEPARATOR"), constant("DISPLAY_VALUE_SEPARATOR") )));
    if ( $intschedulevalue != intval( substr( $strscheduleindex, strpos( $strscheduleindex . constant("DISPLAY_VALUE_SEPARATOR"), constant("DISPLAY_VALUE_SEPARATOR") ) + 1 )))
    {
      // dropdownbox had been changed
      // -> update

      $strdbsql = "NULL";
      if ( $intschedulevalue != constant("DB_ID_NONE") )
      {
        $strdbsql = strval( intval( $intschedulevalue ));
      }

      $strdbsql = " update tbl_schedule " .
                " set sd_ws_id = " . $strdbsql .
                " where sd_id = " . strval( intval( $intscheduleindex ));

      addmsg ( 'Running SQL: ' . $strdbsql );
      if ( db_sql( $intdbconnid, $strdbsql, $intdbresult, $lngdbrows, $strdberror ) )
      {
        if ( $lngdbrows > 0 )
        {
          // schedule updated
          // continue
          $intcount = $intcount + 1;
        }
        else
        {
          // schedule not updated
          addmsg ( 'Sorry, die Scheduleposition mit der ID ' . strval( intval( $intscheduleindex )) . ' konnte nicht geschrieben werden.<br />Die Datenbank sagt: ' . $strdberror );
          $bolok = false;
        }
      }
      else
      {
        // error accessing database
        addmsg ( 'Sorry, die Datenbank ist momentan nicht für die Aktualisierung des Schedules verfügbar.<br />Die Datenbank sagt: ' . $strdberror );
        $bolok = false;
      }
    }
    else
    {
      // dropdownbox had not been changed
      // -> ignore
    }
  }
  addmsg ( 'Es wurden ' . $intcount . ' Slots erfolgreich aktualisiert.' );
  showmsg();
}


if ( $bolsdupdate || $bolsdactivate )
{
  $bolok = false;
  $strtablehead = '';

  // prepare table header with room names
  // read rooms
  $strdbsql = " select ro_name" .
              " from tbl_rooms ro" .
              " order by ro_schedpos";
  //addmsg ( 'Running SQL: ' . $strdbsql );
  if ( db_sql( $intdbconnid, $strdbsql, $intdbresult, $lngdbrows, $strdberror ) )
  {
    if ( $lngdbrows > 0 )
    {
      // rooms found
      // -> use them

      $strtablehead = '';

      while ( db_row ( $intdbresult, $strdbrow, constant("DB_ROW_NEXT"), $strdberror ))
      {
        // for each room:
        {
        $strtablehead = $strtablehead .
        '
                <td class="db">' . $strdbrow['ro_name'] . '</td>
        ';
        }
      }
      $bolok = true;
    }
    else
    {
      // no rooms found
      // -> hmm, that should not happen, but even then there should be no data anyway...
    }
  }
  else
  {
    // error accessing database
    addmsg ( 'Sorry, die Datenbank ist momentan nicht für die Abfrage der Raumliste verfügbar.<br />Die Datenbank sagt: ' . $strdberror );
  }

  // Achtung:
  // Der "Fahrplan Editor" benötigt für die Dropdownlisten auch die Variable $strworkshoplist,
  // welche weiter oben im Rahmen des Kapitels "Workshop Editor" erstellt wurde.

  showmsg();
}

echo
'
<div>
<form id="sdeditorform" name="sdeditorform" action="' . constant("SERVER_FILE_MYSELF") . '" method="post">
<p>
Hier kann der Fahrplan bearbeitet werden, der anschließend mittels &quot;make install Fahrplan&quot; veröffentlicht werden kann. <br />
Achtung: Der alte Fahrplan wird dabei in der Datenbank unwiderruflich überschrieben! <br />
</p>
';


//write fahrplan

if ( $bolsdupdate || $bolsdactivate )
{
  $stroutput = '';

  if ( $bolok )
  {
    // read schedule slots with workshops
    $strdbsql = " select extract(hour from sd_begintime) as sd_begintime_hour, extract(day from sd_begintime) as sd_begintime_day," .
                " extract(month from sd_begintime) as sd_begintime_month, extract(year from sd_begintime) as sd_begintime_year," .
                " extract(dow from sd_begintime) as sd_begintime_weekday, sd_begintime," .
                " sd_id, ws_id, ws_name, ws_speakers,".
                " ro_name" .
                " from tbl_schedule sd" .
                " left join tbl_workshops ws on sd.sd_ws_id = ws.ws_id" .
                " left join tbl_rooms ro on sd.sd_ro_id = ro.ro_id" .
                " order by sd_begintime, ro_schedpos";
    //addmsg ( 'Running SQL: ' . $strdbsql );
    if ( db_sql( $intdbconnid, $strdbsql, $intdbresult, $lngdbrows, $strdberror ) )
    {
      if ( $lngdbrows > 0 )
      {
        // scheduled events found
        // -> use them

        // es folgt: Gruppenwechsel über Tag, Timeslot, Raum, Schedule-Event

        // Gesamtvorlauf
        $intsdyear = 0;
        $intsdmonth = 0;
        $intsdday = 0;
        $intsdhour = 0;
        $strroname = '';
        $boleof = false;

        $boleof = !db_row ( $intdbresult, $strdbrow, constant("DB_ROW_NEXT"), $strdberror );

        while ( !$boleof )
        {
          // Gruppenvorlauf Tag
          $intsdyear = $strdbrow['sd_begintime_year'];
          $intsdmonth = $strdbrow['sd_begintime_month'];
          $intsdday = $strdbrow['sd_begintime_day'];
          // neue Tabelle initialisieren
          $intcolrot = 1;
          $stroutput = $stroutput .
          '
            <div class="chapter">
              <table class="db">
                <tr class="dbhead">
                  <td class="db">
                    ' . $strweekdayname[ $strdbrow['sd_begintime_weekday'] ] . '<br />
                    ' . $intsdday . '.' . $intsdmonth . '.
                  </td>
          ';
          $stroutput = $stroutput . $strtablehead;
          $stroutput = $stroutput .
          '
                </tr>
          ';

          while
          (
            !$boleof
            &&
            (
              $intsdyear == $strdbrow['sd_begintime_year']
              &&
              $intsdmonth == $strdbrow['sd_begintime_month']
              &&
              $intsdday == $strdbrow['sd_begintime_day']
            )
          )
          {
            // Gruppenvorlauf Timeslot
            $intsdhour = $strdbrow['sd_begintime_hour'];
            // neue Tabellenzeile initialisieren
            $intcolrot = abs( $intcolrot - 1 );
            $stroutput = $stroutput .
            '
                <tr class="db' . $intcolrot . '">
                  <td class="db">
                    ' . $intsdhour . '<span class="small">:00</span>
                  </td>
            ';

            while
            (
              !$boleof
              &&
              (
                $intsdyear == $strdbrow['sd_begintime_year']
                &&
                $intsdmonth == $strdbrow['sd_begintime_month']
                &&
                $intsdday == $strdbrow['sd_begintime_day']
              )
              &&
              (
                $intsdhour == $strdbrow['sd_begintime_hour']
              )
            )
            {

              // Gruppenvorlauf Schedule-Event
              $strroname = $strdbrow['ro_name'];
              // neue Tabellenzelle initialisieren
              $stroutput = $stroutput .
              '
                  <td class="dbdata">
              ';

              while
              (
                !$boleof
                &&
                (
                  $intsdyear == $strdbrow['sd_begintime_year']
                  &&
                  $intsdmonth == $strdbrow['sd_begintime_month']
                  &&
                  $intsdday == $strdbrow['sd_begintime_day']
                )
                &&
                (
                  $intsdhour == $strdbrow['sd_begintime_hour']
                )
                &&
                (
                  $strroname == $strdbrow['ro_name']
                )
              )
              {
                // Datensatz (Schedule-Event) verarbeiten
                $stroutput = $stroutput . '<select class="dbdata" name="cboschedule[' . $strdbrow["sd_id"] . constant("DISPLAY_VALUE_SEPARATOR") . $strdbrow['ws_id'] . ']">' . selectws( $strdbrow['ws_id'] ) . '</select>';

                // neuen Datensatz lesen
                $boleof = !db_row ( $intdbresult, $strdbrow, constant("DB_ROW_NEXT"), $strdberror );
              }
              // Gruppennachlauf Schedule-Event
              // Tabellenzelle finalisieren
              $stroutput = $stroutput .
              '
                  </td>
              ';

            }
            // Gruppennachlauf Timeslot
            // Tabellenzeile finalisieren
            $stroutput = $stroutput .
            '
                </tr>
            ';

          }

          // Gruppennachlauf Tag
          // Tabelle finalisieren
          $stroutput = $stroutput .
          '
              </table>
            </div>
          ';
        }

        // Gesamtnachlauf
        // Gesamtausgabe finalisieren

        //addmsg ( 'Die Fahrplandaten wurden erfolgreich zusammengestellt. Die Fahrplandatei kann jetzt geschrieben werden.' );
        $bolok = true;
      }
      else
      {
        // no scheduled events found
        // -> hmm, that should not happen, but even then there should be no data anyway...
      }
    }
    else
    {
      // error accessing database
      addmsg ( 'Sorry, die Datenbank ist momentan nicht für die Abfrage der Workshops verfügbar.<br />Die Datenbank sagt: ' . $strdberror );
    }
  }

  if ( $bolok )
  {
    // operation has succeeded -> now write fahrplan
    echo
    '
    <div class="box">' . $stroutput .
    '
    <p>
    <input name="cmdsdupdate" type="submit" value="Fahrplan jetzt aktualisieren!" />
    </p>
    </div>
    ';
  }
}
else
{
  echo
  '
  <p>
  <input name="cmdsdactivate" type="submit" value="Fahrplan editieren..." />
  </p>
  ';
}

echo
'
</form>
</div>
';
showmsg();





// show run SQL chapter

echo
'
<div class="chapter">
<h4>run SQL</h4>
</div>
';

$bolok = false;

if ( $bolrunsql && $strsql != '' )
{
  // runs SQL statement

  // be careful now:
  // fire raw sql statement to database
  $strdbsql = $pstrsql;
  // write defused sql statement to screen
  addmsg ( 'Running SQL: ' . $strdbsql );

  if ( db_sql( $intdbconnid, $strdbsql, $intdbresult, $lngdbrows, $strdberror ) )
  {
    addmsg ( $lngdbrows . ' records found.' );

    if ( db_fields ( $intdbresult, $strdbfields, $strdberror ))
    {

      echo
      '
        <div>
          <table class="db">
            <tr class="dbhead">
      ';

      foreach ( $strdbfields[constant("DB_FIELD_NAME")] as $intindex => $strvalue )
      {
      echo
      '
              <td class="db">' . $strvalue . '</td>
      ';
      }

      echo
      '
            </tr>
      ';

      //if ( db_row ( $intdbresult, $strdbrow, constant("DB_ROW_FIRST"), $strdberror ))
      $intcolrot = 0;
      while ( db_row ( $intdbresult, $strdbrow, constant("DB_ROW_NEXT"), $strdberror ))
      {
        echo
        '
            <tr class="db' . $intcolrot . '">
        ';

        $intindex = 1;
        foreach ( $strdbfields[constant("DB_FIELD_NAME")] as $intindex => $strvalue )
        {
          echo
          '
              <td class="db">' . $strdbrow[ $strvalue ] . '</td>
          ';
        }

      echo
      '
            </tr>
      ';

        $intcolrot = abs( $intcolrot - 1 );
      }

      echo '</table></div>';

      $bolok = true;
    }
    else
    {
      addmsg ( 'Error reading the fields!<br />Database says: ' . $strdberror );
    }
  }
  else
  {
    addmsg ( 'Error accessing the database!<br />Database says: ' . $strdberror );
  }
}
showmsg();

echo
'
<div>
<form id="runsqlform" name="runsqlform" action="' . constant("SERVER_FILE_MYSELF") . '" method="post">
<p>
Hier können beliebige SQL-Kommandos (getrennt durch Semikoli, Zeilenumbrüche möglich) auf die Datenbank abgesetzt werden.<br />
Vorsicht: Dabei lässt sich auf sehr einfache und hochperformante Weise die Datenbank schrotten. ;-) <br />
<span class="line important"><span class="topic">Erste und einzige Regel:</span>Prüfe immer zuerst mit SELECT, was Du mit UPDATE oder DELETE anfassen willst!</span>
</p>
<p>
<span class="topic">SQL:</span><textarea class="db" name="txtsql">'. $strsql .'</textarea>
<input name="cmdrunsql" type="submit" value="Three-Two-One...Fire!" />
</p>
</form>
</div>
';
showmsg();





// close page and stoprun.
echo
'
<!-- end of specific page content -->

';
readfile( constant("SERVER_FILE_EXTRO") );

die();

?>