<?php 
//vim: ts=2 sw=2

set_include_path(get_include_path() . PATH_SEPARATOR . '../../app');
include_once "base_controller.php";

function cmp($a, $b) {
  if ($a['order'] == $b['order'])
    return 0;
  else 
    return $a['order'] > $b['order'];
}

class ServiceControlController extends BaseController {

  function __construct() {
    $this->service_mapping = array(
      array(
        'name' => 'http',
        'label' => 'HTTP',
        'proc_name' => 'nginx',
        'service_name' => 'http',
        'order' => 1
      ),
      array(
        'name' => 'https',
        'label' => 'HTTPS',
        'proc_name' => 'nginx',
        'service_name' => 'https',
        'order' => 2
      ),
      array(
        'name' => 'mqtt',
        'label' => 'MQTT',
        'proc_name' => 'mqtt-service',
        'order' => 30
      ),
    );

    $pname = platformName();
    if ($pname == 'FS') {
      array_push($this->service_mapping, 
        array(
          'name' => 'ftp',               //service name
          'label' => 'Ftp',
          'proc_name' => 'pure-ftpd',  // service process pattern 
          'order' => 10
        ),
        array(
          'name' => 'ssh',
          'label' => 'SSH',
          'proc_name' => 'sshd',
          'order' => 20 
        ),
        array(
          'name' => 'openvpn',
          'label' => 'OpenVPN',
          'proc_name' => 'openvpn',
          'order' => 25 
        ),
        array( 
          'name' => 'smb',
          'label' => 'Samba',
          'proc_name' => 'smbd',
          'service_name' => 'smb',
          'order' => 40
        )
      );
    } else if ($pname == "FW") {
      array_push($this->service_mapping, 
        array(
          'name' => 'ssh',
          'label' => 'SSH',
          'proc_name' => 'dropbear',
          'order' => 20 
        ),
        array( 
          'name' => 'smb',
          'label' => 'Samba',
          'proc_name' => 'smbd',
          'service_name' => 'samba',
          'order' => 40
        )
      );
    }

    //sort service tuples by 'order' value
    usort($this->service_mapping, "cmp");
  }

  protected function signinRequired() {
    return true;
  }

  protected function adminRequired() {
    return true;
  }

  protected function isProcessRunning($proc_name) {
    $cmd = 'ps | grep "' . $proc_name . '" | grep -v grep';
    return !is_null(shell_exec($cmd))
  }

  protected function isServiceEnabled($name) {
    $cmd = null;
    if ($name == 'http') {
      $cmd = 'cat /etc/nginx/nginx.conf | grep "^\s*include http_server.conf;\s*$"';
    } else if ($name == 'https') {
      $cmd = 'cat /etc/nginx/nginx.conf | grep "^\s*include https_server.conf;\s*$"';
    } else {
      $pname = platformName();
      if ($pname == "FS")
        $cmd = 'ls /etc/init.d/S??' . $name ;
      else if ($pname == "FW")
        $cmd = 'ls /etc/rc.d/S??' . $name ;
      else {
        error_log("$pname is not supported yet");
        return;
      }
    }

    return !is_null(shell_exec($cmd))
  }

  protected function doAjaxGet() {
    $response = array('services' => array());
    foreach($this->service_mapping as $service) {
      $service_name = isset($service['service_name']) ? $service['service_name'] : $service['proc_name'];
      $response['services'][] = array(
        'name' => $service['name'],
        'label' => $service['label'],
        'running' => $this->isProcessRunning($service['proc_name']),
        'enabled' => $this->isServiceEnabled($service_name),
      );
    }
    $this->renderAjaxSuccess2($response);
  }

  protected function controlWeb($service_name, $action) {
    $cmd = null;
    if ($action == 'enable') {
      $cmd = 'sed -i -re "s/^\s*#(\s*include ' . $service_name . '_server.conf;\s*)$/\1/" /etc/nginx/nginx.conf';
    } else if ($action == 'disable') {
      if ( ($service_name == 'http' && !$this->isServiceEnabled('https')) 
        || ($service_name == 'https' && !$this->isServiceEnabled('http')) )
        $this->renderAjaxError($response, "can not disable both http and https service");

      $cmd = 'sed -i -re "s/^(\s*include ' . $service_name . '_server.conf;\s*)$/#\1/" /etc/nginx/nginx.conf';
    }
    else {
      error_log("action '$action' is not supported for web service");
      return;
    }

    $pname = platformName();
    $cmd = $cmd . ' && ' . ($pname == 'FS' ? '/etc/init.d/S??nginx restart' : '/etc/rc.d/S??nginx restart');

    shell_exec($cmd)
  }

  private function controlCmd($service_name, $action) {
    $cmd = null;
    $pname = platformName();
    if ($action == 'enable') {
      if ($pname == 'FS')
        $cmd = 'for s in /etc/init.d/D??' . $service_name . ' ; do $s start && mv $s /etc/init.d/S${s#/etc/init.d/D}; done'; 
      else if ($pname == 'FW')
        $cmd = '/etc/init.d/' . $service_name . ' enable && /etc/init.d/' . $service_name . ' restart'; 
    } else if ($action == 'disable') {
      if ($pname == 'FS')
        $cmd = 'for s in /etc/init.d/S??' . $service_name . ' ; do $s stop && mv $s /etc/init.d/D${s#/etc/init.d/S}; done'; 
      else
        $cmd = '/etc/init.d/' . $service_name . ' disable && /etc/init.d/' . $service_name . ' stop'; 
    } else  {
      error_log("action '$action' is not supported");
    }
    return $cmd;
  }

  protected function doAction($service, $action) {
    if ($service['name'] == 'http' || $service['name'] == 'https') {
      $this->controlWeb($service['service_name'], $action);
      return;
    }

    $cmd = null;
    $service_name = isset($service['service_name']) ? $service['service_name'] : $service['proc_name'];
    
    $cmd = $this->controlCmd($service_name, $action);
    if (!is_null($cmd))
      shell_exec($cmd)
  }

  protected function doAjaxPost() {
    $response = array();

    if (!isset($_POST['name']) || !isset($_POST['action'])) {
      $this->renderAjaxError($response, "missing parameter");
      return;
    }

    $name = $_POST['name'];
    $action = $_POST['action'];

    $valid_actions = array('enable', 'disable');
    if (!in_array($action, $valid_actions)) {
      $this->renderAjaxError($response, "invalid service action");
      return;
    }

    $found = false;
    foreach($this->service_mapping as $service) {
      if ($service['name'] != $name)
        continue;

      $this->doAction($service, $action);
      $found = true;
      break;
    }

    if ($found)
      $this->renderAjaxSuccess(array('resultCode' => 0));
    else
      $this->renderAjaxError($response, "invalid service name");
  }

}

$controller = new ServiceControlController();
$controller->run();

?>
<!DOCTYPE html>
<html>
  <head>
    <eta charset="utf-8" />
    <title>Service Control</title>
    <eta name="viewport" content="width=device-width, initial-scale=1.0">

    <link rel="stylesheet" href="../../css/bootstrap.min.css" media="screen" />
  </head>
  <body>
    <div class="container" id="service_control_content">
      <div class="navbar">
        <div class="navbar-inner">
          <a class="brand" href="/">EasyIO</a>
          <!-- <ul class="nav"> -->
          <!--   <li class="divider&#45;vertical"></li> -->
          <!--   <li v&#45;for="sec in sections" :class="{active:isSectionActive(sec)}"><a href="#" @click="active_sec_id=sec.sec_id">{{ sec.name }}</a></li> -->
          <!-- </ul> -->
        </div>
      </div>

      <div class="row">
        <div><h2 style="text-align:center">Service Control Panel</h2></div>
        <service-control></service-control>
      </div>
    </div>

    <!-- component templates -->
    <script type="text/x-template" id="service-control-template">
      <div class="span12">
        <table class="table table-striped table-hover">
          <thead>
            <tr>
              <th>Name</th>
              <th>Status</th>
              <th>Action</th>
            </tr>
          </thead>
          <tbody>
            <tr v-for="service in service_list" :class="{warning:!service.enabled}">
              <td>{{ service.label }}</td>
              <td><span class="label" :class="[service.enabled ? 'label-success' : 'label-warning',]">{{ service.enabled ? "Enabled" : "Disabled" }}</span></td>
              <td>
                <button class="btn" :class="{'btn-danger':service.enabled, 'disabled':!isServiceControllable(service)}" :disabled="!isServiceControllable(service)" @click="service.enabled ? disableService(service.name) : enableService(service.name)"> 
                  {{ service.enabled ? "Disable" : "Enable" }}
                </button>
              </td>
            </tr>
          </tbody>
        </table>
      </div>
    </script>

    <script type="text/javascript" src="../../js/jquery-1.10.0.min.js"></script>
    <script type="text/javascript" src="../../js/bootstrap.min.js"></script>
    <script type="text/javascript" src="../../js/underscore-min.js"></script>
    <script type="text/javascript" src="../../js/spin.min.js"></script>

<?php
  if (isset($_GET["dev"])) {
?>
    <script type="text/javascript" src="../../js/vue.js"></script>
<?php
  } else {
?>
    <script type="text/javascript" src="../../js/vue.min.js"></script>
<?php
  }
?>
    <script type="text/javascript" src="../../js/plugin-utils.js"></script>
    <script type="text/javascript" src="js/service_control.js"></script>
  </body>
</html>