[Subversion] / DadaFork / plugins / dada_bridge.pl  

View of /DadaFork/plugins/dada_bridge.pl

Parent Directory | Revision Log
Revision: 2253 - (download)
Wed Jan 10 14:34:26 2007 UTC (17 years, 2 months ago) by pje
File size: 83606 byte(s)
Base version: DadaMail 2.10.12
#!/usr/bin/perl 
use strict;

#---------------------------------------------------------------------#
# dada_bridge.pl (No Cute Name Yet) 
# For instructions, see the pod of this file. try:
#  pod2text ./dada_bridge.pl | less
#
# Or try online: 
#  http://mojo.skazat.com/support/documentation/dada_bridge.pl.html
#
#---------------------------------------------------------------------#
# REQUIRED:
#
# You must change (below) the: 
#
# Absolute path of the, dada, dada/DADA and dada/DADA/perllib 
# directories. 
#
# The path to your Perl Libraries must be changed and include: 
# Your Site-Wide Perl Libraries
#---------------------------------------------------------------------#

use lib qw(

../
../DADA
../DADA/perllib

/home/youraccount/www/cgi-bin/dada
/home/youraccount/www/cgi-bin/dada/DADA
/home/youraccount/www/cgi-bin/dada/DADA/perllib
  

/usr/local/lib/perl5/site_perl/5.8.0/mach
/usr/local/lib/perl5/site_perl/5.8.0
/usr/local/lib/perl5/site_perl
/usr/local/lib/perl5/5.8.0/BSDPAN
/usr/local/lib/perl5/5.8.0/mach
/usr/local/lib/perl5/5.8.0

);



use CGI::Carp qw(fatalsToBrowser);
use DADA::Config qw(!:DEFAULT);
use CGI; CGI->nph(1) if $DADA::Config::NPH == 1; my $q = new CGI; 



# Usually, this doesn't need to be changed. 
# But, if you are having trouble saving settings 
# and are redirected to an 
# outside page, you may need to set this manually. 
my $Plugin_URL = $q->url; 



# How many messages does Dada Mail look at, at once? 

my $MessagesAtOnce = 1;


# This is the message sent to the List Owner, 
# telling them a message is waiting for their
# Approval! Yeah!

my $Moderation_Msg = <<EOF

The attached message needs to be moderated:

    List:    [list_name]
    From:    [message_from]
    Subject: [message_subject]

To send this message to the list, click here: 

    <[moderation_confirm_link]>
    
To deny sending this message to the list, click here: 

    <[moderation_deny_link]>

-- dada_bridge.pl

EOF
; 


my $Rejection_Message = <<EOF

Hello, 

Your recent message to [list_name] with the subject of: 

    [message_subject]
    
was rejected by the list owner. You may email the list owner at: 

    [list_owner_email]
    
for more details. 

-- dada_bridge.pl

EOF
; 



#
# There is nothing else to configure in this program. 
#---------------------------------------------------------------------#




#---------------------------------------------------------------------#

$ENV{PATH} = "/bin:/usr/bin"; 
delete @ENV{'IFS', 'CDPATH', 'ENV', 'BASH_ENV'};

my $App_Version = '0.0';

# Phowaa - let's import *a few* things
use DADA::Template::HTML;
use DADA::App::Guts; 
use DADA::Mail::Send; 
use DADA::MailingList::Subscribers; 
use DADA::MailingList::Settings; 
use DADA::Security::Password;  
use Email::Address;
use Digest::MD5 qw(md5_hex);
use Net::POP3;
use MIME::Parser;
use MIME::Entity; 
use Getopt::Long; 

# This is for the reusable DBI handle...
my $dbi_handle; 
if($DADA::Config::SUBSCRIBER_DB_TYPE =~ m/SQL/ || $DADA::Config::ARCHIVE_DB_TYPE =~ m/SQL/ || $DADA::Config::SETTINGS_DB_TYPE =~ m/SQL/){        
    require DADA::App::DBIHandle; 
    $dbi_handle = DADA::App::DBIHandle->new; 
}

$DADA::MailingList::Subscribers::dbi_obj = $dbi_handle;
$DADA::MailingList::Settings::dbi_obj    = $dbi_handle;
$DADA::Mail::Send::dbi_obj               = $dbi_handle;


my %Global_Template_Options = (
		#debug              => 1, 		
		path                => [$DADA::Config::TEMPLATES],
		die_on_bad_params   => 0,	

		Plugin_URL          => $Plugin_URL, 


		(
            ($DADA::Config::CPAN_DEBUG_SETTINGS{HTML_TEMPLATE} == 1) ? 
                (debug => 1, ) :
                ()
        ), 
        
        
);


my $parser = new MIME::Parser; 
   $parser = optimize_mime_parser($parser); 


	 
my $test; 

my $help;
my $verbose = 0;
my $debug   = 0; # not used? 
my $list;
my $run_list; 
my $check_deletions = 0; 

my $root_login = 0; 

my $checksums = {}; 

GetOptions("help"            => \$help, 
		   "test=s"          => \$test,
		   "verbose"         => \$verbose,
		   "list=s"          => \$run_list, 
		   "check_deletions" => \$check_deletions, 
		   );

main();




sub main { 
	if(!$ENV{GATEWAY_INTERFACE}){ 
		&cl_main(); 
	}else{ 
		&cgi_main(); 
	}
}


sub cgi_main {
	
	my $admin_list; 
	
	($admin_list, $root_login) = check_list_security(-cgi_obj    => $q,  
										             -Function   => 'dada_bridge',
										             -dbi_handle => $dbi_handle,
										            );
										                									                
	$list  = $admin_list; 
	
	my $ls = DADA::MailingList::Settings->new(-List => $list); 
	my $li = $ls->get(); 
								  							  
	my $flavor = $q->param('flavor') || 'cgi_default';
	
	my %Mode = ( 
	'cgi_default'  => \&cgi_default, 
	'cgi_edit'     => \&cgi_edit, 
	'test_pop3'    => \&cgi_test_pop3,
	'manual_start' => \&cgi_manual_start, 
	'mod'          => \&cgi_mod, 
	); 
	
	if(exists($Mode{$flavor})) { 
		$Mode{$flavor}->();  #call the correct subroutine 
	}else{
		&cgi_default;
	}

}




sub cgi_test_pop3 { 

	print(admin_html_header(-Title      => "POP3 Login Test",
		                    -List       => $list,
		                    -Form       => 0,
		                    -Root_Login => $root_login
		                    ));
		                    
	$run_list = $list;
	$verbose  = 1; 
	print '<pre>';
	test_pop3();
	print '</pre>';
	print '<p><a href="#" onclick="history.back();return false;">Back...</a></p>';
	
	print admin_html_footer(-Form    => 0, 
							-List    => $list,
						    );

}




sub cgi_manual_start { 

	print(admin_html_header(
							-Title      => "Manually Running Mailing...",
		                    -List       => $list,
		                    -Form       => 0,
		                    -Root_Login => $root_login
		                    ));
		                    
	$run_list        = $list;
	$verbose         = 1; 
	$check_deletions = 1; 
	print '<pre>';
	start();
	print '</pre>';
	print '<p><a href="#" onclick="history.back();return false;">Back...</a></p>';
	 
	print admin_html_footer(-Form    => 0, 
							-List    => $list,
						    ); 

}




sub cgi_mod { 

    print(admin_html_header(
							-Title      => "Moderation",
		                    -List       => $list,
		                    -Form       => 0,
		                    -Root_Login => $root_login
		                    ));
	
	
	# $list is global, for some reason...
	if($list ne $q->param('list')){ 
	    print $q->header(); 
	    print "<p>Gah. You're either logged into a different list, or not logged in at all!</p>"; 
	}
										            
    my $ls = DADA::MailingList::Settings->new(-List => $list); 
	my $li = $ls->get(); 
	
    my $mod = SimpleModeration->new({-List => $list}); 
	my $msg_id = $q->param('msg_id');     

    my $valid_msg = $mod->is_moderated_msg($msg_id); 

    if($valid_msg == 1){ 
        print "<p>Message appears to be valid and exists</p>"; 
        
    if($q->param('process') eq 'confirm'){ 
        process($list, $li, $mod->get_msg({-msg_id => $msg_id})); 
        $mod->remove_msg({-msg_id => $msg_id}); 
        print "<p>Message has been sent!</p>";
    } 
    elsif($q->param('process') eq 'deny'){ 

     
        print "<p>Message has been denied and being removed!</p>"; 
        if($li->{send_moderation_rejection_msg} == 1){ 
            print "<p>Sending rejection message!</p>"; 
            $mod->send_reject_msg({-msg_id => $msg_id, -parser => $parser, -send_out_msg => $Rejection_Message}); 

        }
        
        #gotta do this, after, since removing it will not make the send rejection message thing to work. 
        
        $mod->remove_msg({-msg_id => $msg_id}); 
           
           
    }
    else{ 
        print "<p>Invalid action - wazzah?</p>";
    }
    
    
    } else {
        print "<p>Moderated message doesn't exist - have you already moderated it?</p>"; 
    }
    
    
    

    print admin_html_footer(-Form    => 0, 
                            -List    => $list,
                            ); 

}







 
sub cgi_default { 

	require HTML::Template::Expr; 
	
	my $ls = DADA::MailingList::Settings->new(-List => $list); 
	my $li = $ls->get(); 


    my $spam_level_popup_menu = $q->popup_menu('-values' => [1..50],
                                                -default => $li->{ignore_spam_messages_with_status_of},
                                                -name    => 'ignore_spam_messages_with_status_of',
                                              ); 
    
    
	print(admin_html_header(
		                    -Title      => "Discussion List Options",
		                    -List       => $list,
		                    -Form       => 0,
		                    -Root_Login => $root_login,
		                    -li         => $li, 
		                    
		                    
		                    ));
		                    
	my $tmpl = default_cgi_template(); 	                
	my $template = HTML::Template::Expr->new(%Global_Template_Options,
											 scalarref => \$tmpl, 
											);
	
	my $can_use_set_to_header_to_list_address = 1; 
	if($li->{send_via_smtp} == 1){ 
	    $can_use_set_to_header_to_list_address = 0;
	}
	
	
	my $done      = $q->param('done') || 0; 

	 $template->param(
					 done                              => $done,
					 GOOD_JOB_MESSAGE                  => $DADA::Config::GOOD_JOB_MESSAGE, 
					 list     				           => $list,
					 list_name                         => $li->{list_name}, 
					 disable_discussion_sending        => $li->{disable_discussion_sending}, 
					 group_list                        => $li->{group_list},
					 append_list_name_to_subject       => $li->{append_list_name_to_subject},
					 add_reply_to                      => $li->{add_reply_to},
					 discussion_pop_email              => $li->{discussion_pop_email},
					 discussion_pop_server             => $li->{discussion_pop_server},
					 discussion_pop_username           => $li->{discussion_pop_username},
					 discussion_pop_password           => DADA::Security::Password::cipher_decrypt($li->{cipher_key}, $li->{discussion_pop_password}),
					
					 append_discussion_lists_with      => $li->{append_discussion_lists_with},
					 
					 no_append_list_name_to_subject_in_archives => $li->{no_append_list_name_to_subject_in_archives}, 
					 
					 list_owner_email                  => $li->{list_owner_email}, 
					 admin_email                       => $li->{admin_email}, 	
					 enable_moderation                 => $li->{enable_moderation}, 
					 send_moderation_rejection_msg     => $li->{send_moderation_rejection_msg}, 
					 send_msgs_to_list                 => $li->{send_msgs_to_list},  
					 send_msg_copy_to                  => $li->{send_msg_copy_to}, 
					 send_msg_copy_address             => $li->{send_msg_copy_address}, 
					 send_not_allowed_to_post_msg      => $li->{send_not_allowed_to_post_msg}, 
					 send_invalid_msgs_to_owner        => $li->{send_invalid_msgs_to_owner},
					 mail_discussion_message_to_poster => $li->{mail_discussion_message_to_poster}, 
					 PROGRAM_URL                       => $DADA::Config::PROGRAM_URL, 
					 archive_messages                  => $li->{archive_messages}, 
					 
					 strip_file_attachments            => $li->{strip_file_attachments}, 
					 file_attachments_to_strip         => $li->{file_attachments_to_strip}, 
					 
					 can_use_spam_assassin             => &can_use_spam_assassin(), 
					 spam_level_popup_menu             => $spam_level_popup_menu, 
					 
					 ignore_spam_messages              => $li->{ignore_spam_messages}, 
					 ignore_spam_messages_with_status_of => $li->{ignore_spam_messages_with_status_of}, 
					 
					 find_spam_assassin_score_by_calling_spamassassin_directly         => ($li->{find_spam_assassin_score_by} eq 'calling_spamassassin_directly') ? 1 : 0, 
					 find_spam_assassin_score_by_looking_for_embedded_headers          => ($li->{find_spam_assassin_score_by} eq 'looking_for_embedded_headers')  ? 1 : 0,       
					 
					 can_use_set_to_header_to_list_address => $can_use_set_to_header_to_list_address, 
					 set_to_header_to_list_address       => $li->{set_to_header_to_list_address}, 
					 
					 
					);
	                
	print $template->output();
	
	print admin_html_footer(-Form    => 0, 
							-List    => $list,
							-li      => $li, 
						    ); 
}




sub cgi_edit { 
	

	my $disable_discussion_sending        = $q->param('disable_discussion_sending')        || 0; 
	my $group_list                        = $q->param('group_list')                        || 0; 
	my $append_list_name_to_subject       = $q->param('append_list_name_to_subject')       || 0; 
	
	my $no_append_list_name_to_subject_in_archives = $q->param('no_append_list_name_to_subject_in_archives') || 0; 
	
	my $add_reply_to                      = $q->param('add_reply_to')                      || 0; 
    my $discussion_pop_email              = $q->param('discussion_pop_email')              || undef;
	my $discussion_pop_server             = $q->param('discussion_pop_server')             || undef;
	my $discussion_pop_username           = $q->param('discussion_pop_username')           || undef;
	my $discussion_pop_password           = $q->param('discussion_pop_password')           || undef;
	my $append_discussion_lists_with      = $q->param('append_discussion_lists_with')      || '';
	
	my $enable_moderation                 = $q->param('enable_moderation')                 || 0; 
	my $send_moderation_rejection_msg     = $q->param('send_moderation_rejection_msg')     || 0; 
	my $send_msgs_to_list                 = $q->param('send_msgs_to_list')                 || 0; 
	my $send_msg_copy_to                  = $q->param('send_msg_copy_to')                  || 0; 
	my $send_msg_copy_address             = $q->param('send_msg_copy_address')             || ''; 
	my $send_not_allowed_to_post_msg      = $q->param('send_not_allowed_to_post_msg')      || 0; 
	my $send_invalid_msgs_to_owner        = $q->param('send_invalid_msgs_to_owner')        || 0; 
	my $mail_discussion_message_to_poster = $q->param('mail_discussion_message_to_poster') || 0; 
	
	my $strip_file_attachments            = $q->param('strip_file_attachments')            || 0; 
	my $file_attachments_to_strip         = $q->param('file_attachments_to_strip')         || '';
	
	my $ignore_spam_messages                = $q->param('ignore_spam_messages')                || 0; 
	my $ignore_spam_messages_with_status_of = $q->param('ignore_spam_messages_with_status_of') || 0; 
	my $set_to_header_to_list_address       = $q->param('set_to_header_to_list_address')       || 0; 
	
	my $find_spam_assassin_score_by         = $q->param('find_spam_assassin_score_by')         || undef; 
	
	
	my $ls = DADA::MailingList::Settings->new(-List => $list); 

	my $li = $ls->get; 
	
	   $ls->save({
				disable_discussion_sending   => $disable_discussion_sending, 
				group_list                   => $group_list,
				append_list_name_to_subject  => $append_list_name_to_subject,
				no_append_list_name_to_subject_in_archives => $no_append_list_name_to_subject_in_archives, 
				
				add_reply_to                 => $add_reply_to,
				
				discussion_pop_email         => $discussion_pop_email,
				discussion_pop_server        => $discussion_pop_server,
				discussion_pop_username      => $discussion_pop_username,
				append_discussion_lists_with => $append_discussion_lists_with, 
				discussion_pop_password      => DADA::Security::Password::cipher_encrypt($li->{cipher_key}, $discussion_pop_password),			
				
				enable_moderation            => $enable_moderation, 
				send_moderation_rejection_msg => $send_moderation_rejection_msg, 
				
				send_msgs_to_list            => $send_msgs_to_list,  
				send_msg_copy_to             => $send_msg_copy_to, 
				send_msg_copy_address        => $send_msg_copy_address, 
	
				send_not_allowed_to_post_msg => $send_not_allowed_to_post_msg, 
				send_invalid_msgs_to_owner   => $send_invalid_msgs_to_owner, 
				
				mail_discussion_message_to_poster => $mail_discussion_message_to_poster, 
				
				strip_file_attachments            => $strip_file_attachments, 
				file_attachments_to_strip         => $file_attachments_to_strip, 
				
				
				ignore_spam_messages                 => $ignore_spam_messages, 
				ignore_spam_messages_with_status_of  => $ignore_spam_messages_with_status_of, 
				set_to_header_to_list_address        => $set_to_header_to_list_address, 
				
				find_spam_assassin_score_by          => $find_spam_assassin_score_by, 
				
				}); 
	
				print $q->redirect(-uri => $Plugin_URL . '?done=1'); 	
}




sub cl_main { 
	
	init(); 

	if($test){ 

		$verbose = 1; 
		
		if($test eq 'pop3'){ 

			test_pop3(); 	

		}else{ 

			print "I don't know what you want to test!\n\n"; 
			help(); 

		}

	}elsif($help){ 

		help();		

	}else{ 

		start(); 

	}
	
}




sub init {};




sub start { 

	my @lists; 
	
	if(!$run_list){ 

		print "Running all lists - \nTo test an individual list, pass the list shortname in the '--list' parameter...\n\n"
			if $verbose; 
		@lists = available_lists(-dbi_handle => $dbi_handle);	

	}else{ 

		$lists[0] = $run_list; 

	}

	my $messages_viewed = 0; 
	
	QUEUE: foreach my $list (@lists){ 
	
					
		if ($messages_viewed >= $MessagesAtOnce){ 
			last; 
		}
			
					
		print "\n" . '-' x 72 . "\nList: " . $list . "\n"
			if $verbose;
		
		my $ls = DADA::MailingList::Settings->new(-List => $list); 
		my $li = $ls->get(); 
		
		
		
		if($li->{discussion_pop_email} eq $li->{list_owner_email}){ 
			print "\t\t***Warning!*** Misconfiguration of plugin! The list owner email cannot be the same address as the list email address!\n\t\tSkipping $list...\n"
				if $verbose; 
			next; 
		}
		
		
		next if ! valid_login_information($list);
		
		my $pop = pop3_login(
							$list, 
							$li, 
							$li->{discussion_pop_server}, 
							$li->{discussion_pop_username}, 
							$li->{discussion_pop_password},
		); 
		
		if($pop){  
			my $msgnums = $pop->list; # hashref of msgnum => size
			
			my $local_msg_viewed = 0; 
			
			foreach my $msgnum (keys %$msgnums) {
			
			    $local_msg_viewed++;
			    
				if ($li->{disable_discussion_sending} != 1){     
				
					
				
					my $msg = $pop->get($msgnum);
					my $full_msg;  
					$full_msg .= $_ foreach(@$msg);
					
					push(@{$checksums->{$list}}, create_checksum(\$full_msg));  
					
					my ($status, $errors) = validate_msg($list, $full_msg, $li);
					if($status){  
						
						process($list, $li, $full_msg); 
						
					}else{  
						print "\tMessage did not pass verification - handling issues...\n"
							if $verbose; 
						handle_errors($list, $errors, $full_msg, $li);  
					}                
				}else{  
					print "\tThis sending method has been disabled for $list, deleting message... \n" 
						if $verbose;
				}
				
				$messages_viewed++; 
				
				if ($messages_viewed >= $MessagesAtOnce){ 
						print "\n\nThe limit has been reached of the amount of messages to be looked at for this execution\n\n"
							if $verbose;
						last; 
				}
					
					
			}
			
			my $delete_msg_count = 0; 

			foreach my $msgnum_d (keys %$msgnums) {  
				print "\tremoving message from server...\n"
					 if $verbose;
				$pop->delete($msgnum_d);  
				$delete_msg_count++; 
				
				
				last
					if $delete_msg_count >= $local_msg_viewed;
				
			} 
			print "\tdisconnecting from POP3 server\n" 
				if $verbose;
			
			$pop->quit(); 
			
			if($check_deletions){
				if(keys %$msgnums){ 	
					message_was_deleted_check($list, $li); 
				}else{ 
					print "\tNo messages received, skipping deletion check.\n" 
						if $verbose;
				}	
			}
		}else{ 
			print "\tPOP3 connection failed!\n" 
				if $verbose; 
		}
	}	
}




sub message_was_deleted_check() { 
	
	print "\n\tWaiting 5 seconds before removal check...\n"
		if $verbose; 
		
	sleep(5); 
	
	my $list = shift;
	my $li   = shift; 
	
	#my $ls   = DADA::MailingList::Settings->new(-List => $list); 
	#my $li   = $ls->get(); 
			
	my $pop = pop3_login(
						$list, 
						$li, 
						$li->{discussion_pop_server},  
						$li->{discussion_pop_username}, 
						$li->{discussion_pop_password},
						);
	if($pop){  
		my $msgnums = $pop->list; # hashref of msgnum => size
		foreach my $msgnum (keys %$msgnums) {
			my $msg = $pop->get($msgnum);
			my $full_msg;  
			$full_msg .= $_ foreach(@$msg);
			
			my $cs = create_checksum(\$full_msg); 
			
			print "\t\tcs:             $cs\n" 
				if $verbose; 
			
			my @cs = @{$checksums->{$list}}; 

				
				
			foreach my $s_cs(@cs){ 
			
				print "\t\tsaved checksum: $s_cs\n"
						if $verbose; 
						
				if($cs eq $s_cs){ 
					print "\t\tMessage was NOT deleted from POP server! Will attempt to do that now...\n"
						if $verbose; 
					$pop->delete($msgnum);
				} else { 
					print "\t\tMessage checksum does not match saved checksum, keeping message for later delivery...\n"
						if $verbose; 							 
				}
			}
		}	
		$pop->quit(); 
	}else{ 
		print "POP3 login failed.\n";
	}
}




sub help { 

	print "This is where the help should be, but it's not here.\n\n";
}




sub test_pop3 { 

    my $li = shift || undef; 
    
	
	my @lists; 
	
	if(!$run_list){ 
		print "Testing all lists - \nTo test an individual list, pass the list shortname in the '--list' parameter...\n\n"; 
		@lists = available_lists(-dbi_handle => $dbi_handle);
	}else{ 
		push(@lists, $run_list); 
	}

	foreach my $l(@lists){
		
		print "\n" . '-' x 72 . "\nTesting List: '" . $l . "'\n";
		
		unless(check_if_list_exists(-List => $l, -dbi_handle => $dbi_handle)){ 
			print "'$l' does not exist! - skipping\n";
			next;
		}
		
		if(!$li){ 
		    my $ls  = DADA::MailingList::Settings->new(-List => $l); 
		       $li  = $ls->get();
		}
		
		if($li->{disable_discussion_sending} == 1){ 
			print "'$l' has this feature disabled - skipping.\n";
		}else{
		
			my $pop = pop3_login($l,
			                     $li, 
								 $li->{discussion_pop_server}, 
								 $li->{discussion_pop_username}, 
								 $li->{discussion_pop_password},
								);
		 	if($pop){
		 		$pop->quit();
			   print "\tLogging off of the POP Server.\n";
			}
		}	
	}
	print "\n\nPOP3 Login Test Complete.\n\n";
}


sub pop3_login { 

	my ($l, $li, $server, $username, $password) = @_;
	
	#my $ls = DADA::MailingList::Settings->new(-List => $l); 
	#my $li = $ls->get(); 

	$password = DADA::Security::Password::cipher_decrypt($li->{cipher_key}, $password);
	
	if(!valid_login_information($l)){ 
			print "Some POP3 Login Information is missing - please double check! (aborting login attempt)\n"
				if $verbose;
			return undef; 
	}else{
	
		print "\tLogging into POP3 server: $server\n"
			if $verbose; 
			
		my $pop = Net::POP3->new($server,
		                            (
                                    ($DADA::Config::CPAN_DEBUG_SETTINGS{NET_POP3} == 1) ? 
                                        (Debug => 1, ) :
                                        ()
                                    ),
                                ) or warn "\tConnection to '$server' wasn't successful: $!";
		
		if(!$pop){ 
			print "\tCouldn't estabilish a connection to $server!\n"
				if $verbose;
		}else{	
			my $messagecount;
			
			eval {require Digest::MD5};
			if(!$@){ 
				print "\tTrying secure login...\n"
					if $verbose;
				$messagecount = $pop->apop($username,$password);			
				if(!$messagecount){ 
					print "\tHmm, secure login failed, switching to regular login...\n"
						if $verbose;
					 $pop = Net::POP3->new($server,
				                            (
                                                ($DADA::Config::CPAN_DEBUG_SETTINGS{NET_POP3} == 1) ? 
                                                    (Debug => 1, ) :
                                                    ()
                                            ),
					 
					 ) or warn "\tConnection to '$server' wasn't successful: $!";				
					$messagecount = $pop->login($username,$password);
				}
			}else{ 
				$messagecount = $pop->login($username,$password);
			}	
			
			if(($messagecount ne '') && ($messagecount >= 0)){ 
				print "\tPOP3 Login succeeded.\n"
					if $verbose; 
				print "\tPOP3 Server says: " . $pop->banner 
					if $verbose; 
				print "\n\tMessage count: $messagecount\n"
					if $verbose; 
			}else{ 
				print "\tPOP3 login failed.\n"
					if $verbose; 
			}
		}

		return undef if !$pop;
		return $pop; 	
	}
}




sub valid_login_information { 

	my $list = shift; 
	
	my $ls = DADA::MailingList::Settings->new(-List => $list); 
	my $li = $ls->get(); 
	
	return 0 if ! $li->{discussion_pop_server};
	return 0 if ! $li->{discussion_pop_username};
	return 0 if ! $li->{discussion_pop_email};
	return 0 if ! $li->{discussion_pop_password};
	return 1; 
}




sub validate_msg { 

	my $list   = shift; 
	my $msg    = shift;
	my $li     = shift; 
	
	
	my $status = 1; 
	my $errors = {msg_not_from_list_owner => 0, msg_from_list_address => 0}; 
	

	#my $ls = DADA::MailingList::Settings->new(   -List => $list); 
	my $lh = DADA::MailingList::Subscribers->new(-List => $list); 
	#my $li = $ls->get; 
	
	
	if($li->{discussion_pop_email} eq $li->{list_owner_email}){ 
		print "\t\t***Warning!*** Misconfiguration of plugin! The list owner email cannot be the same address as the list email address!\n"
			if $verbose; 
		$errors->{list_email_address_is_list_owner_address} = 1;
	}
	
	my $entity; 
	
	eval { $entity = $parser->parse_data($msg) };
	
	if(!$entity){
		print "\t\tMessage invalid! - no entity found.\n" if $verbose;  
		$errors->{invalid_msg} = 1;
		return (0, $errors); 
	}
	
	if($entity->head->count('X-BeenThere')){ 
	    my $x_been_there_header = $entity->head->get('X-BeenThere', 0);
	    chomp($x_been_there_header);
	    
	    if($x_been_there_header eq $li->{discussion_pop_email}){ 
	        print "\t\tMessage is from myself (the, X-BeenThere header has been set), message should be ignored...\n"
	            if $verbose;
	        $errors->{x_been_there_header_found} = 1;
	    } else { 
	        $errors->{x_been_there_header_found} = 0; 
        }	     

	}
	
	my $rough_from = $entity->head->get('From', 0); 
	my $from_address = '';

	if (defined($rough_from)){; 
		eval { $from_address = (Email::Address->parse($rough_from))[0]->address; }
	}
	
	print '\t\tWarning! Something\'s wrong with the From address - ' . $@ 
		if $@ && $verbose;
		
	$from_address = lc_email($from_address); 
	
	print "\t\tMessage is from: '" . $from_address . "'\n"
		if $verbose; 
	
	if($from_address eq $li->{list_owner_email}){ 
		print "\t\t * From: address is the list owner address ; (". $li->{list_owner_email} .')' . "\n"
			if $verbose;
	}else{ 
	
		print "\t\t * From address is NOT from list owner address\n"
			if $verbose;
		$errors->{msg_not_from_list_owner} = 1; 
		
		if($li->{enable_moderation}){ 
			print "\t\tModeration enabled...\n"
				if $verbose; 
		
			#my ($m_status, $m_errors) = $lh->subscription_check(-Email => $from_address, 
			#													-Type  => 'moderators',
			#												   );
			#if($m_errors->{subscribed} != 1){ 												   
			#	
			#	$errors->{msg_not_from_moderator} = 1;
			#	print "\t\t*Message is NOT from a moderator.\n"
			#		if $verbose; 
			#}else{ 
			#	
			#	print "\t\t*Message *is* from a moderator!\n"
			#		if $verbose; 
			#	$errors->{msg_not_from_list_owner} = 0
			#		if $errors->{msg_not_from_list_owner} == 1; 
			#}
			
			if($errors->{msg_not_from_list_owner} == 1){ 
			
			    print "\t\tMessage is not from list owner.\n"
			        if $verbose;
			        $errors->{needs_moderation} = 1; 
			}
							
		}else{ 
			print "\t\tModeration disabled...\n"
				if $verbose; 
		}
		
			
		if($li->{group_list} == 1){
		
			print "\t\tDiscussion Support enabled...\n"
				if $verbose; 
				
			#if($li->{enable_moderation} && $errors->{msg_not_from_moderator} == 0){ 
			#
			#	print "\t\tSubscription checked skipped - moderation enabled and address passed validation.\n"
			#	    if $verbose; 
				
			#}else{ 
			
				my ($s_status, $s_errors) = $lh->subscription_check(-Email => $from_address);
			
				if ($s_errors->{subscribed} != 1){ 
					$errors->{msg_not_from_subscriber} = 1;
					print "\t\t*Message is NOT from a subscriber.\n"
						if $verbose; 
				}else{ 
					print "\t\t*Message *is* from a current subscriber.\n"
						if $verbose; 
					#$errors->{msg_not_from_moderator}  = 0; 
					$errors->{msg_not_from_list_owner} = 0; 			
				}
			#}
			
		}else{ 
			print "\t\tDiscussion Support disabled...\n"
			    if $verbose; 
		}
	}

 
    if ($li->{ignore_spam_messages} == 1){ 
        print "\n\t\tSpamAssassin check enabled...\n\n"
            if $verbose;

        if($li->{find_spam_assassin_score_by} eq 'calling_spamassassin_directly'){ 
        
            print "\t\tLoading SpamAssassin directly...\n"
                if $verbose;
        
            eval { require Mail::SpamAssassin; }; 
            if(!$@){ 
                    
                if($Mail::SpamAssassin::VERSION <= 2.60 && $Mail::SpamAssassin::VERSION >= 2){ 
                    require Mail::SpamAssassin::NoMailAudit; 
                    
                    # this needs to be optimized...
                    my $spam_check_message = $entity->as_string; 
                    my @spam_check_message = split("\n", $spam_check_message); 
                  
                    my $mail = Mail::SpamAssassin::NoMailAudit->new(data => \@spam_check_message);
                      
                    my $spamtest = Mail::SpamAssassin->new({debug => 'all', local_tests_only => 1, dont_copy_prefs => 1, });
                  
                    my $score; 
                    my $report;
                    
                    if($spamtest){ 
                        my $spam_status;
                          
                       # $spam_status = $spamtest->check()
                        #$spam_status   = $spamtest->parse($entity->as_string, 0);
                        
                        $spam_status = $spamtest->check($mail);
                          
                        if($spam_status){ 
                            $score  = $spam_status->get_hits();
                            $report = $spam_status->get_report();
                        }
                        
                    }
            
                   #  print $entity->as_string;
    
            
                    if($score eq undef && $score != 0){ 
                        print "\t\t\tTrouble parsing scoring information - letting message pass...\n"; 
                  
                    } else { 
                        
                        if($score >= $li->{ignore_spam_messages_with_status_of}){
                            print "\t\t\t Message has *failed* Spam Test (Score of: $score, " . $li->{ignore_spam_messages_with_status_of} . " needed.) - ignoring message.\n"
                                if $verbose;
                            
                            $errors->{message_seen_as_spam} = 1;
                            
                            
                            
                            print "\n" . $report
                                if $verbose; 
                            
                        }else{ 
                            $errors->{message_seen_as_spam} = 0;
                            
                            print "\t\t\t Message passed! Spam Test (Score of: $score, " . $li->{ignore_spam_messages_with_status_of} . " needed.)\n"
                                if $verbose;
                        }
                    
                    }
                    
                    undef $mail;
                    undef $spamtest;
                    undef $score;
                    undef $report; 
                
                }else{ 
                    print "\t\tSpamAssassin 2.60 and below is currently only supported, you have version $Mail::SpamAssassin::VERSION, skipping test\n"
                        if $verbose;
                }
                
            } else { 
                print "\t\tSpamAssassin doesn't seem to be available. Skipping test.\n"
                    if $verbose;
            }
            

        } elsif($li->{find_spam_assassin_score_by} eq 'looking_for_embedded_headers'){ 
        
            print "\t\tLooking for embedding SpamAssassin Headers...\n"
                if $verbose;
           
           
           my $score = undef; 
           if($entity->head->count('X-Spam-Status')){
               
               my @x_spam_status_fields = split(' ', $entity->head->get('X-Spam-Status', 0)); 
               foreach(@x_spam_status_fields){ 
                   if($_ =~ m/score\=/){ 
                          $score = $_; 
                          $score =~ s/score\=//; 
                          
                          print "\t\tFound them...\n"
                            if $verbose;
                          
                       last; 
                    
                    }
               }
           }
           
           if($score eq undef && $score != 0){ 
                    
                print "\t\t\tTrouble parsing scoring information - letting message pass...\n"; 
              
            } else { 
                
                if($score >= $li->{ignore_spam_messages_with_status_of}){
                    print "\t\t\t Message has *failed* Spam Test (Score of: $score, " . $li->{ignore_spam_messages_with_status_of} . " needed.) - ignoring message.\n"
                        if $verbose;
                    
                    $errors->{message_seen_as_spam} = 1;
                    
                    if($verbose){   
                        my @x_spam_report = $entity->head->get('X-Spam-Report');
                        print "\n\t";
                        print "$_\n" foreach @x_spam_report;
                    }
                    
                   
                }else{ 
                    $errors->{message_seen_as_spam} = 0;
                    
                    print "\t\t\t Message passed! Spam Test (Score of: $score, " . $li->{ignore_spam_messages_with_status_of} . " needed.)\n"
                        if $verbose;
                }
            
            }
       } else { 
       
            print "\t\t\tDon't know how to find the SpamAssassin score, sorry!\n"
                if $verbose; 
       
       }
            
   } else{ 
        print "\n\t\tSpamAssassin check disabled...\n"
            if $verbose; 
   }

    print "\n"
        if $verbose;
    
    

    # This below probably can't happen anymore...
	if ($li->{discussion_pop_email} eq $from_address){ 
		$errors->{msg_from_list_address} = 1;
		print "\t\t *WARNING!* Message is from the List Address. That's bad.\n"
			if $verbose; 
	}	 
		
    foreach(keys %$errors){
        if($errors->{$_} == 1){ 
            #print $_ . ' => ' . $errors->{$_} . "\n"; 
            $status = 0 ;
            last;
        }
    }	
    
	return ($status, $errors); 
}




sub process { 

	my $list     = shift; 
	my $li       = shift; 
	my $full_msg = shift; 
	
	print "\n\t\tProcessing Message...\n" 
		if $verbose; 
		
	if($li->{send_msgs_to_list} == 1){ 
	
		my $n_full_msg = dm_format($li->{list}, $full_msg, $li);
					
		print "\t\tMessage being delivered! \n"
			if $verbose; 
		
		my ($msg_id, $saved_message) = deliver($list, $n_full_msg);
		archive($list, $li, $n_full_msg, $msg_id, $saved_message);  
	
	}
	
	if($li->{send_msg_copy_to} && $li->{send_msg_copy_address}){ 
		print "\t\t Sending a copy of the message to: " . $li->{send_msg_copy_address}  . "\n"
			if $verbose; 
			
		deliver_copy($li->{list}, $full_msg); 
	}
	
	print "\t\tFinished Processing Message.\n\n"
		if $verbose; 
						
}




sub dm_format { 
	
	my $list       = shift; 
	my $msg        = shift; 
	my $li         = shift; 
	
	if($li->{strip_file_attachments} == 1){ 
		$msg = strip_file_attachments($msg, $li);
	}
	
	require DADA::App::FormatMessages; 
	
	my $fm = DADA::App::FormatMessages->new(-List => $list); 
	   $fm->treat_as_discussion_msg(1); 
	
	my ($header_str, $body_str) = $fm->format_headers_and_body(-msg => $msg);
	
	return $header_str . "\n\n" . $body_str; 
	
}




sub strip_file_attachments { 

	my $msg = shift; 
	my $li  = shift; 
	
		my $entity; 
	
	
	eval { $entity = $parser->parse_data($msg) };
	if(!$entity){
		die "no entity found! die'ing!";   
	}
	
	print "\t\t\tStripping banned file attachments...\n\n"
		if $verbose; 
	
	($entity, $li) = process_stripping_file_attachments($entity, $li); 
	
	#$entity->make_singlepart(); 
	
	return $entity->as_string; 


}




sub process_stripping_file_attachments { 

	my $entity = shift; 
	my $li     = shift; 
	
	my @att_bl = split(' ', $li->{file_attachments_to_strip}); 
	my $lt = {};
	
	foreach(@att_bl){ 
		
		$lt->{$_} = lc($lt->{$_}); 
		$lt->{$_} = 1; 
	}

	my @parts  = $entity->parts; 

	if(@parts){
	
		# multipart... 
		my $i;
		foreach $i (0 .. $#parts) {       			
			($parts[$i], $li) = process_stripping_file_attachments($parts[$i], $li);
			
	
		}
		
		my @new_parts; 
		
		foreach $i (0 .. $#parts) { 
			if(!$parts[$i]){

			}else{ 
			
				push(@new_parts, $parts[$i]); 
			}
		}
			
		$entity->parts(\@new_parts); 	
		
		
		
		
		$entity->sync_headers('Length'      =>  'COMPUTE',
							  'Nonstandard' =>  'ERASE');
		

		return ($entity, $li); 

			  
	}else{ 		
			
			my $name = $entity->head->mime_attr("content-type.name") || 
			   $entity->head->mime_attr("content-disposition.filename");
			   
			   my $f_ending = $name; 
			   
			      $f_ending =~ s/(.*)\.//g;
						      
			if($lt->{lc($entity->head->mime_type)} == 1 || $lt->{lc($f_ending)} == 1){ 
			
				print "\t\t\t * Stripping attachment with:\n\t\t\t\tname: $name and mime-type:\n\t\t\t\t" . $entity->head->mime_type . "\n";
				return (undef, $li);
			}
			
			$entity->sync_headers('Length'      =>  'COMPUTE',
					      		'Nonstandard' =>  'ERASE');
			return ($entity, $li); 
	}

	return ($entity, $li); 
}




sub deliver_copy { 

	print "Delivering Copy...\n"
		if $verbose; 
		
	my $list = shift;
	my $msg  = shift; 
	
	my $ls = DADA::MailingList::Settings->new(-List => $list); 
	my $li = $ls->get; 
	my $mh = DADA::Mail::Send->new($li);
	
	my $entity; 
	 
	eval { $entity = $parser->parse_data($msg) };
	
	if(!$entity){
		print "\t\tMessage sucks!\n" 
			if $verbose; 
	
	}else{

		my %headers =  $mh->return_headers($entity->stringify_header);
	       $headers{To} = $li->{send_msg_copy_address};
		   
		if($verbose){ 
			print "\tMessage Details: \n\t" . '-' x 50 . "\n"; 
			print "\tSubject: " .  $headers{Subject} . "\n";
		}
		
		my $msg_id = $mh->send(
							  %headers,
						      # Trust me on these :) 
							  Body => $entity->stringify_body,
				
				             );
		
	}
	
}




sub deliver { 

	my $list = shift;
	my $msg  = shift; 
	
	my $ls = DADA::MailingList::Settings->new(-List => $list); 
	my $li = $ls->get; 
	my $mh = DADA::Mail::Send->new($li);
	
	my $entity; 
	 
	eval { $entity = $parser->parse_data($msg) };
	
	if(!$entity){
		print "\t\tMessage sucks!\n" 
			if $verbose; 
	
	}else{
	
		my %headers     =  $mh->return_headers($entity->stringify_header);
	       $headers{To} = $li->{list_owner_email};
		
		if($verbose){ 
			print "\tMessage Details: \n\t" . '-' x 50 . "\n"; 
			print "\tSubject: " .  $headers{Subject} . "\n";
		}
		
		if($li->{group_list} == 1 && $li->{mail_discussion_message_to_poster} != 1){ 
		
			my $f_a; 
	
			if (defined($headers{From})){
				
				eval { $f_a = (Email::Address->parse($headers{From}))[0]->address; }
			}	

			if(!$@){ 
				print "\tGoing to skip sending original poster ($f_a) a copy of their own  message...\n"
					if $verbose; 
				$mh->do_not_send_to([$f_a]);
			}else{ 
				print "Problems not sending copy to original sender: $@\n\n" 
					if $verbose; 
			}
		}

		my $msg_id = $mh->bulk_send(
								%headers,
								  # Trust me on these :) 
								 Body => $entity->stringify_body,
				
				 );

		return ($msg_id, $mh->saved_message); 

	}
	
}




sub archive {
	
	my $list      = shift; 
	my $li        = shift; 
	my $full_msg  = shift; 
	my $msg_id    = shift; 
	my $saved_msg = shift; 
	


	
	#my $ls = DADA::MailingList::Settings->new(-List => $list); 	
	#my $li = $ls->get; 
	
	
	if ($li->{archive_messages} == 1){ 
		
		require DADA::MailingList::Archives; 
        $DADA::MailingList::Archives::dbi_obj = $dbi_handle;
        
		my $la = DADA::MailingList::Archives->new(-List => $li); 
		
		my $entity;  
		
		eval { $entity = $parser->parse_data($full_msg) };
			
		if($entity){
		
			my $Subject = $entity->head->get('Subject', 0);
			   $Subject = $la->strip_subjects_appended_list_name($Subject)
			   	if $li->{no_append_list_name_to_subject_in_archives} == 1; 
			   	
           eval { 

                $la->set_archive_info(
                                  $msg_id, 
                                  $Subject, 
                                  undef, 
                                  undef,
                                  $saved_msg, 
                                 );
		  }; 
		  
		  if($@){ 
		      warn "$DADA::Config::PROGRAM_NAME $DADA::Config::VER warning! message did not archive correctly!: $@"; 
		  }
		}else{ 
			warn "Problem archiving message..."; 
		}
	
	}	
}




sub send_msg_not_from_subscriber { 

	my $list   = shift; 
	my $msg    = shift; 
	my $entity = $parser->parse_data($msg);
	
	
	
	my $rough_from = $entity->head->get('From', 0); 
	my $from_address;
	 	if (defined($rough_from)){; 
	
			eval { $from_address = (Email::Address->parse($rough_from))[0]->address; }
	
		}

	if($from_address && $from_address ne ''){ 
	
	
		my $ls = DADA::MailingList::Settings->new(-List => $list); 
		my $li = $ls->get; 
		
		
		my $mh = DADA::Mail::Send->new($li); 
		
		my $reply = MIME::Entity->build(Type 	=> "multipart/mixed", 
										From    => $li->{list_owner_email},
										To      => $from_address, 
										Subject => "DADA::Config::$DADA::Config::PROGRAM_NAME Error - Not Allowed to Post On " . $li->{list_name} . " (original message attached)", 									
										);
										
		$reply->attach(Type => 'text/plain', 
					  Data  => $li->{not_allowed_to_post_message}
					  ); 
					
		$reply->attach( Type        => 'message/rfc822', 
						Disposition  => "attachment",
						Data         => $entity->as_string,
						); 
		
		
		require DADA::App::FormatMessages; 
	
		my $fm = DADA::App::FormatMessages->new(-List => $list); 
		   #$fm->treat_as_discussion_msg(1); 
			$fm->use_email_templates(0); 
		my ($header_str, $body_str) = $fm->format_headers_and_body(-msg => $reply->as_string);
		
	
		$mh->send(
					$mh->return_headers($header_str),
					Body => $body_str,
				); 
	}else{ 
		warn "Problem with send_msg_not_from_subscriber!";
	}

}





sub send_invalid_msgs_to_owner { 
	
	my $li     = shift; 
	my $list   = shift; 
	my $msg    = shift; 
	my $entity = $parser->parse_data($msg);
	
	
	
	my $rough_from = $entity->head->get('From', 0); 
	my $from_address;
	 	if (defined($rough_from)){; 
	
			eval { $from_address = (Email::Address->parse($rough_from))[0]->address; }
	
		}

	if($from_address && $from_address ne ''){ 

		my $mh = DADA::Mail::Send->new($li); 
		
		my $reply = MIME::Entity->build(Type 	=> "multipart/mixed", 
										From    => $li->{list_owner_email},
										To      => $li->{list_owner_email},
										Subject => "$DADA::Config::PROGRAM_NAME Error - $from_address Not Allowed to Post On " . $li->{list_name} . " (original message attached)", 									
										);
										
		$reply->attach(Type => 'text/plain', 
					  Data  => 'The attached message was not sent from one of the subscribers of ' . $li->{list_name}, 
					  ); 
					  
					
		$reply->attach( Type        => 'message/rfc822', 
						Disposition  => "attachment",
						Data         => $entity->as_string,
						); 
						
		$mh->send(
					$mh->return_headers($reply->stringify_header),
					Body => $reply->stringify_body
				); 
	}else{ 
		warn "Problem with send_invalid_msgs_to_owner!";
	}

}




sub handle_errors { 

	my $list     = shift; 
	my $errors   = shift; 
	my $full_msg = shift; 
	my $li       = shift; 


	my $entity; 
	eval { $entity = $parser->parse_data($full_msg) };
	if(!$entity){
		die "no entity found! die'ing!";   
	}
	
	my $reasons = '';
	foreach(keys %$errors){ 
	    $reasons .=  $_ . ', ' 
	        if $errors->{$_} == 1; 
	}
	my $subject     = $entity->head->get('Subject', 0); 
	   $subject =~ s/\n//g; 
	my $from        = $entity->head->get('From', 0);
	   $from =~ s/\n//g;
	my $message_id  = $entity->head->get('Message-Id', 0);
       $message_id =~ s/\n//g; 
    warn "dada_bridge.pl rejecting sending of received message - \tFrom: $from\tSubject: $subject\tMessage-ID: $message_id\tReasons: $reasons";	
	
	
	print "\t\tError delivering message! Reasons:\n\n"
		if $verbose; 
	foreach(keys %$errors){ 
		print "\t\t\t" . $_ . "\n" 
			if $errors->{$_} == 1 &&$verbose;
	}
	
	
	
	
	
	if($errors->{message_seen_as_spam} == 1){ 
	
	    print "\n\n\t\t *** Message seen as SPAM - ignoring. ***\n\n"
	        if $verbose;
	
	}
	
	elsif($errors->{msg_not_from_subscriber} == 1 || $errors->{msg_not_from_list_owner} == 1 || $errors->{msg_not_from_moderator} == 1){ 
            
        if($li->{send_not_allowed_to_post_msg} == 1){ 
        
            print "\t\tmsg_not_from_subscriber on its way! \n\n"
                if $verbose; 
            send_msg_not_from_subscriber($list, $full_msg); 
        
        }
        
        if($li->{send_invalid_msgs_to_owner} == 1){ 
            print "\t\tinvalid_msgs_to_owner on its way! \n\n"
                if $verbose; 
            send_invalid_msgs_to_owner($li, $list, $full_msg); 
        
        }
        
        
        if($errors->{msg_from_list_address}){ 
            warn "$DADA::Config::PROGRAM_NAME Error: message was from the list address - will not process! - (ignoring)";
        }  			

    } 
    elsif($errors->{needs_moderation}){ 
	    
	    print "\t\Message being saved for moderation by list owner... \n\n"
	        if $verbose; 
	    
	    my $mod = SimpleModeration->new({-List => $list}); 
	       $mod->save_msg({-msg => $full_msg, -msg_id => $message_id});     
	       
	       $mod->alert_list_owner({-msg => $full_msg, -msg_id => $message_id, -subject => $subject, -from => $from, -parser => $parser, -send_out_msg => $Moderation_Msg}); 
	       my $awaiting_msgs = $mod->awaiting_msgs(); 
	       
	       print "\t\tOther awaiting messages:\n\n"
	        if $verbose; 
	        
	        foreach(@$awaiting_msgs){ 
	            print "\t\t * " . $_ . "\n"
	                if $verbose; 
	       }
	}


}




sub create_checksum { 
 
	my $data = shift; 
	
	if($] >= 5.008){
		require Encode;
		my $cs = md5_hex(Encode::encode_utf8($$data));
		return $cs;
	}else{ 			
		my $cs = md5_hex($$data);
		return $cs;
	}
} 




#=cut

sub can_use_spam_assassin { 

    eval { require Mail::SpamAssassin; }; 
    
    if(!$@){ 
        return 1; 
    }else{ 
        return 0; 
    }
    
}

#=cut






sub default_cgi_template {


my $sf = submit_form();  

return  q{ 

<!--tmpl_if done -->
	<!-- tmpl_var GOOD_JOB_MESSAGE  -->
<!--/tmpl_if-->

<form name="default_form" action="<!-- tmpl_var Plugin_URL --> "method="post">


<fieldset> 
 <legend> 
General
</legend> 


 <table width="100%" cellspacing="0" cellpadding="5">
  <tr align="left">
   <td align="right">
    <input name="disable_discussion_sending" id="disable_discussion_sending" type="checkbox" value="1" <!--tmpl_if disable_discussion_sending -->checked="checked"<!--/tmpl_if--> />
   </td>
   <td>
    <p>
     <label for="disable_discussion_sending">
      Disable sending using this method
     </label>
    </p>
   </td>
  </tr>
  <tr align="left"> 
   <td align="right"> 
    <input name="enable_moderation" id="enable_moderation" type="checkbox" value="1" <!--tmpl_if enable_moderation -->checked="checked"<!--/tmpl_if--> /> 
   </td>
   <td>
    <p>
     <label for="enable_moderation">
      Use Moderation
     </label>
     <br /> 
     
          Messages sent to your discussion list will have to be approved by the List Owner. 
      </p>
      
     
     <table  cellspacing="0" cellpadding="5">
      <tr>
       <td>
        <input name="send_moderation_rejection_msg" id="send_moderation_rejection_msg" type="checkbox" value="1" <!--tmpl_if send_moderation_rejection_msg -->checked="checked"<!--/tmpl_if--> />
       </td>
       <td>
        <p>
         <label for="send_moderation_rejection_msg">
          Send a Rejection Message
         </label><br /> 
         The original poster will receive a message stating that the message was rejected.
        </p>
       </td>
      </tr>
    </table> 
    

     
     <!-- 
     Moderators may post to announce-only lists and discussions lists without being on the subscription list themselves. Once enabled, you may 
     add moderators using the 
     
     <!-- tmpl_if enable_moderation --> 
      <a href="<!-- tmpl_var PROGRAM_URL -->?f=view_list&type=moderators">
     <!--/tmpl_if-->
     
     View/Add list administration screens.
     <!-- tmpl_if enable_moderation --> 
      </a>
     <!--/tmpl_if-->
     
     

     <!-- Moderators will only receive a copy of list messages they themselves post.  --> 
    
    --> 
    
    </p>
    <!--
    <p>Currently, moderators cannot accept/reject posts from other users of the list.</p>
    --> 
    
   </td>
  </tr>
 </table> 
</fieldset> 

<fieldset> 
 <legend> 
 Discussion List Options
 </legend> 


 <table width="100%" cellspacing="0" cellpadding="5">
  <tr> 
   <td align="right">
    <input name="group_list" id="group_list" type="checkbox" value="1" <!--tmpl_if group_list -->checked="checked"<!--/tmpl_if--> /> 
   </td>
   <td>
    <p>
     <label for="group_list">
      Make this list a discussion list
     </label>
     <br />
     Everyone subscribed to your list may send messages to everyone else 
     on your list by posting  messages to the <strong>List Email</strong>
     (below).
    </p>
  
  
  	 <table width="100%" cellspacing="0" cellpadding="5">
	<tr> 
   <td align="right">
    <input name="append_list_name_to_subject" id="append_list_name_to_subject" type="checkbox" value="1" <!--tmpl_if append_list_name_to_subject -->checked="checked"<!--/tmpl_if--> />
   </td>
   <td>  
    <p>
     <label for="append_list_name_to_subject">
      Append message subjects with the:
     </label>
     <br />
     <select name="append_discussion_lists_with">
      <option value="list_shortname" <!--tmpl_if expr="(append_discussion_lists_with eq 'list_shortname')" -->selected="selected" <!--/tmpl_if--> >list shortname (<!-- tmpl_var name="list" escape="HTML" -->)</option>
      <option value="list_name"      <!--tmpl_if expr="(append_discussion_lists_with eq 'list_name')" -->selected="selected" <!--/tmpl_if--> >List Name (<!-- tmpl_var name="list_name" escape="HTML" -->)</option>
     </select> 
     <br />
     The List Name/Short Name will be surrounded by square brackets. 
     
     <table>
      <tr> 
       <td>
           <input name="no_append_list_name_to_subject_in_archives" id="no_append_list_name_to_subject_in_archives" type="checkbox" value="1" <!--tmpl_if no_append_list_name_to_subject_in_archives -->checked="checked"<!--/tmpl_if--> />
       </td> 
       <td> 
        <label for="no_append_list_name_to_subject_in_archives">
         Do not append the list/list shortname to archived messages (only outgoing messages).  
        </label>
       </td> 
      </tr> 
     </table> 
    </p>
   </td>
  </tr>
  <tr> 
   <td align="right">
    <input name="add_reply_to" id="add_reply_to" type="checkbox" value="1" <!--tmpl_if add_reply_to -->checked="checked"<!--/tmpl_if--> />
   </td>
   <td>
    <label for="add_reply_to">
     Automatically have replies to messages directed to the group
    </label>
    <br />
     A 'Reply-To' header will be added to group list mailings that will direct 
     replies to list messages back to the list.
   </td>
  </tr>
   <tr> 
   <td align="right">
    <input name="mail_discussion_message_to_poster" id="mail_discussion_message_to_poster" type="checkbox" value="1" <!--tmpl_if mail_discussion_message_to_poster -->checked="checked"<!--/tmpl_if--> />
   </td>
   <td>
    <label for="mail_discussion_message_to_poster">
     Send message posters a copy of the message they've sent the discussion list. 
    </label>
    <br />
   </td>
  </tr>
  
  
  
     <tr> 
   <td align="right">
    <input name="set_to_header_to_list_address" id="set_to_header_to_list_address" type="checkbox" value="1" <!--tmpl_if set_to_header_to_list_address -->checked="checked"<!--/tmpl_if--> />
   </td>
   <td>
    <label for="set_to_header_to_list_address">
     Set the <strong>To:</strong> header of discussion list messages to the <strong>List Address</strong>, rather than the subscribers address.
     
     <!-- tmpl_unless can_use_set_to_header_to_list_address --> 
        <p class="error">Warning! Your current mailing backend does not support this feature.<br /> 
        Only the <strong>Net::SMTP</strong> SMTP engine and the <strong>sendmail</strong> command support this feature. 
     <!--/tmpl_unless --> 
     
    </label>
    <br />
   </td>
  </tr>
  
  
  
	</table>
  
  </td>
  </tr>
  
  
  
 </table> 


</fieldset> 



<fieldset> 
 <legend> 
 Message Routing
 </legend> 

 <table width="100%" cellspacing="0" cellpadding="5">
  <tr> 
   <td> 
    <p>
     <label>
      Messages from addresses that are <em>allowed</em> to post to this list should:
     </label>
    </p>
    <table>
     <tr>
      <td> 
       <input type="checkbox" name="send_msgs_to_list" id="send_msgs_to_list" value="1" <!-- tmpl_if send_msgs_to_list -->checked="checked"<!--/tmpl_if--> />
      </td> 
      <td>
       <label for="send_msgs_to_list">
        be sent to the Subscription List.
       </label>
      </td>
     </tr> 
     <tr> 
      <td>
       <input type="checkbox" name="send_msg_copy_to" id="send_msg_copy_to" value="1" <!-- tmpl_if send_msg_copy_to -->checked="checked"<!--/tmpl_if--> />
      </td>
      <td>
       <label for="send_msg_copy_to">
        have a copy of the original message forwarded <label for="send_msg_copy_address">to</label>:
       </label>
       <p>
        <input type="text" name="send_msg_copy_address" id="send_msg_copy_address"value="<!-- tmpl_var send_msg_copy_address -->" />
       </p>
      </td> 
     </tr> 
     <tr> 
      <td>
		&nbsp;
      </td>
      <td>
       <p>
        <!-- tmpl_if archive_messages --> 
         <p class="positive"> 
         * Archiving is Enabled.
         </p>
        <!--/tmpl_if-->
       </p>
      </td> 
     </tr> 
    </table> 
   </td>
  </tr>
  <tr> 
  
  
  
  
   <td> 
    <p>
     <label>
      Message from addresses <em>not allowed</em> to post to this list should:
     </label>
    </p>
    <table> 
     <tr>
      <td> 
       <input type="checkbox" name="send_invalid_msgs_to_owner" id="send_invalid_msgs_to_owner" value="1" <!-- tmpl_if send_invalid_msgs_to_owner -->checked="checked"<!--/tmpl_if--> />
      </td> 
      <td>
       <label for="send_invalid_msgs_to_owner">
        send the list owner a &quot;Not a Subscriber&quot; email message, with original message attached.
       </label>
      </td>
     </tr> 
     
     <!--
     <tr> 
      <td>
       <input type="checkbox" />
      </td>
      <td>
       be forwarded to the moderators (moderation must be turned on!).
      </td> 
     </tr>
     --> 
     
     <tr> 
      <td> 
       <input type="checkbox" name="send_not_allowed_to_post_msg" id="send_not_allowed_to_post_msg" value="1" <!-- tmpl_if send_not_allowed_to_post_msg -->checked="checked"<!--/tmpl_if--> />
      </td> 
      <td> 
       <label for="send_not_allowed_to_post_msg">
        send back a &quot;Not Allowed to Post&quot; message.
       </label>
      </td>  
     </tr> 
    </table> 
   </td> 
  </tr>
 </table>
 
 </fieldset> 



<fieldset> 
 <legend> 
Mailing List Security
</legend> 
 


   <table>


   <tr>
      <td> 
       <input type="checkbox" name="ignore_spam_messages" id="ignore_spam_messages" value="1" <!-- tmpl_if ignore_spam_messages -->checked="checked"<!--/tmpl_if--> />
      </td> 
      <td>
       <label for="ignore_spam_messages">
        Ignore messages labeled as, &quot;SPAM&quot; by SpamAssassin filters. 
       </label></p> 
      
       
        <!-- tmpl_unless can_use_spam_assassin --> 
          <p class="error">* SpamAssassin may not be installed on your server.</p>
        <!--/tmpl_unless--> 
      
        <p>Find SpamAssassin Score By: 
        <table border="0"> 
         <tr> 
          <td><input type="radio" id="looking_for_embedded_headers" name="find_spam_assassin_score_by" value="looking_for_embedded_headers" <!-- tmpl_if find_spam_assassin_score_by_looking_for_embedded_headers -->checked="checked"<!--/tmpl_if--> /></td>
          <td>
           <p>
            <label for="looking_for_embedded_headers">
            Look for the embedded SpamAssassin Headers (Fast! But may not be available)
            </label> 
           </p>
          </td>
         </tr>
         
         <tr> 
          <td><input type="radio" id="calling_spamassassin_directly" name="find_spam_assassin_score_by" value="calling_spamassassin_directly" <!-- tmpl_if find_spam_assassin_score_by_calling_spamassassin_directly -->checked="checked"<!--/tmpl_if--> /></td>
          <td>
           <p>
            <label for="calling_spamassassin_directly">
            Use the SpamAssassin Modules directly (Slow, resource-intensive)
            </label> 
           </p>
          </td>
         </tr>
         
         <!-- 
         
         <tr> 
          <td><input type="radio" disabled="disabled" /></td>
          <td>
           <p>
            <label> 
             Use the spamd daemon (not currently supported)
            </label>
           </p>
          </td>
         </tr>
         
         --> 
         
        </table> 
      
       <p> 
        Messages must reach a SpamAssassin level of at least: <!-- tmpl_var spam_level_popup_menu --> to be considered SPAM.
       </p> 

      </td>
     </tr> 


     
     <tr>
      <td> 
      
 <input type="checkbox" name="strip_file_attachments" id="strip_file_attachments" value="1" <!-- tmpl_if strip_file_attachments -->checked="checked"<!--/tmpl_if--> />
 
 </td>
 <td>
 <p>
 <label for="strip_file_attachments">Strip attachments that have the following file ending or mime-type:</label> <em>(separated by spaces)</em>
	 <br />
	 
         <input type="text" name="file_attachments_to_strip" id="file_attachments_to_strip"value="<!-- tmpl_var file_attachments_to_strip -->" class="full" />

  </p>
 </td>
 </tr>
 </table> 
 
 
 </fieldset> 
 
 

 
 <p>
  <em>
   The 
   <strong> 
    List Email 
   </strong>
   address is the email address you will be sending to to have your messages 
   broadcast to your entire list. This email address needs to be created, 
   if it's not already available. Make sure this address is not being used 
   for any other purpose.
  </em>
 </p> 
 <p>
  <em>
   The 
   <strong>
    List Email 
   </strong>
   should be different than both your list owner email address 
   (<!-- tmpl_var name="list_owner_email" escape="HTML" -->)
   and your list admin email address (<!-- tmpl_var name="admin_email" escape="HTML" -->). 
   If 
   <strong>
    &quot;Make this list a discussion list&quot;
   </strong> 
   has been checked, all subscribers can mail to this address 
   and have their message sent all other subscribers. 
   Otherwise, only the list owner can email to this address. 
  </em>
 </p>

 <table width="100%" cellpadding="5" cellspacing="0">
  <tr> 
   <td>
    <label for="discussion_pop_email">
     List Email:
    </label>
   </td>
   <td>
    <input name="discussion_pop_email" id="discussion_pop_email" type="text" value="<!-- tmpl_var name=discussion_pop_email -->" class="full" />
   </td>
  </tr>
  <tr> 
   <td width="125">
    <label for="discussion_pop_server">
     POP3 Server
    </label>
   </td>
   <td>
    <input name="discussion_pop_server" id="discussion_pop_server" type="text" value="<!-- tmpl_var name=discussion_pop_server -->" class="full" />
   </td>
  </tr>
  <tr>
   <td width="125">
    <label for="discussion_pop_username">
     POP3 Username:
    </label>
   </td>
   <td>
    <input name="discussion_pop_username" id="discussion_pop_username" type="text" value="<!-- tmpl_var name=discussion_pop_username -->" class="full" />
   </td>
  </tr>
  <tr>
   <td width="125">
    <label for="discussion_pop_password">
     POP3 Password:
    </label>
   </td>
   <td>
    <input name="discussion_pop_password" id="discussion_pop_password" type="password" value="<!-- tmpl_var name=discussion_pop_password escape="HTML"-->" />
   </td>
  </tr>
 </table> 
 
 <input name="flavor"  type="hidden" value="cgi_edit" />
 <input name="process" type="hidden" value="true" />
 <div class="buttonfloat"> 
  <input type="reset"  class="cautionary" value="Clear Changes" />
  <input type="submit" class="processing" value="Save Changes" />
 </div> 
 <div class="floatclear"></div> 
 
 
</form>
<hr />

<form method="get">
 <input name="flavor" type="hidden" value="test_pop3" />
 <div class="buttonfloat">
  <input type="submit" class="cautionary" value="Test Saved POP3 Login Information..." />
 </div> 
 <div class="floatclear"></div> 
</form> 

<form method="get">
 <input name="flavor" type="hidden" value="manual_start" />
 <div class="buttonfloat"> 
  <input type="submit" class="cautionary" value="Manually Check and Send Waiting Messages..." />
 </div>
 <div class="floatclear"></div> 
</form> 


};

}


END { 

	$parser->filer->purge;

}

package SimpleModeration;

use strict; 

use Carp qw(croak carp);
use DADA::Config qw(!:DEFAULT);
use DADA::App::Guts qw(!:DEFAULT); 
use MIME::Entity;

sub new { 
	my $class = shift;
	my $self = {@_};
	bless $self, $class;  


    my ($args) = @_;
    
    if ( !$args->{-List} ) {
        carp
            "You need to supply a list ->new({-List => your_list}) in the constructor.";
        return undef;
    }
    else {
    
        $self->{list} = $args->{-List}; 
    }
    
    
    $self->init; 
    
	return $self;

}

sub init { 

    my $self = shift; 
    $self->check_moderation_dir(); 

}




sub check_moderation_dir { 

        # Basically, just makes the tmp directory that we need...
        
        my $self = shift; 
        if(-d $self->mod_dir){ 
            # Well, ok!
        } else { 
        
            croak "$DADA::Config::PROGRAM_NAME $DADA::Config::VER warning! Could not create, '" . $self->mod_dir . "'- $!" 
			    unless mkdir ($self->mod_dir, $DADA::Config::DIR_CHMOD );
			    
            chmod($DADA::Config::DIR_CHMOD, $self->mod_dir)
			    if -d $self->mod_dir; 
        }
}




sub  awaiting_msgs { 

    my $self = shift; 
    my $pattern = quotemeta($self->{list} . '-'); 
    my @awaiting_msgs; 
    my %allfiles; 
    
    if(opendir(MOD_MSGS, $self->mod_dir)){ 

        %allfiles = map { $_ , (stat($_))[9]} readdir(MOD_MSGS);
			
        closedir(MOD_MSGS) 
            or carp "couldn't close: " . $self->mod_dir; 
            
        foreach my $key (sort $allfiles{$a} <=> $allfiles{$b}, keys %allfiles) {
        
            next if($key =~ /^\.\.?$/); 
            
            $key  =~ s(^.*/)();
            if($key =~ m/$pattern/){  
                push(@awaiting_msgs, $key); 
            }
        
        }
        
    }else{
		carp "could not open " . $self->mod_dir . " $!"; 
	}
	
	return [@awaiting_msgs]; 
	
}




sub save_msg { 

    my $self = shift; 
    my ($args) = @_;

    if(!$args->{-msg}){ 
        croak "You must supply a message!"; 
    }
    
    if(!$args->{-msg_id}){ 
        croak "You must supply a message id!"; 
    }    
    
    my $file = $self->mod_msg_filename($args->{-msg_id}); 
    
    open my $MSG_FILE, '>', $file
        or croak "Cannot write saved raw message at: '" . $file . " because: $!";
    
    print $MSG_FILE $args->{-msg}; 
    
    close($MSG_FILE)
        or croak "Coulnd't close: " . $file . "because: " . $!;

}



sub alert_list_owner { 
    
    my $self = shift; 
    my ($args) = @_;
    
    
    if(!$args->{-msg}){ 
        croak "You must supply a message!"; 
    }
    
    if(!$args->{-msg_id}){ 
        croak "You must supply a message id!"; 
    }
    $args->{-msg_id} =~ s/\@/_at_/g;
    $args->{-msg_id} =~ s/\>|\<//g;
    $args->{-msg_id} = DADA::App::Guts::strip($args->{-msg_id});
    
    
    if(!$args->{-from}){ 
        croak "You must supply a from!"; 
    }
    
    if(!$args->{-parser}){ 
        croak "You must supply a parser!"; 
    }
    
    require DADA::MailingList::Settings; 
    my $ls = DADA::MailingList::Settings->new(-List => $self->{list}); 
    my $li = $ls->get; 
    
    
    require DADA::App::Messages; 
    
    my $parser = $args->{-parser};
    
    my $entity = $parser->parse_data($args->{-msg});
    
    
    		my $mh = DADA::Mail::Send->new($li); 

    my $reply = MIME::Entity->build(Type 	=> "multipart/mixed", 
										From    => $li->{list_owner_email},
										To      => $li->{list_owner_email},
										Subject => "Message on: " . $li->{list_name} . " needs to be moderated. (original message attached)", 									
										);
		
		$args->{-send_out_msg} =~ s{\[message_from\]}{$args->{-from}}g; 
		$args->{-send_out_msg} =~ s{\[message_subject\]}{$args->{-subject}}g; 
		
		my $guess_self_url = $DADA::Config::S_PROGRAM_URL; 
		   $guess_self_url =~ s/mail\.cgi$/plugins\/dada_bridge\.pl/; 
		
		my $confirm_link = $guess_self_url . '?flavor=mod&list=' . $self->{list} . '&process=confirm&msg_id=' . $args->{-msg_id};
    	my $deny_link    = $guess_self_url . '?flavor=mod&list=' . $self->{list} . '&process=deny&msg_id='    . $args->{-msg_id};
		
	    $args->{-send_out_msg} =~ s{\[moderation_confirm_link\]}{$confirm_link}g; 
	    $args->{-send_out_msg} =~ s{\[moderation_deny_link\]}{$deny_link}g; 

		
		
		$reply->attach(Type => 'text/plain', 
					  Data  => $args->{-send_out_msg}, 
					  
					  ); 
					
		$reply->attach( Type        => 'message/rfc822', 
						Disposition  => "attachment",
						Data         => $entity->as_string,
						); 
		
		require DADA::App::FormatMessages; 
	
		my $fm = DADA::App::FormatMessages->new(-List => $self->{list}); 
		   #$fm->treat_as_discussion_msg(1); 
			$fm->use_email_templates(0); 
		my ($header_str, $body_str) = $fm->format_headers_and_body(-msg => $reply->as_string);
		
	
		$mh->send(
					$mh->return_headers($header_str),
					Body => $body_str,
				); 
		
		
    
    

}




sub send_reject_msg { 
    
    my $self = shift; 
    my ($args) = @_;
    
    
    if(!$args->{-msg_id}){ 
        croak "You must supply a message id!"; 
    }
    $args->{-msg_id} =~ s/\@/_at_/g;
    $args->{-msg_id} =~ s/\>|\<//g;
    $args->{-msg_id} = DADA::App::Guts::strip($args->{-msg_id});
       
    if(!$args->{-parser}){ 
        croak "You must supply a parser!"; 
    }
    
    my $parser = $args->{-parser}; 
    
    if(!$args->{-send_out_msg}){ 
        croak "You must supply a -send_out_msg!"; 
    }
    
    my $entity; 
	eval { $entity = $parser->parse_data(
	                                     $self->get_msg(
	                                                    {
	                                                     -msg_id => $args->{-msg_id} 
	                                                    }
	                                                   )
	                                   ); 
	                                    
	     };
	if(!$entity){
		croak "no entity found! die'ing!";   
	}
    my $subject     = $entity->head->get('Subject', 0); 
	   $subject =~ s/\n//g; 
	my $from        = $entity->head->get('From', 0);
	   $from =~ s/\n//g;
	   
    require DADA::MailingList::Settings; 
    my $ls = DADA::MailingList::Settings->new(-List => $self->{list}); 
    my $li = $ls->get; 
    
    
    require DADA::App::Messages; 
    
    my $parser = $args->{-parser};
  
    my $entity = $parser->parse_data($args->{-msg});
    
    require DADA::Mail::Send; 
    my $mh = DADA::Mail::Send->new($li); 

    $args->{-send_out_msg} =~ s{\[message_from\]}{$args->{-from}}g; 
    $args->{-send_out_msg} =~ s{\[message_subject\]}{$subject}g; 

    my $reply = MIME::Entity->build(Type 	=> "text/plain", 
										From    => $li->{list_owner_email},
										To      => $from,
										Subject => "Message to: " . $li->{list_name} . ", Subject: " . $subject .", rejected.", 	
										Data     => $args->{-send_out_msg}, 
										);
			
    require DADA::App::FormatMessages; 

    my $fm = DADA::App::FormatMessages->new(-List => $self->{list}); 
        $fm->use_email_templates(0); 
    my ($header_str, $body_str) = $fm->format_headers_and_body(-msg => $reply->as_string);
    
    $mh->send(
                $mh->return_headers($header_str),
                Body => $body_str,
            ); 

    return 1; 
}






sub is_moderated_msg { 

    my $self = shift; 
    my $msg_id = shift; 
    
        print '<pre>' ;
        print "looking for:\n"; 
        print $self->mod_msg_filename($msg_id) . "\n"; 
        print '</pre>'; 
        
    if(-e $self->mod_msg_filename($msg_id)){ 
        return 1; 
    } else {
        return 0; 
    }

}




sub get_msg { 

    my $self   = shift; 
    my ($args) = @_;
    
    if(! $args->{-msg_id}){ 
        croak "You must supply a message id!"; 
    }    
    
    my $file = $self->mod_msg_filename($args->{-msg_id}); 

    if(! -e $file){ 
    
        croak "Message: $file doesn't exist?!"; 
  
    } 
    else { 
    
        open my $MSG_FILE, '<', $file
            or die "Cannot read saved raw message at: '" . $file
            . "' because: "
            . $!;


            my     $msg = do { local $/; <$MSG_FILE> };
            

        close $MSG_FILE
            or die "Didn't close: '" . $file . "'properly because: " . $!;

        return $msg; 
        
    }
    
    
    

}



sub remove_msg { 

    my $self   = shift; 
    my ($args) = @_;
    
    if(! $args->{-msg_id}){ 
        croak "You must supply a message id!"; 
    }    
    
    my $file = $self->mod_msg_filename($args->{-msg_id}); 


    if(-e $file){ 
    
        my $count = unlink($file); 
        if($count != 1){ 
            carp "Weird file delete count is: $count - should be, '1'";     
        }
    }else{ 
        carp "no file at: $file to delete!"; 
    }
    
    return 1; 
    
}




sub mod_msg_filename { 

    my $self = shift; 
    my $message_id = shift; 
    
    $message_id =~ s/\@/_at_/g;
    $message_id =~ s/\>|\<//g;
    $message_id = DADA::App::Guts::strip($message_id);

    return $self->mod_dir . '/' . $self->{list} . '-' . $message_id; 
    
}



sub mod_dir { 

    my $self = shift; 
    
    return $DADA::Config::TMP . '/moderated_msgs'; 

}






=pod

=head1 NAME dada_bridge.pl (BETA RELEASE)


=head1 Obtaining The Program

dada_bridge.pl is located in the, I<dada/plugins> directory of the Dada Mail distribution.

=head1 DESCRIPTION 

dada_bridge.pl is a proof of concept program created to allow the support of sending email from your mail reader to a Dada Mail list, both for announce-only tasks and discussion lists.

This plugin gives support for B<Discussion Lists> and sending announce-only messages from your mail reader to Dada Mail. 


=head1 Intended Audience

Before I get asked the inevitable question, "why did you reinvent another wheel?", here's my response: 

dada_bridge.pl, along with Dada Mail is not meant to be a replacement for similar systems, such as Mailman or Majordomo. dada_bridge.pl is a much simpler program with far fewer features then either of these two programs. 

As with most of Dada Mail, the primary goals are usability and... well - style! 

dada_bridge.pl I<does> solve a few problems with trying to use similar programs  - 

=over

=item * You do NOT need root access to the server to install the program, or setup the list address

=item * You do NOT need to use an alias to a script to use dada_bridge.pl

=back

Having solved these two problems also makes dada_bridge.pl potentially more secure to use and opens its use to a wider audience. 

=head1 How does dada_bridge.pl work?

Many of dada_bridge.pl's concepts are slightly different than what you may be used to in traditional mailing lists: 


=over

=item * Subscription/Unsubscription requests are handled via Dada Mail itself

In other words, it's all web-based. There are currently no subscription mechanisms that use email commands. 


=item *  A, "List Email" is just a POP3 email account. 

In Dada Mail, a "List Email" is the address you send to when you want to post a message to the list. This differs from the "List Owner" email, which is the address that messages will be sent on behalf of (unless discussion lists are enabled). 

Usually, in a mailing list manager, this address is created automatically by the program itself: not so in Dada Mail - you'll have to manually create the email  (POP3) account and plug in the email, pop3 server and username/password into Dada Mail.

This sounds like a step I<backward>, but it allows anyone who can make POP3 accounts to have a discussion mailing list. You also have a whole lot of flexibility when it comes to what the List Email can be. 

In normal use, dada_bridge.pl will check this account and route any messages it finds accordingly. When in normal use, do not check this account yourself. 

=back

Saying all this, dada_bridge.pl's niche is probably with small to medium sized lists. This program has not been tested with lists larger than a few hundred, so your mileage may vary. 

The other thing you may want to take into consideration is the lack of proper threading in Dada Mail's web-based archives. At the moment, archives are only sorted by date. 

This may/may not be a deal breaker, but also take into consideration that the displaying of complex email messages is usually actually I<better> in Dada Mail than most other mail archive viewing programs. 

One more thing to take into consideration is that there is currently no filter in place to reject messages based on size or type. There is a way currently to strip messages with attachments of a certain file ending or mime-type. 

These two issues may be at least partly worked around using the preferences of your POP email account. Many services will at least allow you to set a per-mailbox limit, or even a per-message limit for size. 

As for content, Dada Mail is currently completely MIME-aware and will accept anything it can parse, which means, multipart messages, attachments, inline embedded images - the works. 

For a stopgap solution to the last issues, you may look into a mail filtering program like Procmail, which can be configured to death. 

=head1 REQUIREMENTS

=over

=item * Familiarity with setting cron jobs, working in a shell environment and the basics of creating an email account.

Or, at least a openess to learn. These topics are slightly out of the pale of support that you'd get from the Dada Mail boards, so it is suggested that you do your own research into these topics. 

=item * Dada Mail 2.10

Make sure to always use the version of Dada Mail the plugin comes with - in this case, Dada Mail 2.10 

=item * a free POP3 account for each list. 

=item * Ability to set cron jobs

=back

That's about it. 

=head1 RECOMMENDATIONS

=over

=item * secure shell (ssh) access to your hosting account

This will really help with debugging

=item * Use the *SQL backend for Archives

if not for subscribers as well. 

Multipart messages, attachments and inline embedded images will work very well if you use the *SQL backend for Archives. They may not work at all if you don't. 

Since you don't have any control over the type of messages being sent using dada_bridge.pl, I would use the *SQL backend for Archives. 

For the same reason, I also and cannot stress enough that you check,

B<Disable Embedded JavaScript in Archived Messages>

In Dada Mail's List control panel under, I<Manage Archives - Archive Options - Advanced>. This will prevent exploitations embedded in messages sent to the list when viewed in Dada Mail's own archives. Along with Javascript, this option will strip out: embed, object, frame, iframe, and meta tags. 

This feature does require the use of a CPAN module called, B<HTML::Scrubber>, which you may have to install yourself. 

If you do not have this available, I do urgently suggest you do not use archiving for B<discussion> lists. 

=back

=head1 INSTALLATION 

This script is both a command line tool you'll probably only call via cron job once everything is set up B<and> it's a Dada Mail plugin. That means, most of the configuration is done using your web browser, and it does its dirty work behind the scenes. Nice, huh? 

=head2 Change the lib path

Since the bounce handler is going to be run via a command line, you need to explicitly state where both your path to the regular Perl libs are, and the Dada Mail libraries are. For example:

 use lib qw(
 /home/myaccount/www/cgi-bin/dada
 /home/myaccount/www/cgi-bin/dada/DADA
 /home/myaccount/www/cgi-bin/dada/DADA/perllib
 
 
 /usr/local/lib/perl5/site_perl/5.8.0/mach
 /usr/local/lib/perl5/site_perl/5.8.0
 /usr/local/lib/perl5/site_perl
 /usr/local/lib/perl5/5.8.0/BSDPAN
 /usr/local/lib/perl5/5.8.0/mach
 /usr/local/lib/perl5/5.8.0
 );

If you don't know where your Perl library is, trying running this via the command line:

 perl -e 'print $_ ."\n" foreach @INC'; 

If you do not know how to run the above command, visit Dada Mail in a web browser, log into your list and on the left hand menu and: click, B<About Dada Mail> 

Under B<Script Information>, click the, B<More...> link and under the, B<Perl Library Locations>, select each point that begins with a, "/" and use those as your site-wide path to your perl libraries. 


Ok! Done configuring the script!

=head2 set $MessagesAtOnce (optional)

You can specificy how many messages you want to have the program actually handle per execution of the script by changing the, B<$MessagesAtOnce> variable. By default, it's set conservatively to, B<1>.

=head2 Upload into the plugins directory

We're assuming your cgi-bin looks like this: 

 /home/account/cgi-bin/dada

and inside the I<dada> directory is the I<mail.cgi> file and the I<DADA> (uppercase) directory. Good! Make a B<new> directory in the I<dada> directory called, B<plugins>. 

Upload your tweaked copy of I<dada_bridge.pl> into that B<plugins> directory. chmod 755 dada_bridge.pl

OK, we're done with that. 

=head2 Configure the Config.pm file

This plugin will give you a new menu item in your list control panel. Tell Dada Mail to make this menu item by tweaking the Config.pm file. Find this line in Config.pm file: 

 #		 {-Title           => 'Discussion lists', 
 #		   -Title_URL      => $PLUGIN_URL."/dada_bridge.pl",
 #		   -Function       => 'dada_bridge',
 #		   -Activated      => 1, 
 #		  },

Uncomment it (take off the "#"'s) 

Save the Config.pm file. 

Ok. Done with that. 

=head2 Configuring the POP3 email, server, username, password

dada_bridge.pl accesses a POP3 email account, checks it for new messages and, after validating the message, sends it off to your subscribers. 

Make a new POP3 account for your list. Each list needs its own POP account. Note the email address, server, username and password. 

B<Do not use this POP3 account for anything else.> 

Log into your list control panel. On the left hand menu, you should see a new link entitled, "Discussion Lists". Follow that link. 

You will see a form that will want your POP3 email address, server, username and password. Enter those. 

Done. Dada Mail is now connected up to your new mailing list address. If you're the list owner, mail to this address, it will mail to the rest of your users. If you have a discussion list, everyone on the discussion list can email to the rest of the list using your new mailing list address. Life is sweet. 

Oh - one more thing 

=head2 Set the cron job 

Cron Jobs are scheduled tasks. We need something to check your POP3 email account quite a bit. We're going to set a cron job to test for new messages every minute. Here's an example cron tab: 

  *  *  *  *  * /usr/bin/perl /home/myaccount/cgi-bin/dada/plugins/dada_bridge.pl >/dev/null 2>&1

Where, I</home/myaccount/cgi-bin/dada/plugins/dada_bridge.pl> is the full path to the script we just configured. 

That's it. 

=head1 TESTING

You can access the I<dada_bridge.pl> script via the command line. There are a few options you can use: 

=over

=item * --help

Displays a help menu. May not be so helpful at the moment. 

=item * --list

Will allow you to work on one list at a time, instead of all the lists you have. 

=item * --verbose 

Prints out a whole lot of stuff on the command line that may be helpful in determining what's happening. 

=item * --test pop3

Allows you to test the pop3 login information on the command line. Currently the only test available. 

=item * --check_deletions

When this flag is run, an extra check is done to ensure that messages on the POP server that should have been removed, have been removed. Shouldn't have to be used, but this problem has been... problematic. 

=back

Example: 

 prompt>dada_bridge.pl --test pop3 --list yourlistshortname

Will test the pop3 connection of a list with a shortname of, B<yourlistshortname>

Another Example: 

 prompt>dada_bridge.pl --verbose --list yourlistshortname

Will check for messages to deliver for list, B<yourlistshortname> and outputting a lot of information on the command line. 

=head1 BETA Software?! Why are you releasing it? 

Because. This plugin isn't complete. It needs more work. Here's a few things: 

=head1 Current Program Status

dada_bridge.pl is currently in beta form, but progress to complete the script is moving along quite nicely. 

=head1 Example of dada_bridge.pl use, "In the Wild"

Dada Mail's own development list uses dada_bridge.pl, as we'd fee really embarrassed if we were using anything else. It seems to be working quite well: 

List: 

http://mojo.skazat.com/cgi-bin/dada/mail.cgi/list/dadadev/

Archives:

http://mojo.skazat.com/cgi-bin/dada/mail.cgi/archive/dadadev/

=head1 Sponsoring New Features

If you are interested in sponsoring development of this program, please contact us at: 

http://mojo.skazat.com/contact/


=head1 Thanks To: 

The following organizations have already helped in the development of this plugin: 

B<Eastside Arts Coalition> - http://eastsidearts.org/

=head1 COPYRIGHT

Copyright (c) 2004 - 2006 Justin Simoni http://justinsimoni.com 

All rights reserved.


=head1 LICENSE

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, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

=cut

cvs-admin@eby-sarna.com

Powered by ViewCVS 1.0-dev

ViewCVS and CVS Help