<?php
// vim: set ai ts=4 sw=4 ft=php:
/**
 * Writes config files
 * This writes configuration files to /etc/asterisk
 *
 * License for all code of this FreePBX module can be found in the license file inside the module directory
 * Copyright 2006-2014 Schmooze Com Inc.
 */

class WriteConfig {

	/**
	 * Header gets added to every generated file
	 */
	const HEADER = ";--------------------------------------------------------------------------------;
;          Do NOT edit this file as it is auto-generated by FreePBX.             ;
;--------------------------------------------------------------------------------;
; For information on adding additional paramaters to this file, please visit the ;
; FreePBX.org wiki page, or ask on IRC. This file was created by the new FreePBX ;
; BMO - Big Module Object. Any similarity in naming with BMO from Adventure Time ;
; is totally deliberate.                                                         ;
;--------------------------------------------------------------------------------;
";

	/**
	 * __construct function
	 *
	 * @param object $freepbx The FreePBX BMO Object
	 * @param array $array of files to write out with data
	 * Such as : array('modules.conf' => 'string')
	 * or array('modules.conf' => array('line','line','line'))
	 */
	public function __construct($freepbx = null, $array = null) {
		if ($freepbx == null) {
			throw new Exception("Need to be instantiated with a FreePBX Object");
		}

		$this->freepbx = $freepbx;

		if ($array !== null) {
			$this->writeConfigs($array);
		}
	}

	/**
	 * Write single configuration file
	 *
	 * Simply builds an array and passes it to writeConfigs()
	 * @param string $filename File to write
	 * @param mixed $contents What should be written to the file
	 * @param bool $generateHeader Backward compatibility to generate FreePBX header or not
	 */
	public function writeConfig($filename = null, $contents, $generateHeader = true) {
		if ($filename == null)
			throw new Exception("No filename given to writeConfig. This is a bug");

		$this->writeConfigs(array($filename => $contents), $generateHeader);
	}

	/**
	 * Write multiple configuration files.
	 * This is the public call to write configuration files.
	 * @param array $array An array of [filename]=>array(line, line, line), or [filename]=>string
	 * @param bool $generateHeader Backward compatibility to generate FreePBX header or not
	 */
	public function writeConfigs($array, $generateHeader = true) {
		if(!is_array($array)){
			return true;
		}
		foreach ($array as $file => $contents) {
			$this->writeFile($this->validateFilename($file), $contents, $generateHeader);
		}
	}

	/**
	 * Ensure filename is safe to write
	 * @param string $file Filename (without any directory)
	 * @return string Returns full path to file
	 * @access private
	 */
	private function validateFilename($file) {
		// Check to make sure it doesn't have any /'s or ..'s
		// in it. We're only allowed to write to /etc/asterisk

		if (strpos($file, "/") !== false) {
			// We EXPLICITLY ALLOW 'digium_phones/$filename'
			if (strpos($file, "digium_phones/") !== 0) {
				throw new Exception("$file contains a / and isn't a digium_phones file");
			}
		}

		if (strpos($file, "..") !== false) {
			throw new Exception("$file contains ..");
		}
		$dir = $this->freepbx->Config->get('ASTETCDIR');
		$filename = $dir."/$file";
		if (is_link($filename)) {
			$filename = readlink($filename);
		}
		return $filename;
	}

	/**
	 * Actually write the file
	 * @param string $filename Full path to file
	 * @param mixed $contents String or Array to write to the file
	 * @param bool $generateHeader Backward compatibility to generate FreePBX header or not
	 * @return boolean Always returns true, unless it throws and exception
	 * @access private
	 */
	private function writeFile($filename, $contents, $generateHeader = true) {
		if ($contents === false) {
			// False means 'delete'
			unlink($filename);
			return true;
		}

		$header = "";
		if (is_array($contents)) {
			// It's an array of things.
			//
			// It should be array('object' => array('line', 'line', 'line'))
			//    or
			// array('object' => 'string\nstring\n')
			//
			// Note that the magic item 'HEADER' will be placed at the start of the file,
			// after the default 'Generated by FreePBX' header.
			//
			$output = "\n";
			foreach ($contents as $title => $item) {
				if ($title == "HEADER") {
					if (is_array($item)) {
						$header = implode("\n", $item)."\n";
					} else {
						$header = $item."\n";
					}
				} else {
					$output .= "[$title]\n";
					if (is_array($item)) {
						foreach ($item as $i => $v) {
							if (is_array($v)) {
								// Multiple settings to the same key
								foreach ($v as $opt) {
									$output .= "$i = $opt\n";
								}
							} else {
								if (is_numeric($i)) { // It's not keyed
									$output .= "$v\n";
								} else { // It has a key.
									$output .= "$i=$v\n";
								}
							}
						}
					} else {
						$output .= $item;
					}
					$output .= "\n";
				}
			}
		} else {
			$output = $contents;
		}

		// Now I have a string, and can write it out.
		// print "Writing: ".$this->getHeader().$header.$output."\n";
		$freepbxHeader = ($generateHeader) ? $this->getHeader() : '';
		file_put_contents($filename, $freepbxHeader.$header.$output);
		return true;
	}

	/**
	 * Return the static header, as a function.
	 * @return string Header
	 */
	public function getHeader() {
		return self::HEADER;
	}
}
