1<?php 2 3/** 4 * IMAP modules 5 * @package modules 6 * @subpackage imap 7 */ 8 9if (!defined('DEBUG_MODE')) { die(); } 10 11/** 12 * Check for attachments when forwarding a message 13 * @subpackage imap/handler 14 */ 15class Hm_Handler_imap_forward_attachments extends Hm_Handler_Module { 16 public function process() { 17 if (!array_key_exists('forward', $this->request->get)) { 18 return; 19 } 20 if (!array_key_exists('list_path', $this->request->get)) { 21 return; 22 } 23 if (!array_key_exists('uid', $this->request->get)) { 24 return; 25 } 26 $uid = $this->request->get['uid']; 27 $list_path = $this->request->get['list_path']; 28 $path = explode('_', $list_path); 29 if (count($path) != 3) { 30 return; 31 } 32 if ($path[0] != 'imap') { 33 return; 34 } 35 $filepath = $this->config->get('attachment_dir'); 36 if (!$filepath) { 37 return; 38 } 39 $cache = Hm_IMAP_List::get_cache($this->cache, $path[1]); 40 $imap = Hm_IMAP_List::connect($path[1], $cache); 41 if (!imap_authed($imap)) { 42 return; 43 } 44 if (!$imap->select_mailbox(hex2bin($path[2]))) { 45 return; 46 } 47 $content = $imap->get_message_content($uid, 0); 48 if (!$content) { 49 return; 50 } 51 $file = array( 52 'name' => 'mail.mime', 53 'type' => 'message/rfc822', 54 'no_encoding' => true, 55 'size' => strlen($content) 56 ); 57 $draft_id = count($this->session->get('compose_drafts', array())); 58 attach_file($content, $file, $filepath, $draft_id, $this); 59 } 60} 61 62/** 63 * Get the status of an IMAP folder 64 * @subpackage imap/handler 65 */ 66class Hm_Handler_imap_folder_status extends Hm_Handler_Module { 67 public function process() { 68 list($success, $form) = $this->process_form(array('imap_server_id', 'folder')); 69 if ($success) { 70 $cache = Hm_IMAP_List::get_cache($this->cache, $form['imap_server_id']); 71 $imap = Hm_IMAP_List::connect($form['imap_server_id'], $cache); 72 if (imap_authed($imap)) { 73 $this->out('folder_status', array('imap_'.$form['imap_server_id'].'_'.$form['folder'] => $imap->get_mailbox_status(hex2bin($form['folder'])))); 74 } 75 } 76 } 77} 78 79/** 80 * Process input from the per page count setting 81 * @subpackage imap/handler 82 */ 83class Hm_Handler_process_imap_per_page_setting extends Hm_Handler_Module { 84 /** 85 * Allowed values are greater than zero and less than MAX_PER_SOURCE 86 */ 87 public function process() { 88 process_site_setting('imap_per_page', $this, 'max_source_setting_callback', DEFAULT_PER_SOURCE); 89 } 90} 91 92/** 93 * Process input from the max per source setting for the Sent E-mail page in the settings page 94 * @subpackage imap/handler 95 */ 96class Hm_Handler_process_sent_source_max_setting extends Hm_Handler_Module { 97 /** 98 * Allowed values are greater than zero and less than MAX_PER_SOURCE 99 */ 100 public function process() { 101 process_site_setting('sent_per_source', $this, 'max_source_setting_callback', DEFAULT_PER_SOURCE); 102 } 103} 104 105/** 106 * Process "simple message parts" setting for the message view page in the settings page 107 * @subpackage imap/handler 108 */ 109class Hm_Handler_process_simple_msg_parts extends Hm_Handler_Module { 110 /** 111 * valid values are true or false 112 */ 113 public function process() { 114 function simple_msg_view_callback($val) { 115 return $val; 116 } 117 process_site_setting('simple_msg_parts', $this, 'simple_msg_view_callback', false, true); 118 } 119} 120 121/** 122 * Process "message part icons" setting for the message view page in the settings page 123 * @subpackage imap/handler 124 */ 125class Hm_Handler_process_msg_part_icons extends Hm_Handler_Module { 126 /** 127 * valid values are true or false 128 */ 129 public function process() { 130 function msg_part_icons_callback($val) { 131 return $val; 132 } 133 process_site_setting('msg_part_icons', $this, 'msg_part_icons_callback', false, true); 134 } 135} 136 137/** 138 * Process "text only" setting for the message view page in the settings page 139 * @subpackage imap/handler 140 */ 141class Hm_Handler_process_text_only_setting extends Hm_Handler_Module { 142 /** 143 * valid values are true or false 144 */ 145 public function process() { 146 function text_only_callback($val) { 147 return $val; 148 } 149 process_site_setting('text_only', $this, 'text_only_callback', false, true); 150 } 151} 152 153/** 154 * Process "since" setting for the Sent page in the settings page 155 * @subpackage imap/handler 156 */ 157class Hm_Handler_process_sent_since_setting extends Hm_Handler_Module { 158 /** 159 * valid values are defined in the process_since_argument function 160 */ 161 public function process() { 162 process_site_setting('sent_since', $this, 'since_setting_callback'); 163 } 164} 165 166 /** 167 * Process an IMAP move/copy action 168 * @subpackage imap/handler 169 */ 170class Hm_Handler_imap_process_move extends Hm_Handler_Module { 171 public function process() { 172 list($success, $form) = $this->process_form(array('imap_move_to', 'imap_move_page', 'imap_move_action', 'imap_move_ids')); 173 if ($success) { 174 list($msg_ids, $dest_path, $same_server_ids, $other_server_ids) = process_move_to_arguments($form); 175 $moved = array(); 176 if (count($same_server_ids) > 0) { 177 $moved = array_merge($moved, imap_move_same_server($same_server_ids, $form['imap_move_action'], $this->cache, $dest_path)); 178 } 179 if (count($other_server_ids) > 0) { 180 $moved = array_merge($moved, imap_move_different_server($other_server_ids, $form['imap_move_action'], $dest_path, $this->cache)); 181 182 } 183 if (count($moved) > 0 && count($moved) == count($msg_ids)) { 184 if ($form['imap_move_action'] == 'move') { 185 Hm_Msgs::add('Messages moved'); 186 } 187 else { 188 Hm_Msgs::add('Messages copied'); 189 } 190 $this->session->set('imap_cache', array()); 191 } 192 elseif (count($moved) > 0) { 193 if ($form['imap_move_action'] == 'move') { 194 Hm_Msgs::add('Some messages moved (only IMAP message types can be moved)'); 195 } 196 else { 197 Hm_Msgs::add('Some messages copied (only IMAP message types can be copied)'); 198 } 199 $this->session->set('imap_cache', array()); 200 } 201 elseif (count($moved) == 0) { 202 Hm_Msgs::add('ERRUnable to move/copy selected messages'); 203 } 204 if ($form['imap_move_action'] == 'move' && $form['imap_move_page'] == 'message') { 205 $msgs = Hm_Msgs::get(); 206 Hm_Msgs::flush(); 207 $this->session->secure_cookie($this->request, 'hm_msgs', base64_encode(json_encode($msgs))); 208 } 209 $this->out('move_count', $moved); 210 } 211 } 212} 213 214 /** 215 * Save a sent message 216 * @subpackage imap/handler 217 */ 218class Hm_Handler_imap_save_sent extends Hm_Handler_Module { 219 public function process() { 220 if (!$this->get('save_sent_msg')) { 221 return; 222 } 223 $imap_id = $this->get('save_sent_server'); 224 $mime = $this->get('save_sent_msg'); 225 226 if ($imap_id === false) { 227 return; 228 } 229 $msg = $mime->get_mime_msg(); 230 $msg = str_replace("\r\n", "\n", $msg); 231 $msg = str_replace("\n", "\r\n", $msg); 232 $msg = rtrim($msg)."\r\n"; 233 $cache = Hm_IMAP_List::get_cache($this->cache, $imap_id); 234 $imap = Hm_IMAP_List::connect($imap_id, $cache); 235 $imap_details = Hm_IMAP_List::dump($imap_id); 236 $sent_folder = false; 237 if (imap_authed($imap)) { 238 $specials = $this->user_config->get('special_imap_folders', array()); 239 if (array_key_exists($imap_id, $specials)) { 240 if (array_key_exists('sent', $specials[$imap_id])) { 241 if ($specials[$imap_id]['sent']) { 242 $sent_folder = $specials[$imap_id]['sent']; 243 } 244 } 245 } 246 247 if (!$sent_folder) { 248 $auto_sent = $imap->get_special_use_mailboxes('sent'); 249 if (!array_key_exists('sent', $auto_sent)) { 250 return; 251 } 252 $sent_folder = $auto_sent['sent']; 253 } 254 if (!$sent_folder) { 255 Hm_Debug::add(sprintf("Unable to save sent message, no sent folder for IMAP %s", $imap_details['server'])); 256 } 257 if ($sent_folder) { 258 Hm_Debug::add(sprintf("Attempting to save sent message for IMAP server %s in folder %s", $imap_details['server'], $sent_folder)); 259 if ($imap->append_start($sent_folder, strlen($msg), true)) { 260 $imap->append_feed($msg."\r\n"); 261 if (!$imap->append_end()) { 262 Hm_Msgs::add('ERRAn error occurred saving the sent message'); 263 } 264 } 265 } 266 } 267 } 268} 269 270 /** 271 * Unflag a message after replying to it 272 * @subpackage imap/handler 273 */ 274class Hm_Handler_imap_unflag_on_send extends Hm_Handler_Module { 275 public function process() { 276 if ($this->get('msg_sent')) { 277 list($success, $form) = $this->process_form(array('compose_unflag_send', 'compose_msg_uid', 'compose_msg_path')); 278 if ($success) { 279 $path = explode('_', $form['compose_msg_path']); 280 if (count($path) == 3 && $path[0] == 'imap') { 281 $cache = Hm_IMAP_List::get_cache($this->cache, $path[1]); 282 $imap = Hm_IMAP_List::connect($path[1], $cache); 283 if (imap_authed($imap) && $imap->select_mailbox(hex2bin($path[2]))) { 284 $imap->message_action('UNFLAG', array($form['compose_msg_uid'])); 285 } 286 } 287 } 288 } 289 } 290} 291 292 /** 293 * Flag a message as answered 294 * @subpackage imap/handler 295 */ 296class Hm_Handler_imap_mark_as_answered extends Hm_Handler_Module { 297 public function process() { 298 if ($this->get('msg_sent')) { 299 list($success, $form) = $this->process_form(array('compose_msg_uid', 'compose_msg_path')); 300 if ($success) { 301 $path = explode('_', $form['compose_msg_path']); 302 if (count($path) == 3 && $path[0] == 'imap') { 303 $cache = Hm_IMAP_List::get_cache($this->cache, $path[1]); 304 $imap = Hm_IMAP_List::connect($path[1], $cache); 305 if (imap_authed($imap) && $imap->select_mailbox(hex2bin($path[2]))) { 306 $this->out('folder_status', array('imap_'.$path[1].'_'.$path[2] => $imap->folder_state)); 307 $imap->message_action('ANSWERED', array($form['compose_msg_uid'])); 308 } 309 } 310 } 311 } 312 } 313} 314 315 /** 316 * Flag a message as read 317 * @subpackage imap/handler 318 */ 319class Hm_Handler_imap_mark_as_read extends Hm_Handler_Module { 320 public function process() { 321 list($success, $form) = $this->process_form(array('imap_server_id', 'imap_msg_uid', 'folder')); 322 if ($success) { 323 $cache = Hm_IMAP_List::get_cache($this->cache, $form['imap_server_id']); 324 $imap = Hm_IMAP_List::connect($form['imap_server_id'], $cache); 325 if (imap_authed($imap) && $imap->select_mailbox(hex2bin($form['folder']))) { 326 $this->out('folder_status', array('imap_'.$form['imap_server_id'].'_'.$form['folder'] => $imap->folder_state)); 327 $imap->message_action('READ', array($form['imap_msg_uid'])); 328 } 329 } 330 } 331} 332 333/** 334 * Process a request to change a combined page source 335 * @subpackage imap/handler 336 */ 337class Hm_Handler_process_imap_source_update extends Hm_Handler_Module { 338 /** 339 * Add or remove an IMAP folder to the combined view 340 */ 341 public function process() { 342 list($success, $form) = $this->process_form(array('combined_source_state', 'list_path')); 343 if ($success) { 344 $sources = $this->user_config->get('custom_imap_sources'); 345 if ($form['combined_source_state'] == 1) { 346 $sources[$form['list_path']] = 'add'; 347 Hm_Msgs::add('Folder added to combined pages'); 348 $this->session->record_unsaved('Added folder to combined pages'); 349 } 350 else { 351 if (is_array($sources) && array_key_exists($form['list_path'], $sources)) { 352 unset($sources[$form['list_path']]); 353 } 354 else { 355 $sources[$form['list_path']] = 'remove'; 356 } 357 Hm_Msgs::add('Folder removed from combined pages'); 358 $this->session->record_unsaved('Removed folder from combined pages'); 359 } 360 $this->session->set('custom_imap_sources', $sources, true); 361 } 362 } 363} 364 365/** 366 * Stream a message from IMAP to the browser 367 * @subpackage imap/handler 368 */ 369class Hm_Handler_imap_download_message extends Hm_Handler_Module { 370 /** 371 * Download a message from the IMAP server 372 */ 373 public function process() { 374 if (array_key_exists('imap_download_message', $this->request->get) && $this->request->get['imap_download_message']) { 375 376 $server_id = NULL; 377 $uid = NULL; 378 $folder = NULL; 379 $msg_id = NULL; 380 381 if (array_key_exists('uid', $this->request->get) && $this->request->get['uid']) { 382 $uid = $this->request->get['uid']; 383 } 384 if (array_key_exists('list_path', $this->request->get) && preg_match("/^imap_(\d+)_(.+)/", $this->request->get['list_path'], $matches)) { 385 $server_id = $matches[1]; 386 $folder = hex2bin($matches[2]); 387 } 388 if (array_key_exists('imap_msg_part', $this->request->get) && preg_match("/^[0-9\.]+$/", $this->request->get['imap_msg_part'])) { 389 $msg_id = preg_replace("/^0.{1}/", '', $this->request->get['imap_msg_part']); 390 } 391 if ($server_id !== NULL && $uid !== NULL && $folder !== NULL && $msg_id !== NULL) { 392 $cache = Hm_IMAP_List::get_cache($this->cache, $server_id); 393 $imap = Hm_IMAP_List::connect($server_id, $cache); 394 if (imap_authed($imap)) { 395 if ($imap->select_mailbox($folder)) { 396 $msg_struct = $imap->get_message_structure($uid); 397 $struct = $imap->search_bodystructure($msg_struct, array('imap_part_number' => $msg_id)); 398 if (!empty($struct)) { 399 $part_struct = array_shift($struct); 400 $encoding = false; 401 if (array_key_exists('encoding', $part_struct)) { 402 $encoding = trim(strtolower($part_struct['encoding'])); 403 } 404 $stream_size = $imap->start_message_stream($uid, $msg_id); 405 if ($stream_size > 0) { 406 $name = get_imap_part_name($part_struct, $uid, $msg_id); 407 header('Content-Disposition: attachment; filename="'.$name.'"'); 408 $charset = ''; 409 if (array_key_exists('attributes', $part_struct)) { 410 if (is_array($part_struct['attributes']) && array_key_exists('charset', $part_struct['attributes'])) { 411 $charset = '; charset='.$part_struct['attributes']['charset']; 412 } 413 } 414 header('Content-Type: '.$part_struct['type'].'/'.$part_struct['subtype'].$charset); 415 header('Content-Transfer-Encoding: binary'); 416 ob_end_clean(); 417 $output_line = ''; 418 while($line = $imap->read_stream_line()) { 419 if ($encoding == 'quoted-printable') { 420 $line = quoted_printable_decode($line); 421 } 422 elseif ($encoding == 'base64') { 423 $line = base64_decode($line); 424 } 425 echo $output_line; 426 $output_line = $line; 427 } 428 if ($part_struct['type'] == 'text') { 429 $output_line = preg_replace("/\)(\r\n)$/m", '$1', $output_line); 430 } 431 echo $output_line; 432 Hm_Functions::cease(); 433 } 434 } 435 } 436 } 437 } 438 Hm_Msgs::add('ERRAn Error occurred trying to download the message'); 439 } 440 } 441} 442 443/** 444 * Process the list_path input argument 445 * @subpackage imap/handler 446 */ 447class Hm_Handler_imap_message_list_type extends Hm_Handler_Module { 448 /** 449 * Output a list title 450 */ 451 public function process() { 452 if (array_key_exists('list_path', $this->request->get)) { 453 $path = $this->request->get['list_path']; 454 if (preg_match("/^imap_\d+_.+$/", $path)) { 455 $this->out('list_meta', false, false); 456 $this->out('list_path', $path, false); 457 $this->out('move_copy_controls', true); 458 $parts = explode('_', $path, 3); 459 $details = Hm_IMAP_List::dump(intval($parts[1])); 460 $custom_link = 'add'; 461 foreach (imap_data_sources(false, $this->user_config->get('custom_imap_sources', array())) as $vals) { 462 if ($vals['id'] == $parts[1] && $vals['folder'] == $parts[2]) { 463 $custom_link = 'remove'; 464 break; 465 } 466 } 467 $this->out('custom_list_controls_type', $custom_link); 468 if (array_key_exists('keyword', $this->request->get)) { 469 $this->out('list_keyword', $this->request->get['keyword']); 470 } 471 if (array_key_exists('filter', $this->request->get)) { 472 if (in_array($this->request->get['filter'], array('all', 'unseen', 'seen', 473 'answered', 'unanswered', 'flagged', 'unflagged'), true)) { 474 $this->out('list_filter', $this->request->get['filter']); 475 } 476 } 477 if (array_key_exists('sort', $this->request->get)) { 478 if (in_array($this->request->get['sort'], array('arrival', 'from', 'subject', 479 'date', 'to', '-arrival', '-from', '-subject', '-date', '-to'), true)) { 480 $this->out('list_sort', $this->request->get['sort']); 481 } 482 } 483 if (!empty($details)) { 484 if (array_key_exists('folder_label', $this->request->get)) { 485 $folder = $this->request->get['folder_label']; 486 $this->out('folder_label', $folder); 487 } 488 else { 489 $folder = hex2bin($parts[2]); 490 } 491 $title = array('IMAP', $details['name'], $folder); 492 if ($this->get('list_page', 0)) { 493 $title[] = sprintf('Page %d', $this->get('list_page', 0)); 494 } 495 $this->out('mailbox_list_title', $title); 496 } 497 } 498 elseif ($path == 'sent') { 499 $this->out('mailbox_list_title', array('Sent')); 500 $this->out('per_source_limit', $this->user_config->get('sent_per_source_setting', DEFAULT_PER_SOURCE)); 501 $this->out('message_list_since', $this->user_config->get('sent_since_setting', DEFAULT_SINCE)); 502 } 503 } 504 } 505} 506 507/** 508 * Expand an IMAP folder section 509 * @subpackage imap/handler 510 */ 511class Hm_Handler_imap_folder_expand extends Hm_Handler_Module { 512 /** 513 * Return cached subfolder contents or query the IMAP server for it 514 */ 515 public function process() { 516 517 list($success, $form) = $this->process_form(array('imap_server_id')); 518 if ($success) { 519 $folder = ''; 520 if (isset($this->request->post['folder'])) { 521 $folder = $this->request->post['folder']; 522 } 523 $path = sprintf("imap_%d_%s", $form['imap_server_id'], $folder); 524 $page_cache = $this->cache->get('imap_folders_'.$path); 525 if (array_key_exists('imap_prefetch', $this->request->post)) { 526 $prefetched = $this->session->get('imap_prefetched_ids', array()); 527 $prefetched[] = $form['imap_server_id']; 528 $this->session->set('imap_prefetched_ids', array_unique($prefetched, SORT_NUMERIC)); 529 } 530 if ($page_cache) { 531 $this->out('imap_expanded_folder_data', $page_cache); 532 $this->out('imap_expanded_folder_id', $form['imap_server_id']); 533 $this->out('imap_expanded_folder_path', $path); 534 return; 535 } 536 $cache = Hm_IMAP_List::get_cache($this->cache, $form['imap_server_id']); 537 $imap = Hm_IMAP_List::connect($form['imap_server_id'], $cache); 538 if (imap_authed($imap)) { 539 $msgs = $imap->get_folder_list_by_level(hex2bin($folder)); 540 if (isset($msgs[$folder])) { 541 unset($msgs[$folder]); 542 } 543 $this->cache->set('imap_folders_'.$path, $msgs); 544 $this->out('imap_expanded_folder_data', $msgs); 545 $this->out('imap_expanded_folder_id', $form['imap_server_id']); 546 $this->out('imap_expanded_folder_path', $path); 547 } 548 else { 549 Hm_Msgs::add(sprintf('ERRCould not authenticate to the selected %s server', $imap->server_type)); 550 } 551 } 552 } 553} 554 555/** 556 * Fetch the message headers for a an IMAP folder page 557 * @subpackage imap/handler 558 */ 559class Hm_Handler_imap_folder_page extends Hm_Handler_Module { 560 561 /** 562 * Use IMAP FETCH to get a page of headers 563 */ 564 public function process() { 565 566 $filter = 'ALL'; 567 if ($this->get('list_filter')) { 568 $filter = strtoupper($this->get('list_filter')); 569 } 570 $keyword = $this->get('list_keyword', ''); 571 list($sort, $rev) = process_sort_arg($this->get('list_sort')); 572 $limit = $this->user_config->get('imap_per_page_setting', DEFAULT_PER_SOURCE); 573 $offset = 0; 574 $msgs = array(); 575 $list_page = 1; 576 577 list($success, $form) = $this->process_form(array('imap_server_id', 'folder')); 578 if ($success) { 579 if (isset($this->request->get['list_page'])) { 580 $list_page = (int) $this->request->get['list_page']; 581 if ($list_page && $list_page > 1) { 582 $offset = ($list_page - 1)*$limit; 583 } 584 else { 585 $list_page = 1; 586 } 587 } 588 $path = sprintf("imap_%d_%s", $form['imap_server_id'], $form['folder']); 589 $details = Hm_IMAP_List::dump($form['imap_server_id']); 590 $cache = Hm_IMAP_List::get_cache($this->cache, $form['imap_server_id']); 591 $imap = Hm_IMAP_List::connect($form['imap_server_id'], $cache); 592 if (imap_authed($imap)) { 593 $this->out('imap_mailbox_page_path', $path); 594 list($total, $results) = $imap->get_mailbox_page(hex2bin($form['folder']), $sort, $rev, $filter, $offset, $limit, $keyword); 595 foreach ($results as $msg) { 596 $msg['server_id'] = $form['imap_server_id']; 597 $msg['server_name'] = $details['name']; 598 $msg['folder'] = $form['folder']; 599 $msgs[] = $msg; 600 } 601 if ($imap->selected_mailbox) { 602 $imap->selected_mailbox['detail']['exists'] = $total; 603 $this->out('imap_folder_detail', array_merge($imap->selected_mailbox, array('offset' => $offset, 'limit' => $limit))); 604 } 605 $this->out('folder_status', array('imap_'.$form['imap_server_id'].'_'.$form['folder'] => $imap->folder_state)); 606 } 607 $this->out('imap_mailbox_page', $msgs); 608 $this->out('list_page', $list_page); 609 $this->out('imap_server_id', $form['imap_server_id']); 610 } 611 } 612} 613 614/** 615 * Build a list of IMAP servers as the top level folders 616 * @subpackage imap/handler 617 */ 618class Hm_Handler_load_imap_folders extends Hm_Handler_Module { 619 /** 620 * Used by the folder list 621 */ 622 public function process() { 623 $servers = Hm_IMAP_List::dump(); 624 $folders = array(); 625 if (!empty($servers)) { 626 foreach ($servers as $id => $server) { 627 $folders[$id] = $server['name']; 628 } 629 } 630 $this->out('imap_folders', $folders); 631 } 632} 633 634/** 635 * Delete a message 636 * @subpackage imap/handler 637 */ 638class Hm_Handler_imap_delete_message extends Hm_Handler_Module { 639 /** 640 * Use IMAP to delete the selected message uid 641 */ 642 public function process() { 643 list($success, $form) = $this->process_form(array('imap_msg_uid', 'imap_server_id', 'folder')); 644 if ($success) { 645 $del_result = false; 646 $cache = Hm_IMAP_List::get_cache($this->cache, $form['imap_server_id']); 647 $imap = Hm_IMAP_List::connect($form['imap_server_id'], $cache); 648 $trash_folder = false; 649 $specials = $this->user_config->get('special_imap_folders', array()); 650 if (array_key_exists($form['imap_server_id'], $specials)) { 651 if (array_key_exists('trash', $specials[$form['imap_server_id']])) { 652 if ($specials[$form['imap_server_id']]['trash']) { 653 $trash_folder = $specials[$form['imap_server_id']]['trash']; 654 } 655 } 656 } 657 if (imap_authed($imap)) { 658 if ($imap->select_mailbox(hex2bin($form['folder']))) { 659 $this->out('folder_status', array('imap_'.$form['imap_server_id'].'_'.$form['folder'] => $imap->folder_state)); 660 if ($trash_folder && $trash_folder != hex2bin($form['folder'])) { 661 if ($imap->message_action('MOVE', array($form['imap_msg_uid']), $trash_folder)) { 662 $del_result = true; 663 } 664 } 665 else { 666 if ($imap->message_action('DELETE', array($form['imap_msg_uid']))) { 667 $del_result = true; 668 $imap->message_action('EXPUNGE', array($form['imap_msg_uid'])); 669 } 670 } 671 } 672 } 673 if (!$del_result) { 674 Hm_Msgs::add('ERRAn error occurred trying to delete this message'); 675 $this->out('imap_delete_error', true); 676 } 677 else { 678 Hm_Msgs::add('Message deleted'); 679 $this->out('imap_delete_error', false); 680 } 681 $msgs = Hm_Msgs::get(); 682 Hm_Msgs::flush(); 683 $this->session->secure_cookie($this->request, 'hm_msgs', base64_encode(json_encode($msgs))); 684 } 685 } 686} 687 688 689/** 690 * Archive a message 691 * @subpackage imap/handler 692 */ 693class Hm_Handler_imap_archive_message extends Hm_Handler_Module { 694 /** 695 * Use IMAP to archive the selected message uid 696 */ 697 public function process() { 698 list($success, $form) = $this->process_form(array('imap_msg_uid', 'imap_server_id', 'folder')); 699 700 if (!$success) { 701 return; 702 } 703 $cache = Hm_IMAP_List::get_cache($this->cache, $form['imap_server_id']); 704 $imap = Hm_IMAP_List::connect($form['imap_server_id'], $cache); 705 $archive_folder = false; 706 707 $specials = $this->user_config->get('special_imap_folders', array()); 708 if (array_key_exists($form['imap_server_id'], $specials)) { 709 if (array_key_exists('archive', $specials[$form['imap_server_id']])) { 710 if ($specials[$form['imap_server_id']]['archive']) { 711 $archive_folder = $specials[$form['imap_server_id']]['archive']; 712 } 713 } 714 } 715 716 if(!$archive_folder) { 717 $archive_folder = "Archive"; 718 } 719 720 if (imap_authed($imap)) { 721 $new_folder = prep_folder_name($imap, hex2bin($form['folder']), false, $archive_folder); 722 $archive_exists = count($imap->get_mailbox_status($archive_folder)); 723 $folder_exists = count($imap->get_mailbox_status($new_folder)); 724 $error = false; 725 726 /* if archive folders don't exist try to create them */ 727 if (!$archive_exists && !$imap->create_mailbox($archive_folder)) { 728 $error = true; 729 } 730 if (!$error && !$folder_exists && !$imap->create_mailbox($new_folder)) { 731 $error = true; 732 } 733 734 /* select source folder */ 735 if (!$error && !$imap->select_mailbox(hex2bin($form['folder']))) { 736 $error = true; 737 } 738 739 /* try to move the message */ 740 if (!$error && $imap->message_action('MOVE', array($form['imap_msg_uid']), $new_folder)) { 741 Hm_Msgs::add("Message archived"); 742 743 /* bust imap cache if we created a new folder */ 744 if (!$archive_exists || !$folder_exists) { 745 $this->session->secure_cookie($this->request, 'hm_reload_folders', '1'); 746 $this->cache->del('imap'.$form['imap_server_id']); 747 $this->cache->del('imap_folders_imap_'.$form['imap_server_id'].'_'.bin2hex($archive_folder)); 748 } 749 } 750 else { 751 Hm_Msgs::add('ERRAn error occurred archiving the message'); 752 } 753 } 754 755 $msgs = Hm_Msgs::get(); 756 Hm_Msgs::flush(); 757 $this->session->secure_cookie($this->request, 'hm_msgs', base64_encode(json_encode($msgs))); 758 } 759} 760 761/** 762 * Flag a message 763 * @subpackage imap/handler 764 */ 765class Hm_Handler_flag_imap_message extends Hm_Handler_Module { 766 /** 767 * Use IMAP to flag the selected message uid 768 */ 769 public function process() { 770 list($success, $form) = $this->process_form(array('imap_flag_state', 'imap_msg_uid', 'imap_server_id', 'folder')); 771 if ($success) { 772 $flag_result = false; 773 $cache = Hm_IMAP_List::get_cache($this->cache, $form['imap_server_id']); 774 $imap = Hm_IMAP_List::connect($form['imap_server_id'], $cache); 775 if (imap_authed($imap)) { 776 if ($imap->select_mailbox(hex2bin($form['folder']))) { 777 $this->out('folder_status', array('imap_'.$form['imap_server_id'].'_'.$form['folder'] => $imap->folder_state)); 778 if ($form['imap_flag_state'] == 'flagged') { 779 $cmd = 'UNFLAG'; 780 } 781 else { 782 $cmd = 'FLAG'; 783 } 784 if ($imap->message_action($cmd, array($form['imap_msg_uid']))) { 785 $flag_result = true; 786 } 787 } 788 } 789 if (!$flag_result) { 790 Hm_Msgs::add('ERRAn error occurred trying to flag this message'); 791 } 792 } 793 } 794} 795 796/** 797 * Perform an IMAP message action 798 * @subpackage imap/handler 799 */ 800class Hm_Handler_imap_message_action extends Hm_Handler_Module { 801 /** 802 * Read, unread, delete, flag, or unflag a set of message uids 803 */ 804 public function process() { 805 list($success, $form) = $this->process_form(array('action_type', 'message_ids')); 806 if ($success) { 807 if (in_array($form['action_type'], array('delete', 'read', 'unread', 'flag', 'unflag'))) { 808 $ids = process_imap_message_ids($form['message_ids']); 809 $errs = 0; 810 $msgs = 0; 811 $status = array(); 812 $specials = $this->user_config->get('special_imap_folders', array()); 813 foreach ($ids as $server => $folders) { 814 $trash_folder = false; 815 if ($form['action_type'] == 'delete') { 816 if (array_key_exists($server, $specials)) { 817 if (array_key_exists('trash', $specials[$server])) { 818 if ($specials[$server]['trash']) { 819 $trash_folder = $specials[$server]['trash']; 820 } 821 } 822 } 823 } 824 $cache = Hm_IMAP_List::get_cache($this->cache, $server); 825 $imap = Hm_IMAP_List::connect($server, $cache); 826 if (imap_authed($imap)) { 827 foreach ($folders as $folder => $uids) { 828 if ($imap->select_mailbox(hex2bin($folder))) { 829 $status['imap_'.$server.'_'.$folder] = $imap->folder_state; 830 831 if ($form['action_type'] == 'delete' && $trash_folder && $trash_folder != hex2bin($folder)) { 832 if (!$imap->message_action('MOVE', $uids, $trash_folder)) { 833 $errs++; 834 } 835 } 836 else { 837 if (!$imap->message_action(strtoupper($form['action_type']), $uids)) { 838 $errs++; 839 } 840 else { 841 $msgs += count($uids); 842 if ($form['action_type'] == 'delete') { 843 $imap->message_action('EXPUNGE', $uids); 844 } 845 } 846 } 847 } 848 } 849 } 850 } 851 if ($errs > 0) { 852 Hm_Msgs::add(sprintf('ERRAn error occurred trying to %s some messages!', $form['action_type'], $server)); 853 } 854 if (count($status) > 0) { 855 $this->out('folder_state', $status); 856 } 857 } 858 } 859 } 860} 861 862/** 863 * Search for a message 864 * @subpackage imap/handler 865 */ 866class Hm_Handler_imap_search extends Hm_Handler_Module { 867 /** 868 * Use IMAP SEARCH to find matching messages 869 */ 870 public function process() { 871 list($success, $form) = $this->process_form(array('imap_server_ids')); 872 if ($success) { 873 $terms = $this->session->get('search_terms', false); 874 $since = $this->session->get('search_since', DEFAULT_SINCE); 875 $fld = $this->session->get('search_fld', 'TEXT'); 876 $ids = explode(',', $form['imap_server_ids']); 877 $date = process_since_argument($since); 878 $folder = bin2hex('INBOX'); 879 if (array_key_exists('folder', $this->request->post)) { 880 $folder = $this->request->post['folder']; 881 } 882 list($status, $msg_list) = merge_imap_search_results($ids, 'ALL', $this->session, $this->cache, array(hex2bin($folder)), MAX_PER_SOURCE, array(array('SINCE', $date), array($fld, $terms))); 883 $this->out('imap_search_results', $msg_list); 884 $this->out('folder_status', $status); 885 $this->out('imap_server_ids', $form['imap_server_ids']); 886 } 887 } 888} 889 890/** 891 * Get message headers for the Sent page 892 * @subpackage imap/handler 893 */ 894class Hm_Handler_imap_sent extends Hm_Handler_Module { 895 /** 896 * Returns list of message data for the Everthing page 897 */ 898 public function process() { 899 list($success, $form) = $this->process_form(array('imap_server_ids')); 900 if ($success) { 901 $limit = $this->user_config->get('sent_per_source_setting', DEFAULT_PER_SOURCE); 902 $date = process_since_argument($this->user_config->get('sent_since_setting', DEFAULT_SINCE)); 903 $ids = explode(',', $form['imap_server_ids']); 904 $folder = bin2hex('INBOX'); 905 if (array_key_exists('folder', $this->request->post)) { 906 $folder = $this->request->post['folder']; 907 } 908 if (hex2bin($folder) == 'SPECIAL_USE_CHECK' || hex2bin($folder) == 'INBOX') { 909 list($status, $msg_list) = merge_imap_search_results($ids, 'ALL', $this->session, $this->cache, array(hex2bin($folder)), $limit, array(array('SINCE', $date)), true); 910 } 911 else { 912 list($status, $msg_list) = merge_imap_search_results($ids, 'ALL', $this->session, $this->cache, array(hex2bin($folder)), $limit, array(array('SINCE', $date)), false); 913 } 914 $folders = array(); 915 foreach ($msg_list as $msg) { 916 if (hex2bin($msg['folder']) != hex2bin($folder)) { 917 $folders[] = hex2bin($msg['folder']); 918 } 919 } 920 if (count($folders) > 0) { 921 $auto_folder = $folders[0]; 922 $this->out('auto_sent_folder', $msg_list[0]['server_name'].' '.$auto_folder); 923 } 924 $this->out('folder_status', $status); 925 $this->out('imap_sent_data', $msg_list); 926 $this->out('imap_server_ids', $form['imap_server_ids']); 927 } 928 } 929} 930 931/** 932 * Get message headers for the Everthing page 933 * @subpackage imap/handler 934 */ 935class Hm_Handler_imap_combined_inbox extends Hm_Handler_Module { 936 /** 937 * Returns list of message data for the Everthing page 938 */ 939 public function process() { 940 list($success, $form) = $this->process_form(array('imap_server_ids')); 941 if ($success) { 942 if (array_key_exists('list_path', $this->request->get) && $this->request->get['list_path'] == 'email') { 943 $limit = $this->user_config->get('all_email_per_source_setting', DEFAULT_PER_SOURCE); 944 $date = process_since_argument($this->user_config->get('all_email_since_setting', DEFAULT_SINCE)); 945 } 946 else { 947 $limit = $this->user_config->get('all_per_source_setting', DEFAULT_PER_SOURCE); 948 $date = process_since_argument($this->user_config->get('all_since_setting', DEFAULT_SINCE)); 949 } 950 $ids = explode(',', $form['imap_server_ids']); 951 $folder = bin2hex('INBOX'); 952 if (array_key_exists('folder', $this->request->post)) { 953 $folder = $this->request->post['folder']; 954 } 955 list($status, $msg_list) = merge_imap_search_results($ids, 'ALL', $this->session, $this->cache, array(hex2bin($folder)), $limit, array(array('SINCE', $date))); 956 $this->out('folder_status', $status); 957 $this->out('imap_combined_inbox_data', $msg_list); 958 $this->out('imap_server_ids', $form['imap_server_ids']); 959 } 960 } 961} 962 963/** 964 * Get message headers for the Flagged page 965 * @subpackage imap/handler 966 */ 967class Hm_Handler_imap_flagged extends Hm_Handler_Module { 968 /** 969 * Fetch flagged messages from an IMAP server 970 */ 971 public function process() { 972 list($success, $form) = $this->process_form(array('imap_server_ids')); 973 if ($success) { 974 $limit = $this->user_config->get('flagged_per_source_setting', DEFAULT_PER_SOURCE); 975 $ids = explode(',', $form['imap_server_ids']); 976 $date = process_since_argument($this->user_config->get('flagged_since_setting', DEFAULT_SINCE)); 977 $folder = bin2hex('INBOX'); 978 if (array_key_exists('folder', $this->request->post)) { 979 $folder = $this->request->post['folder']; 980 } 981 list($status, $msg_list) = merge_imap_search_results($ids, 'FLAGGED', $this->session, $this->cache, array(hex2bin($folder)), $limit, array(array('SINCE', $date))); 982 $this->out('folder_status', $status); 983 $this->out('imap_flagged_data', $msg_list); 984 $this->out('imap_server_ids', $form['imap_server_ids']); 985 } 986 } 987} 988 989/** 990 * Check the status of an IMAP server connection 991 * @subpackage imap/handler 992 */ 993class Hm_Handler_imap_status extends Hm_Handler_Module { 994 /** 995 * Output used on the info page to display the server status 996 */ 997 public function process() { 998 list($success, $form) = $this->process_form(array('imap_server_ids')); 999 if ($success) { 1000 $ids = explode(',', $form['imap_server_ids']); 1001 foreach ($ids as $id) { 1002 $cache = Hm_IMAP_List::get_cache($this->cache, $id); 1003 $start_time = microtime(true); 1004 $imap = Hm_IMAP_List::connect($id, $cache); 1005 $this->out('imap_connect_time', microtime(true) - $start_time); 1006 if (imap_authed($imap)) { 1007 $this->out('imap_connect_status', $imap->get_state()); 1008 $this->out('imap_status_server_id', $id); 1009 } 1010 else { 1011 $this->out('imap_connect_status', 'disconnected'); 1012 $this->out('imap_status_server_id', $id); 1013 } 1014 } 1015 } 1016 } 1017} 1018 1019/** 1020 * Fetch messages for the Unread page 1021 * @subpackage imap/handler 1022 */ 1023class Hm_Handler_imap_unread extends Hm_Handler_Module { 1024 /** 1025 * Returns UNSEEN messages for an IMAP server 1026 */ 1027 public function process() { 1028 list($success, $form) = $this->process_form(array('imap_server_ids')); 1029 if ($success) { 1030 $limit = $this->user_config->get('unread_per_source_setting', DEFAULT_PER_SOURCE); 1031 $date = process_since_argument($this->user_config->get('unread_since_setting', DEFAULT_SINCE)); 1032 $ids = explode(',', $form['imap_server_ids']); 1033 $msg_list = array(); 1034 $folder = bin2hex('INBOX'); 1035 if (array_key_exists('folder', $this->request->post)) { 1036 $folder = $this->request->post['folder']; 1037 } 1038 list($status, $msg_list) = merge_imap_search_results($ids, 'UNSEEN', $this->session, $this->cache, array(hex2bin($folder)), $limit, array(array('SINCE', $date))); 1039 $this->out('folder_status', $status); 1040 $this->out('imap_unread_data', $msg_list); 1041 $this->out('imap_server_ids', $form['imap_server_ids']); 1042 } 1043 } 1044} 1045 1046/** 1047 * Add a new JMAP server 1048 * @subpackage imap/handler 1049 */ 1050class Hm_Handler_process_add_jmap_server extends Hm_Handler_Module { 1051 public function process() { 1052 /** 1053 * Used on the servers page to add a new JMAP server 1054 */ 1055 if (isset($this->request->post['submit_jmap_server'])) { 1056 list($success, $form) = $this->process_form(array('new_jmap_name', 'new_jmap_address')); 1057 if (!$success) { 1058 $this->out('old_form', $form); 1059 Hm_Msgs::add('ERRYou must supply a name and a JMAP server URL'); 1060 return; 1061 } 1062 $hidden = false; 1063 if (isset($this->request->post['new_jmap_hidden'])) { 1064 $hidden = true; 1065 } 1066 $parsed = parse_url($form['new_jmap_address']); 1067 if (array_key_exists('host', $parsed) && @get_headers($form['new_jmap_address'])) { 1068 1069 Hm_IMAP_List::add(array( 1070 'name' => $form['new_jmap_name'], 1071 'server' => $form['new_jmap_address'], 1072 'hide' => $hidden, 1073 'type' => 'jmap', 1074 'port' => false, 1075 'tls' => false)); 1076 Hm_Msgs::add('Added server!'); 1077 $this->session->record_unsaved('JMAP server added'); 1078 } 1079 else { 1080 Hm_Msgs::add('ERRCound not access supplied URL'); 1081 } 1082 } 1083 } 1084} 1085 1086/** 1087 * Add a new IMAP server 1088 * @subpackage imap/handler 1089 */ 1090class Hm_Handler_process_add_imap_server extends Hm_Handler_Module { 1091 public function process() { 1092 /** 1093 * Used on the servers page to add a new IMAP server 1094 */ 1095 if (isset($this->request->post['submit_imap_server'])) { 1096 list($success, $form) = $this->process_form(array('new_imap_name', 'new_imap_address', 'new_imap_port')); 1097 if (!$success) { 1098 $this->out('old_form', $form); 1099 Hm_Msgs::add('ERRYou must supply a name, a server and a port'); 1100 } 1101 else { 1102 $tls = false; 1103 if (array_key_exists('tls', $this->request->post) && $this->request->post['tls']) { 1104 $tls = true; 1105 } 1106 $hidden = false; 1107 if (isset($this->request->post['new_imap_hidden'])) { 1108 $hidden = true; 1109 } 1110 if ($con = fsockopen($form['new_imap_address'], $form['new_imap_port'], $errno, $errstr, 2)) { 1111 Hm_IMAP_List::add(array( 1112 'name' => $form['new_imap_name'], 1113 'server' => $form['new_imap_address'], 1114 'hide' => $hidden, 1115 'port' => $form['new_imap_port'], 1116 'tls' => $tls)); 1117 Hm_Msgs::add('Added server!'); 1118 $this->session->record_unsaved('IMAP server added'); 1119 } 1120 else { 1121 Hm_Msgs::add(sprintf('ERRCound not add server: %s', $errstr)); 1122 } 1123 } 1124 } 1125 } 1126} 1127 1128/** 1129 * Save IMAP caches in the session 1130 * @subpackage imap/handler 1131 */ 1132class Hm_Handler_save_imap_cache extends Hm_Handler_Module { 1133 /** 1134 * Save IMAP cache data for re-use 1135 */ 1136 public function process() { 1137 $servers = Hm_IMAP_List::dump(false, true); 1138 $cache = array(); 1139 foreach ($servers as $index => $server) { 1140 if (isset($server['object']) && is_object($server['object'])) { 1141 if ($server['object']->use_cache) { 1142 $cache[$index] = $server['object']->dump_cache('array'); 1143 } 1144 } 1145 } 1146 if (count($cache) > 0) { 1147 foreach ($cache as $id => $data) { 1148 $this->cache->set('imap'.$id, $cache[$id]); 1149 } 1150 } 1151 } 1152} 1153 1154/** 1155 * Save IMAP servers 1156 * @subpackage imap/handler 1157 */ 1158class Hm_Handler_save_imap_servers extends Hm_Handler_Module { 1159 /** 1160 * Save IMAP servers in the user config 1161 */ 1162 public function process() { 1163 $servers = Hm_IMAP_List::dump(false, true); 1164 $this->user_config->set('imap_servers', $servers); 1165 Hm_IMAP_List::clean_up(); 1166 } 1167} 1168 1169/** 1170 * Load IMAP servers for the search page 1171 * @subpackage imap/handler 1172 */ 1173class Hm_Handler_load_imap_servers_for_search extends Hm_Handler_Module { 1174 /** 1175 * Output IMAP server array used on the search page 1176 */ 1177 public function process() { 1178 foreach(imap_data_sources('imap_search_page_content', $this->user_config->get('custom_imap_sources', array())) as $vals) { 1179 $this->append('data_sources', $vals); 1180 } 1181 } 1182} 1183 1184/** 1185 * Load IMAP servers for message list pages 1186 * @subpackage imap/handler 1187 */ 1188class Hm_Handler_load_imap_servers_for_message_list extends Hm_Handler_Module { 1189 /** 1190 * Used by combined views excluding normal folder view and search pages 1191 */ 1192 public function process() { 1193 $callback = false; 1194 if (array_key_exists('list_path', $this->request->get)) { 1195 $path = $this->request->get['list_path']; 1196 } 1197 else { 1198 $path = ''; 1199 } 1200 switch ($path) { 1201 case 'unread': 1202 $callback = 'imap_combined_unread_content'; 1203 break; 1204 case 'flagged': 1205 $callback = 'imap_combined_flagged_content'; 1206 break; 1207 case 'combined_inbox': 1208 $callback = 'imap_combined_inbox_content'; 1209 break; 1210 case 'email': 1211 $callback = 'imap_all_mail_content'; 1212 break; 1213 case 'sent': 1214 $callback = 'imap_sent_content'; 1215 break; 1216 default: 1217 $callback = 'imap_background_unread_content'; 1218 break; 1219 } 1220 if ($callback) { 1221 if ($callback != 'imap_background_unread_content') { 1222 $this->out('move_copy_controls', true); 1223 } 1224 if ($path == 'sent') { 1225 foreach (imap_sent_sources($callback, $this->user_config->get('special_imap_folders', array()), 1226 $this->user_config->get('smtp_auto_bcc_setting', false)) as $vals) { 1227 $this->append('data_sources', $vals); 1228 } 1229 } 1230 else { 1231 foreach (imap_data_sources($callback, $this->user_config->get('custom_imap_sources', array())) as $vals) { 1232 if ($callback == 'imap_background_unread_content') { 1233 $vals['group'] = 'background'; 1234 } 1235 $this->append('data_sources', $vals); 1236 } 1237 } 1238 } 1239 } 1240} 1241 1242/** 1243 * Load IMAP servers for the user config object 1244 * @subpackage imap/handler 1245 */ 1246class Hm_Handler_load_imap_servers_from_config extends Hm_Handler_Module { 1247 /** 1248 * This list is cached in the session between page loads by Hm_Handler_save_imap_servers 1249 */ 1250 public function process() { 1251 $servers = $this->user_config->get('imap_servers', array()); 1252 $added = false; 1253 $updated = false; 1254 $new_servers = array(); 1255 $max = 0; 1256 foreach ($servers as $index => $server) { 1257 if ($this->session->loaded) { 1258 if (array_key_exists('expiration', $server)) { 1259 $updated = true; 1260 $server['expiration'] = 1; 1261 } 1262 } 1263 $new_servers[] = $server; 1264 $max = $index; 1265 Hm_IMAP_List::add($server, $index); 1266 if (array_key_exists('default', $server) && $server['default']) { 1267 $added = true; 1268 } 1269 } 1270 $max++; 1271 if ($updated) { 1272 $this->user_config->set('imap_servers', $new_servers); 1273 } 1274 if (!$added) { 1275 $auth_server = $this->session->get('imap_auth_server_settings', array()); 1276 if (!empty($auth_server)) { 1277 if (array_key_exists('name', $auth_server)) { 1278 $name = $auth_server['name']; 1279 } 1280 else { 1281 $name = $this->config->get('imap_auth_name', 'Default'); 1282 } 1283 Hm_IMAP_List::add(array( 1284 'name' => $name, 1285 'default' => true, 1286 'server' => $auth_server['server'], 1287 'port' => $auth_server['port'], 1288 'tls' => $auth_server['tls'], 1289 'user' => $auth_server['username'], 1290 'pass' => $auth_server['password']), 1291 $max); 1292 } 1293 } 1294 } 1295} 1296 1297/** 1298 * Check for IMAP server oauth2 token refresh 1299 * @subpackage imap/handler 1300 */ 1301class Hm_Handler_imap_oauth2_token_check extends Hm_Handler_Module { 1302 public function process() { 1303 $active = array(); 1304 if (array_key_exists('imap_server_ids', $this->request->post)) { 1305 $active = explode(',', $this->request->post['imap_server_ids']); 1306 } 1307 if (array_key_exists('imap_server_id', $this->request->post)) { 1308 $active[] = $this->request->post['imap_server_id']; 1309 } 1310 $updated = 0; 1311 foreach ($active as $server_id) { 1312 $server = Hm_IMAP_List::dump($server_id, true); 1313 if (array_key_exists('auth', $server) && $server['auth'] == 'xoauth2') { 1314 $results = imap_refresh_oauth2_token($server, $this->config); 1315 if (!empty($results)) { 1316 if (Hm_IMAP_List::update_oauth2_token($server_id, $results[1], $results[0])) { 1317 Hm_Debug::add(sprintf('Oauth2 token refreshed for IMAP server id %d', $server_id)); 1318 $updated++; 1319 } 1320 } 1321 } 1322 } 1323 if ($updated > 0) { 1324 $servers = Hm_IMAP_List::dump(false, true); 1325 $this->user_config->set('imap_servers', $servers); 1326 $this->session->set('user_data', $this->user_config->dump()); 1327 } 1328 } 1329} 1330 1331/** 1332 * Set IMAP server ids to prefetch on login 1333 * @subpackage imap/handler 1334 */ 1335class Hm_Handler_prefetch_imap_folders extends Hm_Handler_Module { 1336 /** 1337 * Check for imap servers to prefetch 1338 */ 1339 public function process() { 1340 1341 $servers = array(); 1342 foreach ($this->get('imap_servers', array()) as $index => $vals) { 1343 if (array_key_exists('user', $vals)) { 1344 $servers[$index] = $vals; 1345 } 1346 } 1347 if (count($servers) == 0) { 1348 return; 1349 } 1350 $fetched = $this->session->get('imap_prefetched_ids', array()); 1351 $ids = array_keys($servers); 1352 if (count($fetched) > 0) { 1353 $ids = array_diff($ids, $fetched); 1354 } 1355 if (count($ids) > 0) { 1356 $this->out('prefetch_folder_ids', $ids); 1357 } 1358 } 1359} 1360 1361/** 1362 * Output IMAP server data for other modules to use 1363 * @subpackage imap/handler 1364 */ 1365class Hm_Handler_add_imap_servers_to_page_data extends Hm_Handler_Module { 1366 /** 1367 * Creates folder source for the folder list and outputs IMAP server details 1368 */ 1369 public function process() { 1370 $servers = Hm_IMAP_List::dump(); 1371 if (!empty($servers)) { 1372 $this->out('imap_servers', $servers); 1373 } 1374 } 1375} 1376 1377/** 1378 * Delete IMAP cache 1379 * @subpackage imap/handler 1380 */ 1381class Hm_Handler_imap_bust_cache extends Hm_Handler_Module { 1382 /** 1383 * Deletes all the saved IMAP cache data 1384 */ 1385 public function process() { 1386 list($success, $form) = $this->process_form(array('imap_server_id')); 1387 if (!$success) { 1388 return; 1389 } 1390 $this->cache->del('imap'.$form['imap_server_id']); 1391 Hm_Debug::add(sprintf('Busted cache for IMAP server %s', $form['imap_server_id'])); 1392 } 1393} 1394 1395/** 1396 * Test a connection to an IMAP server 1397 * @subpackage imap/handler 1398 */ 1399class Hm_Handler_imap_connect extends Hm_Handler_Module { 1400 /** 1401 * Used by the servers page to test/authenticate with an IMAP server 1402 */ 1403 public function process() { 1404 if (isset($this->request->post['imap_connect'])) { 1405 list($success, $form) = $this->process_form(array('imap_user', 'imap_pass', 'imap_server_id')); 1406 $imap = false; 1407 $cache = Hm_IMAP_List::get_cache($this->cache, $form['imap_server_id']); 1408 if ($success) { 1409 $imap = Hm_IMAP_List::connect($form['imap_server_id'], $cache, $form['imap_user'], $form['imap_pass']); 1410 } 1411 elseif (isset($form['imap_server_id'])) { 1412 $imap = Hm_IMAP_List::connect($form['imap_server_id'], $cache); 1413 } 1414 if ($imap) { 1415 if ($imap->get_state() == 'authenticated') { 1416 Hm_Msgs::add(sprintf("Successfully authenticated to the %s server", $imap->server_type)); 1417 } 1418 else { 1419 Hm_Msgs::add(sprintf("ERRFailed to authenticate to the %s server", $imap->server_type)); 1420 } 1421 } 1422 else { 1423 Hm_Msgs::add('ERRUsername and password are required'); 1424 $this->out('old_form', $form); 1425 } 1426 } 1427 } 1428} 1429 1430/** 1431 * Forget IMAP server credentials 1432 * @subpackage imap/handler 1433 */ 1434class Hm_Handler_imap_forget extends Hm_Handler_Module { 1435 /** 1436 * Used on the servers page to forget login information for an IMAP server 1437 */ 1438 public function process() { 1439 $just_forgot_credentials = false; 1440 if (isset($this->request->post['imap_forget'])) { 1441 list($success, $form) = $this->process_form(array('imap_server_id')); 1442 if ($success) { 1443 Hm_IMAP_List::forget_credentials($form['imap_server_id']); 1444 $just_forgot_credentials = true; 1445 Hm_Msgs::add('Server credentials forgotten'); 1446 $this->session->record_unsaved('IMAP server credentials forgotten'); 1447 } 1448 else { 1449 $this->out('old_form', $form); 1450 } 1451 } 1452 $this->out('just_forgot_credentials', $just_forgot_credentials); 1453 } 1454} 1455 1456/** 1457 * Save a user/pass combination for an IMAP server 1458 * @subpackage imap/handler 1459 */ 1460class Hm_Handler_imap_save extends Hm_Handler_Module { 1461 /** 1462 * Authenticate then save the username and password for an IMAP server 1463 */ 1464 public function process() { 1465 $just_saved_credentials = false; 1466 if (isset($this->request->post['imap_save'])) { 1467 list($success, $form) = $this->process_form(array('imap_user', 'imap_pass', 'imap_server_id')); 1468 if (!$success) { 1469 Hm_Msgs::add('ERRUsername and Password are required to save a connection'); 1470 } 1471 else { 1472 if (in_server_list('Hm_IMAP_List', $form['imap_server_id'], $form['imap_user'])) { 1473 Hm_Msgs::add('ERRThis server and username are already configured'); 1474 return; 1475 } 1476 $cache = Hm_IMAP_List::get_cache($this->cache, $form['imap_server_id']); 1477 $imap = Hm_IMAP_List::connect($form['imap_server_id'], $cache, $form['imap_user'], $form['imap_pass'], true); 1478 if (imap_authed($imap)) { 1479 $just_saved_credentials = true; 1480 Hm_Msgs::add("Server saved"); 1481 $this->session->record_unsaved(sprintf('%s server saved', $imap->server_type)); 1482 } 1483 else { 1484 Hm_Msgs::add("ERRUnable to save this server, are the username and password correct?"); 1485 Hm_IMAP_List::forget_credentials($form['imap_server_id']); 1486 } 1487 } 1488 } 1489 $this->out('just_saved_credentials', $just_saved_credentials); 1490 } 1491} 1492 1493/** 1494 * Get message content from an IMAP server 1495 * @subpackage imap/handler 1496 */ 1497class Hm_Handler_imap_message_content extends Hm_Handler_Module { 1498 /** 1499 * Fetch the content, message parts, and headers for the supplied message 1500 */ 1501 public function process() { 1502 list($success, $form) = $this->process_form(array('imap_server_id', 'imap_msg_uid', 'folder')); 1503 if ($success) { 1504 $this->out('msg_text_uid', $form['imap_msg_uid']); 1505 $this->out('msg_server_id', $form['imap_server_id']); 1506 $this->out('msg_folder', $form['folder']); 1507 $part = false; 1508 $prefetch = false; 1509 if (isset($this->request->post['imap_msg_part']) && preg_match("/[0-9\.]+/", $this->request->post['imap_msg_part'])) { 1510 $part = $this->request->post['imap_msg_part']; 1511 } 1512 elseif (isset($this->request->post['imap_prefetch']) && $this->request->post['imap_prefetch']) { 1513 $prefetch = true; 1514 } 1515 if (array_key_exists('imap_allow_images', $this->request->post) && $this->request->post['imap_allow_images']) { 1516 $this->out('imap_allow_images', true); 1517 } 1518 $this->out('header_allow_images', $this->config->get('allow_external_image_sources')); 1519 1520 $cache = Hm_IMAP_List::get_cache($this->cache, $form['imap_server_id']); 1521 $imap = Hm_IMAP_List::connect($form['imap_server_id'], $cache); 1522 if (imap_authed($imap)) { 1523 $imap->read_only = $prefetch; 1524 if ($imap->select_mailbox(hex2bin($form['folder']))) { 1525 $this->out('folder_status', array('imap_'.$form['imap_server_id'].'_'.$form['folder'] => $imap->folder_state)); 1526 $msg_struct = $imap->get_message_structure($form['imap_msg_uid']); 1527 $this->out('msg_struct', $msg_struct); 1528 if ($part !== false) { 1529 if ($part == 0) { 1530 $max = 500000; 1531 } 1532 else { 1533 $max = false; 1534 } 1535 $struct = $imap->search_bodystructure($msg_struct, array('imap_part_number' => $part)); 1536 $msg_struct_current = array_shift($struct); 1537 $msg_text = $imap->get_message_content($form['imap_msg_uid'], $part, $max, $msg_struct_current); 1538 } 1539 else { 1540 if (!$this->user_config->get('text_only_setting', false)) { 1541 list($part, $msg_text) = $imap->get_first_message_part($form['imap_msg_uid'], 'text', 'html', $msg_struct); 1542 if (!$part) { 1543 list($part, $msg_text) = $imap->get_first_message_part($form['imap_msg_uid'], 'text', false, $msg_struct); 1544 } 1545 } 1546 else { 1547 list($part, $msg_text) = $imap->get_first_message_part($form['imap_msg_uid'], 'text', false, $msg_struct); 1548 } 1549 $struct = $imap->search_bodystructure( $msg_struct, array('imap_part_number' => $part)); 1550 $msg_struct_current = array_shift($struct); 1551 if (!trim($msg_text)) { 1552 if (is_array($msg_struct_current) && array_key_exists('subtype', $msg_struct_current)) { 1553 if ($msg_struct_current['subtype'] == 'plain') { 1554 $subtype = 'html'; 1555 } 1556 else { 1557 $subtype = 'plain'; 1558 } 1559 list($part, $msg_text) = $imap->get_first_message_part($form['imap_msg_uid'], 'text', $subtype, $msg_struct); 1560 $struct = $imap->search_bodystructure($msg_struct, array('imap_part_number' => $part)); 1561 $msg_struct_current = array_shift($struct); 1562 } 1563 } 1564 } 1565 if (isset($msg_struct_current['subtype']) && strtolower($msg_struct_current['subtype'] == 'html')) { 1566 $msg_text = add_attached_images($msg_text, $form['imap_msg_uid'], $msg_struct, $imap); 1567 } 1568 $save_reply_text = false; 1569 if ($part == 0 || (isset($msg_struct_current['type']) && strtolower($msg_struct_current['type'] == 'text'))) { 1570 $save_reply_text = true; 1571 } 1572 $msg_headers = $imap->get_message_headers($form['imap_msg_uid']); 1573 $this->out('list_headers', get_list_headers($msg_headers)); 1574 $this->out('msg_headers', $msg_headers); 1575 $this->out('imap_prefecth', $prefetch); 1576 $this->out('imap_msg_part', "$part"); 1577 $this->out('use_message_part_icons', $this->user_config->get('msg_part_icons_setting', false)); 1578 $this->out('simple_msg_part_view', $this->user_config->get('simple_msg_parts_setting', false)); 1579 if ($msg_struct_current) { 1580 $this->out('msg_struct_current', $msg_struct_current); 1581 } 1582 $this->out('msg_text', $msg_text); 1583 $this->out('msg_download_args', sprintf("page=message&uid=%s&list_path=imap_%d_%s&imap_download_message=1", $form['imap_msg_uid'], $form['imap_server_id'], $form['folder'])); 1584 if (!$prefetch) { 1585 clear_existing_reply_details($this->session); 1586 if ($part == 0) { 1587 $msg_struct_current['type'] = 'text'; 1588 $msg_struct_current['subtype'] = 'plain'; 1589 } 1590 $this->session->set(sprintf('reply_details_imap_%d_%s_%s', $form['imap_server_id'], $form['folder'], $form['imap_msg_uid']), 1591 array('msg_struct' => $msg_struct_current, 'msg_text' => ($save_reply_text ? $msg_text : ''), 'msg_headers' => $msg_headers)); 1592 } 1593 } 1594 } 1595 } 1596 } 1597} 1598 1599/** 1600 * Hide or unhide an IMAP server 1601 * @subpackage imap/handler 1602 */ 1603class Hm_Handler_imap_hide extends Hm_Handler_Module { 1604 /** 1605 * Hide or unhide an IMAP server from combined pages and searches 1606 */ 1607 public function process() { 1608 if (isset($this->request->post['hide_imap_server'])) { 1609 list($success, $form) = $this->process_form(array('imap_server_id')); 1610 if ($success) { 1611 Hm_IMAP_List::toggle_hidden($form['imap_server_id'], (bool) $this->request->post['hide_imap_server']); 1612 Hm_Msgs::add('Hidden status updated'); 1613 $this->session->record_unsaved(sprintf('%s server hidden status updated', imap_server_type($form['imap_server_id']))); 1614 } 1615 } 1616 } 1617} 1618 1619/** 1620 * Delete an IMAP server 1621 * @subpackage imap/handler 1622 */ 1623class Hm_Handler_imap_delete extends Hm_Handler_Module { 1624 /** 1625 * Remove an IMAP server completely, used on the servers page 1626 */ 1627 public function process() { 1628 if (isset($this->request->post['imap_delete'])) { 1629 list($success, $form) = $this->process_form(array('imap_server_id')); 1630 if ($success) { 1631 $res = Hm_IMAP_List::del($form['imap_server_id']); 1632 if ($res) { 1633 $this->out('deleted_server_id', $form['imap_server_id']); 1634 Hm_Msgs::add('Server deleted'); 1635 $this->session->record_unsaved(sprintf('%s server deleted', imap_server_type($form['imap_server_id']))); 1636 } 1637 } 1638 else { 1639 $this->out('old_form', $form); 1640 } 1641 } 1642 } 1643} 1644