diff -c -r sympa-6.1.11/src/bulk.pl.in sympa-6.1.11.mod/src/bulk.pl.in
*** sympa-6.1.11/src/bulk.pl.in	2012-01-06 05:48:57.000000000 +1300
--- sympa-6.1.11.mod/src/bulk.pl.in	2013-11-18 14:21:57.366089510 +1300
***************
*** 241,246 ****
--- 241,250 ----
  	}
  
  	my $data; #HASH which will contain the attributes of the subscriber
+ 
+ # SJS : For passing message headers
+ 	$data->{'messageid'} = $message_from_spool->{'messageid'};
+ # SJS END
  	
  	# Initialization of the HASH : $data. It will be used by parse_tt2 to personalized messages.
  	$data->{'listname'} = $bulk->{'listname'};
diff -c -r sympa-6.1.11/src/lib/Bulk.pm sympa-6.1.11.mod/src/lib/Bulk.pm
*** sympa-6.1.11/src/lib/Bulk.pm	2012-04-20 01:59:43.000000000 +1200
--- sympa-6.1.11.mod/src/lib/Bulk.pm	2013-11-18 14:15:19.563367286 +1300
***************
*** 266,271 ****
--- 266,279 ----
  	return undef;
      }
  
+ # SJS : Add headers to stash
+     $data->{'headers'} = {} if(!defined $data->{'headers'});
+     my $headers = $entity->head;
+     foreach my $key ( qw/subject x-originating-ip message-id date x-original-to from to thread-topic content-type/ ) {
+         $data->{'headers'}{$key} = $headers->get($key) if($headers->count($key));
+     }
+ # END
+ 
      my $body;
      if(defined $entity->bodyhandle){
  	$body      = $entity->bodyhandle->as_string;
diff -c -r sympa-6.1.11/src/lib/List.pm sympa-6.1.11.mod/src/lib/List.pm
*** sympa-6.1.11/src/lib/List.pm	2012-05-09 19:00:35.000000000 +1200
--- sympa-6.1.11.mod/src/lib/List.pm	2013-11-15 16:03:13.356190690 +1300
***************
*** 801,806 ****
--- 801,813 ----
  							      'gettext_id' => "extracted attribute",
  							      'order' => 8
  							      },
+ 						# SJS add for gecos support
+ 						  'gecosattr' => {'format' => '\w+',
+ 							      'length' => 15,
+ 							      'default' => 'displayName',
+ 							      'gettext_id' => "extracted attribute",
+ 							      'order' => 10
+ 							      },
  						  'select' => {'format' => ['all','first'],
  							       'default' => 'first',
  							       'gettext_id' => "selection (if multiple)",
***************
*** 1012,1018 ****
  							       'order' => 1
  							       },
  						 'host' => {'format' => &tools::get_regexp('host'),
! 							    'occurrence' => '1',
  							    'gettext_id' => "remote host",
  							    'order' => 2
  							    },
--- 1019,1026 ----
  							       'order' => 1
  							       },
  						 'host' => {'format' => &tools::get_regexp('host'),
! # Not required for ODBC
! #							    'occurrence' => '1',
  							    'gettext_id' => "remote host",
  							    'order' => 2
  							    },
***************
*** 3029,3034 ****
--- 3037,3049 ----
  	&do_log('err', 'No recipient for sending %s', $tpl);
  	return undef;
      }
+ 
+     # If multiple recipients as CSV then convert to list
+     if(!ref $who and $who =~ /,/) {
+         my (@a) = ();
+         foreach ( Mail::Address->parse($who) ) { push @a, $_->format; }
+ 	$who = \@a;
+     }
      
      ## Unless multiple recipients
      unless (ref ($who)) {
***************
*** 8036,8042 ****
  	    $total++;
  	}
  	$u{'email'} = $email;
! 	$u{'gecos'} = $gecos;
  	$u{'id'} = join (',', split(',', $u{'id'}), $id);
  
  	$u{'visibility'} = $default_user_options->{'visibility'} if (defined $default_user_options->{'visibility'});
--- 8051,8057 ----
  	    $total++;
  	}
  	$u{'email'} = $email;
! 	$u{'gecos'} = $gecos if($gecos);
  	$u{'id'} = join (',', split(',', $u{'id'}), $id);
  
  	$u{'visibility'} = $default_user_options->{'visibility'} if (defined $default_user_options->{'visibility'});
***************
*** 8119,8125 ****
  		$total++;
  	    }
  	    $u{'email'} = $email;
! 	    $u{'gecos'} = $gecos;
  	    $u{'id'} = join (',', split(',', $u{'id'}), $id);
  	    
  	    $u{'visibility'} = $default_user_options->{'visibility'} if (defined $default_user_options->{'visibility'});
--- 8134,8140 ----
  		$total++;
  	    }
  	    $u{'email'} = $email;
! 	    $u{'gecos'} = $gecos if($gecos);
  	    $u{'id'} = join (',', split(',', $u{'id'}), $id);
  	    
  	    $u{'visibility'} = $default_user_options->{'visibility'} if (defined $default_user_options->{'visibility'});
***************
*** 8159,8164 ****
--- 8174,8180 ----
      my $ldap_suffix = $param->{'suffix'};
      my $ldap_filter = $param->{'filter'};
      my $ldap_attrs = $param->{'attrs'};
+     my $ldap_gecosattr = $param->{'gecosattr'};
      my $ldap_select = $param->{'select'};
      
      ## LDAP and query handler
***************
*** 8179,8188 ****
  	    return undef;
  	}
      
!     do_log('debug2', 'Searching on server %s ; suffix %s ; filter %s ; attrs: %s', $param->{'host'}, $ldap_suffix, $ldap_filter, $ldap_attrs);
      $fetch = $ldaph->search ( base => "$ldap_suffix",
  			      filter => "$ldap_filter",
! 			      attrs => [ "$ldap_attrs" ],
  			      scope => "$param->{'scope'}");
      if ($fetch->code()) {
  	do_log('err','Ldap search (single level) failed : %s (searching on server %s ; suffix %s ; filter %s ; attrs: %s)', 
--- 8195,8204 ----
  	    return undef;
  	}
      
!     do_log('debug2', 'Searching on server %s ; suffix %s ; filter %s ; attrs: %s %s', $param->{'host'}, $ldap_suffix, $ldap_filter, $ldap_attrs, $ldap_gecosattr);
      $fetch = $ldaph->search ( base => "$ldap_suffix",
  			      filter => "$ldap_filter",
! 			      attrs => [ "$ldap_attrs", "$ldap_gecosattr" ],
  			      scope => "$param->{'scope'}");
      if ($fetch->code()) {
  	do_log('err','Ldap search (single level) failed : %s (searching on server %s ; suffix %s ; filter %s ; attrs: %s)', 
***************
*** 8199,8218 ****
      while (my $e = $fetch->shift_entry) {
  
  	my $entry = $e->get_value($ldap_attrs, asref => 1);
  	
  	## Multiple values
  	if (ref($entry) eq 'ARRAY') {
  	    foreach my $email (@{$entry}) {
  		my $cleanmail = &tools::clean_email($email);
  		next if ($emailsViewed{$cleanmail});
! 		push @emails, $cleanmail;
  		$emailsViewed{$cleanmail} = 1;
  		last if ($ldap_select eq 'first');
  	    }
  	}else {
  	    my $cleanmail = &tools::clean_email($entry);
  	    unless ($emailsViewed{$cleanmail}) {
! 		push @emails, $cleanmail;
  		$emailsViewed{$cleanmail} = 1;
  	    }
  	}
--- 8215,8238 ----
      while (my $e = $fetch->shift_entry) {
  
  	my $entry = $e->get_value($ldap_attrs, asref => 1);
+ 	my $gecosentry = $e->get_value($ldap_gecosattr, asref => 1);
+ 	if (ref($gecosentry) eq 'ARRAY') {
+ 		$gecosentry = $gecosentry->[0];
+ 	}
  	
  	## Multiple values
  	if (ref($entry) eq 'ARRAY') {
  	    foreach my $email (@{$entry}) {
  		my $cleanmail = &tools::clean_email($email);
  		next if ($emailsViewed{$cleanmail});
! 		push @emails, [ $cleanmail, $gecosentry ];
  		$emailsViewed{$cleanmail} = 1;
  		last if ($ldap_select eq 'first');
  	    }
  	}else {
  	    my $cleanmail = &tools::clean_email($entry);
  	    unless ($emailsViewed{$cleanmail}) {
! 		push @emails, [ $cleanmail, $gecosentry ];
  		$emailsViewed{$cleanmail} = 1;
  	    }
  	}
***************
*** 8223,8229 ****
  	return undef;
      }
      
!     foreach my $email (@emails) {
  	next if ($email =~ /^\s*$/);
  
  	$email = &tools::clean_email($email);
--- 8243,8250 ----
  	return undef;
      }
      
!     foreach my $emailgecos (@emails) {
! 	my ($email,$gecos) = @$emailgecos;
  	next if ($email =~ /^\s*$/);
  
  	$email = &tools::clean_email($email);
***************
*** 8241,8246 ****
--- 8262,8268 ----
  	}
  
  	$u{'email'} = $email;
+ 	$u{'gecos'} = $gecos if($gecos);
  	$u{'date'} = time;
  	$u{'update_date'} = time;
  	$u{'id'} = join (',', split(',', $u{'id'}), $id);
***************
*** 8460,8465 ****
--- 8482,8489 ----
  
      foreach my $row (@{$array_of_users}) {
  	my $email = $row->[0]; ## only get first field
+ 	# SJS add gecos support	
+ 	my $gecos = $row->[1]; 
  	## Empty value
  	next if ($email =~ /^\s*$/);
  
***************
*** 8482,8487 ****
--- 8506,8514 ----
  	$u{'update_date'} = time;
  	$u{'id'} = join (',', split(',', $u{'id'}), $id);
  
+ 	# SJS add gecos support	
+ 	$u{'gecos'} = $gecos if($gecos);
+ 
  	$u{'visibility'} = $default_user_options->{'visibility'} if (defined $default_user_options->{'visibility'});
  	$u{'reception'} = $default_user_options->{'reception'} if (defined $default_user_options->{'reception'});
  	$u{'profile'} = $default_user_options->{'profile'} if (defined $default_user_options->{'profile'});
***************
*** 9739,9744 ****
--- 9766,9779 ----
      my @query = (@{$options->{'filter_query'} || []});
      my @clause_perl = ();
      my @clause_sql = ();
+ 
+ # SJS
+     if( $options->{'sql'} ) {
+         push @clause_sql, $options->{'sql'};
+         push @clause_perl, '1';
+     }
+ # SJS END
+ 
      while (1 < scalar @query) {
          my @expr_perl = ();
          my @expr_sql = ();
diff -c -r sympa-6.1.11/src/lib/mail.pm sympa-6.1.11.mod/src/lib/mail.pm
*** sympa-6.1.11/src/lib/mail.pm	2011-04-21 18:29:49.000000000 +1200
--- sympa-6.1.11.mod/src/lib/mail.pm	2013-11-15 16:05:03.495579368 +1300
***************
*** 185,196 ****
  
  	if (ref ($rcpt)) {
  	    if ($data->{'to'}) {
! 		$to = $data->{'to'};
  	    }else {
! 		$to = join(",\n   ", @{$rcpt});
  	    }
  	}else{
! 	    $to = $rcpt;
  	}   
  	$headers .= "To: ".MIME::EncWords::encode_mimewords(
  	    Encode::decode('utf8', $to),
--- 185,204 ----
  
  	if (ref ($rcpt)) {
  	    if ($data->{'to'}) {
! 	      my (@a) = ();
! 	      foreach ( Mail::Address->parse($data->{'to'}) ) { push @a, $_->format; }
! 	      $to = join(",\n  ",@a);
  	    }else {
! 	        my (@a) = ();
! 	        foreach my $r ( @$rcpt ) { foreach ( Mail::Address->parse($r) ) { push @a, $_->format; } }
! 	        $to = join(",\n  ",@a);
  	    }
  	}else{
! 	    # Why do it like this?  Because if $to ends up with a line >40chr
! 	    # it will not reencode correctly with encode_mimewords
! 	    my (@a) = ();
! 	    foreach ( Mail::Address->parse($rcpt) ) { push @a, $_->format; }
! 	    $to = join(",\n  ",@a);
  	}   
  	$headers .= "To: ".MIME::EncWords::encode_mimewords(
  	    Encode::decode('utf8', $to),
***************
*** 412,417 ****
--- 420,427 ----
  	my @tab =  @sendto ; push @sendtobypacket, \@tab ;# do not replace this line by push @sendtobypacket, \@sendto !!!
      }
  
+     return 0 if ($numsmtp == 0);
+ 
      return $numsmtp if (&sendto('msg_header' => $msg_header, 
  				'msg_body' => $msg_body,
  				'from' => $from,
***************
*** 558,568 ****
      if ($encrypt eq 'smime_crypted') {
          # encrypt message for each rcpt and send the message
  	# this MUST be moved to the bulk mailer. This way, merge will be applied after the SMIME encryption is applied ! This is a bug !
! 	foreach my $unique_rcpt (@{$rcpt}) {
! 	    my $email = lc(@{$unique_rcpt}[0]);
! 	    if (($email !~ /@/) || ($#{@$unique_rcpt} != 0)) {
! 		do_log('err',"incorrect call for encrypt with incorrect number of recipient"); 
! 		# internal check, if encryption is on packet should be unique and shoud contain only one rcpt 
  		return undef;
  	    }
  	    my $encrypted_msg_as_string;
--- 568,585 ----
      if ($encrypt eq 'smime_crypted') {
          # encrypt message for each rcpt and send the message
  	# this MUST be moved to the bulk mailer. This way, merge will be applied after the SMIME encryption is applied ! This is a bug !
! 
! # Adding Olaf Menkens patch to make s/mime encryption work
! #       foreach my $unique_rcpt (@{$rcpt}) {
! #           my $email = lc(@{$unique_rcpt}[0]);
! #           if (($email !~ /@/) || ($#{@$unique_rcpt} != 0)) {
! #               do_log('err',"incorrect call for encrypt with incorrect number of recipient");
! #               # internal check, if encryption is on packet should be unique and shoud contain only one rcpt
!         foreach my $rcpt_list (@{$rcpt}) {
!           foreach my $unique_rcpt (@{$rcpt_list}) {
!             my $email = lc($unique_rcpt);
!             if ($email !~ /@/) {
!                 do_log('err','Incorrect email address %s', $email);
  		return undef;
  	    }
  	    my $encrypted_msg_as_string;
***************
*** 578,583 ****
--- 595,601 ----
  			 'tag_as_last' => $tag_as_last);
  	    }
  	    $tag_as_last = 0;
+ 	  }
  	}
      }else{
  	$msg = $msg_header->as_string . "\n" . $msg_body;   
diff -c -r sympa-6.1.11/src/lib/Message.pm sympa-6.1.11.mod/src/lib/Message.pm
*** sympa-6.1.11/src/lib/Message.pm	2012-05-09 19:00:35.000000000 +1200
--- sympa-6.1.11.mod/src/lib/Message.pm	2012-09-03 13:47:46.100401177 +1200
***************
*** 158,168 ****
      my $hdr = $message->{'msg'}->head;
  
      ## Extract sender address
!     unless ($hdr->get('From')) {
! 	do_log('err', 'No From found in message %s, skipping.', $file);
! 	return undef;
!     }   
!     my @sender_hdr = Mail::Address->parse($hdr->get('From'));
      if ($#sender_hdr == -1) {
  	do_log('err', 'No valid address in From: field in %s, skipping', $file);
  	return undef;
--- 158,187 ----
      my $hdr = $message->{'msg'}->head;
  
      ## Extract sender address
!     ## SJS UOA START
!     # Use alternative methods to determine sender, not just From header
!     my @sender_hdr = ();
!     if ($hdr->get('From')) {
!       @sender_hdr = Mail::Address->parse($hdr->get('From'));
!       } elsif ($hdr->get('Envelope-From')) {
!               do_log('err', 'No From found in message %s, using Envelope-From', $file);
!               @sender_hdr = Mail::Address->parse($hdr->get('Envelope-From'));
!       } elsif ($hdr->get('X-Sender')) {
!               do_log('err', 'No From found in message %s, using X-Sender', $file);
!               @sender_hdr = Mail::Address->parse($hdr->get('X-Sender'));
!       } elsif ($hdr->get('Return-Path')) {
!               do_log('err', 'No From found in message %s, using Return-Path', $file);
!               @sender_hdr = Mail::Address->parse($hdr->get('Return-Path'));
!       } else {
!               do_log('err', 'No From found in message %s, skipping.', $file);
!               return undef;
!     }
!     ## SJS UOA END
! #    unless ($hdr->get('From')) {
! #	do_log('err', 'No From found in message %s, skipping.', $file);
! #	return undef;
! #    }   
! #    my @sender_hdr = Mail::Address->parse($hdr->get('From'));
      if ($#sender_hdr == -1) {
  	do_log('err', 'No valid address in From: field in %s, skipping', $file);
  	return undef;
diff -c -r sympa-6.1.11/src/lib/SQLSource.pm sympa-6.1.11.mod/src/lib/SQLSource.pm
*** sympa-6.1.11/src/lib/SQLSource.pm	2012-04-20 03:39:29.000000000 +1200
--- sympa-6.1.11.mod/src/lib/SQLSource.pm	2012-07-19 16:33:59.039394533 +1200
***************
*** 104,112 ****
  	    return undef;
  	}
      }
!     ## SQLite just need a db_name
!     unless ($param->{'db_type'} eq 'SQLite') {
! 	foreach my $db_param ('db_type','db_name','db_host','db_user') {
  	    unless ($param->{$db_param}) {
  		do_log('info','Missing parameter %s for DBI connection', $db_param);
  		return undef;
--- 104,121 ----
  	    return undef;
  	}
      }
!     if ($param->{'db_type'} eq 'SQLite') {
!         ## SQLite just need a db_name
!     } elsif ($param->{'db_type'} eq 'ODBC') {
!         ## ODBC just needs a db_name, db_user
! 	foreach my $db_param ('db_user','db_passwd') {
! 	    unless ($param->{$db_param}) {
! 		do_log('info','Missing parameter %s for DBI connection', $db_param);
! 		return undef;
! 	    }
! 	}
!     } else {
! 	foreach my $db_param ('db_host','db_user','db_passwd') {
  	    unless ($param->{$db_param}) {
  		do_log('info','Missing parameter %s for DBI connection', $db_param);
  		return undef;
***************
*** 138,143 ****
--- 147,155 ----
  	$connect_string = "DBI:SQLite:dbname=$param->{'db_name'}";
      }elsif ($param->{'db_type'} eq 'Informix') {
          $connect_string = "DBI:Informix:".$param->{'db_name'}."@".$param->{'db_host'}; 
+     # ODBC support
+     }elsif ($param->{'db_type'} eq 'ODBC') {
+ 	$connect_string = "DBI:ODBC:".$param->{'db_name'};
      }else {
  	$connect_string = "DBI:$param->{'db_type'}:$param->{'db_name'}:$param->{'db_host'}";
      }
diff -c -r sympa-6.1.11/src/lib/tools.pm sympa-6.1.11.mod/src/lib/tools.pm
*** sympa-6.1.11/src/lib/tools.pm	2012-04-20 03:44:07.000000000 +1200
--- sympa-6.1.11.mod/src/lib/tools.pm	2012-09-03 13:43:52.647397230 +1200
***************
*** 111,116 ****
--- 111,120 ----
      &do_log('debug3','tools::_create_xss_parser(%s)',$parameters{'robot'});
      my $hss = HTML::StripScripts::Parser->new({ Context => 'Document',
  						AllowSrc        => 1,
+ # Stop stripping hrefs!  SJS
+                                               AllowHref => 1,
+                                               AllowMailto => 1,
+ # SJS END
  						Rules => {
  						    '*' => {
  							src => '^http://'.&Conf::get_robot_conf($parameters{'robot'},'http_host'),
diff -c -r sympa-6.1.11/src/lib/tt2.pm sympa-6.1.11.mod/src/lib/tt2.pm
*** sympa-6.1.11/src/lib/tt2.pm	2010-03-30 23:10:05.000000000 +1300
--- sympa-6.1.11.mod/src/lib/tt2.pm	2013-11-15 11:48:25.953830505 +1300
***************
*** 244,250 ****
  	    encode_utf8 => [\&encode_utf8, 0]
  	    }
      };
!     
      unless($options->{'is_not_template'}){
  	$config->{'INCLUDE_PATH'} = $include_path;
      }
--- 244,257 ----
  	    encode_utf8 => [\&encode_utf8, 0]
  	    }
      };
!    
! # SJS START 
!     if($options->{'eval_perl'}) {
!         # Allow perl embedding in templates
!         $config->{'EVAL_PERL'} = 1;
!     }
! # SJS END
! 
      unless($options->{'is_not_template'}){
  	$config->{'INCLUDE_PATH'} = $include_path;
      }
diff -c -r sympa-6.1.11/wwsympa/wwsympa.fcgi.in sympa-6.1.11.mod/wwsympa/wwsympa.fcgi.in
*** sympa-6.1.11/wwsympa/wwsympa.fcgi.in	2012-05-11 21:13:29.000000000 +1200
--- sympa-6.1.11.mod/wwsympa/wwsympa.fcgi.in	2013-11-15 11:54:00.029593702 +1300
***************
*** 578,614 ****
  			   'close_list' => ['privileged_owner'],
  			   'close_list_request' => ['privileged_owner'],
  			   'copy_template' => ['listmaster'],
! 			   'd_install_shared' => ['editor'],
! 			   'd_reject_shared' => ['editor'],
! 			   'distribute' => ['editor'],
  			   'dump_scenario' => ['listmaster'],
  			   'edit_list' => ['owner'],
  			   'edit_list_request' => ['owner'],
  			   'edit_template' => ['listmaster'],
! 			   'editsubscriber' => ['owner'],
  			   'get_closed_lists' => ['listmaster'],
  			   'get_inactive_lists' => ['listmaster'],
  			   'get_latest_lists' => ['listmaster'],
  			   'get_pending_lists' => ['listmaster'],
! 			   'ignoresub' => ['owner'],
  			   'install_pending_list' => ['listmaster'],
  			   'edit_config' => ['listmaster'],
  			   'ls_templates' => ['listmaster'],
  			   'manage_template' => ['owner'],
  			   'manage_template' => ['owner'],
! 			   'modindex' => ['editor'],
  			   'purge_list' => ['privileged_owner','listmaster'],
  			   'rebuildallarc' => ['listmaster'],
  			   'rebuildarc' => ['listmaster'],
! 			   'reject' => ['editor'],
  			   'remove_template' => ['listmaster'],
  			   'rename_list' => ['privileged_owner'],
! 			   'copy_list' => ['owner'],
  			   'rename_list_request' => ['privileged_owner'],
! 			   'resetbounce' => ['owner'],
  			   'restore_list' => ['listmaster'],
  			   'review_family' => ['listmaster'],
! 			   'reviewbouncing' => ['owner'],
  			   'search_user' => ['listmaster'],
  			   'serveradmin' => ['listmaster'],
  			   'set_dumpvars' => ['listmaster'],
--- 578,614 ----
  			   'close_list' => ['privileged_owner'],
  			   'close_list_request' => ['privileged_owner'],
  			   'copy_template' => ['listmaster'],
! 			   'd_install_shared' => ['editor','owner'],
! 			   'd_reject_shared' => ['editor','owner'],
! 			   'distribute' => ['editor','owner','listmaster'],
  			   'dump_scenario' => ['listmaster'],
  			   'edit_list' => ['owner'],
  			   'edit_list_request' => ['owner'],
  			   'edit_template' => ['listmaster'],
! 			   'editsubscriber' => ['owner','editor'],
  			   'get_closed_lists' => ['listmaster'],
  			   'get_inactive_lists' => ['listmaster'],
  			   'get_latest_lists' => ['listmaster'],
  			   'get_pending_lists' => ['listmaster'],
! 			   'ignoresub' => ['owner','editor'],
  			   'install_pending_list' => ['listmaster'],
  			   'edit_config' => ['listmaster'],
  			   'ls_templates' => ['listmaster'],
  			   'manage_template' => ['owner'],
  			   'manage_template' => ['owner'],
! 			   'modindex' => ['editor','owner','listmaster'],
  			   'purge_list' => ['privileged_owner','listmaster'],
  			   'rebuildallarc' => ['listmaster'],
  			   'rebuildarc' => ['listmaster'],
! 			   'reject' => ['editor','owner','listmaster'],
  			   'remove_template' => ['listmaster'],
  			   'rename_list' => ['privileged_owner'],
! 			   'copy_list' => ['owner','listmaster'],
  			   'rename_list_request' => ['privileged_owner'],
! 			   'resetbounce' => ['owner','editor'],
  			   'restore_list' => ['listmaster'],
  			   'review_family' => ['listmaster'],
! 			   'reviewbouncing' => ['owner','editor'],
  			   'search_user' => ['listmaster'],
  			   'serveradmin' => ['listmaster'],
  			   'set_dumpvars' => ['listmaster'],
***************
*** 617,629 ****
  			   'set_session_email' => ['listmaster'],
  			   'show_sessions' => ['listmaster'],
  			   'stats' => ['owner'],
! 			   'subindex' => ['owner'],
! 			   'sync_include' => ['owner'],
  			   'skinedit' => ['listmaster'],
  			   'view_template' => ['listmaster'],
! 			   'viewbounce' => ['owner'],
  			   'viewlogs' => ['owner','editor'],
! 			   'viewmod' => ['editor'],
  			  );
  
  # this definition is used to choose the left side menu type (admin -> listowner admin menu | serveradmin -> server_admin menu | none list or your_list menu)
--- 617,629 ----
  			   'set_session_email' => ['listmaster'],
  			   'show_sessions' => ['listmaster'],
  			   'stats' => ['owner'],
! 			   'subindex' => ['owner','editor'],
! 			   'sync_include' => ['owner','editor'],
  			   'skinedit' => ['listmaster'],
  			   'view_template' => ['listmaster'],
! 			   'viewbounce' => ['owner','editor'],
  			   'viewlogs' => ['owner','editor'],
! 			   'viewmod' => ['editor','owner','listmaster'],
  			  );
  
  # this definition is used to choose the left side menu type (admin -> listowner admin menu | serveradmin -> server_admin menu | none list or your_list menu)
***************
*** 1581,1587 ****
  
  	 my $lang = &Language::Lang2Locale($param->{'lang'});
  	 my $tt2_include_path = &tools::make_tt2_include_path($robot,'web_tt2',$lang,$list);
! 	 
   	 unless (&tt2::parse_tt2($param,'rss.tt2' ,\*STDOUT, $tt2_include_path, {})) {
   	     my $error = &tt2::get_error();
   	     $param->{'tt2_error'} = $error;
--- 1581,1587 ----
  
  	 my $lang = &Language::Lang2Locale($param->{'lang'});
  	 my $tt2_include_path = &tools::make_tt2_include_path($robot,'web_tt2',$lang,$list);
! 	
   	 unless (&tt2::parse_tt2($param,'rss.tt2' ,\*STDOUT, $tt2_include_path, {})) {
   	     my $error = &tt2::get_error();
   	     $param->{'tt2_error'} = $error;
***************
*** 2323,2330 ****
  	    &do_log('err','Failed to sanitize $param in host %s', $robot);
  	}
      }
!     
!     unless (&tt2::parse_tt2($param_copy,$tt2_file , \*STDOUT, $tt2_include_path, {})) {
  	my $error = &tt2::get_error();
  	$param->{'tt2_error'} = $error;
  	$param_copy->{'tt2_error'} = $error;
--- 2323,2333 ----
  	    &do_log('err','Failed to sanitize $param in host %s', $robot);
  	}
      }
! 
! # SJS START    
! #    unless (&tt2::parse_tt2($param_copy,$tt2_file , \*STDOUT, $tt2_include_path, {})) {
!     unless (&tt2::parse_tt2($param_copy,$tt2_file , \*STDOUT, $tt2_include_path, (($wwsconf->{'use_eval_perl'})?{eval_perl=>1}:{}))) {
! # SJS END
  	my $error = &tt2::get_error();
  	$param->{'tt2_error'} = $error;
  	$param_copy->{'tt2_error'} = $error;
***************
*** 2804,2810 ****
  	 $main::action = $result->{'action'} if (ref($result) eq 'HASH');
  	 
  	 $param->{'may_subscribe'} = 1 if ($main::action =~ /do_it|owner|request_auth/);
! 	 
  	
  	 
  	 ## Archives Access control
--- 2807,2828 ----
  	 $main::action = $result->{'action'} if (ref($result) eq 'HASH');
  	 
  	 $param->{'may_subscribe'} = 1 if ($main::action =~ /do_it|owner|request_auth/);
! 	
! # SJS START 
! 	 ## May Add or del subscribers
! 	 my $result = $list->check_list_authz('add',$param->{'auth_method'},
! 					      {'sender' =>$param->{'user'}{'email'},
! 					       'remote_host' => $param->{'remote_host'},
! 					       'remote_addr' => $param->{'remote_addr'}});
! 	 $main::action = $result->{'action'} if (ref($result) eq 'HASH');
! 	 $param->{'may_add'} = 1 if ($main::action =~ /do_it/);
! 	 my $result = $list->check_list_authz('del',$param->{'auth_method'},
! 					      {'sender' =>$param->{'user'}{'email'},
! 					       'remote_host' => $param->{'remote_host'},
! 					       'remote_addr' => $param->{'remote_addr'}});
! 	 $main::action = $result->{'action'} if (ref($result) eq 'HASH');
! 	 $param->{'may_del'} = 1 if ($main::action =~ /do_it/);
! # SJS END
  	
  	 
  	 ## Archives Access control
***************
*** 3840,3847 ****
   ## The list of list
   sub do_lists {
       my @lists;
!      &wwslog('info', 'do_lists(%s,%s)', $in{'topic'}, $in{'subtopic'});
! 
       my %topics = &List::load_topics($robot);
  
       if ($in{'topic'}) {
--- 3858,3868 ----
   ## The list of list
   sub do_lists {
       my @lists;
! ## SJS patch
! #     &wwslog('info', 'do_lists(%s,%s)', $in{'topic'}, $in{'subtopic'});
!      &wwslog('info', 'do_lists(%s,%s)', $in{'topic'} ? $in{'topic'} : "", $in{'subtopic'} ? $in{'subtopic'} : "");
! ## Patch end
! 	
       my %topics = &List::load_topics($robot);
  
       if ($in{'topic'}) {
***************
*** 3855,3861 ****
  	 }
       }
  
!      my $all_lists = &List::get_lists($robot);
       foreach my $list ( @$all_lists ) {
  
  	 my $sender = $param->{'user'}{'email'} || 'nobody';
--- 3876,3888 ----
  	 }
       }
  
! # SJS START
! #     my $all_lists = &List::get_lists($robot);
!      my $all_lists = &List::get_lists($robot, ($in{'topic'}?{
!         'sql' => (" `topics_list` RLIKE '".$in{'topic'}."' ")
!      }:{}) );
! # SJS END
! 
       foreach my $list ( @$all_lists ) {
  
  	 my $sender = $param->{'user'}{'email'} || 'nobody';
***************
*** 6777,6783 ****
  
  
       ## messages
!      foreach my $id (split (/,/, $in{'id'})) {
  	 my $mail_command = sprintf ("QUIET DISTRIBUTE %s %s\n",$list->{'name'},$id);
  	 $data->{'body'} .= $mail_command;
  
--- 6804,6811 ----
  
  
       ## messages
!      foreach my $id (split (/,/, $in{'id'})) { # QUIET DISTRIBUTE
!          &do_log('notice', 'Moderator approves message: %s %s', $list->{'name'},$id);
  	 my $mail_command = sprintf ("QUIET DISTRIBUTE %s %s\n",$list->{'name'},$id);
  	 $data->{'body'} .= $mail_command;
  
***************
*** 8867,8873 ****
  
       ## Members list
       my $record = 0;
!      my $all_lists = &List::get_lists($robot);
       foreach my $list ( @$all_lists ) {
  	 my $is_admin;
  	 ## Search filter
--- 8895,8906 ----
  
       ## Members list
       my $record = 0;
! # SJS START
! #     my $all_lists = &List::get_lists($robot);
!      my $all_lists = &List::get_lists($robot, ($in{'filter'}?{
!         'sql' => (" ( `name_list` RLIKE '".$in{'filter'}."' OR `subject_list` RLIKE '".$in{'filter'}."' ) ")
!      }:{}) );
! # SJS END
       foreach my $list ( @$all_lists ) {
  	 my $is_admin;
  	 ## Search filter
