rc = rcmail::get_instance(); $this->load_config(); $this->add_texts('localization/', false); $this->setCustomLabels(); if ($this->rc->task == 'mail') { # -- disable plugin when printing message if ($this->rc->action == 'print') return; if (!$this->rc->config->get('tb_label_enable')) // disable plugin according to prefs return; // pass 'tb_label_enable_shortcuts' and 'tb_label_style' prefs to JS $this->rc->output->set_env('tb_label_enable_shortcuts', $this->rc->config->get('tb_label_enable_shortcuts')); $this->rc->output->set_env('tb_label_style', $this->rc->config->get('tb_label_style')); $this->include_script('tb_label.js'); $this->add_hook('messages_list', array($this, 'read_flags')); $this->add_hook('message_load', array($this, 'read_single_flags')); $this->add_hook('template_object_messageheaders', array($this, 'color_headers')); $this->add_hook('render_page', array($this, 'tb_label_popup')); $this->add_hook('check_recent', array($this, 'check_recent_flags')); $this->include_stylesheet($this->local_skin_path() . '/tb_label.css'); #$this->include_stylesheet($this->local_skin_path() . '/tb_label.php'); $this->name = get_class($this); # -- additional TB flags $this->add_tb_flags = array( /*'LABEL1' => '$Label1', 'LABEL2' => '$Label2', 'LABEL3' => '$Label3', 'LABEL4' => '$Label4', 'LABEL5' => '$Label5',*/ ); $this->message_tb_labels = array(); $html = $this->template_file2html('toolbar'); if ($html) $this->api->add_content($html, 'toolbar'); // JS function "set_flags" => PHP function "set_flags" $this->register_action('plugin.thunderbird_labels.set_flags', array($this, 'set_flags')); if (method_exists($this, 'require_plugin') && in_array('contextmenu', $this->rc->config->get('plugins')) && $this->require_plugin('contextmenu') && $this->rc->config->get('tb_label_enable_contextmenu')) { if ($this->rc->action == '') $this->add_hook('render_mailboxlist', array($this, 'show_tb_label_contextmenu')); } } elseif ($this->rc->task == 'settings') { $this->include_stylesheet($this->local_skin_path() . '/tb_label.css'); $this->add_hook('preferences_list', array($this, 'prefs_list')); $this->add_hook('preferences_sections_list', array($this, 'prefs_section')); $this->add_hook('preferences_save', array($this, 'prefs_save')); } } private function setCustomLabels() { $c = $this->rc->config->get('tb_label_custom_labels'); if (empty($c) || isset($c[3])) { // if no user specific labels, use localized strings by default $this->rc->config->set('tb_label_custom_labels', array( 'LABEL0' => $this->getText('label0'), 'LABEL1' => $this->getText('label1'), 'LABEL2' => $this->getText('label2'), 'LABEL3' => $this->getText('label3'), 'LABEL4' => $this->getText('label4'), 'LABEL5' => $this->getText('label5') )); } // pass label strings to JS $this->rc->output->set_env('tb_label_custom_labels', $this->rc->config->get('tb_label_custom_labels')); } // create a section for the tb-labels Settings public function prefs_section($args) { $args['list']['thunderbird_labels'] = array( 'id' => 'thunderbird_labels', 'section' => rcube::Q($this->gettext('tb_label_options')) ); return $args; } // display thunderbird-labels prefs in Roundcube Settings public function prefs_list($args) { if ($args['section'] != 'thunderbird_labels') return $args; $this->load_config(); $dont_override = (array) $this->rc->config->get('dont_override', array()); $args['blocks']['tb_label'] = array(); $args['blocks']['tb_label']['name'] = $this->gettext('tb_label_options'); $key = 'tb_label_enable'; if (!in_array($key, $dont_override)) { $input = new html_checkbox(array( 'name' => $key, 'id' => $key, 'value' => 1 )); $content = $input->show($this->rc->config->get($key)); $args['blocks']['tb_label']['options'][$key] = array( 'title' => $this->gettext('tb_label_enable_option'), 'content' => $content ); } $key = 'tb_label_enable_shortcuts'; if (!in_array($key, $dont_override)) { $input = new html_checkbox(array( 'name' => $key, 'id' => $key, 'value' => 1 )); $content = $input->show($this->rc->config->get($key)); $args['blocks']['tb_label']['options'][$key] = array( 'title' => $this->gettext('tb_label_enable_shortcuts_option'), 'content' => $content ); } $key = 'tb_label_style'; if (!in_array($key, $dont_override)) { $select = new html_select(array( 'name' => $key, 'id' => $key )); $select->add([$this->gettext('thunderbird'), $this->gettext('bullets'), $this->gettext('badges')], self::LABEL_STYLES); $content = $select->show($this->rc->config->get($key)); $args['blocks']['tb_label']['options'][$key] = array( 'title' => $this->gettext('tb_label_style_option'), 'content' => $content ); } if (!in_array('tb_label_custom_labels', $dont_override) && $this->rc->config->get('tb_label_modify_labels')) { $custom_labels = $this->rc->config->get('tb_label_custom_labels'); foreach ($custom_labels as $key => $value) { $input = new html_inputfield(array( 'name' => "custom_$key", 'id' => "custom_$key", 'type' => 'text', 'autocomplete' => 'off', 'title' => $this->getText(strtolower($key)), # shows default value on hover 'value' => $value)); $args['blocks']['tb_label']['options']["option_$key"] = array( 'title' => $key, 'content' => $input->show() ); } } return $args; } // save prefs after modified in UI public function prefs_save($args) { if ($args['section'] != 'thunderbird_labels') return $args; $this->load_config(); $dont_override = (array) $this->rc->config->get('dont_override', array()); if (!in_array('tb_label_enable', $dont_override)) $args['prefs']['tb_label_enable'] = rcube_utils::get_input_value('tb_label_enable', rcube_utils::INPUT_POST) ? true : false; if (!in_array('tb_label_enable_shortcuts', $dont_override)) $args['prefs']['tb_label_enable_shortcuts'] = rcube_utils::get_input_value('tb_label_enable_shortcuts', rcube_utils::INPUT_POST) ? true : false; if (!in_array('tb_label_style', $dont_override)) { $tb_label_style = rcube_utils::get_input_value('tb_label_style', rcube_utils::INPUT_POST); if (in_array($tb_label_style, self::LABEL_STYLES)) { $args['prefs']['tb_label_style'] = $tb_label_style; } } if (!in_array('tb_label_custom_labels', $dont_override) && $this->rc->config->get('tb_label_modify_labels')) { $args['prefs']['tb_label_custom_labels'] = array( 'LABEL0' => $this->gettext('label0'), 'LABEL1' => rcube_utils::get_input_value('custom_LABEL1', rcube_utils::INPUT_POST), 'LABEL2' => rcube_utils::get_input_value('custom_LABEL2', rcube_utils::INPUT_POST), 'LABEL3' => rcube_utils::get_input_value('custom_LABEL3', rcube_utils::INPUT_POST), 'LABEL4' => rcube_utils::get_input_value('custom_LABEL4', rcube_utils::INPUT_POST), 'LABEL5' => rcube_utils::get_input_value('custom_LABEL5', rcube_utils::INPUT_POST) ); } return $args; } public function show_tb_label_contextmenu($args) { # no longer needed #$this->include_script('tb_label_contextmenu.js'); return null; } private function _gen_label_submenu($args, $id) { $out = ''; $custom_labels = $this->rc->config->get('tb_label_custom_labels'); for ($i = 0; $i < 6; $i++) { $separator = ($i == 0)? ' separator_below' :''; $out .= html::tag('li', null, $this->api->output->button(array( 'label' => rcube::Q($i.' '.$custom_labels["LABEL$i"]), 'command' => 'test.comm.and', 'type' => 'link', 'class' => 'label'.$i.$separator, 'aria-disabled' => 'true' ) ) ); /*$out .= '
  • '. $i.' '.$custom_labels[$i]. '
  • ';*/ } $out = html::tag('ul', array('id' => $id, 'role' => 'menu'), $out); return $out; } public function read_single_flags($args) { #rcube::write_log($this->name, print_r(($args['object']), true)); if (!isset($args['object'])) { return; } if (is_array($args['object']->headers->flags)) { $this->message_tb_labels = $this->custom_flags(array_keys($args['object']->headers->flags)); } # -- no return value for this hook } /** * Writes labelnumbers for single message display * Coloring of Message header table happens via Javascript */ public function color_headers($p) { #rcube::write_log($this->name, print_r($p, true)); # -- always write array, even when empty $p['content'] .= ''; return $p; } public function read_flags($args) { #rcube::write_log($this->name, print_r($args, true)); // add color information for all messages // dont loop over all messages if we dont have any highlights or no msgs if (!isset($args['messages']) or !is_array($args['messages'])) { return $args; } // loop over all messages and add $LabelX info to the extra_flags foreach($args['messages'] as $message) { #rcube::write_log($this->name, print_r($message->flags, true)); $message->list_flags['extra_flags']['tb_labels'] = array(); # always set extra_flags, needed for javascript later! if (is_array($message->flags)) $message->list_flags['extra_flags']['tb_labels'] = $this->custom_flags(array_keys($message->flags)); } return($args); } // set flags in IMAP server function set_flags() { #rcube::write_log($this->name, print_r($_GET, true)); $imap = $this->rc->storage; $cbox = rcube_utils::get_input_value('_cur', rcube_utils::INPUT_GET); $mbox = rcube_utils::get_input_value('_mbox', rcube_utils::INPUT_GET); $toggle_label = rcube_utils::get_input_value('_toggle_label', rcube_utils::INPUT_GET); $flag_uids = rcube_utils::get_input_value('_flag_uids', rcube_utils::INPUT_GET); $flag_uids = explode(',', $flag_uids); $unflag_uids = rcube_utils::get_input_value('_unflag_uids', rcube_utils::INPUT_GET); $unflag_uids = explode(',', $unflag_uids); $imap->conn->flags = array_merge($imap->conn->flags, $this->add_tb_flags); #rcube::write_log($this->name, print_r($flag_uids, true)); #rcube::write_log($this->name, print_r($unflag_uids, true)); if (!is_array($unflag_uids) || !is_array($flag_uids)) return false; # FIXME: there is no reliable way to know if roundcube mangled a label of different client # here is just a workaround for the known Thunderbird labels if (preg_match("/^LABEL[1-5]$/", $toggle_label)) # only for Thunderbird labels { $imap->set_flag($flag_uids, "UN$toggle_label", $mbox); # quickhack to remove non-$ labels $imap->set_flag($unflag_uids, "UN$toggle_label", $mbox); # quickhack to remove non-$ labels # prepend $ again to be compatible to Thunderbird (roundcube removes $ from labels) $imap->set_flag($flag_uids, "\$$toggle_label", $mbox); $imap->set_flag($unflag_uids, "UN\$$toggle_label", $mbox); } else { $imap->set_flag($flag_uids, "$toggle_label", $mbox); $imap->set_flag($unflag_uids, "UN$toggle_label", $mbox); } $this->api->output->send(); } function template_include_markup($tpl_name) { $path = '/' . $this->local_skin_path() . '/includes/' . $tpl_name . '.html'; $filepath = slashify($this->home) . $path; if (is_file($filepath) && is_readable($filepath)) return ""; return null; } function template_file2html($tpl_name) { $tpl_cmd = $this->template_include_markup($tpl_name); if ($tpl_cmd) return $this->template2html($tpl_cmd); return null; } function template2html($tpl_code) { if ($this->api->output->type == 'html') { if ($tpl_code) { $this->add_texts('localization/'); return $this->rc->output->just_parse($tpl_code); } } return null; } function tb_label_popup($args) { // Other plugins may use template parsing method, this causes more than one render_page execution. // We have to make sure the menu is added only once (when content is going to be written to client). // roundcube < 1.4 does not send 'write' key if (array_key_exists('write', $args) && !$args['write']) return; $html = $this->template_file2html($this->rc->task); if ($html) $this->rc->output->add_footer($html); # create a RC template for the popup-menu of tb-labels, make html from it and inject $tpl = '

    '; $tpl_menu = ''; $custom_labels = $this->rc->config->get('tb_label_custom_labels'); $i = 0; foreach ($custom_labels as $label_name => $human_readable) { $tpl_menu .= ''; $i++; } $html = $this->template2html($tpl.$tpl_menu.$tpl_end); if ($html) $this->rc->output->add_footer($html); } /* Bastardised hook, actually supposed to modify the list of folders for refresh * what we do here is fetching the imap-label changes using GPC variables! */ function check_recent_flags($params) { $mbox_name = rcube_utils::get_input_value('_mbox', rcube_utils::INPUT_GPC); // appears to be the current one $uids = rcube_utils::get_input_value('_uids', rcube_utils::INPUT_GPC); if ($uids && $mbox_name && isset($params['folders'][0])) { $mbox_name = $params['folders'][0]; $RCMAIL = $this->rc; # -- from here it's from check_recent.inc $data = $RCMAIL->storage->folder_data($mbox_name); if (empty($_SESSION['list_mod_seq']) || (isset($data['HIGHESTMODSEQ']) && $_SESSION['list_mod_seq'] != $data['HIGHESTMODSEQ'])) { $flags = $RCMAIL->storage->list_flags($mbox_name, explode(',', $uids), (empty($_SESSION['list_mod_seq']) ? null : $_SESSION['list_mod_seq'])); foreach ($flags as $idx => $row) { $flags[$idx] = array_change_key_case(array_map('intval', $row)); } // remember last HIGHESTMODSEQ value (if supported) if (!empty($data['HIGHESTMODSEQ'])) { $_SESSION['list_mod_seq'] = $data['HIGHESTMODSEQ']; } $RCMAIL->output->set_env('recent_flags', $flags); } # -- end of code copy from check_recent.inc if (isset($data['PERMANENTFLAGS'])) { //rcube::write_log($this->name, "data:".print_r($data['PERMANENTFLAGS'], true)); $RCMAIL->output->set_env('custom_flags', $this->custom_flags($data['PERMANENTFLAGS'])); } } return $params; } /** * Checks if the IMAP Server has support for custom flags * According to RFC the server must respond with a '\*' within PERMANENTFLAGS */ function custom_flags_allowed($permanent_flags) { if (!is_null($this->_custom_flags_allowed)) // primitive caching return $this->_custom_flags_allowed; $this->_custom_flags_allowed = false; foreach ($permanent_flags as $pf) { if ($pf == '\*') $this->_custom_flags_allowed = true; } return $this->_custom_flags_allowed; } /** * creates a list of custom flags besides the RFC default ones */ function custom_flags($permanent_flags) { $default_flags = [ '\Seen', '\Answered', // RFC3501 '\Flagged', '\Deleted', // RFC3501 '\Draft', '\Recent', // RFC3501 'SEEN', 'ANSWERED', // RFC3501 roundcubed 'FLAGGED', 'DELETED', // RFC3501 roundcubed 'DRAFT', 'RECENT', // RFC3501 roundcubed '$MDNSent', // Message Disposition Notification, not of interest 'MDNSENT', // Message Disposition Notification, not of interest roundcubed 'Junk', // not a useful flag for the user? 'JUNK', // not a useful flag for the user? roundcubed 'NonJunk', // not a useful flag for the user? 'NONJUNK', // not a useful flag for the user? roundcubed '\\*', // means labels allowed '*', // means labels allowed roundcubed ]; $default_flags = array_unique(array_merge($default_flags, $this->rc->config->get('tb_label_hidden_flags', []))); /* TODO: flagnames contain $ sign, or umlauts (imap-utf-7 encoded meanging & will be in the name) * smart way to recode those characters and create valid variable names? * Valid CSS classname is easy, just escape everything outside of [a-zA-Z0-9_] using backslash */ $custom_flags = array(); foreach ($permanent_flags as $pf) { $pf = $this->roundcube_flag($pf); if (!in_array($pf, $default_flags)) $custom_flags[] = $pf; } return $custom_flags; } /** * Roundcube mangles the flagnames for some reason to uppercase and removes backslash and $ */ function roundcube_flag($flag) { return ltrim(strtoupper($flag), '$\\'); } }