Hi Cedric,
The BayesStore API is designed in such a way that implementing a
separate store for this sort of thing would be super easy. I suggest
you subclass SQL and make the changes and call it something new.
I'm probably -1 on changing the top level, fairly generic, SQL.pm to do
what you're asking, but would have to examine the change a little more
before I made a final determination.
Michael
Cedric Lejeune wrote:
> Hi list!
>
> First, this is my first submission to a project, so please excuse me if
> I do something that do not follow the rules.
>
> I'm in charged with spamassassin (SA) and after an update from 3.0 to
> 3.1, users starts to complain about SA improved effectiveness (to more
> false positive). After some investigation, the problem seems to come
> from bayesian filter. I use a global bayesian database (using
> bayes_sql_override_username) but with customers coming from all over the
> world, it seems a more fine grain filtering should be better. But it
> seems it is currently impossible. I use SQL bayesian database setup and
> it should have been great if it has offered the same kind of feature
> that user_scores_sql_custom_query. What I wanted to do is make bayesian
> filter retrieve database first for the current user, then for the
> routing domain to which user belongs to, then fall back to global
> database. For instance:
>
> [EMAIL PROTECTED] -> [EMAIL PROTECTED] -> *
>
> This way, it is possible for users to have their own personal bayes
> database and if they do no want to create one or they do no have one
> already, they still can benefit from others' databases. Grouping users
> per routing domain is like grouping users per center of interest: if one
> declares mail as spam, there is little few chance that others consider
> it as ham.
>
> So this feature was not implemented yet and I have started writing it
> myself. I warn you that I did not write a single perl line before and
> "my" code is made of doc quotes and cut & paste. I've added the
> following configuration option bayes_sql_custom_query to SA
> configuration file. It acts the same way bayes_sql_override_username does.
>
> Please, let me know if this feature could be useful to others and/or if
> it requires some rewriting.
>
> Please, find diff as attachments. They applied against SA 3.1.4 because
> it is the SA version shipped with Debian testing at this time.
>
> Best regards =)
>
> cedric.
>
>
> ------------------------------------------------------------------------
>
> --- SpamAssassin/Conf.pm 2006-08-12 18:08:44.000000000 +0200
> +++ Conf.pm 2006-11-13 10:37:16.000000000 +0100
> @@ -2330,6 +2330,52 @@
> type => $CONF_TYPE_STRING
> });
>
> +#### Start of modification (last modified on 20061109).
> +=item bayes_sql_custom_query query
> +
> +This option gives you the ability to create a custom SQL query to
> +retrieve username. In order to work correctly your query should
> +return only one value, the desired username. In addition, there
> +are several "variables" that you can use as part of your query,
> +these variables will be substituted for the current values right
> +before the query is run. The current allowed variables are:
> +
> +=over 2
> +
> +=item _USERNAME_
> +
> +The current user's username.
> +
> +=item _DOMAIN_
> +
> +The portion after the @ as derived from the current user's username, this
> +value may be null.
> +
> +=back
> +
> +The query must be one continuous line in order to parse correctly.
> +
> +Here is an example query, please note that it is broken up for easy
> +reading, in your config it should be one continuous line.
> +
> +=over 1
> +
> +=item Current default query:
> +
> +C<SELECT username FROM bayes_vars WHERE username = '*' OR Username =
> CONCAT('*@',_DOMAIN_) OR Username = _USERNAME_ ORDER BY username ASC>
> +
> +=back
> +
> +=cut
> +
> + push (@cmds, {
> + setting => 'bayes_sql_custom_query',
> + is_admin => 1,
> + type => $CONF_TYPE_STRING
> + });
> +
> +#### End of modification.
> +
> =item bayes_sql_username_authorized ( 0 | 1 ) (default: 0)
>
> Whether to call the services_authorized_for_username plugin hook in BayesSQL.
>
>
> ------------------------------------------------------------------------
>
> --- SpamAssassin/BayesStore/SQL.pm 2005-08-11 09:00:37.000000000 +0200
> +++ SQL.pm.bayesstore 2006-11-13 11:15:43.000000000 +0100
> @@ -85,15 +85,70 @@
> if ($self->{bayes}->{conf}->{bayes_sql_override_username}) {
> $self->{_username} =
> $self->{bayes}->{conf}->{bayes_sql_override_username};
> }
> +#### Start of modification (last modified on 20061113).
> else {
> - $self->{_username} = $self->{bayes}->{main}->{username};
> + if ($self->{bayes}->{conf}->{bayes_sql_custom_query}) {
>
> - # Need to make sure that a username is set, so just in case there is
> - # no username set in main, set one here.
> - unless ($self->{_username}) {
> - $self->{_username} = "GLOBALBAYES";
> - }
> + # Connect to database.
> + return 0 unless ($self->_connect_db());
> +
> + # Retrieve current username and play with it.
> + my $username = $self->{bayes}->{main}->{username};
> + my ($mailbox, $domain) = split('@', $username);
> +
> + my $quoted_username = $self->{_dbh}->quote($username);
> + my $quoted_domain = $self->{_dbh}->quote($domain);
> +
> + my $custom_query =
> $self->{bayes}->{conf}->{bayes_sql_custom_query};
> + $custom_query =~ s/_USERNAME_/$quoted_username/g;
> + $custom_query =~ s/_DOMAIN_/$quoted_domain/g;
> +
> + dbg("bayes: new: quoted_username = ".$quoted_username);
> + dbg("bayes: new: quoted_domain = ".$quoted_domain);
> + dbg("bayes: new: custom_query = ".$custom_query);
> +
> + # Prepare query.
> + my $sth = $self->{_dbh}->prepare($custom_query);
> + unless (defined($sth)) {
> + dbg("bayes: new: SQL error:
> ".$self->{_dbh}->errstr());
> + return 0;
> + }
> +
> + # Execute query.
> + my $rc = $sth->execute();
> + unless ($rc) {
> + dbg("bayes: new: SQL error:
> ".$self->{_dbh}->errstr());
> + return 0;
> + }
> +
> + # Retrieve _username.
> + my $ary_ref = $sth->fetchall_arrayref();
> + $self->{_username} = $ary_ref->[-1]->[-1];
> +
> + dbg("bayes: new: _username = ".$self->{_username});
> +
> + # Tell database server to free buffer allocated to query.
> + $sth->finish();
> +
> + # Close database connection.
> + $self->{_dbh}->disconnect();
> +
> + # Set _dbh to initial state.
> + $self->{_dbh} = undef;
> +
> + }
> +#### End of modification.
> + else {
> + $self->{_username} = $self->{bayes}->{main}->{username};
> + }
> + }
> +
> + # Need to make sure that a username is set, so just in case there is
> + # no username set in main, set one here.
> + unless ($self->{_username}) {
> + $self->{_username} = "GLOBALBAYES";
> }
> +
> dbg("bayes: using username: ".$self->{_username});
>
> return $self;