/modules/asterisk-1.0/libraries/Asterisk.php

https://github.com/robertleeplummerjr/bluebox · PHP · 269 lines · 163 code · 42 blank · 64 comment · 24 complexity · f433215b59043050e8a1216fcfa3dfc3 MD5 · raw file

  1. <?php defined('SYSPATH') or die('No direct access allowed.');
  2. /**
  3. * @package Asterisk
  4. * @author K Anderson <bitbashing@gmail.com>
  5. * @license Mozilla Public License (MPL)
  6. * @created Oct 5, 2009
  7. */
  8. class Asterisk extends Telephony_Driver
  9. {
  10. /**
  11. * Multi-dimensional array. Key is the filename, which contains an array generated by parse_ini_file
  12. * @var array
  13. */
  14. public $config;
  15. /**
  16. * An instance of the AsteriskManager object, allowing configuration remotely via the AMI interface.
  17. * @var AsteriskManager
  18. */
  19. public $ami;
  20. /**
  21. * Instance of AsteriskDoc. Keeps a working copy of any relevant loaded/modified Asterisk configuration files in memory
  22. * for committing later to disk or AMI.
  23. * @var AsteriskDoc
  24. */
  25. public $doc;
  26. /**
  27. *
  28. * @return Asterisk
  29. */
  30. public static function getInstance()
  31. {
  32. // create a new instance if there isnt one already
  33. if (!isset(self::$instance))
  34. {
  35. self::$instance = new self();
  36. Kohana::log('debug', 'Asterisk -> New instance of Asterisk telephony driver created.');
  37. // reset all the accumulators in this driver
  38. self::reset();
  39. }
  40. // return this instance
  41. return self::$instance;
  42. }
  43. /**
  44. * Loads a context/section from an Asterisk config file.
  45. * @param array $options Array with keys for filename and context (both are required)
  46. * @param boolean $useCache OK to use cache if already in memory? Defaults to TRUE
  47. * @return string String object containing loaded data, if any, or FALSE if failed
  48. *
  49. * TODO: Add ability to load an entire file (should just be the built-in php ini options command, but need to check AMI equiv)
  50. */
  51. public function load($options, $useCache = TRUE)
  52. {
  53. // sanity check on our necessary vars
  54. if (empty($options['filename']) || empty($options['context']))
  55. {
  56. return FALSE;
  57. }
  58. else
  59. {
  60. extract($options);
  61. }
  62. // CACHE: check if this file's config section is already loaded and if we're allowed to use it
  63. if ($useCache and isset(self::$instance->doc->fileCache[$filename][$context]))
  64. {
  65. // Already loaded
  66. Kohana::log('debug', 'Asterisk -> Using cached file ' . $filename . ' for context ' . $context);
  67. return self::$instance->doc->fileCache[$filename][$context];
  68. }
  69. Kohana::log('debug', 'Asterisk -> Loading file ' . $filename . ' for context ' . $context . ' into cache');
  70. // get the asterisk manager interface
  71. $ami = self::$instance->ami;
  72. // make sure we are connected/can connect
  73. if (!self::connectAMI($ami)) {
  74. return FALSE;
  75. }
  76. // load the config section and store it in the active in-memory document
  77. self::$instance->doc->fileCache[$filename][$context] = $ami->loadConfigContext($filename, $context);
  78. //Kohana::log('debug', 'Loaded ' . $filename . ' / context ' . $context . ":\n" . print_r(self::$instance->doc->fileCache, TRUE));
  79. return self::$instance->doc->fileCache[$filename][$context];;
  80. }
  81. public function save($options = NULL)
  82. {
  83. // Make sure there is something to do
  84. if (empty(self::$instance->doc->fileCache))
  85. {
  86. Kohana::log('debug', 'Asterisk -> Not saving - nothing was changed!');
  87. return TRUE;
  88. }
  89. Kohana::log('debug', 'Asterisk -> Saving queued changes to Asterisk config files (via AMI)');
  90. // get the asterisk manager interface
  91. $ami = self::$instance->ami;
  92. // make sure we are connected/can connect
  93. if (!self::connectAMI($ami))
  94. {
  95. Kohana::log('error', 'Asterisk -> Failed to connect to Asterisk AMI interface.');
  96. return FALSE;
  97. }
  98. // Loop through all the filenames and contexts that have changed
  99. foreach(self::$instance->doc->fileCache as $filename => $contexts)
  100. {
  101. // Loop through all the config contexts
  102. foreach($contexts as $context => $lines)
  103. {
  104. // Remove this config section (ignoring any errors during) and re-create and empty one
  105. if ($context != 'general')
  106. {
  107. $ami->queueConfigUpdate($filename, 'DelCat', $context, NULL, NULL, array(
  108. 'ignoreResponse' => AsteriskManager::AMI_DEL_FAIL2
  109. ));
  110. }
  111. // Only re-add this context if there's something actually in it
  112. if ($lines)
  113. {
  114. // Go through and add the category and all associated lines back to the file
  115. if ($context != 'general')
  116. {
  117. $ami->queueConfigUpdate($filename, 'NewCat', $context);
  118. }
  119. // Loop through all the updates for this config section
  120. foreach($lines as $lineNum => $line)
  121. {
  122. // try to split the update on the =
  123. $lineParts = explode('=', $line, 2);
  124. // if the split returned false (no = found) or fewer than two parts
  125. if (!empty($lineParts) && count($lineParts) == 2)
  126. {
  127. $ami->queueConfigUpdate($filename, 'Append', $context, $lineParts[0], $lineParts[1], array(
  128. 'skippredelete' => TRUE
  129. ));
  130. }
  131. else
  132. {
  133. Kohana::log('error', 'Asterisk -> Unable to queue \'' . $line . '\' for [' . $context . '] in ' . $filename);
  134. }
  135. }
  136. }
  137. }
  138. // Clear the internal queue of actions
  139. try
  140. {
  141. $ami->commitConfigUpdates();
  142. }
  143. catch(AsteriskManager_Exception $e)
  144. {
  145. // This is a place holder for later error checking
  146. Kohana::log('error', 'Asterisk -> Exception during commit for [' . $context . '] in ' . $filename . ': ' . $e->getMessage());
  147. }
  148. }
  149. }
  150. public function commit()
  151. {
  152. // get the asterisk manager interface
  153. $ami = self::$instance->ami;
  154. // make sure we are connected/can connect
  155. if (!self::connectAMI($ami))
  156. {
  157. Kohana::log('error', 'Asterisk -> Failed to connect to Asterisk AMI interface.');
  158. return FALSE;
  159. }
  160. $ami->send('reload');
  161. return TRUE;
  162. }
  163. public function render()
  164. {
  165. }
  166. public function reset()
  167. {
  168. // Are we already instantiated? If not, create an instance.
  169. if (!is_object(self::$instance->ami) || get_class(self::$instance->ami) != 'AsteriskManager')
  170. {
  171. self::$instance->ami = new AsteriskManager();
  172. }
  173. else
  174. {
  175. // We are instantiated - close any existing AMI connections
  176. Kohana::log('debug', 'Asterisk -> Disconnecting from active Asterisk server');
  177. try
  178. {
  179. //self::$instance->ami->logoff();
  180. }
  181. catch(Exception $e)
  182. {
  183. // If we can't disconnect, no biggie. Ignore
  184. }
  185. self::$instance->ami->cancelConfigUpdates();
  186. }
  187. // Reset the in-memory config document
  188. if (self::$instance->doc)
  189. {
  190. self::$instance->doc->reset();
  191. }
  192. else
  193. {
  194. self::$instance->doc = new AsteriskDoc();
  195. }
  196. }
  197. private static function connectAMI($ami)
  198. {
  199. // is the $ami a valid AsteriskManager object?
  200. if (!is_object($ami) || get_class($ami) != 'AsteriskManager')
  201. {
  202. return FALSE;
  203. }
  204. // Are we already connected? Don't connect again.
  205. if (!$ami->connected())
  206. {
  207. $config = array(
  208. 'host' => Kohana::config('asterisk.AmiHost') ,
  209. 'port' => Kohana::config('asterisk.AmiPort') ,
  210. 'username' => Kohana::config('asterisk.AmiUser') ,
  211. 'password' => Kohana::config('asterisk.AmiPass')
  212. );
  213. $ami->setConfig($config);
  214. try
  215. {
  216. $ami->connect();
  217. }
  218. catch(AsteriskManager_Exception $e)
  219. {
  220. // Server unavailable for whatever reason.
  221. Kohana::log('error', 'Unable to connect to Asterisk AMI interface: ' . $e->getMessage());
  222. return FALSE;
  223. }
  224. }
  225. return TRUE;
  226. }
  227. }