# -*- indent-tabs-mode: nil; -*- # vim:ft=perl:et:sw=4 # $Id$ # Sympa - SYsteme de Multi-Postage Automatique # # Copyright (c) 1997, 1998, 1999 Institut Pasteur & Christophe Wolfhugel # Copyright (c) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, # 2006, 2007, 2008, 2009, 2010, 2011 Comite Reseau des Universites # Copyright (c) 2011, 2012, 2013, 2014, 2015 GIP RENATER # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . package Sympa::Robot; use strict; use warnings; use Encode qw(); use Conf; use Sympa::Language; use Sympa::Log; use SDM; use tools; use Sympa::Tools::File; my $language = Sympa::Language->instance; my $log = Sympa::Log->instance; ## Database and SQL statement handlers my ($sth, @sth_stack); our %list_of_topics = (); ## Last modification times our %mtime; our %listmaster_messages_stack; # MOVED: Use tools::send_file(), or Sympa::Message::new_from_template() with # Sympa::Mailer::send_message(). # sub send_global_file($tpl, $who, $robot, $context, $options); # MOVED: Use tools::send_notify_to_listmaster() or Sympa::Alarm::flush(). # sub send_notify_to_listmaster($operation, $robot, $data, $checkstack, $purge); ## Is the user listmaster sub is_listmaster { my $who = shift; my $robot = shift; return unless $who; $who =~ y/A-Z/a-z/; foreach my $listmaster (@{Conf::get_robot_conf($robot, 'listmasters')}) { return 1 if (lc($listmaster) eq lc($who)); } foreach my $listmaster (@{Conf::get_robot_conf('*', 'listmasters')}) { return 1 if (lc($listmaster) eq lc($who)); } return 0; } ## get idp xref to locally validated email address sub get_netidtoemail_db { my $robot = shift; my $netid = shift; my $idpname = shift; $log->syslog('debug', '(%s, %s)', $netid, $idpname); my ($l, %which, $email); push @sth_stack, $sth; unless ( $sth = SDM::do_query( "SELECT email_netidmap FROM netidmap_table WHERE netid_netidmap = %s and serviceid_netidmap = %s and robot_netidmap = %s", SDM::quote($netid), SDM::quote($idpname), SDM::quote($robot) ) ) { $log->syslog( 'err', 'Unable to get email address from netidmap_table for id %s, service %s, robot %s', $netid, $idpname, $robot ); return undef; } $email = $sth->fetchrow; $sth->finish(); $sth = pop @sth_stack; return $email; } ## set idp xref to locally validated email address sub set_netidtoemail_db { my $robot = shift; my $netid = shift; my $idpname = shift; my $email = shift; $log->syslog('debug', '(%s, %s, %s)', $netid, $idpname, $email); my ($l, %which); unless ( SDM::do_query( "INSERT INTO netidmap_table (netid_netidmap,serviceid_netidmap,email_netidmap,robot_netidmap) VALUES (%s, %s, %s, %s)", SDM::quote($netid), SDM::quote($idpname), SDM::quote($email), SDM::quote($robot) ) ) { $log->syslog( 'err', 'Unable to set email address %s in netidmap_table for id %s, service %s, robot %s', $email, $netid, $idpname, $robot ); return undef; } return 1; } ## Update netidmap table when user email address changes sub update_email_netidmap_db { my ($robot, $old_email, $new_email) = @_; unless (defined $robot && defined $old_email && defined $new_email) { $log->syslog('err', 'Missing parameter'); return undef; } unless ( SDM::do_query( "UPDATE netidmap_table SET email_netidmap = %s WHERE (email_netidmap = %s AND robot_netidmap = %s)", SDM::quote($new_email), SDM::quote($old_email), SDM::quote($robot) ) ) { $log->syslog( 'err', 'Unable to set new email address %s in netidmap_table to replace old address %s for robot %s', $new_email, $old_email, $robot ); return undef; } return 1; } ## Loads the list of topics if updated ## FIXME: This might be moved to Robot package. sub load_topics { my $robot = shift; $log->syslog('debug2', '(%s)', $robot); my $conf_file = tools::search_fullpath($robot, 'topics.conf'); unless ($conf_file) { $log->syslog('err', 'No topics.conf defined'); return undef; } my $topics = {}; ## Load if not loaded or changed on disk if (!$list_of_topics{$robot} or Sympa::Tools::File::get_mtime($conf_file) > $mtime{'topics'}{$robot}) { ## delete previous list of topics %list_of_topics = (); unless (-r $conf_file) { $log->syslog('err', 'Unable to read %s', $conf_file); return undef; } unless (open(FILE, "<", $conf_file)) { $log->syslog('err', 'Unable to open config file %s', $conf_file); return undef; } ## Rough parsing my $index = 0; my (@rough_data, $topic); while () { Encode::from_to($_, $Conf::Conf{'filesystem_encoding'}, 'utf8'); if (/^([\-\w\/]+)\s*$/) { $index++; $topic = { 'name' => $1, 'order' => $index }; } elsif (/^([\w\.]+)\s+(.+)\s*$/) { next unless (defined $topic->{'name'}); $topic->{$1} = $2; } elsif (/^\s*$/) { next unless defined $topic->{'name'}; push @rough_data, $topic; $topic = {}; } } close FILE; ## Last topic if (defined $topic->{'name'}) { push @rough_data, $topic; $topic = {}; } $mtime{'topics'}{$robot} = Sympa::Tools::File::get_mtime($conf_file); unless ($#rough_data > -1) { $log->syslog('notice', 'No topic defined in %s', $conf_file); return undef; } ## Analysis foreach my $topic (@rough_data) { my @tree = split '/', $topic->{'name'}; if ($#tree == 0) { my $title = _get_topic_titles($topic); $list_of_topics{$robot}{$tree[0]}{'title'} = $title; $list_of_topics{$robot}{$tree[0]}{'visibility'} = $topic->{'visibility'} || 'default'; #$list_of_topics{$robot}{$tree[0]}{'visibility'} = _load_scenario_file('topics_visibility', $robot,$topic->{'visibility'}||'default'); $list_of_topics{$robot}{$tree[0]}{'order'} = $topic->{'order'}; } else { my $subtopic = join('/', @tree[1 .. $#tree]); my $title = _get_topic_titles($topic); $list_of_topics{$robot}{$tree[0]}{'sub'}{$subtopic} = _add_topic($subtopic, $title); } } ## Set undefined Topic (defined via subtopic) foreach my $t (keys %{$list_of_topics{$robot}}) { unless (defined $list_of_topics{$robot}{$t}{'visibility'}) { #$list_of_topics{$robot}{$t}{'visibility'} = _load_scenario_file('topics_visibility', $robot,'default'); } unless (defined $list_of_topics{$robot}{$t}{'title'}) { $list_of_topics{$robot}{$t}{'title'} = {'default' => $t}; } } } ## Set the title in the current language my $lang = $language->get_lang; foreach my $top (keys %{$list_of_topics{$robot}}) { my $topic = $list_of_topics{$robot}{$top}; foreach my $l (Sympa::Language::implicated_langs($lang)) { if (exists $topic->{'title'}{$l}) { $topic->{'current_title'} = $topic->{'title'}{$l}; } } unless (exists $topic->{'current_title'}) { if (exists $topic->{'title'}{'gettext'}) { $topic->{'current_title'} = $language->gettext($topic->{'title'}{'gettext'}); } else { $topic->{'current_title'} = $topic->{'title'}{'default'} || $top; } } foreach my $subtop (keys %{$topic->{'sub'}}) { foreach my $l (Sympa::Language::implicated_langs($lang)) { if (exists $topic->{'sub'}{$subtop}{'title'}{$l}) { $topic->{'sub'}{$subtop}{'current_title'} = $topic->{'sub'}{$subtop}{'title'}{$l}; } } unless (exists $topic->{'sub'}{$subtop}{'current_title'}) { if (exists $topic->{'sub'}{$subtop}{'title'}{'gettext'}) { $topic->{'sub'}{$subtop}{'current_title'} = $language->gettext( $topic->{'sub'}{$subtop}{'title'}{'gettext'}); } else { $topic->{'sub'}{$subtop}{'current_title'} = $topic->{'sub'}{$subtop}{'title'}{'default'} || $subtop; } } } } return %{$list_of_topics{$robot}}; } sub _get_topic_titles { my $topic = shift; my $title; foreach my $key (%{$topic}) { if ($key =~ /^title\.gettext$/i) { $title->{'gettext'} = $topic->{$key}; } elsif ($key =~ /^title\.(\S+)$/i) { my $lang = $1; # canonicalize lang if possible. $lang = Sympa::Language::canonic_lang($lang) || $lang; $title->{$lang} = $topic->{$key}; } elsif ($key =~ /^title$/i) { $title->{'default'} = $topic->{$key}; } } return $title; } ## Inner sub used by load_topics() sub _add_topic { my ($name, $title) = @_; my $topic = {}; my @tree = split '/', $name; if ($#tree == 0) { return {'title' => $title}; } else { $topic->{'sub'}{$name} = _add_topic(join('/', @tree[1 .. $#tree]), $title); return $topic; } } 1;