1<?php 2 3/** 4 * WAP Client plugin. 5 * 6 * @version @package_version@ 7 * @author Aleksander Machniak <machniak@kolabsys.com> 8 * 9 * Copyright (C) 2016, Kolab Systems AG <contact@kolabsys.com> 10 * 11 * This program is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Affero General Public License as 13 * published by the Free Software Foundation, either version 3 of the 14 * License, or (at your option) any later version. 15 * 16 * This program is distributed in the hope that it will be useful, 17 * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 * GNU Affero General Public License for more details. 20 * 21 * You should have received a copy of the GNU Affero General Public License 22 * along with this program. If not, see <http://www.gnu.org/licenses/>. 23 */ 24 25class wap_client extends rcube_plugin 26{ 27 public $task = 'settings'; 28 public $noajax = true; 29 30 protected $rc; 31 protected $wap; 32 protected $userinfo; 33 protected $token; 34 35 36 /** 37 * Initializes the plugin 38 */ 39 function init() 40 { 41 $this->rc = rcmail::get_instance(); 42 43 $this->add_hook('preferences_list', array($this, 'prefs_table')); 44 $this->add_hook('preferences_save', array($this, 'save_prefs')); 45 } 46 47 /** 48 * Hook to inject plugin-specific user settings 49 */ 50 public function prefs_table($args) 51 { 52 global $CURR_SECTION; 53 54 if ($args['section'] != 'server') { 55 return; 56 } 57 58 $this->load_config(); 59 60 $accounts = (array) $this->rc->config->get('wap_client_accounts'); 61 62 if (empty($accounts)) { 63 return; 64 } 65 66 $this->add_texts('localization'); 67 68 if ($CURR_SECTION) { 69 $account_type = $this->get_account_type(); 70 $_SESSION['wap_client_account_type'] = $account_type; 71 } 72 73 $input = new html_radiobutton(array('name' => '_account_type', 'style' => 'display:block; float:left')); 74 $content = ''; 75 76 foreach ($accounts as $idx => $def) { 77 $id = 'account_type_' . strtolower(asciiwords($idx, true)); 78 $name = $idx; 79 $name = $this->rc->text_exists('wap_client.account.' . $name) ? $this->gettext('account.' . $name) : $name; 80 $desc = $this->rc->text_exists('wap_client.accountdesc.' . $name) ? $this->gettext('accountdesc.' . $name) : $def['description']; 81 82 $name = html::span(array('style' => 'font-weight: bold'), rcube::Q($name)); 83 if ($desc) { 84 $name .= html::br() . html::span(null, rcube::Q($desc)); 85 } 86 87 $label_style = 'display:block; margin: 5px 0; padding-left: 30px'; 88 $content .= $input->show($account_type, array('value' => $idx, 'id' => $id)) 89 . html::label(array('for' => $id, 'style' => $label_style), $name); 90 } 91 92 $conf = array( 93 'account' => array( 94 'name' => rcube::Q($this->gettext('accountoptions')), 95 'options' => array( 96 'account_type' => array( 97 'title' => $this->gettext('accounttype'), 98 'content' => $content, 99 ) 100 ) 101 ) 102 ); 103 104 $args['blocks'] = array_merge($conf, $args['blocks']); 105 106 return $args; 107 } 108 109 /** 110 * Hook to save plugin-specific user settings 111 */ 112 public function save_prefs($args) 113 { 114 if ($args['section'] != 'server') { 115 return; 116 } 117 118 $account_type = rcube_utils::get_input_value('_account_type', rcube_utils::INPUT_POST); 119 120 if (!$account_type || $account_type == $_SESSION['wap_client_account_type']) { 121 return; 122 } 123 124 $this->add_texts('localization'); 125 126 $this->set_account_type($account_type); 127 } 128 129 /** 130 * Get current account type (from WAP) 131 */ 132 protected function get_account_type() 133 { 134 $this->init_wap(); 135 136 if (empty($this->userinfo)) { 137 $this->rc->output->show_message($this->gettext('failedtypedetection'), 'warning'); 138 return; 139 } 140 141 $roles = (array) $this->userinfo['nsroledn']; 142 $accounts = (array) $this->rc->config->get('wap_client_accounts'); 143 $root_dn = $this->rc->config->get('wap_client_root_dn'); 144 $base_dn = $this->rc->config->get('wap_client_base_dn'); 145 146 foreach ($accounts as $name => $account) { 147 foreach ((array) $account['nsroledn'] as $role) { 148 $value = str_replace('$base_dn', $base_dn, $value); 149 $value = str_replace('$root_dn', $root_dn, $value); 150 151 if (!in_array($value, $roles)) { 152 continue 2; 153 } 154 } 155 156 return $name; 157 } 158 } 159 160 /** 161 * Set account type (in WAP) 162 */ 163 protected function set_account_type($type) 164 { 165 if (!$this->init_wap()) { 166 return false; 167 } 168 169 $query = $this->userinfo; 170 $accounts = (array) $this->rc->config->get('wap_client_accounts'); 171 $root_dn = $this->rc->config->get('wap_client_root_dn'); 172 $base_dn = $this->rc->config->get('wap_client_base_dn'); 173 $account = $accounts[$type]; 174 175 if (empty($account)) { 176 $this->rc->output->show_message($this->gettext('failedtypeupdate'), 'warning'); 177 return; 178 } 179 180 unset($account['description']); 181 182 foreach ($account as $attr => $value) { 183 switch ($attr) { 184 case 'nsroledn': 185 $value = array(); 186 foreach ((array) $account['nsroledn'] as $role) { 187 $role = str_replace('$base_dn', $base_dn, $role); 188 $role = str_replace('$root_dn', $root_dn, $role); 189 $value[] = $role; 190 } 191 192 default: 193 $query[$attr] = $value; 194 } 195 } 196 197 $response = $this->post('user.edit', $query); 198 199 if (!$response || $response['status'] != 'OK') { 200 $this->rc->output->show_message($this->gettext('failedtypeupdate'), 'warning'); 201 return; 202 } 203 204 $this->userinfo = $query; 205 } 206 207 /** 208 * Initialize WAP connection and user session 209 */ 210 protected function init_wap() 211 { 212 if ($this->wap) { 213 return $this->wap; 214 } 215 216 $this->load_config(); 217 $this->require_plugin('libkolab'); 218 219 $uri = $this->rc->config->get('wap_client_uri'); 220 $user = $this->rc->get_user_name(); 221 $pass = $this->rc->decrypt($_SESSION['password']); 222 223 if (!$uri) { 224 rcube::raise_error("wap_client_uri is not set", true, false); 225 return; 226 } 227 228 // get HTTP_Request2 object 229 $this->uri = rcube_utils::resolve_url($uri); 230 $this->wap = libkolab::http_request($this->uri); 231 232 $query = array( 233 'username' => $user, 234 'password' => $pass, 235 // 'domain' => $domain, 236 'info' => true, 237 ); 238 239 // authenticate the user 240 $response = $this->post('system.authenticate', $query); 241 242 if ($response) { 243 $this->userinfo = $response['result']['info']; 244 $this->token = $response['result']['session_token']; 245 } 246 247 return $this->wap; 248 } 249 250 /** 251 * API's POST request. 252 * 253 * @param string $action Action name 254 * @param array $post POST arguments 255 * 256 * @return kolab_client_api_result Response 257 */ 258 protected function post($action, $post = array()) 259 { 260 $url = $this->build_url($action); 261 262 if ($this->rc->config->get('wap_client_debug')) { 263 $this->rc->write_log('wap', "Calling API POST: $url\n" . @json_encode($post)); 264 } 265 266 if ($this->token) { 267 $this->wap->setHeader('X-Session-Token', $this->token); 268 } 269 270 $this->wap->setMethod(HTTP_Request2::METHOD_POST); 271 $this->wap->setBody(@json_encode($post)); 272 273 return $this->get_response($url); 274 } 275 276 /** 277 * Build Net_URL2 object for the request 278 * 279 * @param string $action Action GET parameter 280 * @param array $args GET parameters (hash array: name => value) 281 * 282 * @return Net_URL2 URL object 283 */ 284 private function build_url($action, $args = array()) 285 { 286 $url = rtrim($this->uri, '/'); 287 288 if ($action) { 289 $url .= '/' . urlencode($action); 290 } 291 292 $url = new Net_URL2($url); 293 294 if (!empty($args)) { 295 $url->setQueryVariables($args); 296 } 297 298 return $url; 299 } 300 301 /** 302 * HTTP Response handler. 303 * 304 * @param Net_URL2 $url URL object 305 * 306 * @return array Response data 307 */ 308 protected function get_response($url) 309 { 310 try { 311 $this->wap->setUrl($url); 312 $response = $this->wap->send(); 313 } 314 catch (Exception $e) { 315 rcube::raise_error($e, true, false); 316 return; 317 } 318 319 try { 320 $body = $response->getBody(); 321 } 322 catch (Exception $e) { 323 rcube::raise_error($e, true, false); 324 return; 325 } 326 327 if ($this->rc->config->get('wap_client_debug')) { 328 $this->rc->write_log('wap', "Response:\n$body"); 329 } 330 331 $body = @json_decode($body, true); 332 333 if (!is_array($body)) { 334 rcube::raise_error("Failed to decode WAP response", true, false); 335 return; 336 } 337 338 return $body; 339 } 340} 341