<?php
/*
  ----------------------------------------------------------------------
  AlternC - Web Hosting System
  Copyright (C) 2000-2012 by the AlternC Development Team.
  https://alternc.org/
  ----------------------------------------------------------------------
  LICENSE
  
  This program is free software; you can redistribute it and/or
  modify it under the terms of the GNU General Public License (GPL)
  as published by the Free Software Foundation; either version 2
  of the License, or (at your option) any later version.
  
  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.
  
  To read the license please visit http://www.gnu.org/copyleft/gpl.html
  ----------------------------------------------------------------------
  Purpose of file: Manage UPnP ports forwarding from router
  ----------------------------------------------------------------------
*/

/**
* This class handle UPnP forwarding from a IGD/UPnP compliant router
* you need this only when you are behind a IGD-compliant router
* each class may exports a hook that defined named port/protocol to
* forward to the local IP address of the server.
* this class manage the upnp table 
* and its configuration from admin control panel
*/
class m_upnp {


  /* ----------------------------------------------------------------- */
  /** get the list of current upnp forwards and their status
   * @return array the attributes of all port-forwards
   */
  function get_forward_list() {
    global $db,$err;
    $err->log("upnp","get_forward_list");
    $db->query("SELECT * FROM upnp");
    $res=array();
    while ($db->next_record()) {
      $res[]=$db->Record;
    }
    return $res;
  }


  /* ----------------------------------------------------------------- */
  /** enable a upnp port in the upnp table
   * @param integer the id of the port to enable
   * @return boolean TRUE if the port has been properly forwarded
   * FALSE if an error occurred
   */
  function enable_port($id) {
    global $db,$err;
    $id=intval($id);
    $err->log("upnp","enable_port($id)");
    $db->query("SELECT enabled FROM upnp WHERE id=$id;");
    if (!$db->next_record()) {
      $err->raise("upnp",_("The required port is not currently defined"));
      return false;
    }
    if (!$db->f("enabled")) {
      $db->query("UPDATE upnp SET enabled=1 WHERE id=$id;");
      $err->raise("upnp",_("The specified upnp port is now enabled"));
      return true;
    }
    $err->raise("upnp",_("The specified upnp port is already enabled"));
    return true;
  }


  /* ----------------------------------------------------------------- */
  /** disable a upnp port in the upnp table
   * @param integer the id of the port to disable
   * @return boolean TRUE if the port has been properly forwarded
   * FALSE if an error occurred
   */
  function disable_port($id) {
    global $db,$err;
    $id=intval($id);
    $err->log("upnp","disable_port($id)");
    $db->query("SELECT enabled,mandatory FROM upnp WHERE id=$id;");
    if (!$db->next_record()) {
      $err->raise("upnp",_("The required port is not currently defined"));
      return false;
    }
    if ($db->f("mandatory")) {
      $err->raise("upnp",_("You can't disable that mandatory port forward"));
      return false;
    }
    if ($db->f("enabled")) {
      $db->query("UPDATE upnp SET enabled=0 WHERE id=$id;");
      $err->raise("upnp",_("The specified upnp port is now disabled"));
      return true;
    }
    $err->raise("upnp",_("The specified upnp port is already disabled"));
    return true;
  }


  /* ----------------------------------------------------------------- */
  /** cron launched every minute to check the status of UPnP forwarding
   */
  function cron() {
    global $hooks;
    // if we check anything less than 5 minutes ago, or if the upnp table is empty, let's make a check...
    $db->query("SELECT UNIX_TIMESTAMP(lastcheck) AS lc, * FROM upnp ORDER BY lastcheck ASC;");
    $forwards=array();
    $bigcheck=false;
    if (!$db->next_record()) {
      $bigcheck=true;
    } else {
      if ($db->f("lc")+600<time()) { 
	$bigcheck=true;
      }
      do {
	$db->Record["found"]=false;
	$forwards[]=$db->Record;
      } while ($db->next_record());
    }
    
    if ($bigcheck) {
      // Do the check first by calling the hooks & comparing the arrays
      $res=$hooks->invoke("hooks_upnp_list");
      foreach($res as $c=>$tmp) {
	foreach($tmp as $name=>$v) {

	  // We compare the hook array with the forwards array
	  $found=false;
	  for($i=0;$i<count($forwards);$i++) {
	    if ($forwards[$i]["class"]==$c && 
		$forwards[$i]["name"]==$name && 
		$forwards[$i]["protocol"]==$v["protocol"] && 
		$forwards[$i]["port"]==$v["port"] && 
		$forwards[$i]["mandatory"]==$v["mandatory"]) {
	      // Found it and unchanged
	      $forwards[$i]["found"]=true;
	      $found=true;
	    }
	  } // compare with forwards class.
	  if (!$found) {
	    // Mark it for creation
	    $db->query("INSERT INTO upnp SET mandatory='".addslashes($v["mandatory"])."', protocol='".addslashes($v["protocol"])."', port='".addslashes($v["port"])."', name='".addslashes($name)."', action='CREATE'");
	    $id=$db->last_id();
	    $forwards[]=array("id"=>$id, "mandatory" => intval($v["mandatory"]), "protocol" => $v["protocol"], "port" => intval($v["port"]), "name" => $name, "action" => "CREATE");
	  }
	} // for each port forward in that class
      } // for each hooked class
      // We search the "not found" and remove them from the array
      for($i=0;$i<count($forwards);$i++) {
	if (!$forwards[$i]["found"]) {
	  $forwards[$i]["action"]="DELETING";
	  $db->query("UPDATE upnp SET action='DELETING' WHERE id=".$forwards[$i]["id"].";");
	}
      }
      
      
    } // bigcheck ?
  }
  



  

} /* Class UPnP */