You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

rcmail_output_json.php 7.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  1. <?php
  2. /**
  3. +-----------------------------------------------------------------------+
  4. | program/include/rcmail_output_json.php |
  5. | |
  6. | This file is part of the Roundcube Webmail client |
  7. | Copyright (C) 2008-2012, The Roundcube Dev Team |
  8. | |
  9. | Licensed under the GNU General Public License version 3 or |
  10. | any later version with exceptions for skins & plugins. |
  11. | See the README file for a full license statement. |
  12. | |
  13. | PURPOSE: |
  14. | Class to handle JSON (AJAX) output |
  15. +-----------------------------------------------------------------------+
  16. | Author: Thomas Bruederli <roundcube@gmail.com> |
  17. | Author: Aleksander Machniak <alec@alec.pl> |
  18. +-----------------------------------------------------------------------+
  19. */
  20. /**
  21. * View class to produce JSON responses
  22. *
  23. * @package Webmail
  24. * @subpackage View
  25. */
  26. class rcmail_output_json extends rcmail_output
  27. {
  28. protected $texts = array();
  29. protected $commands = array();
  30. protected $callbacks = array();
  31. protected $message = null;
  32. public $type = 'js';
  33. public $ajax_call = true;
  34. /**
  35. * Issue command to set page title
  36. *
  37. * @param string $title New page title
  38. */
  39. public function set_pagetitle($title)
  40. {
  41. if ($this->config->get('devel_mode') && !empty($_SESSION['username'])) {
  42. $name = $_SESSION['username'];
  43. }
  44. else {
  45. $name = $this->config->get('product_name');
  46. }
  47. $this->command('set_pagetitle', empty($name) ? $title : $name . ' :: ' . $title);
  48. }
  49. /**
  50. * Register a template object handler
  51. *
  52. * @param string $obj Object name
  53. * @param string $func Function name to call
  54. */
  55. public function add_handler($obj, $func)
  56. {
  57. // ignore
  58. }
  59. /**
  60. * Register a list of template object handlers
  61. *
  62. * @param array $arr Hash array with object=>handler pairs
  63. */
  64. public function add_handlers($arr)
  65. {
  66. // ignore
  67. }
  68. /**
  69. * Call a client method
  70. *
  71. * @param string Method to call
  72. * @param ... Additional arguments
  73. */
  74. public function command()
  75. {
  76. $cmd = func_get_args();
  77. if (strpos($cmd[0], 'plugin.') === 0) {
  78. $this->callbacks[] = $cmd;
  79. }
  80. else {
  81. $this->commands[] = $cmd;
  82. }
  83. }
  84. /**
  85. * Add a localized label to the client environment
  86. */
  87. public function add_label()
  88. {
  89. $args = func_get_args();
  90. if (count($args) == 1 && is_array($args[0])) {
  91. $args = $args[0];
  92. }
  93. foreach ($args as $name) {
  94. $this->texts[$name] = $this->app->gettext($name);
  95. }
  96. }
  97. /**
  98. * Invoke display_message command
  99. *
  100. * @param string $message Message to display
  101. * @param string $type Message type [notice|confirm|error]
  102. * @param array $vars Key-value pairs to be replaced in localized text
  103. * @param boolean $override Override last set message
  104. * @param int $timeout Message displaying time in seconds
  105. *
  106. * @uses self::command()
  107. */
  108. public function show_message($message, $type='notice', $vars=null, $override=true, $timeout=0)
  109. {
  110. if ($override || !$this->message) {
  111. if ($this->app->text_exists($message)) {
  112. if (!empty($vars)) {
  113. $vars = array_map(array('rcmail', 'Q'), $vars);
  114. }
  115. $msgtext = $this->app->gettext(array('name' => $message, 'vars' => $vars));
  116. }
  117. else
  118. $msgtext = $message;
  119. $this->message = $message;
  120. $this->command('display_message', $msgtext, $type, $timeout * 1000);
  121. }
  122. }
  123. /**
  124. * Delete all stored env variables and commands
  125. */
  126. public function reset()
  127. {
  128. parent::reset();
  129. $this->texts = array();
  130. $this->commands = array();
  131. }
  132. /**
  133. * Redirect to a certain url
  134. *
  135. * @param mixed $p Either a string with the action or url parameters as key-value pairs
  136. * @param int $delay Delay in seconds
  137. *
  138. * @see rcmail::url()
  139. */
  140. public function redirect($p = array(), $delay = 1)
  141. {
  142. $location = $this->app->url($p);
  143. $this->remote_response(sprintf("window.setTimeout(function(){ %s.redirect('%s',true); }, %d);",
  144. self::JS_OBJECT_NAME, $location, $delay));
  145. exit;
  146. }
  147. /**
  148. * Send an AJAX response to the client.
  149. */
  150. public function send()
  151. {
  152. $this->remote_response();
  153. exit;
  154. }
  155. /**
  156. * Show error page and terminate script execution
  157. *
  158. * @param int $code Error code
  159. * @param string $message Error message
  160. */
  161. public function raise_error($code, $message)
  162. {
  163. if ($code == 403) {
  164. header('HTTP/1.1 403 Forbidden');
  165. die("Invalid Request");
  166. }
  167. $this->show_message("Application Error ($code): $message", 'error');
  168. $this->remote_response();
  169. exit;
  170. }
  171. /**
  172. * Send an AJAX response with executable JS code
  173. *
  174. * @param string $add Additional JS code
  175. */
  176. protected function remote_response($add = '')
  177. {
  178. static $s_header_sent = false;
  179. if (!$s_header_sent) {
  180. $s_header_sent = true;
  181. $this->nocacheing_headers();
  182. header('Content-Type: text/plain; charset=' . $this->get_charset());
  183. }
  184. // unset default env vars
  185. unset($this->env['task'], $this->env['action'], $this->env['comm_path']);
  186. $rcmail = rcmail::get_instance();
  187. $response['action'] = $rcmail->action;
  188. if ($unlock = rcube_utils::get_input_value('_unlock', rcube_utils::INPUT_GPC)) {
  189. $response['unlock'] = $unlock;
  190. }
  191. if (!empty($this->env))
  192. $response['env'] = $this->env;
  193. if (!empty($this->texts))
  194. $response['texts'] = $this->texts;
  195. // send function calls
  196. $response['exec'] = $this->get_js_commands() . $add;
  197. if (!empty($this->callbacks))
  198. $response['callbacks'] = $this->callbacks;
  199. // trigger generic hook where plugins can put additional content to the response
  200. $hook = $this->app->plugins->exec_hook("render_response", array('response' => $response));
  201. // save some memory
  202. $response = $hook['response'];
  203. unset($hook['response']);
  204. echo self::json_serialize($response, $this->devel_mode, false);
  205. }
  206. /**
  207. * Return executable javascript code for all registered commands
  208. */
  209. protected function get_js_commands()
  210. {
  211. $out = '';
  212. foreach ($this->commands as $i => $args) {
  213. $method = array_shift($args);
  214. foreach ($args as $i => $arg) {
  215. $args[$i] = self::json_serialize($arg, $this->devel_mode, false);
  216. }
  217. $out .= sprintf(
  218. "this.%s(%s);\n",
  219. preg_replace('/^parent\./', '', $method),
  220. implode(',', $args)
  221. );
  222. }
  223. return $out;
  224. }
  225. }