1<?php
2
3/**
4 * SAUserPrefs
5 *
6 * Plugin to allow the user to manage their SpamAssassin settings using an SQL database
7 *
8 * @version @package_version@
9 * @author Philip Weir
10 */
11class sauserprefs extends rcube_plugin
12{
13	public $task = 'mail|addressbook|settings';
14	private $storage;
15	private $sections = array();
16	private $cur_section;
17	private $global_prefs;
18	private $user_prefs;
19	private $addressbook = '0';
20	private $sa_locales = array('en', 'ja', 'ko', 'ru', 'th', 'zh');
21	private $sa_user;
22	static $deprecated_prefs = array('required_hits' => 'required_score');
23
24	function init()
25	{
26		$rcmail = rcube::get_instance();
27		$this->load_config();
28		$this->sa_user = $rcmail->config->get('sauserprefs_userid', "%u");
29
30		$identity_arr = $rcmail->user->get_identity();
31		$identity = $identity_arr['email'];
32		$this->sa_user = str_replace('%u', $_SESSION['username'], $this->sa_user);
33		$this->sa_user = str_replace('%l', $rcmail->user->get_username('local'), $this->sa_user);
34		$this->sa_user = str_replace('%d', $rcmail->user->get_username('domain'), $this->sa_user);
35		$this->sa_user = str_replace('%i', $identity, $this->sa_user);
36
37		// init storage
38		include('include/rcube_sauserprefs_storage.php');
39		$this->storage = new rcube_sauserprefs_storage($rcmail->config->get('sauserprefs_db_dsnw'), $rcmail->config->get('sauserprefs_db_dsnr'), $rcmail->config->get('sauserprefs_db_persistent'),
40							$this->sa_user, $rcmail->config->get('sauserprefs_sql_table_name'), $rcmail->config->get('sauserprefs_sql_username_field'), $rcmail->config->get('sauserprefs_sql_preference_field'),
41							$rcmail->config->get('sauserprefs_sql_value_field'), $rcmail->config->get('sauserprefs_bayes_delete_query'));
42
43		if ($rcmail->config->get('sauserprefs_whitelist_abook_id', false))
44			$this->addressbook = $rcmail->config->get('sauserprefs_whitelist_abook_id');
45
46		if ($rcmail->task == 'settings') {
47			$this->add_texts('localization/', array('sauserprefs', 'managespam'));
48			$this->include_stylesheet($this->local_skin_path() . '/tabstyles.css');
49
50			$this->sections = array(
51				'general' => array('id' => 'general', 'section' => $this->gettext('spamgeneralsettings')),
52				'tests' => array('id' => 'tests', 'section' => $this->gettext('spamtests')),
53				'bayes' => array('id' => 'bayes', 'section' => $this->gettext('bayes')),
54				'headers' => array('id' => 'headers', 'section' => $this->gettext('headers')),
55				'report' => array('id' => 'report','section' => $this->gettext('spamreportsettings')),
56				'addresses' => array('id' => 'addresses', 'section' => $this->gettext('spamaddressrules')),
57			);
58			$this->cur_section = rcube_utils::get_input_value('_section', rcube_utils::INPUT_GPC);
59
60			$this->register_action('plugin.sauserprefs', array($this, 'init_html'));
61			$this->register_action('plugin.sauserprefs.edit', array($this, 'init_html'));
62			$this->register_action('plugin.sauserprefs.save', array($this, 'save'));
63			$this->register_action('plugin.sauserprefs.whitelist_import', array($this, 'whitelist_import'));
64			$this->register_action('plugin.sauserprefs.purge_bayes', array($this, 'purge_bayes'));
65			$this->include_script('sauserprefs.js');
66		}
67		elseif ($rcmail->config->get('sauserprefs_whitelist_sync')) {
68			$this->add_hook('contact_create', array($this, 'contact_add'));
69			$this->add_hook('contact_update', array($this, 'contact_save'));
70			$this->add_hook('contact_delete', array($this, 'contact_delete'));
71		}
72	}
73
74	function init_html()
75	{
76		$this->_load_global_prefs();
77		$this->_load_user_prefs();
78
79		$this->api->output->set_pagetitle($this->gettext('sauserprefssettings'));
80
81		if (rcube::get_instance()->action == 'plugin.sauserprefs.edit') {
82			$this->user_prefs = array_merge($this->global_prefs, $this->user_prefs);
83			$this->api->output->add_handler('userprefs', array($this, 'gen_form'));
84			$this->api->output->add_handler('sectionname', array($this, 'prefs_section_name'));
85			$this->api->output->send('sauserprefs.settingsedit');
86		}
87		else {
88			$this->api->output->add_handler('sasectionslist', array($this, 'section_list'));
89			$this->api->output->add_handler('saprefsframe', array($this, 'preference_frame'));
90			$this->api->output->send('sauserprefs.sauserprefs');
91		}
92	}
93
94	function section_list($attrib)
95	{
96		$no_override = array_flip(rcube::get_instance()->config->get('sauserprefs_dont_override'));
97
98		// add id to message list table if not specified
99		if (!strlen($attrib['id']))
100			$attrib['id'] = 'rcmsectionslist';
101
102		$sections = array();
103		$blocks = $attrib['sections'] ? preg_split('/[\s,;]+/', strip_quotes($attrib['sections'])) : array_keys($this->sections);
104		foreach ($blocks as $block) {
105			if (!isset($no_override['{' . $block . '}']))
106				$sections[$block] = $this->sections[$block];
107		}
108
109		// create XHTML table
110		$out = rcube::get_instance()->table_output($attrib, $sections, array('section'), 'id');
111
112		// set client env
113		$this->api->output->add_gui_object('sectionslist', $attrib['id']);
114		$this->api->output->include_script('list.js');
115
116		return $out;
117	}
118
119	function preference_frame($attrib)
120	{
121		if (!$attrib['id'])
122			$attrib['id'] = 'rcmprefsframe';
123
124		return $this->api->output->frame($attrib, true);
125	}
126
127	function gen_form($attrib)
128	{
129		$this->api->output->add_label(
130			'sauserprefs.spamaddressexists', 'sauserprefs.spamenteraddress',
131			'sauserprefs.spamaddresserror', 'sauserprefs.spamaddressdelete',
132			'sauserprefs.spamaddressdeleteall', 'sauserprefs.enabled', 'sauserprefs.disabled',
133			'sauserprefs.importingaddresses', 'sauserprefs.usedefaultconfirm', 'sauserprefs.purgebayesconfirm',
134			'sauserprefs.whitelist_from');
135
136		// output global prefs as default in env
137		foreach($this->global_prefs as $key => $val)
138			$this->api->output->set_env(str_replace(" ", "_", $key), $val);
139
140		unset($attrib['form']);
141
142		list($form_start, $form_end) = get_form_tags($attrib, 'plugin.sauserprefs.save', null,
143			array('name' => '_section', 'value' => $this->cur_section));
144
145		$out = $form_start;
146
147		$out .= $this->_prefs_block($this->cur_section, $attrib);
148
149		return $out . $form_end;
150	}
151
152	function prefs_section_name()
153	{
154		return $this->sections[$this->cur_section]['section'];
155	}
156
157	function save()
158	{
159		$rcmail = rcube::get_instance();
160		$this->_load_global_prefs();
161		$this->_load_user_prefs();
162
163		$no_override = array_flip($rcmail->config->get('sauserprefs_dont_override'));
164		$new_prefs = array();
165		$result = true;
166
167		switch ($this->cur_section)
168		{
169			case 'general':
170				if (!isset($no_override['required_hits']))
171					$new_prefs['required_hits'] = rcube_utils::get_input_value('_spamthres', rcube_utils::INPUT_POST);
172
173				if (!isset($no_override['rewrite_header Subject']))
174					$new_prefs['rewrite_header Subject'] = rcube_utils::get_input_value('_spamsubject', rcube_utils::INPUT_POST);
175
176				if (!isset($no_override['ok_locales'])) {
177					$new_prefs['ok_locales'] = '';
178					if (is_array(rcube_utils::get_input_value('_spamlang', rcube_utils::INPUT_POST))) {
179						$locales = array_intersect(rcube_utils::get_input_value('_spamlang', rcube_utils::INPUT_POST), $this->sa_locales);
180						$new_prefs['ok_locales'] = implode(" ", $locales);
181					}
182				}
183
184				if (!isset($no_override['ok_languages']))
185					$new_prefs['ok_languages'] = is_array(rcube_utils::get_input_value('_spamlang', rcube_utils::INPUT_POST)) ? implode(" ", rcube_utils::get_input_value('_spamlang', rcube_utils::INPUT_POST)) : '';
186
187				break;
188
189			case 'headers':
190				if (!isset($no_override['fold_headers']))
191					$new_prefs['fold_headers'] = empty($_POST['_spamfoldheaders']) ? "0" : "1";
192
193				if (!isset($no_override['add_header all Level'])) {
194					$spamchar = empty($_POST['_spamlevelchar']) ? "*" : rcube_utils::get_input_value('_spamlevelchar', rcube_utils::INPUT_POST);
195
196					if (rcube_utils::get_input_value('_spamlevelstars', rcube_utils::INPUT_POST) == "1") {
197						$new_prefs['add_header all Level'] = "_STARS(". $spamchar .")_";
198						$new_prefs['remove_header all'] = "0";
199					}
200					else {
201						$new_prefs['add_header all Level'] = "";
202						$new_prefs['remove_header all'] = "Level";
203					}
204				}
205
206				break;
207
208			case 'tests':
209				if (!isset($no_override['use_razor1']))
210					$new_prefs['use_razor1'] = empty($_POST['_spamuserazor1']) ? "0" : "1";
211
212				if (!isset($no_override['use_razor2']))
213					$new_prefs['use_razor2'] = empty($_POST['_spamuserazor2']) ? "0" : "1";
214
215				if (!isset($no_override['use_pyzor']))
216					$new_prefs['use_pyzor'] = empty($_POST['_spamusepyzor']) ? "0" : "1";
217
218				if (!isset($no_override['use_dcc']))
219					$new_prefs['use_dcc'] = empty($_POST['_spamusedcc']) ? "0" : "1";
220
221				if (!isset($no_override['skip_rbl_checks']))
222					$new_prefs['skip_rbl_checks'] = empty($_POST['_spamskiprblchecks']) ? "1" : "0";
223
224				break;
225
226			case 'bayes':
227				if (!isset($no_override['use_bayes']))
228					$new_prefs['use_bayes'] = empty($_POST['_spamusebayes']) ? "0" : "1";
229
230				if (!isset($no_override['bayes_auto_learn']))
231					$new_prefs['bayes_auto_learn'] = empty($_POST['_spambayesautolearn']) ? "0" : "1";
232
233				if (!isset($no_override['bayes_auto_learn_threshold_nonspam']) && !empty($_POST['_bayesnonspam']))
234					$new_prefs['bayes_auto_learn_threshold_nonspam'] = rcube_utils::get_input_value('_bayesnonspam', rcube_utils::INPUT_POST);
235
236				if (!isset($no_override['bayes_auto_learn_threshold_spam']) && !empty($_POST['_bayesspam']))
237					$new_prefs['bayes_auto_learn_threshold_spam'] = rcube_utils::get_input_value('_bayesspam', rcube_utils::INPUT_POST);
238
239				if (!isset($no_override['use_bayes_rules']))
240					$new_prefs['use_bayes_rules'] = empty($_POST['_spambayesrules']) ? "0" : "1";
241
242				break;
243
244			case 'report':
245				if (!isset($no_override['report_safe']))
246					$new_prefs['report_safe'] = rcube_utils::get_input_value('_spamreport', rcube_utils::INPUT_POST);
247
248				break;
249
250			case 'addresses':
251				$acts = rcube_utils::get_input_value('_address_rule_act', rcube_utils::INPUT_POST);
252				$prefs = rcube_utils::get_input_value('_address_rule_field', rcube_utils::INPUT_POST);
253				$vals = rcube_utils::get_input_value('_address_rule_value', rcube_utils::INPUT_POST);
254
255				foreach ($acts as $idx => $act)
256					$new_prefs['addresses'][] = array('field' => $prefs[$idx], 'value' => $vals[$idx], 'action' => $act);
257
258				break;
259		}
260
261		// allow additional actions before prefs are saved
262		$data = $rcmail->plugins->exec_hook('sauserprefs_save', array(
263			'section' => $this->cur_section, 'cur_prefs' => $this->user_prefs, 'new_prefs' => $new_prefs, 'global_prefs' => $this->global_prefs));
264
265		if (!$data['abort']) {
266			// save prefs
267			if ($this->storage->save_prefs($data['new_prefs'], $this->user_prefs, $this->global_prefs))
268				$this->api->output->command('display_message', $this->gettext('sauserprefchanged'), 'confirmation');
269			else
270				$this->api->output->command('display_message', $this->gettext('sauserpreffailed'), 'error');
271		}
272		else {
273				$this->api->output->command('display_message', $data['message'] ? $data['message'] : $this->gettext('sauserpreffailed'), 'error');
274		}
275
276		// go to next step
277		$rcmail->overwrite_action('plugin.sauserprefs.edit');
278		$this->_load_user_prefs();
279		$this->init_html();
280	}
281
282	function whitelist_import()
283	{
284		$contacts = rcube::get_instance()->get_address_book($this->addressbook);
285		$contacts->set_page(1);
286		$contacts->set_pagesize(99999);
287		$result = $contacts->list_records(null, 0, true);
288
289		if (empty($result) || $result->count == 0)
290			return;
291
292		$records = $result->records;
293		foreach ($records as $row_data) {
294			foreach ($this->_gen_email_arr($row_data) as $email)
295				$this->api->output->command('sauserprefs_addressrule_import', $email, '', '');
296		}
297
298		$contacts->close();
299	}
300
301	function purge_bayes()
302	{
303		$rcmail = rcube::get_instance();
304
305		if (!$rcmail->config->get('sauserprefs_bayes_delete', false)) {
306			$this->api->output->command('display_message', $this->gettext('servererror'), 'error');
307			return;
308		}
309
310		if ($this->storage->purge_bayes())
311			$this->api->output->command('display_message', $this->gettext('done'), 'confirmation');
312		else
313			$this->api->output->command('display_message', $this->gettext('servererror'), 'error');
314	}
315
316	function contact_add($args)
317	{
318		$rcmail = rcube::get_instance();
319
320		// only works with specified address book
321		if ($args['source'] != $this->addressbook && $args['source'] != null)
322			return;
323
324		$emails = $this->_gen_email_arr($args['record']);
325		$this->storage->whitelist_add($emails);
326	}
327
328	function contact_save($args)
329	{
330		$this->contact_delete($args);
331		$this->contact_add($args);
332	}
333
334	function contact_delete($args)
335	{
336		$rcmail = rcube::get_instance();
337
338		// only works with specified address book
339		if ($args['source'] != $this->addressbook && $args['source'] != null)
340			return;
341
342		if (!is_array($args['id']))
343			$args['id'] = array($args['id']);
344
345		$contacts = $rcmail->get_address_book($this->addressbook);
346		foreach ($args['id'] as $id) {
347			$emails = $this->_gen_email_arr($contacts->get_record($id, true));
348			$this->storage->whitelist_delete($emails);
349		}
350
351		$contacts->close();
352	}
353
354	private function _load_global_prefs()
355	{
356		$rcmail = rcube::get_instance();
357		$this->global_prefs = $this->_load_prefs($rcmail->config->get('sauserprefs_global_userid'));
358		$this->global_prefs = array_merge($rcmail->config->get('sauserprefs_default_prefs'), $this->global_prefs);
359	}
360
361	private function _load_user_prefs()
362	{
363		$this->user_prefs = $this->_load_prefs($this->sa_user);
364	}
365
366	private function _load_prefs($user)
367	{
368		$rcmail = rcube::get_instance();
369		$prefs = $this->storage->load_prefs($user);
370
371		// sort address rules
372		$prefs['addresses'] = $this->_subval_sort($prefs['addresses'], 'value');
373
374		return $prefs;
375	}
376
377	private function _prefs_block($part, $attrib)
378	{
379		$rcmail = rcube::get_instance();
380		$no_override = array_flip($rcmail->config->get('sauserprefs_dont_override'));
381		$locale_info = localeconv();
382
383		switch ($part)
384		{
385			// General tests
386			case 'general':
387				$out = '';
388				$data = '';
389
390				$table = new html_table(array('class' => 'generalprefstable', 'cols' => 2));
391
392				if (!isset($no_override['required_hits'])) {
393					$field_id = 'rcmfd_spamthres';
394					$input_spamthres = new html_select(array('name' => '_spamthres', 'id' => $field_id));
395					$input_spamthres->add($this->gettext('defaultscore'), '');
396
397					$decPlaces = 0;
398					if ($rcmail->config->get('sauserprefs_score_inc') - (int)$rcmail->config->get('sauserprefs_score_inc') > 0)
399						$decPlaces = strlen($rcmail->config->get('sauserprefs_score_inc') - (int)$rcmail->config->get('sauserprefs_score_inc')) - 2;
400
401					$score_found = false;
402					for ($i = 1; $i <= 10; $i = $i + $rcmail->config->get('sauserprefs_score_inc')) {
403						$input_spamthres->add(number_format($i, $decPlaces, $locale_info['decimal_point'], ''), number_format($i, $decPlaces, '.', ''));
404
405						if (!$score_found && $this->user_prefs['required_hits'] && (float)$this->user_prefs['required_hits'] == (float)$i)
406							$score_found = true;
407					}
408
409					if (!$score_found && $this->user_prefs['required_hits'])
410						$input_spamthres->add(str_replace('%s', $this->user_prefs['required_hits'], $this->gettext('otherscore')), (float)$this->user_prefs['required_hits']);
411
412					$table->add('title', html::label($field_id, rcmail::Q($this->gettext('spamthres'))));
413					$table->add(null, $input_spamthres->show(number_format($this->user_prefs['required_hits'], $decPlaces, '.', '')));
414					$table->add(array('colspan' => 2), rcmail::Q($this->gettext('spamthresexp')));
415				}
416
417				if (!isset($no_override['rewrite_header Subject'])) {
418					$field_id = 'rcmfd_spamsubject';
419					$input_spamsubject = new html_inputfield(array('name' => '_spamsubject', 'id' => $field_id, 'value' => $this->user_prefs['rewrite_header Subject'], 'style' => 'width:200px;'));
420
421					$table->add('title', html::label($field_id, rcmail::Q($this->gettext('spamsubject'))));
422					$table->add(null, $input_spamsubject->show());
423
424					$table->add('title', "&nbsp;");
425					$table->add(null, rcmail::Q($this->gettext('spamsubjectblank')));
426				}
427
428				if ($table->size() > 0)
429					$out .= html::tag('fieldset', null, html::tag('legend', null, rcmail::Q($this->gettext('mainoptions'))) . $table->show());
430
431				if (!isset($no_override['ok_languages']) || !isset($no_override['ok_locales'])) {
432					$data = html::p(null, rcmail::Q($this->gettext('spamlangexp')));
433
434					$table = new html_table(array('class' => 'langprefstable', 'cols' => 1));
435
436					$select_all = $this->api->output->button(array('command' => 'plugin.sauserprefs.select_all_langs', 'type' => 'link', 'label' => 'all'));
437					$select_none = $this->api->output->button(array('command' => 'plugin.sauserprefs.select_no_langs', 'type' => 'link', 'label' => 'none'));
438					$select_invert = $this->api->output->button(array('command' => 'plugin.sauserprefs.select_invert_langs', 'type' => 'link', 'label' => 'invert'));
439
440					$table->add(array('id' => 'listcontrols'), $this->gettext('select') .":&nbsp;&nbsp;". $select_all ."&nbsp;&nbsp;". $select_invert ."&nbsp;&nbsp;". $select_none);
441
442					$lang_table = new html_table(array('id' => 'spam-langs-table', 'class' => 'records-table', 'cellspacing' => '0', 'cols' => 2));
443					$lang_table->add_header(array('colspan' => 2), $this->gettext('language'));
444
445					if (!isset($no_override['ok_locales'])) {
446						if ($this->user_prefs['ok_locales'] == "all")
447							$ok_locales = $this->sa_locales;
448						else
449							$ok_locales = explode(" ", $this->user_prefs['ok_locales']);
450					}
451					else {
452						$ok_locales = array();
453					}
454
455					if (!isset($no_override['ok_languages'])) {
456						if ($this->user_prefs['ok_languages'] == "all")
457							$ok_languages = array_keys($rcmail->config->get('sauserprefs_languages'));
458						else
459							$ok_languages = explode(" ", $this->user_prefs['ok_languages']);
460					}
461					else {
462						$tmp_array = $rcmail->config->get('sauserprefs_languages');
463						$rcmail->config->set('sauserprefs_languages', array_intersect_key($tmp_array, array_flip($this->sa_locales)));
464						$ok_languages = array();
465					}
466
467					$i = 0;
468					$locales_langs = array_merge($ok_locales, $ok_languages);
469					foreach ($rcmail->config->get('sauserprefs_languages') as $lang_code => $name) {
470						if (in_array($lang_code, $locales_langs))
471							$button = $this->api->output->button(array('command' => 'plugin.sauserprefs.message_lang', 'prop' => $lang_code, 'type' => 'link', 'class' => 'enabled', 'id' => 'spam_lang_' . $i, 'title' => 'sauserprefs.enabled', 'content' => ' '));
472						else
473							$button = $this->api->output->button(array('command' => 'plugin.sauserprefs.message_lang', 'prop' => $lang_code, 'type' => 'link', 'class' => 'disabled', 'id' => 'spam_lang_' . $i, 'title' => 'sauserprefs.disabled', 'content' => ' '));
474
475						$input_spamlang = new html_checkbox(array('style' => 'display: none;', 'name' => '_spamlang[]', 'value' => $lang_code));
476
477						$lang_table->add('lang', $name);
478						$lang_table->add('tick', $button . $input_spamlang->show(in_array($lang_code, $locales_langs) ? $lang_code : ''));
479
480						$i++;
481					}
482
483					$table->add('scroller', html::div(array('id' => 'spam-langs-cont'), $lang_table->show()));
484
485					$out .= html::tag('fieldset', null, html::tag('legend', null, rcmail::Q($this->gettext('langoptions'))) . $data . $table->show());
486				}
487
488				break;
489
490			// Header settings
491			case 'headers':
492				$data = html::p(null, rcmail::Q($this->gettext('headersexp')));
493
494				$table = new html_table(array('class' => 'headersprefstable', 'cols' => 3));
495
496				if (!isset($no_override['fold_headers'])) {
497					$help_button = html::img(array('class' => $imgclass, 'src' => $attrib['helpicon'], 'alt' => $this->gettext('sieveruleheaders'), 'border' => 0, 'style' => 'margin-left: 4px;'));
498					$help_button = html::a(array('name' => '_headerhlp', 'href' => "#", 'onclick' => 'return '. rcmail_output::JS_OBJECT_NAME .'.sauserprefs_help("fold_help");', 'title' => $this->gettext('help')), $help_button);
499
500					$field_id = 'rcmfd_spamfoldheaders';
501					$input_spamreport = new html_checkbox(array('name' => '_spamfoldheaders', 'id' => $field_id, 'value' => '1'));
502
503					$table->add('title', html::label($field_id, rcmail::Q($this->gettext('foldheaders'))));
504					$table->add(null, $input_spamreport->show($this->user_prefs['fold_headers']));
505					$table->add('help', $help_button);
506					$table->set_row_attribs(array('id' => 'fold_help', 'style' => 'display: none;'));
507					$table->add(array('colspan' => '3'), rcmail::Q($this->gettext('foldhelp')));
508				}
509
510				if (!isset($no_override['add_header all Level'])) {
511					$help_button = html::img(array('class' => $imgclass, 'src' => $attrib['helpicon'], 'alt' => $this->gettext('sieveruleheaders'), 'border' => 0, 'style' => 'margin-left: 4px;'));
512					$help_button = html::a(array('name' => '_headerhlp', 'href' => "#", 'onclick' => 'return '. rcmail_output::JS_OBJECT_NAME .'.sauserprefs_help("level_help");', 'title' => $this->gettext('help')), $help_button);
513
514					if ($this->user_prefs['remove_header all'] != 'Level') {
515						$enabled = "1";
516						$char = $this->user_prefs['add_header all Level'];
517						$char = substr($char, 7, 1);
518					}
519					else {
520						$enabled = "0";
521						$char = "*";
522					}
523
524					$field_id = 'rcmfd_spamlevelstars';
525					$input_spamreport = new html_checkbox(array('name' => '_spamlevelstars', 'id' => $field_id, 'value' => '1',
526						'onchange' => rcmail_output::JS_OBJECT_NAME . '.sauserprefs_toggle_level_char(this)'));
527
528					$table->add('title', html::label($field_id, rcmail::Q($this->gettext('spamlevelstars'))));
529					$table->add(null, $input_spamreport->show($enabled));
530					$table->add('help', $help_button);
531					$table->set_row_attribs(array('id' => 'level_help', 'style' => 'display: none;'));
532					$table->add(array('colspan' => '3'), rcmail::Q($this->gettext('levelhelp')));
533
534					$field_id = 'rcmfd_spamlevelchar';
535					$input_spamsubject = new html_inputfield(array('name' => '_spamlevelchar', 'id' => $field_id, 'value' => $char,
536						'style' => 'width:20px;', 'disabled' => $enabled?0:1));
537
538					$table->add('title', html::label($field_id, rcmail::Q($this->gettext('spamlevelchar'))));
539					$table->add(null, $input_spamsubject->show());
540					$table->add('help', '&nbsp;');
541				}
542
543				$out = html::tag('fieldset', null, html::tag('legend', null, rcmail::Q($this->gettext('mainoptions'))) . $data . $table->show());
544				break;
545
546			// Test settings
547			case 'tests':
548				$data = html::p(null, rcmail::Q($this->gettext('spamtestssexp')));
549
550				$table = new html_table(array('class' => 'testsprefstable', 'cols' => 3));
551
552				if (!isset($no_override['use_razor1'])) {
553					$help_button = html::img(array('class' => $imgclass, 'src' => $attrib['helpicon'], 'alt' => $this->gettext('sieveruleheaders'), 'border' => 0, 'style' => 'margin-left: 4px;'));
554					$help_button = html::a(array('name' => '_headerhlp', 'href' => "#", 'onclick' => 'return '. rcmail_output::JS_OBJECT_NAME .'.sauserprefs_help("raz1_help");', 'title' => $this->gettext('help')), $help_button);
555
556					$field_id = 'rcmfd_spamuserazor1';
557					$input_spamtest = new html_checkbox(array('name' => '_spamuserazor1', 'id' => $field_id, 'value' => '1'));
558
559					$table->add('title', html::label($field_id, rcmail::Q($this->gettext('userazor1'))));
560					$table->add(null, $input_spamtest->show($this->user_prefs['use_razor1']));
561					$table->add('help', $help_button);
562					$table->set_row_attribs(array('id' => 'raz1_help', 'style' => 'display: none;'));
563					$table->add(array('colspan' => '3'), rcmail::Q($this->gettext('raz1help')));
564				}
565
566				if (!isset($no_override['use_razor2'])) {
567					$help_button = html::img(array('class' => $imgclass, 'src' => $attrib['helpicon'], 'alt' => $this->gettext('sieveruleheaders'), 'border' => 0, 'style' => 'margin-left: 4px;'));
568					$help_button = html::a(array('name' => '_headerhlp', 'href' => "#", 'onclick' => 'return '. rcmail_output::JS_OBJECT_NAME .'.sauserprefs_help("raz2_help");', 'title' => $this->gettext('help')), $help_button);
569
570					$field_id = 'rcmfd_spamuserazor2';
571					$input_spamtest = new html_checkbox(array('name' => '_spamuserazor2', 'id' => $field_id, 'value' => '1'));
572
573					$table->add('title', html::label($field_id, rcmail::Q($this->gettext('userazor2'))));
574					$table->add(null, $input_spamtest->show($this->user_prefs['use_razor2']));
575					$table->add('help', $help_button);
576					$table->set_row_attribs(array('id' => 'raz2_help', 'style' => 'display: none;'));
577					$table->add(array('colspan' => '3'), rcmail::Q($this->gettext('raz2help')));
578				}
579
580				if (!isset($no_override['use_pyzor'])) {
581					$help_button = html::img(array('class' => $imgclass, 'src' => $attrib['helpicon'], 'alt' => $this->gettext('sieveruleheaders'), 'border' => 0, 'style' => 'margin-left: 4px;'));
582					$help_button = html::a(array('name' => '_headerhlp', 'href' => "#", 'onclick' => 'return '. rcmail_output::JS_OBJECT_NAME .'.sauserprefs_help("pyz_help");', 'title' => $this->gettext('help')), $help_button);
583
584					$field_id = 'rcmfd_spamusepyzor';
585					$input_spamtest = new html_checkbox(array('name' => '_spamusepyzor', 'id' => $field_id, 'value' => '1'));
586
587					$table->add('title', html::label($field_id, rcmail::Q($this->gettext('usepyzor'))));
588					$table->add(null, $input_spamtest->show($this->user_prefs['use_pyzor']));
589					$table->add('help', $help_button);
590					$table->set_row_attribs(array('id' => 'pyz_help', 'style' => 'display: none;'));
591					$table->add(array('colspan' => '3'), rcmail::Q($this->gettext('pyzhelp')));
592				}
593
594				if (!isset($no_override['use_dcc'])) {
595					$help_button = html::img(array('class' => $imgclass, 'src' => $attrib['helpicon'], 'alt' => $this->gettext('sieveruleheaders'), 'border' => 0, 'style' => 'margin-left: 4px;'));
596					$help_button = html::a(array('name' => '_headerhlp', 'href' => "#", 'onclick' => 'return '. rcmail_output::JS_OBJECT_NAME .'.sauserprefs_help("dcc_help");', 'title' => $this->gettext('help')), $help_button);
597
598					$field_id = 'rcmfd_spamusedcc';
599					$input_spamtest = new html_checkbox(array('name' => '_spamusedcc', 'id' => $field_id, 'value' => '1'));
600
601					$table->add('title', html::label($field_id, rcmail::Q($this->gettext('usedcc'))));
602					$table->add(null, $input_spamtest->show($this->user_prefs['use_dcc']));
603					$table->add('help', $help_button);
604					$table->set_row_attribs(array('id' => 'dcc_help', 'style' => 'display: none;'));
605					$table->add(array('colspan' => '3'), rcmail::Q($this->gettext('dcchelp')));
606				}
607
608				if (!isset($no_override['skip_rbl_checks'])) {
609					$help_button = html::img(array('class' => $imgclass, 'src' => $attrib['helpicon'], 'alt' => $this->gettext('sieveruleheaders'), 'border' => 0, 'style' => 'margin-left: 4px;'));
610					$help_button = html::a(array('name' => '_headerhlp', 'href' => "#", 'onclick' => 'return '. rcmail_output::JS_OBJECT_NAME .'.sauserprefs_help("rbl_help");', 'title' => $this->gettext('help')), $help_button);
611
612					$field_id = 'rcmfd_spamskiprblchecks';
613					$enabled = $this->user_prefs['skip_rbl_checks'] == "1" ? "0" : "1";
614					$input_spamtest = new html_checkbox(array('name' => '_spamskiprblchecks', 'id' => $field_id, 'value' => '1'));
615
616					$table->add('title', html::label($field_id, rcmail::Q($this->gettext('skiprblchecks'))));
617					$table->add(null, $input_spamtest->show($enabled));
618					$table->add('help', $help_button);
619					$table->set_row_attribs(array('id' => 'rbl_help', 'style' => 'display: none;'));
620					$table->add(array('colspan' => '3'), rcmail::Q($this->gettext('rblhelp')));
621				}
622
623				$out = html::tag('fieldset', null, html::tag('legend', null, rcmail::Q($this->gettext('mainoptions'))) . $data . $table->show());
624				break;
625
626			// Bayes settings
627			case 'bayes':
628				$data = html::p(null, rcmail::Q($this->gettext('bayeshelp')));
629
630				$table = new html_table(array('class' => 'bayesprefstable', 'cols' => 3));
631
632				if (!isset($no_override['use_bayes'])) {
633					$help_button = html::img(array('class' => $imgclass, 'src' => $attrib['helpicon'], 'alt' => $this->gettext('sieveruleheaders'), 'border' => 0, 'style' => 'margin-left: 4px;'));
634					$help_button = html::a(array('name' => '_headerhlp', 'href' => "#", 'onclick' => 'return '. rcmail_output::JS_OBJECT_NAME .'.sauserprefs_help("bayes_help");', 'title' => $this->gettext('help')), $help_button);
635
636					$field_id = 'rcmfd_spamusebayes';
637					$input_spamtest = new html_checkbox(array('name' => '_spamusebayes', 'id' => $field_id, 'value' => '1',
638						'onchange' => rcmail_output::JS_OBJECT_NAME . '.sauserprefs_toggle_bayes(this)'));
639
640					if ($rcmail->config->get('sauserprefs_bayes_delete', false))
641						$delete_link =  "&nbsp;&nbsp;&nbsp;" . html::span(array('id' => 'listcontrols'), $this->api->output->button(array('command' => 'plugin.sauserprefs.purge_bayes', 'type' => 'link', 'label' => 'sauserprefs.purgebayes', 'title' => 'sauserprefs.purgebayesexp')));
642
643					$table->add('title', html::label($field_id, rcmail::Q($this->gettext('usebayes'))));
644					$table->add(null, $input_spamtest->show($this->user_prefs['use_bayes']) . $delete_link);
645					$table->add('help', '&nbsp;');
646					$table->set_row_attribs(array('id' => 'bayes_help', 'style' => 'display: none;'));
647					$table->add(array('colspan' => '3'), rcmail::Q($this->gettext('bayeshelp')));
648				}
649
650				if (!isset($no_override['use_bayes_rules'])) {
651					$help_button = html::img(array('class' => $imgclass, 'src' => $attrib['helpicon'], 'alt' => $this->gettext('sieveruleheaders'), 'border' => 0, 'style' => 'margin-left: 4px;'));
652					$help_button = html::a(array('name' => '_headerhlp', 'href' => "#", 'onclick' => 'return '. rcmail_output::JS_OBJECT_NAME .'.sauserprefs_help("bayesrules_help");', 'title' => $this->gettext('help')), $help_button);
653
654					$field_id = 'rcmfd_spambayesrules';
655					$input_spamtest = new html_checkbox(array('name' => '_spambayesrules', 'id' => $field_id, 'value' => '1', 'disabled' => $this->user_prefs['use_bayes']?0:1));
656
657					$table->add('title', html::label($field_id, rcmail::Q($this->gettext('bayesrules'))));
658					$table->add(null, $input_spamtest->show($this->user_prefs['use_bayes_rules']));
659					$table->add('help', $help_button);
660					$table->set_row_attribs(array('id' => 'bayesrules_help', 'style' => 'display: none;'));
661					$table->add(array('colspan' => '3'), rcmail::Q($this->gettext('bayesruleshlp')));
662				}
663
664				if (!isset($no_override['bayes_auto_learn'])) {
665					$help_button = html::img(array('class' => $imgclass, 'src' => $attrib['helpicon'], 'alt' => $this->gettext('sieveruleheaders'), 'border' => 0, 'style' => 'margin-left: 4px;'));
666					$help_button = html::a(array('name' => '_headerhlp', 'href' => "#", 'onclick' => 'return '. rcmail_output::JS_OBJECT_NAME .'.sauserprefs_help("bayesauto_help");', 'title' => $this->gettext('help')), $help_button);
667
668					$field_id = 'rcmfd_spambayesautolearn';
669					$input_spamtest = new html_checkbox(array('name' => '_spambayesautolearn', 'id' => $field_id, 'value' => '1',
670						'onchange' => rcmail_output::JS_OBJECT_NAME . '.sauserprefs_toggle_bayes_auto(this)', 'disabled' => $this->user_prefs['use_bayes']?0:1));
671
672					$table->add('title', html::label($field_id, rcmail::Q($this->gettext('bayesautolearn'))));
673					$table->add(null, $input_spamtest->show($this->user_prefs['bayes_auto_learn']));
674					$table->add('help', $help_button);
675					$table->set_row_attribs(array('id' => 'bayesauto_help', 'style' => 'display: none;'));
676					$table->add(array('colspan' => '3'), rcmail::Q($this->gettext('bayesautohelp')));
677				}
678
679				if ($table->size() > 0)
680					$out = html::tag('fieldset', null, html::tag('legend', null, rcmail::Q($this->gettext('mainoptions'))) . $table->show());
681
682				$table = new html_table(array('class' => 'bayesprefstable', 'cols' => 2));
683
684				$data = "";
685				if (!isset($no_override['bayes_auto_learn_threshold_nonspam'])) {
686					$field_id = 'rcmfd_bayesnonspam';
687					$input_bayesnthres = new html_select(array('name' => '_bayesnonspam', 'id' => $field_id, 'disabled' => (!$this->user_prefs['bayes_auto_learn'] || !$this->user_prefs['use_bayes'])?1:0));
688					$input_bayesnthres->add($this->gettext('defaultscore'), '');
689
690					$decPlaces = 1;
691					//if ($rcmail->config->get('sauserprefs_score_inc') - (int)$rcmail->config->get('sauserprefs_score_inc') > 0)
692					//	$decPlaces = strlen($rcmail->config->get('sauserprefs_score_inc') - (int)$rcmail->config->get('sauserprefs_score_inc')) - 2;
693
694					$score_found = false;
695					for ($i = -1; $i <= 1; $i = $i + 0.1) {
696						$input_bayesnthres->add(number_format($i, $decPlaces, $locale_info['decimal_point'], ''), number_format($i, $decPlaces, '.', ''));
697
698						if (!$score_found && $this->user_prefs['bayes_auto_learn_threshold_nonspam'] && (float)$this->user_prefs['bayes_auto_learn_threshold_nonspam'] == (float)$i)
699							$score_found = true;
700					}
701
702					if (!$score_found && $this->user_prefs['bayes_auto_learn_threshold_nonspam'])
703						$input_bayesnthres->add(str_replace('%s', $this->user_prefs['bayes_auto_learn_threshold_nonspam'], $this->gettext('otherscore')), (float)$this->user_prefs['bayes_auto_learn_threshold_nonspam']);
704
705					$table->add('title', html::label($field_id, rcmail::Q($this->gettext('bayesnonspam'))));
706					$table->add(null, $input_bayesnthres->show(number_format($this->user_prefs['bayes_auto_learn_threshold_nonspam'], $decPlaces, '.', '')));
707					$table->add(array('colspan' => '2'), rcmail::Q($this->gettext('bayesnonspamexp')));
708				}
709
710				if (!isset($no_override['bayes_auto_learn_threshold_spam'])) {
711					$field_id = 'rcmfd_bayesspam';
712					$input_bayesthres = new html_select(array('name' => '_bayesspam', 'id' => $field_id, 'disabled' => (!$this->user_prefs['bayes_auto_learn'] || !$this->user_prefs['use_bayes'])?1:0));
713					$input_bayesthres->add($this->gettext('defaultscore'), '');
714
715					$decPlaces = 0;
716					if ($rcmail->config->get('sauserprefs_score_inc') - (int)$rcmail->config->get('sauserprefs_score_inc') > 0)
717						$decPlaces = strlen($rcmail->config->get('sauserprefs_score_inc') - (int)$rcmail->config->get('sauserprefs_score_inc')) - 2;
718
719					$score_found = false;
720					for ($i = 1; $i <= 20; $i = $i + $rcmail->config->get('sauserprefs_score_inc')) {
721						$input_bayesthres->add(number_format($i, $decPlaces, $locale_info['decimal_point'], ''), number_format($i, $decPlaces, '.', ''));
722
723						if (!$score_found && $this->user_prefs['bayes_auto_learn_threshold_spam'] && (float)$this->user_prefs['bayes_auto_learn_threshold_spam'] == (float)$i)
724							$score_found = true;
725					}
726
727					if (!$score_found && $this->user_prefs['required_hits'])
728						$input_bayesthres->add(str_replace('%s', $this->user_prefs['bayes_auto_learn_threshold_spam'], $this->gettext('otherscore')), (float)$this->user_prefs['bayes_auto_learn_threshold_spam']);
729
730					$table->add('title', html::label($field_id, rcmail::Q($this->gettext('bayesspam'))));
731					$table->add(null, $input_bayesthres->show(number_format($this->user_prefs['bayes_auto_learn_threshold_spam'], $decPlaces, '.', '')));
732					$table->add(array('colspan' => '2'), rcmail::Q($this->gettext('bayesspamexp')));
733				}
734
735				if ($table->size() > 0)
736					$out .= html::tag('fieldset', null, html::tag('legend', null, rcmail::Q($this->gettext('bayesautooptions'))) . $table->show());
737
738				break;
739
740			// Report settings
741			case 'report':
742				$data = html::p(null, rcmail::Q($this->gettext('spamreport')));
743
744				$table = new html_table(array('class' => 'reportprefstable', 'cols' => 2));
745
746				if (!isset($no_override['report_safe'])) {
747					$field_id = 'rcmfd_spamreport';
748					$input_spamreport0 = new html_radiobutton(array('name' => '_spamreport', 'id' => $field_id.'_0', 'value' => '0'));
749					$table->add('title', html::label($field_id.'_0', rcmail::Q($this->gettext('spamreport0'))));
750					$table->add(null, $input_spamreport0->show($this->user_prefs['report_safe']));
751
752					$input_spamreport1 = new html_radiobutton(array('name' => '_spamreport', 'id' => $field_id.'_1', 'value' => '1'));
753					$table->add('title', html::label($field_id.'_1', rcmail::Q($this->gettext('spamreport1'))));
754					$table->add(null, $input_spamreport1->show($this->user_prefs['report_safe']));
755					$data .= $input_spamreport1->show($this->user_prefs['report_safe']) ."&nbsp;". html::label($field_id .'_1', rcmail::Q($this->gettext('spamreport1'))) . "<br />";
756
757					$input_spamreport2 = new html_radiobutton(array('name' => '_spamreport', 'id' => $field_id.'_2', 'value' => '2'));
758					$table->add('title', html::label($field_id.'_2', rcmail::Q($this->gettext('spamreport2'))));
759					$table->add(null, $input_spamreport2->show($this->user_prefs['report_safe']));
760				}
761
762				$out = html::tag('fieldset', null, html::tag('legend', null, rcmail::Q($this->gettext('mainoptions'))) . $table->show());
763				break;
764
765			// Address settings
766			case 'addresses':
767				$data = html::p(null, rcmail::Q($this->gettext('whitelistexp')));
768
769				if ($rcmail->config->get('sauserprefs_whitelist_sync'))
770					$data .= rcmail::Q($this->gettext('autowhitelist')) . "<br /><br />";
771
772				$table = new html_table(array('class' => 'addressprefstable', 'cols' => 4));
773
774				$field_id = 'rcmfd_spamaddressrule';
775				$input_spamaddressrule = new html_select(array('name' => '_spamaddressrule', 'id' => $field_id));
776				$input_spamaddressrule->add($this->gettext('whitelist_from'),'whitelist_from');
777				$input_spamaddressrule->add($this->gettext('blacklist_from'), 'blacklist_from');
778				$input_spamaddressrule->add($this->gettext('whitelist_to'), 'whitelist_to');
779
780				$field_id = 'rcmfd_spamaddress';
781				$input_spamaddress = new html_inputfield(array('name' => '_spamaddress', 'id' => $field_id, 'style' => 'width:200px;'));
782
783				$field_id = 'rcmbtn_add_address';
784				$button_addaddress = $this->api->output->button(array('command' => 'plugin.sauserprefs.addressrule_add', 'type' => 'input', 'class' => 'button', 'label' => 'sauserprefs.addrule'));
785
786				$table->add('ruletype', $input_spamaddressrule->show());
787				$table->add('address', $input_spamaddress->show());
788				$table->add('action', $button_addaddress);
789				$table->add(null, "&nbsp;");
790
791				$import = $this->api->output->button(array('command' => 'plugin.sauserprefs.import_whitelist', 'type' => 'link', 'label' => 'import', 'title' => 'sauserprefs.importfromaddressbook'));
792				$delete_all = $this->api->output->button(array('command' => 'plugin.sauserprefs.whitelist_delete_all', 'type' => 'link', 'label' => 'sauserprefs.deleteall'));
793
794				$table->add(array('colspan' => 4, 'id' => 'listcontrols'), $import ."&nbsp;&nbsp;". $delete_all);
795
796				$address_table = new html_table(array('id' => 'address-rules-table', 'class' => 'records-table', 'cellspacing' => '0', 'cols' => 3));
797				$address_table->add_header('rule', $this->gettext('rule'));
798				$address_table->add_header('email', $this->gettext('email'));
799				$address_table->add_header('control', '&nbsp;');
800
801				$this->_address_row($address_table, null, null, $attrib);
802
803				if (sizeof($this->user_prefs['addresses']) > 0)
804					$norules = 'display: none;';
805
806				$address_table->set_row_attribs(array('style' => $norules));
807				$address_table->add(array('colspan' => '3'), rcube_utils::rep_specialchars_output($this->gettext('noaddressrules')));
808
809				$this->api->output->set_env('address_rule_count', sizeof($this->user_prefs['addresses']));
810				foreach ($this->user_prefs['addresses'] as $address)
811					$this->_address_row($address_table, $address['field'], $address['value'], $attrib);
812
813				$table->add(array('colspan' => 4, 'class' => 'scroller'), html::div(array('id' => 'address-rules-cont'), $address_table->show()));
814
815				if ($table->size())
816					$out = html::tag('fieldset', null, html::tag('legend', null, rcmail::Q($this->gettext('mainoptions'))) . $data . $table->show());
817
818				break;
819
820			default:
821				$out = '';
822		}
823
824		return $out;
825	}
826
827	private function _address_row($address_table, $field, $value, $attrib)
828	{
829		if (!isset($field))
830			$address_table->set_row_attribs(array('style' => 'display: none;'));
831
832		$hidden_action = new html_hiddenfield(array('name' => '_address_rule_act[]', 'value' => ''));
833		$hidden_field = new html_hiddenfield(array('name' => '_address_rule_field[]', 'value' => $field));
834		$hidden_text = new html_hiddenfield(array('name' => '_address_rule_value[]', 'value' => $value));
835
836		switch ($field)
837		{
838			case "whitelist_from":
839				$fieldtxt = rcube_utils::rep_specialchars_output($this->gettext('whitelist_from'));
840				break;
841			case "blacklist_from":
842				$fieldtxt = rcube_utils::rep_specialchars_output($this->gettext('blacklist_from'));
843				break;
844			case "whitelist_to":
845				$fieldtxt = rcube_utils::rep_specialchars_output($this->gettext('whitelist_to'));
846				break;
847		}
848
849		$address_table->add(array('class' => $field), $fieldtxt);
850		$address_table->add(array('class' => 'email'), $value);
851		$del_button = $this->api->output->button(array('command' => 'plugin.sauserprefs.addressrule_del', 'type' => 'link', 'class' => 'delete', 'label' => 'delete', 'content' => ' '));
852		$address_table->add('control', $del_button . $hidden_action->show() . $hidden_field->show() . $hidden_text->show());
853
854		return $address_table;
855	}
856
857	static function map_pref_name($pref, $reverse = false)
858	{
859		if (!$reverse) {
860			if (array_key_exists($pref, self::$deprecated_prefs))
861				$pref = self::$deprecated_prefs[$pref];
862		}
863		else {
864			if (($orig_pref = array_search($pref, self::$deprecated_prefs)) != FALSE)
865				$pref = $orig_pref;
866		}
867
868		return $pref;
869	}
870
871	private function _subval_sort($a, $subkey)
872	{
873		if (sizeof($a) == 0)
874			return array();
875
876		foreach ($a as $k => $v)
877			$b[$k] = strtolower($v[$subkey]);
878
879		asort($b);
880
881		foreach ($b as $k => $v)
882			$c[] = $a[$k];
883
884		return $c;
885	}
886
887	private function _gen_email_arr($contact)
888	{
889		$emails = array();
890
891		if (!is_array($contact))
892			return $emails;
893
894		foreach ($contact as $key => $value) {
895			if (preg_match('/^email(:(.+))?$/i', $key, $matches)) {
896				foreach ((array)$value as $subkey => $subval) {
897					if ($matches[2])
898						$emails[$matches[2] . $subkey] = $subval;
899					else
900						$emails['email' . $subkey] = $subval;
901				}
902			}
903		}
904
905		return $emails;
906	}
907}
908
909?>