diff -Naur --exclude='*.svn*' roundcube_svn/plugins/sauserprefs/config.inc.php roundcube_pub/plugins/sauserprefs/config.inc.php
--- roundcube_svn/plugins/sauserprefs/config.inc.php	1970-01-01 01:00:00.000000000 +0100
+++ roundcube_pub/plugins/sauserprefs/config.inc.php	2009-01-08 18:49:26.000000000 +0000
@@ -0,0 +1,147 @@
+<?php
+
+/*
+ +-----------------------------------------------------------------------+
+ | SAUserPrefs configuration file                                        |
+ |                                                                       |
+ | This file is part of the RoundCube Webmail client                     |
+ | Copyright (C) 2005-2008, RoundCube Dev. - Switzerland                 |
+ | Licensed under the GNU GPL                                            |
+ |                                                                       |
+ +-----------------------------------------------------------------------+
+
+*/
+
+$sauserprefs_config = array();
+
+// spamassassin database settings
+$sauserprefs_config['db_dsnw'] = 'mysql://username:password@localhost/database';
+
+// PEAR database DSN for read only operations (if empty write database will be used)
+// useful for database replication
+$sauserprefs_config['db_dsnr'] = '';
+
+// use persistent db-connections
+// beware this will not "always" work as expected
+// see: http://www.php.net/manual/en/features.persistent-connections.php
+$sauserprefs_config['db_persistent'] = FALSE;
+
+// table that holds user prefs
+$sauserprefs_config['sql_table_name'] = "userpref";
+
+// name of the username field in the user prefs table
+$sauserprefs_config['sql_username_field'] = "username";
+
+// name of the preference field in the user prefs table, holds the name of the preference
+$sauserprefs_config['sql_preference_field'] = "preference";
+
+// name of the value field in the user prefs table, holds the value of the preference
+$sauserprefs_config['sql_value_field'] = "value";
+
+// enable the whitelists synchronisation
+// NOTE: To use this your SpamAssassin prefs table must include a field in which the contact_id from the RC address book can be stored
+// check README for more information
+$sauserprefs_config['whitelist_sync'] = FALSE;
+
+// name of the contact id field in the user prefs table
+// if you are not using whitelist_sync you can ignore this option
+$sauserprefs_config['sql_contactid_field'] = "contact_id";
+
+// define which of the general options to show
+// the order/appearance of the fieldsets is controlled in the template
+$sauserprefs_config['general_settings'] = array(
+									"score" => TRUE,
+									"subject" => TRUE,
+									"language" => TRUE
+								);
+
+// default settings
+// these are overridden by $GLOBAL and user settings from the database
+$sauserprefs_config['default_prefs'] = array(
+									"required_hits" => "5",
+									"rewrite_subject" => "0",
+									"rewrite_header Subject" => "*****SPAM*****",
+									"ok_languages" => "all",
+									"ok_locales" => "all",
+									"fold_headers" => "1",
+									"add_header all Level" => "_STARS(*)_",
+									"use_razor1" => "0",
+									"use_razor2" => "1",
+									"use_pyzor" => "1",
+									"use_dcc" => "1",
+									"use_bayes" => "1",
+									"skip_rbl_checks" => "0",
+									"report_safe" => "1"
+								);
+
+// spam score increment - increment values in the the score threshold drop down by this, from 0 to 10
+$sauserprefs_config['score_inc'] = 1;
+
+// define languages
+$sauserprefs_config['languages'] = array(
+									"af" => "Afrikaans",
+									"sq" => "Albanian",
+									"am" => "Amharic",
+									"ar" => "Arabic",
+									"hy" => "Armenian",
+									"eu" => "Basque",
+									"bs" => "Bosnian",
+									"bg" => "Bulgarian",
+									"be" => "Byelorussian",
+									"ca" => "Catalan",
+									"zh" => "Chinese",
+									"hr" => "Croatian",
+									"cs" => "Czech",
+									"da" => "Danish",
+									"nl" => "Dutch",
+									"en" => "English",
+									"eo" => "Esperanto",
+									"et" => "Estonian",
+									"fi" => "Finnish",
+									"fr" => "French",
+									"fy" => "Frisian",
+									"ka" => "Georgian",
+									"de" => "German",
+									"el" => "Greek",
+									"he" => "Hebrew",
+									"hi" => "Hindi",
+									"hu" => "Hungarian",
+									"is" => "Icelandic",
+									"id" => "Indonesian",
+									"ga" => "Irish Gaelic",
+									"it" => "Italian",
+									"ja" => "Japanese",
+									"ko" => "Korean",
+									"la" => "Latin",
+									"lv" => "Latvian",
+									"lt" => "Lithuanian",
+									"ms" => "Malay",
+									"mr" => "Marathi",
+									"ne" => "Nepali",
+									"no" => "Norwegian",
+									"fa" => "Persian",
+									"pl" => "Polish",
+									"pt" => "Portuguese",
+									"qu" => "Quechua",
+									"rm" => "Rhaeto-Romance",
+									"ro" => "Romanian",
+									"ru" => "Russian",
+									"sa" => "Sanskrit",
+									"sco" => "Scots",
+									"gd" => "Scottish Gaelic",
+									"sr" => "Serbian",
+									"sk" => "Slovak",
+									"sl" => "Slovenian",
+									"es" => "Spanish",
+									"sw" => "Swahili",
+									"sv" => "Swedish",
+									"tl" => "Tagalog",
+									"ta" => "Tamil",
+									"th" => "Thai",
+									"tr" => "Turkish",
+									"uk" => "Ukrainian",
+									"vi" => "Vietnamese",
+									"cy" => "Welsh",
+									"yi" => "Yiddish"
+								);
+?>
\ No newline at end of file
diff -Naur --exclude='*.svn*' roundcube_svn/plugins/sauserprefs/disabled.png roundcube_pub/plugins/sauserprefs/disabled.png
--- roundcube_svn/plugins/sauserprefs/disabled.png	1970-01-01 01:00:00.000000000 +0100
+++ roundcube_pub/plugins/sauserprefs/disabled.png	2009-01-08 18:49:26.000000000 +0000
@@ -0,0 +1,5 @@
+‰PNG
+
+
IHDRóÿa	pHYsšœgAMA±Ž|ûQ“ cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅF‰IDATxÚbøÿÿ?% €(5 €àŒéFFSttú´´ø{ôôæÛÚ®[áævu‰£ã‘~ƒ†MMý	šš}
+
+(ŠµµuÙÚ=ùÿdXØÿ@ú\DÄÿÑÑÿ×{{¿ž¨£“Õ#'‡b@Á“õô$—ÛÙ]8ø‡£ã�íNNU{ÜÝƒç™›§î°µ½û	hÈ!?¿¿½ªªáÈœ1UO¯îˆ·÷ÿ]ÖÖW¶9;k­¶·ghPWgè×ÔLzåêúþ¿»ûÿÇAAÿYZ^A6 €àŒÕ¶¶7Ž¹¸üßëîž°ÉÅ…¡\I‰¡CY9û½“Ó¯ÿnnÿ·››oÞcgwc�ýæÖ­ÿ0}7`›�Ý—³®®Ï×xzò•ÉË3tÊËg²²úõßÑñÿ2
�¥…jj<kLM»¶-¹±u+Ü€‚°hÀE—ÚÚb•‚‚©755½ÖÑù?CNnv€�ïT

†…jj“7:9¡@p6Z[_;`fög®¬ìÆJJî©ªþï_ìÅÃÃ×®¦Æ°@]]d�’ÒÝåVV(^ ¸ÓTUó7[[ÿ¿¥­ýÿŽ²òÿi’’“Ò……údd–jkóÎ–—Ÿ»ÑÌìÿtmíÈ�@pFœ¨¨Ð-­ýW]]ÿïÓÕýÝ/%5y¡’RübEÅÂE**ûwZZþß`fö©JFÆÙ€‚3˜”ÙÙ*×¯³·ÿ¿ÃÁáÿ6 s·ÚÚþFëÿ÷ùù#x™™Q@!<@,ÊÅÄ¤©ÉÅUè#)¹8_Sódœ’Ò6c>¾Ni66W ¼8!@g&€¢Ø€ƒÆAPì€gIEND®B`‚
\ No newline at end of file
diff -Naur --exclude='*.svn*' roundcube_svn/plugins/sauserprefs/enabled.png roundcube_pub/plugins/sauserprefs/enabled.png
--- roundcube_svn/plugins/sauserprefs/enabled.png	1970-01-01 01:00:00.000000000 +0100
+++ roundcube_pub/plugins/sauserprefs/enabled.png	2009-01-08 18:49:26.000000000 +0000
@@ -0,0 +1,5 @@
+‰PNG
+
+
IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<«IDAT8Ë½“Ù.Ca…{ç8ïbnÕSBª†T'êè)E)�ª§­V«CJÇ¥jŽÄ” —ZÕ†g/¡ºü•hÂ…ÿÝ¿ÖÞûÛkþòÿn ^kâ[–ê�¿2P­6ò¦c=úXHø*îGÊ`?xÔ…Ù{7¼7Vè¶Ô¨ðÙ¾%V¬Hyã¡Óq¦âNtn·¢Ò[Œ‡�J2^²5†3¦ç³X¾,åS-OÆœÄo•ËÝâDñX•ÁxÁ–õž2OÜµ	ì®rè]L`ñ}ûZîÆà¿³ƒÝT¡ÌU˜(²çSiˆýçÚÚÞPû£/Ìa:6Í–,A`
É%S†=¾¨Þ[
+”Ž‹b[õa�='šLýaÌW˜{ðÀ¶Âx¤ƒéD�‰°î[˜u9JœÂ—BëGqzfGN“Ê0…ôosú£6¸"f¸ÂfhÖZR°’".—ú2H-[� {·îÈ(7ÃhÊ@`%E–ê[I”ÌWÓu3•¤eÔ+Í °’ÂÑlêGQ&û¥Ë'Ä °žÌÙ¿º‹ÎÉÊø—k|¾¢©<R
+HIEND®B`‚
\ No newline at end of file
diff -Naur --exclude='*.svn*' roundcube_svn/plugins/sauserprefs/sauserprefs.php roundcube_pub/plugins/sauserprefs/sauserprefs.php
--- roundcube_svn/plugins/sauserprefs/sauserprefs.php	1970-01-01 01:00:00.000000000 +0100
+++ roundcube_pub/plugins/sauserprefs/sauserprefs.php	2009-01-08 18:49:26.000000000 +0000
@@ -0,0 +1,36 @@
+<?php
+
+/*
+ +-----------------------------------------------------------------------+
+ | plugins/sauserprefs/sauserprefs.php  								 |
+ |																		 |
+ | This file is part of the RoundCube Webmail client					 |
+ | Copyright (C) 2008, RoundCube Dev. - Switzerland 					 |
+ | Licensed under the GNU GPL											 |
+ |																		 |
+ | PURPOSE: 															 |
+ |	 Provide functionality for user's spamassassin settings modification |
+ |   in an SQL database 												 |
+ |																		 |
+ | CREDITS:                                                              |
+ |   Inspiration for this patch was taken from:                          |
+ |   WebUserPrefs <http://sourceforge.net/projects/webuserprefs/>        |
+ |																		 |
+ +-----------------------------------------------------------------------+
+ | Author: Philip Weir													 |
+ +-----------------------------------------------------------------------+
+
+ $Id: $
+
+*/
+
+class sauserprefs extends rcube_plugin
+{
+	function init()
+	{
+		// preperation for Plugin API
+		// not used yet
+	}
+}
+
+?>
\ No newline at end of file
diff -Naur --exclude='*.svn*' roundcube_svn/plugins/sauserprefs/sauserprefs_sync_whitelist.inc roundcube_pub/plugins/sauserprefs/sauserprefs_sync_whitelist.inc
--- roundcube_svn/plugins/sauserprefs/sauserprefs_sync_whitelist.inc	1970-01-01 01:00:00.000000000 +0100
+++ roundcube_pub/plugins/sauserprefs/sauserprefs_sync_whitelist.inc	2009-01-08 18:49:26.000000000 +0000
@@ -0,0 +1,55 @@
+<?php
+
+/*
+ +-----------------------------------------------------------------------+
+ | plugins/sauserprefs/sauserprefs_sync_whitelist.inc                    |
+ |                                                                       |
+ | This file is part of the RoundCube Webmail client                     |
+ | Copyright (C) 2008, RoundCube Dev. - Switzerland                      |
+ | Licensed under the GNU GPL                                            |
+ |                                                                       |
+ | PURPOSE:                                                              |
+ |   Synchronise address book and whitelist addresses in SpamAssassin    |
+ |                                                                       |
+ +-----------------------------------------------------------------------+
+ | Author: Philip Weir                                                   |
+ +-----------------------------------------------------------------------+
+ | Requires: plugins/sauserprefs/config.inc.php                          |
+ +-----------------------------------------------------------------------+
+
+ $Id: $
+
+*/
+
+require_once('plugins/sauserprefs/config.inc.php');
+
+function sauserprefs_sync_whitelist($a_record, $cid, $action) {
+	global $RCMAIL, $sauserprefs_config;
+	
+	if ($sauserprefs_config['whitelist_sync']) {
+		$user_db = new rcube_mdb2($sauserprefs_config['db_dsnw'], $sauserprefs_config['db_dsnr'], $sauserprefs_config['db_persistent']);
+		$user_db->db_connect('w');
+			
+		// get new email address
+		if ($cid > 0 && !is_array($a_record)) {
+			$contacts = new rcube_contacts($RCMAIL->db, $RCMAIL->user->ID);
+			$a_record = $contacts->get_record($cid);
+			unset($contacts);
+		}
+		$email = $a_record['email'];
+		
+		switch ($action) {
+			case 'insert':
+				$user_db->query("INSERT INTO ". $sauserprefs_config['sql_table_name'] ." (". $sauserprefs_config['sql_username_field'] .", ". $sauserprefs_config['sql_preference_field'] .", ". $sauserprefs_config['sql_value_field'] .", ". $sauserprefs_config['sql_contactid_field'] .") VALUES ('". $_SESSION['username'] ."', 'whitelist_from', '". $email ."', ". $cid .");");
+				break;
+			case 'update':
+				$user_db->query("UPDATE ". $sauserprefs_config['sql_table_name'] ." SET ". $sauserprefs_config['sql_value_field'] ." = '". $email ."' WHERE ". $sauserprefs_config['sql_username_field'] ." = '". $_SESSION['username'] ."' AND ". $sauserprefs_config['sql_preference_field'] ." = 'whitelist_from' AND ". $sauserprefs_config['sql_contactid_field'] ." = ". $cid .";");
+				break;
+			case 'delete':
+				$user_db->query("DELETE FROM ". $sauserprefs_config['sql_table_name'] ." WHERE ". $sauserprefs_config['sql_username_field'] ." = '". $_SESSION['username'] ."' AND ". $sauserprefs_config['sql_preference_field'] ." = 'whitelist_from' AND ". $sauserprefs_config['sql_contactid_field'] ." = ". $cid .";");
+				break;
+		}
+	}
+}
+
+?>
\ No newline at end of file
diff -Naur --exclude='*.svn*' roundcube_svn/program/js/app.js roundcube_pub/program/js/app.js
--- roundcube_svn/program/js/app.js	2009-01-08 18:47:54.000000000 +0000
+++ roundcube_pub/program/js/app.js	2009-01-08 18:49:26.000000000 +0000
@@ -288,7 +288,8 @@
 
       case 'settings':
         this.enable_command('preferences', 'identities', 'save', 'folders', true);
-        
+        this.enable_command('sauserprefs', true);
+
         if (this.env.action=='identities' || this.env.action=='edit-identity' || this.env.action=='add-identity') {
           this.enable_command('add', this.env.identities_level < 2);
           this.enable_command('delete', 'edit', true);
@@ -300,6 +301,9 @@
         if (this.env.action=='folders')
           this.enable_command('subscribe', 'unsubscribe', 'create-folder', 'rename-folder', 'delete-folder', true);
 
+        if (this.env.action=='sauserprefs')
+          this.enable_command('save-sauserprefs', true);
+
         if (this.gui_objects.identitieslist)
           {
           this.identity_list = new rcube_list_widget(this.gui_objects.identitieslist, {multiselect:false, draggable:false, keyboard:false});
@@ -1035,6 +1039,14 @@
         this.goto_url('identities');
         break;
           
+      case 'sauserprefs':
+        this.goto_url('sauserprefs');
+        break;
+
+      case 'save-sauserprefs':
+        this.gui_objects.editform.submit();
+        break;
+
       case 'delete-identity':
         this.delete_identity();
         
diff -Naur --exclude='*.svn*' roundcube_svn/program/js/sauserprefs.js roundcube_pub/program/js/sauserprefs.js
--- roundcube_svn/program/js/sauserprefs.js	1970-01-01 01:00:00.000000000 +0100
+++ roundcube_pub/program/js/sauserprefs.js	2009-01-08 18:49:26.000000000 +0000
@@ -0,0 +1,147 @@
+/*
+ +-----------------------------------------------------------------------+
+ | RoundCube Webmail Client Script										 |
+ |																		 |
+ | This file is part of the RoundCube Webmail client					 |
+ | Copyright (C) 2008, RoundCube Dev, - Switzerland 					 |
+ | Licensed under the GNU GPL											 |
+ |																		 |
+ +-----------------------------------------------------------------------+
+ | Author: Philip Weir													 |
+ +-----------------------------------------------------------------------+
+
+ $Id: $
+
+*/
+
+function select_all_langs() {
+	var langlist = document.getElementsByName('_spamlang[]');
+	var obj;
+
+	for (var i = 0; i < langlist.length; i++) {
+		langlist[i].checked = true;
+		obj = rcube_find_object('spam_lang_'+ i)
+		obj.title = rcmail.get_label('enabled');
+		obj.innerHTML = rcube_find_object('enable_button').innerHTML;
+	}
+
+	return false;
+}
+
+function select_no_langs() {
+	var langlist = document.getElementsByName('_spamlang[]');
+	var obj;
+
+	for (var i = 0; i < langlist.length; i++) {
+		langlist[i].checked = false;
+		obj = rcube_find_object('spam_lang_'+ i)
+		obj.title = rcmail.get_label('disabled');
+		obj.innerHTML = rcube_find_object('disable_button').innerHTML;
+	}
+
+	return false;
+}
+
+function message_lang(lang_code, obj) {
+	var langlist = document.getElementsByName('_spamlang[]');
+	var i = obj.parentNode.parentNode.rowIndex - 2;
+
+	if (langlist[i].checked) {
+		langlist[i].checked = false;
+		obj.title = rcmail.get_label('disabled');
+		obj.innerHTML = rcube_find_object('disable_button').innerHTML;
+	}
+	else {
+		langlist[i].checked = true;
+		obj.title = rcmail.get_label('enabled');
+		obj.innerHTML = rcube_find_object('enable_button').innerHTML;
+	}
+
+	return false;
+}
+
+function addressrule_del(obj) {
+	var adrTable = rcube_find_object('address-rules-table').tBodies[0];
+	var rowidx = obj.parentNode.parentNode.rowIndex - 1;
+	var fieldidx = rowidx - 1;
+
+	if (!confirm(rcmail.get_label('spamaddressdelete')))
+		return false;
+
+	if (document.getElementsByName('_address_rule_act[]')[fieldidx].value == "INSERT") {
+		adrTable.deleteRow(rowidx);
+	}
+	else {
+		adrTable.rows[rowidx].style.display = 'none';
+		document.getElementsByName('_address_rule_act[]')[fieldidx].value = "DELETE";
+	}
+
+	rcmail.env.address_rule_count--;
+	if (rcmail.env.address_rule_count < 1)
+		adrTable.rows[1].style.display = '';
+
+	return false;
+}
+
+function addressrule_add() {
+	var adrTable = rcube_find_object('address-rules-table').tBodies[0];
+	var input_spamaddressrule = rcube_find_object('_spamaddressrule');
+	var selrule = input_spamaddressrule.selectedIndex;
+	var input_spamaddress = rcube_find_object('_spamaddress');
+
+	if (input_spamaddress.value.replace(/^\s+|\s+$/g, '') == '') {
+		alert(rcmail.get_label('spamenteraddress'));
+		input_spamaddress.focus();
+		return false;
+	}
+	else if (!rcube_check_email(input_spamaddress.value.replace(/^\s+/, '').replace(/[\s,;]+$/, ''), true)) {
+		alert(rcmail.get_label('spamaddresserror'));
+		input_spamaddress.focus();
+		return false;
+	}
+	else {
+		var actions = document.getElementsByName('_address_rule_act[]');
+		var prefs = document.getElementsByName('_address_rule_field[]');
+		var addresses = document.getElementsByName('_address_rule_value[]');
+		var insHere;
+
+		for (var i = 1; i < addresses.length; i++){
+			if (addresses[i].value == input_spamaddress.value && actions[i].value != "DELETE") {
+				alert(rcmail.get_label('spamaddressexists'));
+				input_spamaddress.focus();
+				return false;
+			}
+			else if (addresses[i].value > input_spamaddress.value) {
+				insHere = adrTable.rows[i + 1];
+				break;
+			}
+		}
+
+		var newNode = adrTable.rows[0].cloneNode(true);
+		adrTable.rows[1].style.display = 'none';
+
+		if (insHere)
+			adrTable.insertBefore(newNode, insHere);
+		else
+			adrTable.appendChild(newNode);
+
+		newNode.style.display = "";
+		newNode.cells[0].className = input_spamaddressrule.options[selrule].value;
+		newNode.cells[0].innerHTML = input_spamaddressrule.options[selrule].text;
+		newNode.cells[1].innerHTML = input_spamaddress.value;
+		actions[newNode.rowIndex - 2].value = "INSERT";
+		prefs[newNode.rowIndex - 2].value = input_spamaddressrule.options[selrule].value;
+		addresses[newNode.rowIndex - 2].value = input_spamaddress.value;
+
+		input_spamaddressrule.selectedIndex = 0;
+		input_spamaddress.value = '';
+
+		rcmail.env.address_rule_count++;
+	}
+}
+
+function toggle_level_char(checkbox) {
+	var level_char;
+	if (level_char = rcube_find_object('rcmfd_spamlevelchar'))
+		level_char.disabled = !checkbox.checked;
+}
\ No newline at end of file
diff -Naur --exclude='*.svn*' roundcube_svn/program/localization/en_US/labels.inc roundcube_pub/program/localization/en_US/labels.inc
--- roundcube_svn/program/localization/en_US/labels.inc	2008-12-06 20:07:12.000000000 +0000
+++ roundcube_pub/program/localization/en_US/labels.inc	2009-01-08 18:49:26.000000000 +0000
@@ -323,4 +323,35 @@
 $labels['MB'] = 'MB';
 $labels['GB'] = 'GB';
 
+$labels['sauserprefs']  = 'Spam';
+$labels['sauserprefssettings']  = 'Spam settings';
+$labels['spamgeneralsettings']  = 'General Settings';
+$labels['spamthres']  = 'Score threshold';
+$labels['spamsubject']  = 'Subject tag';
+$labels['spamsubjectblank']  = '(leave blank for none)';
+$labels['spamlang']  = 'Message languages';
+$labels['enabled']  = 'Enabled';
+$labels['disabled']  = 'Disabled';
+$labels['headers'] = "Message Headers";
+$labels['foldheaders'] = "Allow multiple lines in headers";
+$labels['spamlevelstars'] = "Use 'Spam Level' header";
+$labels['spamlevelchar'] = "Spam level character";
+$labels['spamtests'] = "Internet Based Spam Tests";
+$labels['userazor1'] = "Use Razor v1";
+$labels['userazor2'] = "Use Razor v2";
+$labels['usepyzor'] = "Use Pyzor";
+$labels['usebayes'] = "Use naive Bayesian style classifier";
+$labels['usedcc'] = "Use DCC";
+$labels['skiprblchecks'] = "Use Realtime Blackhole List";
+$labels['spamreportsettings']  = 'Report Settings';
+$labels['spamreport0']  = 'Include report in headers of original message';
+$labels['spamreport1']  = 'Include original as MIME attachment to report';
+$labels['spamreport2']  = 'Include original as text-only attachment to report';
+$labels['spamaddressrules']  = 'Address Rules';
+$labels['whitelist_from']  = 'Accept Mail From';
+$labels['blacklist_from']  = 'Reject Mail From';
+$labels['whitelist_to']  = 'Accept Mail Sent To';
+$labels['addrule']  = 'Add Rule';
+$labels['rule']  = 'Rule';
+
 ?>
diff -Naur --exclude='*.svn*' roundcube_svn/program/localization/en_US/messages.inc roundcube_pub/program/localization/en_US/messages.inc
--- roundcube_svn/program/localization/en_US/messages.inc	2008-11-03 18:39:42.000000000 +0000
+++ roundcube_pub/program/localization/en_US/messages.inc	2009-01-08 18:49:26.000000000 +0000
@@ -95,4 +95,19 @@
 $messages['nofromaddress'] = 'Missing e-mail address in selected identity';
 $messages['editorwarning'] = 'Switching to the plain text editor will cause all text formatting to be lost. Do you wish to continue?';
 
+$messages['sauserprefchanged'] = 'Successfully changed spam settings';
+$messages['sauserpreffailed'] = 'Error: Cannot change spam settings';
+$messages['spamthresexp'] = 'Anything above the threshold is marked as spam. Increasing this threshold will increase the amount of spam missed, but will reduce the risk of false positives.';
+$messages['spamlangexp'] = 'Select all the languages you expect to receive e-mail in. Any messages received that are written in non selected languages will be treated as possible spam.';
+$messages['headersexp'] = "SpamAssassin adds headers to processed messages providing information about the results. Use the options below to configure these headers.";
+$messages['spamtestssexp'] = "Some checks use internet based services to help identify spam. Select the ones you wish to use:";
+$messages['spamreport']  = 'When a message is identified as spam a report of all tests and scores assigned is created...';
+$messages['autowhitelist'] = 'Email addresses in your Address Book are automatically added to the \'Accept Mail From\' list.';
+$messages['whitelistexp'] = 'An asterisk (*) can be used as a wild card for greater flexibility. For example: *@example.com or *@*.example.com.';
+$messages['spamaddressexists'] = 'A rule already exists for this address';
+$messages['spamenteraddress'] = 'Please enter an address to add';
+$messages['spamaddresserror'] = 'Error: Address appears invalid';
+$messages['spamaddressdelete'] = 'Are you sure you want to delete this rule?';
+$messages['noaddressrules'] = 'No address rules found.';
+
 ?>
diff -Naur --exclude='*.svn*' roundcube_svn/program/steps/addressbook/delete.inc roundcube_pub/program/steps/addressbook/delete.inc
--- roundcube_svn/program/steps/addressbook/delete.inc	2008-05-10 10:37:24.000000000 +0100
+++ roundcube_pub/program/steps/addressbook/delete.inc	2009-01-08 18:49:26.000000000 +0000
@@ -19,6 +19,8 @@
 
 */
 
+require_once('plugins/sauserprefs/sauserprefs_sync_whitelist.inc');
+
 if (($cid = get_input_value('_cid', RCUBE_INPUT_POST)) &&
     (preg_match('/^[0-9]+(,[0-9]+)*$/', $cid) ||
      preg_match('/^[a-zA-Z0-9=]+(,[a-zA-Z0-9=]+)*$/', $cid))
@@ -31,6 +33,8 @@
     exit;
     }
 
+  sauserprefs_sync_whitelist('', $cid, 'delete');
+
   // count contacts for this user
   $result = $CONTACTS->count();
 
diff -Naur --exclude='*.svn*' roundcube_svn/program/steps/addressbook/import.inc roundcube_pub/program/steps/addressbook/import.inc
--- roundcube_svn/program/steps/addressbook/import.inc	2008-10-22 19:29:29.000000000 +0100
+++ roundcube_pub/program/steps/addressbook/import.inc	2009-01-08 18:49:26.000000000 +0000
@@ -19,6 +19,8 @@
 
 */
 
+require_once('plugins/sauserprefs/sauserprefs_sync_whitelist.inc');
+
 /**
  * Handler function to display the import/upload form
  */
@@ -151,6 +153,14 @@
       ));
       
       if ($success) {
+        sauserprefs_sync_whitelist(array(
+          'name' => $vcard->displayname,
+          'firstname' => $vcard->firstname,
+          'surname' => $vcard->surname,
+          'email' => $email,
+          'vcard' => $vcard->export(),
+        ), $success, 'insert');
+
         $IMPORT_STATS->inserted++;
         $IMPORT_STATS->names[] = $vcard->displayname;
       }
diff -Naur --exclude='*.svn*' roundcube_svn/program/steps/addressbook/save.inc roundcube_pub/program/steps/addressbook/save.inc
--- roundcube_svn/program/steps/addressbook/save.inc	2008-05-20 17:45:39.000000000 +0100
+++ roundcube_pub/program/steps/addressbook/save.inc	2009-01-08 18:49:26.000000000 +0000
@@ -19,6 +19,8 @@
 
 */
 
+require_once('plugins/sauserprefs/sauserprefs_sync_whitelist.inc');
+
 // cannot edit record
 if ($CONTACTS->readonly)
 {
@@ -54,6 +56,8 @@
 {
   if ($CONTACTS->update($cid, $a_record))
   {
+    sauserprefs_sync_whitelist($a_record, $cid, 'update');
+
     // define list of cols to be displayed
     $a_js_cols = array();
     $record = $CONTACTS->get_record($cid, true);
@@ -93,6 +97,8 @@
   // insert record and send response
   if ($insert_id = $CONTACTS->insert($a_record))
   {
+    sauserprefs_sync_whitelist($a_record, $insert_id, 'insert');
+
     // add contact row or jump to the page where it should appear
     $CONTACTS->reset();
     $result = $CONTACTS->search($CONTACTS->primary_key, $insert_id);
diff -Naur --exclude='*.svn*' roundcube_svn/program/steps/settings/sauserprefs.inc roundcube_pub/program/steps/settings/sauserprefs.inc
--- roundcube_svn/program/steps/settings/sauserprefs.inc	1970-01-01 01:00:00.000000000 +0100
+++ roundcube_pub/program/steps/settings/sauserprefs.inc	2009-01-08 18:49:26.000000000 +0000
@@ -0,0 +1,402 @@
+<?php
+
+/*
+ +-----------------------------------------------------------------------+
+ | plugins/sauserprefs/sauserprefs.inc                                   |
+ |                                                                       |
+ | This file is part of the RoundCube Webmail client                     |
+ | Copyright (C) 2008, RoundCube Dev. - Switzerland                      |
+ | Licensed under the GNU GPL                                            |
+ |                                                                       |
+ | PURPOSE:                                                              |
+ |	 Provide functionality for user spamassassin settings modification   |
+ |                                                                       |
+ +-----------------------------------------------------------------------+
+ | Author: Philip Weir                                                   |
+ +-----------------------------------------------------------------------+
+ | Requires: plugins/sauserprefs/config.inc.php                          |
+ +-----------------------------------------------------------------------+
+
+ $Id: $
+
+*/
+
+require_once('plugins/sauserprefs/config.inc.php');
+
+$OUTPUT->set_pagetitle(rcube_label('sauserprefssettings'));
+$OUTPUT->add_handler('usersauserprefs', 'rcmail_sauserprefs_form');
+$OUTPUT->include_script('sauserprefs.js');
+$OUTPUT->add_label('spamaddressexists', 'spamenteraddress', 'spamaddresserror',
+					'spamaddressdelete', 'enabled', 'disabled');
+$OUTPUT->send('sauserprefs');
+
+function rcmail_sauserprefs_form($attrib){
+	global $sauserprefs_config;
+
+	$blocks = $attrib['parts'] ? preg_split('/[\s,;]+/', strip_quotes($attrib['parts'])) : array('general','headers','tests','report','addresses');
+
+	$user_db = new rcube_mdb2($sauserprefs_config['db_dsnw'], $sauserprefs_config['db_dsnr'], $sauserprefs_config['db_persistent']);
+	$user_db->db_connect('r');
+
+	// check DB connections and exit on failure
+	if ($err_str = $user_db->is_error()) {
+	  raise_error(array(
+	    'code' => 603,
+	    'type' => 'db',
+	    'message' => $err_str), FALSE, TRUE);
+	}
+
+	// global settings
+	$global_prefs = array();
+
+	$sql_result = $user_db->query(
+	  "SELECT ". $sauserprefs_config['sql_preference_field'] .", ". $sauserprefs_config['sql_value_field'] ."
+	   FROM   ". $sauserprefs_config['sql_table_name'] ."
+	   WHERE  ". $sauserprefs_config['sql_username_field'] ." = '\$GLOBAL'
+	   AND    ". $sauserprefs_config['sql_preference_field'] ." <> 'whitelist_from'
+	   AND    ". $sauserprefs_config['sql_preference_field'] ." <> 'blacklist_from'
+	   AND    ". $sauserprefs_config['sql_preference_field'] ." <> 'whitelist_to';"
+   	  );
+
+	while ($sql_result && ($sql_arr = $user_db->fetch_assoc($sql_result)))
+	    $global_prefs[$sql_arr[$sauserprefs_config['sql_preference_field']]] = $sql_arr[$sauserprefs_config['sql_value_field']];
+
+	// user settings
+	$user_prefs = array();
+
+	$sql_result = $user_db->query(
+	  "SELECT ". $sauserprefs_config['sql_preference_field'] .", ". $sauserprefs_config['sql_value_field'] ."
+	   FROM   ". $sauserprefs_config['sql_table_name'] ."
+	   WHERE  ". $sauserprefs_config['sql_username_field'] ." = '". $_SESSION['username'] ."'
+	   AND    ". $sauserprefs_config['sql_preference_field'] ." <> 'whitelist_from'
+	   AND    ". $sauserprefs_config['sql_preference_field'] ." <> 'blacklist_from'
+	   AND    ". $sauserprefs_config['sql_preference_field'] ." <> 'whitelist_to';"
+	  );
+
+    while ($sql_result && ($sql_arr = $user_db->fetch_assoc($sql_result)))
+	    $user_prefs[$sql_arr[$sauserprefs_config['sql_preference_field']]] = $sql_arr[$sauserprefs_config['sql_value_field']];
+
+	$global_prefs = array_merge($sauserprefs_config['default_prefs'], $global_prefs);
+	$user_prefs = array_merge($global_prefs, $user_prefs);
+
+	list($form_start, $form_end) = get_form_tags($attrib, 'save-sauserprefs');
+	unset($attrib['form']);
+
+	$out = $form_start;
+
+	foreach ($blocks as $part) {
+		$out .= rcmail_sauserprefs_block($part, $global_prefs, $user_prefs, $attrib, $user_db);
+	}
+
+	return $out . $form_end;
+}
+
+function rcmail_sauserprefs_block($part, $global_prefs, $user_prefs, $attrib, $user_db) {
+	global $RCMAIL, $OUTPUT, $sauserprefs_config;
+
+	switch ($part)
+	{
+	// General tests
+	case 'general':
+		$table = new html_table(array('cols' => 2));
+
+		if ($sauserprefs_config['general_settings']['score']) {
+			$field_id = 'rcmfd_spamthres';
+			$input_spamthres = new html_select(array('name' => '_spamthres', 'id' => $field_id));
+
+			$decPlaces = 0;
+			if ($sauserprefs_config['score_inc'] - (int)$sauserprefs_config['score_inc'] > 0)
+				$decPlaces = strlen($sauserprefs_config['score_inc'] - (int)$sauserprefs_config['score_inc']) - 2;
+
+			for ($i = 1; $i <= 10; $i = $i + $sauserprefs_config['score_inc'])
+				$input_spamthres->add(number_format($i, $decPlaces), (float)$i);
+
+			$table->add('title', html::label($field_id, Q(rcube_label('spamthres'))));
+			$table->add(null, $input_spamthres->show((float)$user_prefs['required_hits']));
+
+			$table->add(array('colspan' => 2), Q(rcube_label('spamthresexp')));
+			$table->add_row();
+		}
+
+		if ($sauserprefs_config['general_settings']['subject']) {
+			if ($sauserprefs_config['general_settings']['score']) {
+				$table->add(null, "&nbsp;");
+				$table->add(null, "&nbsp;");
+			}
+
+			$field_id = 'rcmfd_spamsubject';
+			$input_spamsubject = new html_inputfield(array('name' => '_spamsubject', 'id' => $field_id, 'value' => $user_prefs['rewrite_header Subject'], 'style' => 'width:200px;'));
+
+			$table->add('title', html::label($field_id, Q(rcube_label('spamsubject'))));
+			$table->add(null, $input_spamsubject->show());
+
+			$table->add(null, "&nbsp;");
+			$table->add(null, Q(rcube_label('spamsubjectblank')));
+		}
+
+		if ($sauserprefs_config['general_settings']['language']) {
+			if ($sauserprefs_config['general_settings']['subject'] || ($sauserprefs_config['general_settings']['score'] && !$sauserprefs_config['general_settings']['subject'])) {
+				$table->add(null, "&nbsp;");
+				$table->add(null, "&nbsp;");
+			}
+
+			$table->add('title', html::label($field_id, Q(rcube_label('spamlang'))));
+			$table->add(null, "&nbsp;");
+			$table->add(array('colspan' => 2), Q(rcube_label('spamlangexp')));
+			$table->add_row();
+			$table->add(null, "&nbsp;");
+			$table->add(null, "&nbsp;");
+
+			$select_all = html::a(array('href' => "#", 'onclick' => 'return select_all_langs()', 'title' => rcube_label('select') . " " . rcube_label('all')), rcube_label('all'));
+			$select_none = html::a(array('href' => "#", 'onclick' => 'return select_no_langs()', 'title' => rcube_label('select') . " " . rcube_label('none')), rcube_label('none'));
+
+			$table->add(array('colspan' => 2, 'id' => 'listcontrols'), rcube_label('select') .":&nbsp;". $select_all ."&nbsp;". $select_none);
+			$table->add_row();
+
+			if (!empty($attrib['enableicon']))
+				$enable_button = html::img(array('src' => $attrib['enableicon'], 'alt' => rcube_label('enabled'), 'border' => 0));
+			else
+				$enable_button = rcube_label('enabled');
+
+			if (!empty($attrib['disableicon']))
+				$disable_button = html::img(array('src' => $attrib['disableicon'], 'alt' => rcube_label('disabled'), 'border' => 0));
+			else
+				$disable_button = rcube_label('disabled');
+
+			$lang_table = new html_table(array('id' => 'spam-langs-table', 'class' => 'records-table', 'cellspacing' => '0', 'cols' => 2));
+			$lang_table->add_header(array('colspan' => 2), rcube_label('language'));
+			$lang_table->set_row_attribs(array('style' => 'display: none;'));
+			$lang_table->add(array('id' => 'enable_button'), $enable_button);
+			$lang_table->add(array('id' => 'disable_button'), $disable_button);
+
+			if ($user_prefs['ok_locales'] == "all")
+				$ok_locales = array_keys($sauserprefs_config['languages']);
+			else
+				$ok_locales = split(" ", $user_prefs['ok_locales']);
+
+			$i = 0;
+			foreach ($sauserprefs_config['languages'] as $lang_code => $name) {
+				if (in_array($lang_code, $ok_locales)) {
+					$action = rcube_label('enabled');
+					$button = $enable_button;
+				}
+				else {
+					$action = rcube_label('disabled');
+					$button = $disable_button;
+				}
+
+				$button = html::a(array('id' => 'spam_lang_'.$i, 'href' => "#", 'onclick' => 'return message_lang("'.$lang_code.'", this)', 'title' => $action), $button);
+				$input_spamlang = new html_checkbox(array('style' => 'display: none;', 'name' => '_spamlang[]', 'value' => $lang_code));
+
+				$lang_table->add('lang', $name);
+				$lang_table->add('tick', $button . $input_spamlang->show(in_array($lang_code, $ok_locales) ? $lang_code : ''));
+
+				$i++;
+			}
+
+			$table->add(array('colspan' => 2), html::div(array('id' => 'spam-langs-cont'), $lang_table->show()));
+			$table->add_row();
+		}
+
+		if ($table->size())
+			$out = html::tag('fieldset', null, html::tag('legend', null, Q(rcube_label('spamgeneralsettings'))) . $table->show($attrib));
+
+		break;
+
+	// Header settings
+	case 'headers':
+		$data = Q(rcube_label('headersexp')) . "<br /><br />";
+		$enable_block = new html_hiddenfield(array('name' => '_do_headers', 'value' => '1'));
+		$data .= $enable_block->show();
+
+		$field_id = 'rcmfd_spamfoldheaders';
+		$input_spamreport = new html_checkbox(array('name' => '_spamfoldheaders', 'id' => $field_id, 'value' => '1'));
+		$data .= $input_spamreport->show($user_prefs['fold_headers']) ."&nbsp;". html::label($field_id, Q(rcube_label('foldheaders'))) . "<br />";
+
+		if ($user_prefs['remove_header all'] != 'Level') {
+			$enabled = "1";
+			$char = $user_prefs['add_header all Level'];
+			$char = substr($char, 7, 1);
+		}
+		else {
+			$enabled = "0";
+			$char = "*";
+		}
+
+		$field_id = 'rcmfd_spamlevelstars';
+		$input_spamreport = new html_checkbox(array('name' => '_spamlevelstars', 'id' => $field_id, 'value' => '1',
+			'onchange' => 'toggle_level_char(this)'));
+		$data .= $input_spamreport->show($enabled) ."&nbsp;". html::label($field_id, Q(rcube_label('spamlevelstars'))) . "<br />";
+
+		$field_id = 'rcmfd_spamlevelchar';
+		$input_spamsubject = new html_inputfield(array('name' => '_spamlevelchar', 'id' => $field_id, 'value' => $char,
+			'style' => 'width:20px;', 'disabled' => $enabled?0:1));
+		$data .= html::span(array('style' => 'padding-left: 30px;'), $input_spamsubject->show() ."&nbsp;". html::label($field_id, Q(rcube_label('spamlevelchar'))));
+
+		$out = html::tag('fieldset', null, html::tag('legend', null, Q(rcube_label('headers'))) . $data);
+		break;
+
+	// Test settings
+	case 'tests':
+		$data = Q(rcube_label('spamtestssexp')) . "<br /><br />";
+		$enable_block = new html_hiddenfield(array('name' => '_do_tests', 'value' => '1'));
+		$data .= $enable_block->show();
+
+		$field_id = 'rcmfd_spamuserazor1';
+		$input_spamtest = new html_checkbox(array('name' => '_spamuserazor1', 'id' => $field_id, 'value' => '1'));
+		$data .= $input_spamtest->show($user_prefs['use_razor1']) ."&nbsp;". html::label($field_id, Q(rcube_label('userazor1'))) . "<br />";
+
+		$field_id = 'rcmfd_spamuserazor2';
+		$input_spamtest = new html_checkbox(array('name' => '_spamuserazor2', 'id' => $field_id, 'value' => '1'));
+		$data .= $input_spamtest->show($user_prefs['use_razor2']) ."&nbsp;". html::label($field_id, Q(rcube_label('userazor2'))) . "<br />";
+
+		$field_id = 'rcmfd_spamusepyzor';
+		$input_spamtest = new html_checkbox(array('name' => '_spamusepyzor', 'id' => $field_id, 'value' => '1'));
+		$data .= $input_spamtest->show($user_prefs['use_pyzor']) ."&nbsp;". html::label($field_id, Q(rcube_label('usepyzor'))) . "<br />";
+
+		$field_id = 'rcmfd_spamusebayes';
+		$input_spamtest = new html_checkbox(array('name' => '_spamusebayes', 'id' => $field_id, 'value' => '1'));
+		$data .= $input_spamtest->show($user_prefs['use_bayes']) ."&nbsp;". html::label($field_id, Q(rcube_label('usebayes'))) . "<br />";
+
+		$field_id = 'rcmfd_spamusedcc';
+		$input_spamtest = new html_checkbox(array('name' => '_spamusedcc', 'id' => $field_id, 'value' => '1'));
+		$data .= $input_spamtest->show($user_prefs['use_dcc']) ."&nbsp;". html::label($field_id, Q(rcube_label('usedcc'))) . "<br />";
+
+		if ($user_prefs['skip_rbl_checks'] == "1")
+			$enabled = "0";
+		else
+			$enabled = "1";
+
+		$field_id = 'rcmfd_spamskiprblchecks';
+		$input_spamtest = new html_checkbox(array('name' => '_spamskiprblchecks', 'id' => $field_id, 'value' => '1'));
+		$data .= $input_spamtest->show($enabled) ."&nbsp;". html::label($field_id, Q(rcube_label('skiprblchecks'))) . "<br />";
+
+		$out = html::tag('fieldset', null, html::tag('legend', null, Q(rcube_label('spamtests'))) . $data);
+		break;
+
+	// Report settings
+	case 'report':
+		$data = Q(rcube_label('spamreport')) . "<br /><br />";
+		$enable_block = new html_hiddenfield(array('name' => '_do_report', 'value' => '1'));
+		$data .= $enable_block->show();
+
+		$field_id = 'rcmfd_spamreport';
+		$input_spamreport0 = new html_radiobutton(array('name' => '_spamreport', 'id' => $field_id.'_0', 'value' => '0'));
+		$data .= $input_spamreport0->show($user_prefs['report_safe']) ."&nbsp;". html::label($field_id .'_0', Q(rcube_label('spamreport0'))) . "<br />";
+
+		$input_spamreport1 = new html_radiobutton(array('name' => '_spamreport', 'id' => $field_id.'_1', 'value' => '1'));
+		$data .= $input_spamreport1->show($user_prefs['report_safe']) ."&nbsp;". html::label($field_id .'_1', Q(rcube_label('spamreport1'))) . "<br />";
+
+		$input_spamreport2 = new html_radiobutton(array('name' => '_spamreport', 'id' => $field_id.'_2', 'value' => '2'));
+		$data .= $input_spamreport2->show($user_prefs['report_safe']) ."&nbsp;". html::label($field_id .'_2', Q(rcube_label('spamreport2'))) . "<br />";
+
+		$out = html::tag('fieldset', null, html::tag('legend', null, Q(rcube_label('spamreportsettings'))) . $data);
+		break;
+
+	// Address settings
+	case 'addresses':
+		$data = Q(rcube_label('whitelistexp')) . "<br /><br />";
+		$enable_block = new html_hiddenfield(array('name' => '_do_addresses', 'value' => '1'));
+		$data .= $enable_block->show();
+
+		if ($sauserprefs_config['whitelist_sync'])
+			$data .= Q(rcube_label('autowhitelist')) . "<br /><br />";
+
+		$table = new html_table(array('cols' => 3, 'width' => '100%'));
+		$field_id = 'rcmfd_spamaddressrule';
+		$input_spamaddressrule = new html_select(array('name' => '_spamaddressrule', 'id' => $field_id));
+		$input_spamaddressrule->add(rcube_label('whitelist_from'),'whitelist_from');
+		$input_spamaddressrule->add(rcube_label('blacklist_from'), 'blacklist_from');
+		$input_spamaddressrule->add(rcube_label('whitelist_to'), 'whitelist_to');
+
+		$field_id = 'rcmfd_spamaddress';
+		$input_spamaddress = new html_inputfield(array('name' => '_spamaddress', 'id' => $field_id, 'style' => 'width:200px;'));
+
+		$field_id = 'rcmbtn_add_address';
+		$button_addaddress = new html_inputfield(array('type' => 'button', 'value' => rcube_label('addrule'), 'onclick' => 'addressrule_add()', 'id' => $field_id, 'class' => 'button', 'style' => 'width:75px;'));
+
+		$table->add(null, $input_spamaddressrule->show());
+		$table->add(null, $input_spamaddress->show());
+		$table->add(array('align' => 'right'), $button_addaddress->show());
+		$table->add(array('colspan' => 3), "&nbsp;");
+		$table->add_row();
+
+		if (!empty($attrib['deleteicon']))
+			$del_button = html::img(array('src' => $RCMAIL->config->get('skin_path') . $attrib['deleteicon'], 'alt' => rcube_label('delete'), 'border' => 0));
+		else
+			$del_button = rcube_label('delete');
+
+		$address_table = new html_table(array('id' => 'address-rules-table', 'class' => 'records-table', 'cellspacing' => '0', 'cols' => 3));
+		$address_table->add_header(array('width' => '180px'), rcube_label('rule'));
+		$address_table->add_header(null, rcube_label('email'));
+		$address_table->add_header(array('width' => '40px'), '&nbsp;');
+
+		address_row($address_table, null, null, $del_button);
+
+		$sql_result = $user_db->query(
+		  "SELECT ". $sauserprefs_config['sql_preference_field'] .", ". $sauserprefs_config['sql_value_field'] ."
+		   FROM   ". $sauserprefs_config['sql_table_name'] ."
+		   WHERE  ". $sauserprefs_config['sql_username_field'] ." = '". $_SESSION['username'] ."'
+		   AND   (". $sauserprefs_config['sql_preference_field'] ." = 'whitelist_from'
+		   OR     ". $sauserprefs_config['sql_preference_field'] ." = 'blacklist_from'
+		   OR     ". $sauserprefs_config['sql_preference_field'] ." = 'whitelist_to')
+		   ORDER BY ". $sauserprefs_config['sql_value_field'] .";"
+		  );
+
+		if ($sql_result && $user_db->num_rows($sql_result) > 0)
+			$norules = 'display: none;';
+
+		$address_table->set_row_attribs(array('style' => $norules));
+		$address_table->add(array('colspan' => '3'), rep_specialchars_output(rcube_label('noaddressrules')));
+		$address_table->add_row();
+		$OUTPUT->set_env('address_rule_count', $user_db->num_rows());
+		while ($sql_result && $sql_arr = $user_db->fetch_assoc($sql_result)) {
+			$field = $sql_arr[$sauserprefs_config['sql_preference_field']];
+			$value = $sql_arr[$sauserprefs_config['sql_value_field']];
+
+			address_row($address_table, $field, $value, $del_button);
+		}
+
+		$table->add(array('colspan' => 3), html::div(array('id' => 'address-rules-cont'), $address_table->show()));
+		$table->add_row();
+
+		if ($table->size())
+			$out = html::tag('fieldset', null, html::tag('legend', null, Q(rcube_label('spamaddressrules'))) . $data . $table->show($attrib));
+
+		break;
+
+	default:
+		$out = '';
+	}
+
+	return $out;
+}
+
+function address_row($address_table, $field, $value, $del_button) {
+	if (!isset($field))
+		$address_table->set_row_attribs(array('style' => 'display: none;'));
+
+	$hidden_action = new html_hiddenfield(array('name' => '_address_rule_act[]', 'value' => ''));
+	$hidden_field = new html_hiddenfield(array('name' => '_address_rule_field[]', 'value' => $field));
+	$hidden_text = new html_hiddenfield(array('name' => '_address_rule_value[]', 'value' => $value));
+
+	switch ($field) {
+		case "whitelist_from":
+			$fieldtxt = rep_specialchars_output(rcube_label('whitelist_from'));
+			break;
+		case "blacklist_from":
+			$fieldtxt = rep_specialchars_output(rcube_label('blacklist_from'));
+			break;
+		case "whitelist_to":
+			$fieldtxt = rep_specialchars_output(rcube_label('whitelist_to'));
+			break;
+	}
+
+	$address_table->add(array('class' => $field), $fieldtxt);
+	$address_table->add(array('class' => 'email'), $value);
+	$address_table->add('control', '&nbsp;' . html::a(array('href' => "#", 'onclick' => 'return addressrule_del(this)', 'title' => rcube_label('delete')), $del_button) . $hidden_action->show() . $hidden_field->show() . $hidden_text->show());
+
+	return $address_table;
+}
+
+?>
\ No newline at end of file
diff -Naur --exclude='*.svn*' roundcube_svn/program/steps/settings/save_sauserprefs.inc roundcube_pub/program/steps/settings/save_sauserprefs.inc
--- roundcube_svn/program/steps/settings/save_sauserprefs.inc	1970-01-01 01:00:00.000000000 +0100
+++ roundcube_pub/program/steps/settings/save_sauserprefs.inc	2009-01-08 18:49:26.000000000 +0000
@@ -0,0 +1,208 @@
+<?php
+
+/*
+ +-----------------------------------------------------------------------+
+ | plugins/sauserprefs/save_sauserprefs.inc                              |
+ |                                                                       |
+ | This file is part of the RoundCube Webmail client                     |
+ | Copyright (C) 2008, RoundCube Dev. - Switzerland                      |
+ | Licensed under the GNU GPL                                            |
+ |                                                                       |
+ | PURPOSE:                                                              |
+ |   Save user spamassassin settings to sql                              |
+ |                                                                       |
+ +-----------------------------------------------------------------------+
+ | Author: Philip Weir                                                   |
+ +-----------------------------------------------------------------------+
+ | Requires: plugins/sauserprefs/config.inc.php                          |
+ +-----------------------------------------------------------------------+
+
+ $Id: $
+
+*/
+
+require_once('plugins/sauserprefs/config.inc.php');
+
+$user_db = new rcube_mdb2($sauserprefs_config['db_dsnw'], $sauserprefs_config['db_dsnr'], $sauserprefs_config['db_persistent']);
+$user_db->db_connect('w');
+
+// check DB connections and exit on failure
+if ($err_str = $user_db->is_error()) {
+  raise_error(array(
+    'code' => 603,
+    'type' => 'db',
+    'message' => $err_str), FALSE, TRUE);
+}
+
+// global settings
+$global_prefs = array();
+
+$sql_result = $user_db->query(
+  "SELECT ". $sauserprefs_config['sql_preference_field'] .", ". $sauserprefs_config['sql_value_field'] ."
+   FROM   ". $sauserprefs_config['sql_table_name'] ."
+   WHERE  ". $sauserprefs_config['sql_username_field'] ." = '\$GLOBAL'
+   AND    ". $sauserprefs_config['sql_preference_field'] ." <> 'whitelist_from'
+   AND    ". $sauserprefs_config['sql_preference_field'] ." <> 'blacklist_from'
+   AND    ". $sauserprefs_config['sql_preference_field'] ." <> 'whitelist_to';"
+  );
+
+while ($sql_result && ($sql_arr = $user_db->fetch_assoc($sql_result)))
+	$global_prefs[$sql_arr[$sauserprefs_config['sql_preference_field']]] = $sql_arr[$sauserprefs_config['sql_value_field']];
+
+$global_prefs = array_merge($sauserprefs_config['default_prefs'], $global_prefs);
+
+// user settings
+$user_prefs = array();
+
+$sql_result = $user_db->query(
+  "SELECT ". $sauserprefs_config['sql_preference_field'] .", ". $sauserprefs_config['sql_value_field'] ."
+   FROM   ". $sauserprefs_config['sql_table_name'] ."
+   WHERE  ". $sauserprefs_config['sql_username_field'] ." = '". $_SESSION['username'] ."'
+   AND    ". $sauserprefs_config['sql_preference_field'] ." <> 'whitelist_from'
+   AND    ". $sauserprefs_config['sql_preference_field'] ." <> 'blacklist_from'
+   AND    ". $sauserprefs_config['sql_preference_field'] ." <> 'whitelist_to';"
+  );
+
+while ($sql_result && ($sql_arr = $user_db->fetch_assoc($sql_result)))
+	$user_prefs[$sql_arr[$sauserprefs_config['sql_preference_field']]] = $sql_arr[$sauserprefs_config['sql_value_field']];
+
+$new_prefs = array();
+
+if ($sauserprefs_config['general_settings']['score'])
+	$new_prefs['required_hits'] = $_POST['_spamthres'];
+
+if ($sauserprefs_config['general_settings']['subject'])
+	$new_prefs['rewrite_header Subject'] = $_POST['_spamsubject'];
+
+if ($sauserprefs_config['general_settings']['language']) {
+	$new_prefs['ok_locales'] = implode(" ", $_POST['_spamlang']);
+	$new_prefs['ok_languages'] = $new_prefs['ok_locales'];
+}
+
+if ($_POST['_do_headers'] == '1') {
+	$new_prefs['fold_headers'] = empty($_POST['_spamfoldheaders']) ? "0" : $_POST['_spamfoldheaders'];
+	$spamchar = empty($_POST['_spamlevelchar']) ? "*" : $_POST['_spamlevelchar'];
+	if ($_POST['_spamlevelstars'] == "1") {
+		$new_prefs['add_header all Level'] = "_STARS(". $spamchar .")_";
+		$new_prefs['remove_header all'] = "0";
+	}
+	else {
+		$new_prefs['add_header all Level'] = "";
+		$new_prefs['remove_header all'] = "Level";
+	}
+}
+
+if ($_POST['_do_tests'] == '1') {
+	$new_prefs['use_razor1'] = empty($_POST['_spamuserazor1']) ? "0" : $_POST['_spamuserazor1'];
+	$new_prefs['use_razor2'] = empty($_POST['_spamuserazor2']) ? "0" : $_POST['_spamuserazor2'];
+	$new_prefs['use_pyzor'] = empty($_POST['_spamusepyzor']) ? "0" : $_POST['_spamusepyzor'];
+	$new_prefs['use_bayes'] = empty($_POST['_spamusebayes']) ? "0" : $_POST['_spamusebayes'];
+	$new_prefs['use_dcc'] = empty($_POST['_spamusedcc']) ? "0" : $_POST['_spamusedcc'];
+
+	if ($_POST['_spamskiprblchecks'] == "1")
+		$new_prefs['skip_rbl_checks'] = "";
+	else
+		$new_prefs['skip_rbl_checks'] = "1";
+}
+
+if ($_POST['_do_report'] == '1')
+	$new_prefs['report_safe'] = $_POST['_spamreport'];
+
+foreach ($new_prefs as $preference => $value){
+	if ($value == "" || $value == $global_prefs[$preference]) {
+		$result = false;
+
+		$user_db->query(
+		  "DELETE FROM ". $sauserprefs_config['sql_table_name'] ."
+		   WHERE  ". $sauserprefs_config['sql_username_field'] ." = '". $_SESSION['username'] ."'
+		   AND    ". $sauserprefs_config['sql_preference_field'] ." = '". $preference ."';"
+		  );
+
+		$result = $user_db->affected_rows();
+
+		if (!$result)
+			break;
+	}
+	elseif (array_key_exists($preference, $user_prefs) && $value != $user_prefs[$preference]) {
+		$result = false;
+
+		$user_db->query(
+		  "UPDATE ". $sauserprefs_config['sql_table_name'] ."
+		   SET    ". $sauserprefs_config['sql_value_field'] ." = '". $value ."'
+		   WHERE  ". $sauserprefs_config['sql_username_field'] ." = '". $_SESSION['username'] ."'
+		   AND    ". $sauserprefs_config['sql_preference_field'] ." = '". $preference ."';"
+		  );
+
+		$result = $user_db->affected_rows();
+
+		if (!$result)
+			break;
+	}
+	elseif ($value != $global_prefs[$preference] && $value != $user_prefs[$preference]) {
+		$result = false;
+
+		$user_db->query(
+		  "INSERT INTO ". $sauserprefs_config['sql_table_name'] ."
+		   (".$sauserprefs_config['sql_username_field'].", ".$sauserprefs_config['sql_preference_field'].", ".$sauserprefs_config['sql_value_field'].")
+		   VALUES ('". $_SESSION['username'] ."', '". $preference ."', '". $value ."')"
+		  );
+
+		$result = $user_db->affected_rows();
+
+		if (!$result)
+			break;
+	}
+}
+
+if ($result) {
+	if ($_POST['_do_addresses'] == '1') {
+		$acts = $_POST['_address_rule_act'];
+		$prefs = $_POST['_address_rule_field'];
+		$vals = $_POST['_address_rule_value'];
+
+		foreach ($acts as $idx => $act){
+			if ($act == "DELETE") {
+				$result = false;
+
+				$user_db->query(
+				  "DELETE FROM ". $sauserprefs_config['sql_table_name'] ."
+				   WHERE  ". $sauserprefs_config['sql_username_field'] ." = '". $_SESSION['username'] ."'
+				   AND    ". $sauserprefs_config['sql_preference_field'] ." = '". $prefs[$idx] ."'
+				   AND    ". $sauserprefs_config['sql_value_field'] ." = '". $vals[$idx] . "';"
+				  );
+
+				$result = $user_db->affected_rows();
+
+				if (!$result)
+					break;
+			}
+			elseif ($act == "INSERT") {
+				$result = false;
+
+				$user_db->query(
+				  "INSERT INTO ". $sauserprefs_config['sql_table_name'] ."
+				   (".$sauserprefs_config['sql_username_field'].", ".$sauserprefs_config['sql_preference_field'].", ".$sauserprefs_config['sql_value_field'].")
+				   VALUES ('". $_SESSION['username']. "', '". $prefs[$idx] . "', '". $vals[$idx] ."')"
+				  );
+
+				$result = $user_db->affected_rows();
+
+				if (!$result)
+					break;
+			}
+		}
+	}
+
+	if ($result)
+		$OUTPUT->show_message('sauserprefchanged', 'confirmation');
+	else
+		$OUTPUT->show_message('sauserpreffailed', 'error');
+}
+else {
+	$OUTPUT->show_message('sauserpreffailed', 'error');
+}
+
+// go to next step
+rcmail_overwrite_action('sauserprefs');
+
+?>
\ No newline at end of file
diff -Naur --exclude='*.svn*' roundcube_svn/skins/default/includes/settingstabs.html roundcube_pub/skins/default/includes/settingstabs.html
--- roundcube_svn/skins/default/includes/settingstabs.html	2008-05-20 17:45:39.000000000 +0100
+++ roundcube_pub/skins/default/includes/settingstabs.html	2009-01-08 18:49:26.000000000 +0000
@@ -2,4 +2,5 @@
 <span id="settingstabdefault" class="tablink"><roundcube:button command="preferences" type="link" label="preferences" title="editpreferences" /></span>
 <span id="settingstabfolders" class="tablink"><roundcube:button command="folders" type="link" label="folders" title="managefolders" class="tablink" /></span>
 <span id="settingstabidentities" class="tablink"><roundcube:button command="identities" type="link" label="identities" title="manageidentities" class="tablink" /></span>
+<span id="settingstabsauserprefs" class="tablink"><roundcube:button command="sauserprefs" type="link" label="sauserprefs" title="sauserprefssettings" class="tablink" /></span>
 </div>
diff -Naur --exclude='*.svn*' roundcube_svn/skins/default/sauserprefs.css roundcube_pub/skins/default/sauserprefs.css
--- roundcube_svn/skins/default/sauserprefs.css	1970-01-01 01:00:00.000000000 +0100
+++ roundcube_pub/skins/default/sauserprefs.css	2009-01-08 18:49:26.000000000 +0000
@@ -0,0 +1,84 @@
+/***** RoundCube|Mail sauserprefs plugin styles *****/
+
+#address-rules-cont, #spam-langs-cont
+{
+  border: 1px solid #999999;
+  background-color: #F9F9F9;
+  height: 200px;
+  overflow: auto;
+}
+
+body.address-rules-table, body.spam-langs-table
+{
+  margin: 0px;
+  background-color: #F9F9F9;
+}
+
+#address-rules-table, #spam-langs-table
+{
+  width: 100%;
+  display: table;
+  table-layout: fixed;
+  /* css hack for IE */
+  width: expression('auto');
+}
+
+/* safari hack \*/
+html>body*#address-rules-table[id$="address-rules-table"]:not([class="none"]) { table-layout: auto; }
+/**/
+
+/* safari hack \*/
+html>body*#spam-langs-table[id$="spam-langs-table"]:not([class="none"]) { table-layout: auto; }
+/**/
+
+#spam-langs-table td.lang, #address-rules-table td.rule, #address-rules-table td.email, #address-rules-table td.email
+{
+  text-align: left;
+  vertical-align: middle;
+}
+
+#spam-langs-table td.tick, #address-rules-table td.control
+{
+  text-align: right;
+  vertical-align: middle;
+}
+
+.whitelist_from, .whitelist_to
+{
+  color: #008800;
+  text-align: left;
+  vertical-align: middle;
+
+}
+
+.blacklist_from
+{
+  color: #CC0000;
+  text-align: left;
+  vertical-align: middle;
+}
+
+#listcontrols
+{
+  font-size: 11px;
+  text-align: right;
+}
+
+#listcontrols a,
+#listcontrols a:active,
+#listcontrols a:visited
+{
+  color: #CC0000;
+  font-size: 11px;
+  text-decoration: none;
+}
+
+#listcontrols a:hover
+{
+  text-decoration: underline;
+}
+
+.userprefs-block
+{
+  width: 520px;
+}
\ No newline at end of file
diff -Naur --exclude='*.svn*' roundcube_svn/skins/default/templates/sauserprefs.html roundcube_pub/skins/default/templates/sauserprefs.html
--- roundcube_svn/skins/default/templates/sauserprefs.html	1970-01-01 01:00:00.000000000 +0100
+++ roundcube_pub/skins/default/templates/sauserprefs.html	2009-01-08 18:49:26.000000000 +0000
@@ -0,0 +1,39 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<title><roundcube:object name="pagetitle" /></title>
+<roundcube:include file="/includes/links.html" />
+<link rel="stylesheet" type="text/css" href="/settings.css" />
+<link rel="stylesheet" type="text/css" href="/sauserprefs.css" />
+<script type="text/javascript" src="/functions.js"></script>
+</head>
+<body onload="rcube_init_settings_tabs()">
+
+<roundcube:include file="/includes/taskbar.html" />
+<roundcube:include file="/includes/header.html" />
+<roundcube:include file="/includes/settingstabs.html" />
+
+<form name="form" action="./" method="post">
+
+<div id="userprefs-box">
+<div id="userprefs-title"><roundcube:label name="sauserprefssettings" /></div>
+
+<div style="padding:15px 0 15px 15px">
+<div class="userprefs-block"> 
+  <roundcube:object name="usersauserprefs" form="form" parts="general,tests" deleteIcon="/images/icons/folder-trash.png" enableIcon="plugins/sauserprefs/enabled.png" disableIcon="plugins/sauserprefs/disabled.png" />
+</div> 
+<div class="userprefs-block"> 
+  <roundcube:object name="usersauserprefs" form="form" parts="headers,report,addresses" deleteIcon="/images/icons/folder-trash.png" enableIcon="plugins/sauserprefs/enabled.png" disableIcon="plugins/sauserprefs/disabled.png" />
+</div>
+<div style="clear:left"></div> 
+</div>
+</div>
+
+<p id="listbuttons">
+<roundcube:button command="save-sauserprefs" type="input" class="button mainaction" label="save" />
+</p>
+
+</form>
+
+</body>
+</html>
\ No newline at end of file
