<?php
  /*
     * $Id$
     *
     * MAIA MAILGUARD LICENSE v.1.0
     *
     * Copyright 2005 by Robert LeBlanc <rjl@renaissoft.com>
     *                   David Morton   <mortonda@dgrmm.net>
     * All rights reserved.
     *
     * PREAMBLE
     *
     * This License is designed for users of Maia Mailguard
     * ("the Software") who wish to support the Maia Mailguard project by
     * leaving "Maia Mailguard" branding information in the HTML output
     * of the pages generated by the Software, and providing links back
     * to the Maia Mailguard home page.  Users who wish to remove this
     * branding information should contact the copyright owner to obtain
     * a Rebranding License.
     *
     * DEFINITION OF TERMS
     *
     * The "Software" refers to Maia Mailguard, including all of the
     * associated PHP, Perl, and SQL scripts, documentation files, graphic
     * icons and logo images.
     *
     * GRANT OF LICENSE
     *
     * Redistribution and use in source and binary forms, with or without
     * modification, are permitted provided that the following conditions
     * are met:
     *
     * 1. Redistributions of source code must retain the above copyright
     *    notice, this list of conditions and the following disclaimer.
     *
     * 2. Redistributions in binary form must reproduce the above copyright
     *    notice, this list of conditions and the following disclaimer in the
     *    documentation and/or other materials provided with the distribution.
     *
     * 3. The end-user documentation included with the redistribution, if
     *    any, must include the following acknowledgment:
     *
     *    "This product includes software developed by Robert LeBlanc
     *    <rjl@renaissoft.com>."
     *
     *    Alternately, this acknowledgment may appear in the software itself,
     *    if and wherever such third-party acknowledgments normally appear.
     *
     * 4. At least one of the following branding conventions must be used:
     *
     *    a. The Maia Mailguard logo appears in the page-top banner of
     *       all HTML output pages in an unmodified form, and links
     *       directly to the Maia Mailguard home page; or
     *
     *    b. The "Powered by Maia Mailguard" graphic appears in the HTML
     *       output of all gateway pages that lead to this software,
     *       linking directly to the Maia Mailguard home page; or
     *
     *    c. A separate Rebranding License is obtained from the copyright
     *       owner, exempting the Licensee from 4(a) and 4(b), subject to
     *       the additional conditions laid out in that license document.
     *
     * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS
     * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
     * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
     * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
     * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
     * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
     * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
     * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
     * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
     * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     *
     */


     /* This file facilitates upgrades by running upgrade scripts located in 
        the admin/scripts directory.  By convention, these scripts are named
        1.php, 2.php, etc... and each contains functions such as:
           precheck_1()
           updgrade_1()
           postcheck_1()

        the update process will check the database version of the current 
        installation, and perform the needed changes to the database.

      */
      
      require_once ("../core.php");
      require_once ("../maia_db.php");

      
      define("CODE_VERSION", 15);
      define('OK', "ok");
      define('WARN', "warn");
      define('ERROR', "error");
      define('UPDATE', "update");
      
      function table_exists($table_name)
      {
        global $dbh;
        if (is_mysql()) {
          $info = $dbh->tableInfo($table_name);
          if (DB::isError($info)) {
           return false;
          } else {
           return true;
          }

        } else {  // tableInfo generates errors, which I think triggers transaction errors.
          $select = "select count(*) from information_schema.tables WHERE table_name = ?";
          $sth = $dbh->query($select,$table_name);
          $row =  $sth->fetchrow();
          if ($row['count'] == 1) {
             return true;
          } else {
            return false;
          }
           
        }
      }
      
      function column_exists($table, $column_name)
      {
        global $dbh;
        $select = "SELECT $column_name FROM " . $table . " LIMIT 1";
        $sth = $dbh->query($select);
        if (DB::isError($sth)) {
            return false;
        } else {
            $sth->free();
            return true;
        }
      }

      function column_type($table_name, $column_name)
      {
        global $dbh;
        $db_name = database_name();
        if (is_mysql()) {
            $typecol = "data_type";
            $dbcol = "table_schema";
        } else {
            $typecol = "udt_name";
            $dbcol = "table_catalog";
        }
        $select = "SELECT " . $typecol . " FROM information_schema.columns " .
                  "WHERE " . $dbcol . " = ? AND table_name = ? AND column_name = ?";
        $sth = $dbh->query($select, array($db_name, $table_name, $column_name));
         if (DB::isError($sth)) {
             return 'error:' . $sth->getMessage();
         } else {
             if ($row = $sth->fetchRow()) {
	            return $row[$typecol];
             }
             return 'error - no match';
	     }
      }

      function index_exists($table_name, $index_name)
      {
        global $dbh;;
        if (is_mysql()) {

            $select = "SHOW INDEX FROM " . $table_name;
            $sth = $dbh->query($select);
            if (DB::isError($sth)) {
                return false;
            } else {
                $found = false;
                while ($row = $sth->fetchRow()) {
                    if ($row['Key_name'] == $index_name) {
                        $found = true;
                    }
                }
                $sth->free();
                return $found;
            }

        } else {

            $select = "SELECT i.relname AS indexname " .
                      "FROM pg_class c, pg_class i " .
                      "WHERE ((c.relkind = 'r'::\"char\") " .
                      "AND (i.relkind = 'i'::\"char\") " .
                      "AND (i.relname = ?) " .
                      "AND (c.relname = ?))";
            $sth = $dbh->query($select, array($index_name, $table_name));
            if (DB::isError($sth)) {
                return false;
            } else {
                $found = false;
                if ($row = $sth->fetchRow()) {
                    $found = true;
                }
                $sth->free();
                return $found;
            }

         }
      }
       
      function is_mysql() {
        global $maia_sql_dsn ;
        return strpos($maia_sql_dsn, "mysql") === false ? false : true; 
      }

      function database_name() {
        global $maia_sql_dsn;
        if (preg_match('/(.*)\/(.+)$/', $maia_sql_dsn, $matches)) {
          return $matches[2];
        }
        // we're already connected, so the DSN must be valid,
        // ergo the match above should always succeed.
        return '';
      }
      
      function load_script($version) {
        require_once "scripts/$version" . ".php"; 
      }
      
      function process_script($version) {
        print "<h2>Running script $version </h3>\n";
        $pre     = "pre_check_" . $version;
        $upgrade = "upgrade_" . $version;
        $post    = "post_check_" . $version;
        
        if (list($result, $mesg) = $pre()) {
          if ($result == true) {
            print "Pre check successful... starting upgrade to version $version.<br>\n";
          } else {
            print "Pre-check not successful: $mesg<br>skipping...\n";
            return WARN;
          }
        }
         
        if ( list($result, $mesg) = $upgrade()) {
          if ($result == true) {
            print "Upgrade script successful... <br>\n";
            
          } else {
            print "Upgrade not successful: $mesg\n";
            return ERROR;
          }
        }
        
        if ( list($result, $mesg) = $post()) {
          if ($result == true) {
            print "Post check successful... <br>\n";
          } else {
            print "Pre-check not successful: $mesg\n";
            return ERROR;
          }
       }

        
        
      }
      
      function update_schema_info($version) {
        global $dbh;
        $update = "UPDATE schema_info SET version=?";
        return $dbh->query($update, $version); 
      }
      
      //look up the current installed database version. if not found, start with zero.
      if (table_exists('schema_info')) {
        $select = "SELECT version FROM schema_info LIMIT 1";
        $sth = $dbh->query($select);

        $row =  $sth->fetchrow();
        $db_version = $row['version']; 
        $sth->free();
         
      } else {
         $db_version=-1; //off by one error... present state is not yet to revision 0.  
      }     
      
      if ($db_version == CODE_VERSION) {
        print "Database is already up to date!  Exiting.";
        exit(); 
      }
      
      if ($db_version > CODE_VERSION) {
        print "<font color='red'>Big time trouble!</font> - Your database may be more advanced (newer) than this code.  Are you using the right 
               code and database? <br>Database version: " . $db_version . "<br>Code version: " . CODE_VERSION . "<br>Exiting.";
        exit;
      }
      
      //loop from current database version to current code database version,
      // doing pre_check_x, upgrade_x, and post_check_x 
      
      $dbh->autoCommit(false);
      for ($version = $db_version + 1; $version <= CODE_VERSION; $version++) { //start with next revision number.
        load_script($version);
        $result = process_script($version);
        if ($result == ERROR) {
           print "<h1>Aborting upgrade, due to fatal errors.</h1>\n";
           print "Please consult the <a href=\"mailto:maia-users@renaissoft.com\">Maia Users</a> Mailing list for help\n";
           $dbh->rollback();
           exit();
        } else {
          update_schema_info($version);
          print "<li>" . ($result == WARN ? "skipped" : "executed") . " script: " . $version . "</li>"; 
        }
           
      }
      $dbh->commit();
      
      
      
      
      
      
?>
