#!/usr/bin/perl -w
## $Id: cscget,v 1.63 2000/05/12 19:32:04 muhri Exp $
use strict;
use vars qw(%prefs $libpath);

BEGIN { 
 $libpath = $0;
 $libpath =~ s!/[^/]+$!!;
 $libpath =~ s!/bin$!/lib/cscmail!;
 if (! -e $libpath) { die "Can't find required files in $libpath"; };
}
use lib "$libpath";
use lib "$libpath/modules/lib/perl5/site_perl/5.005";

use IO::Socket;

require "csclib.pl";

&read_prefs;

my ($query, $sql, %filter, @row, $acctid, $mailsize, $div, $answer, $reportsize, $i, @test, $socket, $size, $count, $rawbody, $query2, $percent,$sql2, $conn, $acct, $inter, $status_dialog, $header);

# check for currently running copy of cscget
#
if (open(TMP,"<$prefs{'MailDir'}/cscget.running")) {
	printf("CSCget is already running. if this is not true, please delete\n
	cscget.running in $prefs{'MailDir'}\n");
	exit;
}

# Touch lock file
#
open(TMP,">$prefs{'MailDir'}/cscget.running");
print TMP "1\n";
close(TMP);

# Get arguments
#
($acct, $inter) = @ARGV;
if (!$acct) { $acct = "all"; }
if (!$inter) { $inter = 0; }
# Is this an interactive session? (ie: do I draw a gtk status window?)
#
if ($inter == 1) {
	use Gtk;
	init Gtk;
	&init_sd;
}

chomp($acct);

$conn=&open_db_conn;

$sql = "select sorder, type, boxid, regex, addr from filters";
$query=$conn->prepare($sql);
$query->execute();
while (@row = $query->fetchrow_array()) {
	$filter{$row[0]} = {
		'type' => $row[1],
		'boxid' => $row[2],
		'regex' => $row[3],
		'addr' => $row[4]
	}
}

sub init_sd {
	my ($sd_pbar, $sd_label, $sd_button, $sd_vbox);
	$status_dialog = new Gtk::Dialog; 
	$status_dialog->signal_connect("destroy" => sub { $status_dialog->destroy; });
	$status_dialog->signal_connect("delete_event" => sub { $status_dialog->destroy; });
	$status_dialog->set_title("Transfering E-Mail...");
	$status_dialog->position(-mouse);
	$status_dialog->border_width(5);
	$sd_vbox=new Gtk::VBox(0,5);
	$sd_vbox->border_width(5);
	$status_dialog->vbox->pack_start($sd_vbox,1,1,0);
	$sd_vbox->show;
	$status_dialog->{'statuslabel'}=new Gtk::Label "Logging On";
	$status_dialog->{'statuslabel'}->set_alignment(0.5,0.5);
	$sd_vbox->pack_start($status_dialog->{'statuslabel'},0,1,0);
	$status_dialog->{'statuslabel'}->show;
	$status_dialog->{'progressbar'}=new Gtk::ProgressBar;
	$status_dialog->{'progressbar'}->set_usize(200,20);
	$status_dialog->{'progressbar'}->set_show_text(1);
	$status_dialog->{'progressbar'}->set_text_alignment(0.5,0.5);
	$status_dialog->{'progressbar'}->set_format_string("message %v of %u");
	$status_dialog->{'progressbar'}->configure(0,0,0);
	$sd_vbox->pack_start($status_dialog->{'progressbar'},1,1,0);
	$status_dialog->{'progressbar'}->show;
	$status_dialog->{'mailprogressbar'}=new Gtk::ProgressBar;
	$status_dialog->{'mailprogressbar'}->set_usize(200,20);
	$status_dialog->{'mailprogressbar'}->set_show_text(1);
	$status_dialog->{'mailprogressbar'}->set_text_alignment(0.5,0.5);
	$status_dialog->{'mailprogressbar'}->set_format_string("downloaded %v of %u bytes");
	$status_dialog->{'mailprogressbar'}->configure(0,0,0);
	$sd_vbox->pack_start($status_dialog->{'mailprogressbar'},1,1,0);
	$status_dialog->{'mailprogressbar'}->show;
	$sd_button=new Gtk::Button "Hide Status";
	$sd_button->signal_connect("clicked" => sub { $status_dialog->destroy; });
	$sd_button->can_default(1);
	$status_dialog->action_area->pack_start($sd_button,1,1,0);
	$sd_button->grab_default;
	$sd_button->show;
	$status_dialog->show;
	while (events_pending Gtk) { main_iteration Gtk; }
	return 1;
}

if ($acct eq "all") {
	$sql = "select id, uname, friendly, descr, pop, pport, pass, dm, reply, type, dupecheck from accounts where include = 'y'";
} else {
	$sql = "select id, uname, friendly, descr, pop, pport, pass, dm, reply, type, dupecheck from accounts where id = $acct";
}
$query=$conn->prepare($sql);
$query->execute();

while (@row=$query->fetchrow_array()) {
	my $account;
	($account->{'id'}, $account->{'uname'}, $account->{'friendly'},$account->{'desc'}, $account->{'srvr'}, $account->{'port'}, $account->{'pass'}, $account->{'dm'}, $account->{'reply'}, $account->{'type'},$account->{'dupecheck'}) = @row;
	if (!$account->{'type'}) { $account->{'type'} = "Pop3"; }
	if ($account->{'type'} eq "mbox") { 
		my ($x,$y,$w,$h);
		if (defined $status_dialog) {
			$status_dialog->{'mailprogressbar'}->hide;	
			$status_dialog->{'statuslabel'}->set_text("Checking account $account->{'desc'}");
			$percent = 0;
			$status_dialog->{'progressbar'}->set_value($percent);
			while (events_pending Gtk) { main_iteration Gtk; }
		}
		my  ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size)=stat $account->{'srvr'};
		$size=$size/1024;
		if (defined $status_dialog) {
			$status_dialog->{'progressbar'}->configure(0,0,$size);
			$status_dialog->{'progressbar'}->set_format_string("%v of %u kbytes");
			$status_dialog->{'mailprogressbar'}->hide;
			while (events_pending Gtk) { main_iteration Gtk; }
		}
		&read_from_mbox($conn, \%filter, $status_dialog, $account,$size);
		if (defined $status_dialog){
			$status_dialog->{'mailprogressbar'}->show;
			while (events_pending Gtk) { main_iteration Gtk; }
		}
	} elsif ($account->{'type'} eq "Maildir") { 
		if ($account->{'srvr'} !~ /^(.*)\/$/){
			$account->{'srvr'}.="/";
		}
		unless (-e $account->{'srvr'} && -d $account->{'srvr'} && 
		        -e "$account->{'srvr'}new/" && -d "$account->{'srvr'}new/" && 
						-e "$account->{'srvr'}cur/" && -d "$account->{'srvr'}cur/"){
			print "Directory $account->{'srvr'} not found or not in Maildir format!\n";
			next;
		}
		my (@maillist,$mailfile,$isdupe,$error,$div);

		if (defined $status_dialog) {
			$status_dialog->{'statuslabel'}->set_text("Checking account $account->{'desc'}");
			$percent = 0;
			$status_dialog->{'progressbar'}->set_value($percent);
			$status_dialog->{'mailprogressbar'}->set_value($percent);
			$status_dialog->{'progressbar'}->configure(0,0,$percent);
			$status_dialog->{'mailprogressbar'}->configure(0,0,$percent);
			$status_dialog->{'progressbar'}->set_format_string("checking for new mails...");
			while (events_pending Gtk) { main_iteration Gtk; }
		}
		
		# thanks to ish for that trick...
		my $tmpdir="$account->{'srvr'}new/";
		opendir MAILDIR,$tmpdir;
		@maillist=grep !/^\.\.?$/, readdir(MAILDIR);
		closedir MAILDIR;
		if (scalar(@maillist)>0){
			# okay, here we go, we have mails
			if ($prefs{'PlaySound'} eq "y") { system("$prefs{'SndCmd'} $prefs{'SndFl'}"); }
			if (defined $status_dialog) {
				$status_dialog->{'progressbar'}->configure(0,0,scalar(@maillist));
				while (events_pending Gtk) { main_iteration Gtk; }
			}
			# first set dupeworked, so dupes don't get checked in save_message again
			$account->{'dupeworked'}='y';
			$i=1;
			foreach $mailfile (@maillist){
				# read the file
				open MAIL, "<".$tmpdir.$mailfile;
				my (undef,undef,undef,undef,undef,undef,undef,$mailsize)=stat MAIL;
				if (defined $status_dialog) {
					$percent = $i;
					$status_dialog->{'progressbar'}->set_value($percent);
					$status_dialog->{'progressbar'}->set_format_string("message %v of %u");
					if ($mailsize>4096){
						$div=1024;
						$status_dialog->{'mailprogressbar'}->set_format_string("downloaded %v of %u kb");
					} else {
						$div=1;
						$status_dialog->{'mailprogressbar'}->set_format_string("downloaded %v of %u bytes");
					}
					$status_dialog->{'mailprogressbar'}->configure(0,0,$mailsize/$div);
					$status_dialog->{'mailprogressbar'}->set_value(0);
					while (events_pending Gtk) { main_iteration Gtk; }
				}
				$rawbody="";
				while (my $line=<MAIL>){
					$rawbody.=$line;
					if (defined $status_dialog) {
						$status_dialog->{'mailprogressbar'}->set_value(length($rawbody)/$div);
						while (events_pending Gtk) { main_iteration Gtk; }
					}
				}
				close MAIL;
				$isdupe='n';
				# if dupecheck is defined, check for dupe
				if (defined $account->{'dupecheck'} && $account->{'dupecheck'} eq "y"){
					my ($header)=&parseHeader($rawbody);
					if (defined &checkForDupe($conn, $header->{'message-id'}, $account->{'id'})){
						$isdupe='y';
					}
				}
				# save mail if it is no dupe
				if ($isdupe eq "n"){
					$error=&save_message($conn, $rawbody, \%filter, $account);
				}
				if (defined $account->{'dm'} && $account->{'dm'} eq "y" && defined $error){
					# if delete messages is active, and save_message is successful delete the message...
					unlink($tmpdir.$mailfile);
				} else {
					# move it to read mails
					rename($tmpdir.$mailfile, $account->{'srvr'}."cur/".$mailfile.":2,S");
				}
				$i++;
			}
			open(TMP,">$prefs{'MailDir'}/.cscmail.refresh");
			print TMP ("1\n");
			close(TMP);
		}
	} else {
	# pop 3
		if (defined $status_dialog) {
			$status_dialog->{'statuslabel'}->set_text("Checking account $account->{'desc'}");
			$percent = 0;
			$status_dialog->{'progressbar'}->set_value($percent);
			$status_dialog->{'mailprogressbar'}->set_value($percent);
			$status_dialog->{'progressbar'}->configure(0,0,$percent);
			$status_dialog->{'mailprogressbar'}->configure(0,0,$percent);
			while (events_pending Gtk) { main_iteration Gtk; }
		}
		@test = gethostbyname($account->{'srvr'}) or next;
		$socket = IO::Socket::INET->new(PeerAddr => "$account->{'srvr'}", PeerPort => "$account->{'port'}", Proto => "tcp", Type => SOCK_STREAM) or next;
		$answer = <$socket>; 
		print $socket "USER $account->{'uname'}\r\n";
		$answer = <$socket>;
		if (!$answer) { next; }
		$answer =~ /^\+OK/ or next;
		print $socket "PASS $account->{'pass'}\r\n";
		$answer = <$socket>;
		$answer =~ /^\+OK/ or next;
		print $socket "LIST\r\n";
		$answer = <$socket>;
		$answer =~ /^\+OK/ or next;
		my @mails = ();
		my $i;
		while ($answer ne ".\n") {
			if ($answer =~ /(\d+) (\d+)/){
				$mails[$1]->{'size'}=$2;
				$mails[$1]->{'getit'}='y';
			}
			$answer = <$socket>;
			$answer =~ s/\r//g;
			$i++;
		}
		print $socket "STAT\r\n";
		$answer = <$socket>;
		$answer =~ /^\+OK (\d+) (\d+)/ and $count = $1;
		if ($count > 0) { 
		
		if ($prefs{'PlaySound'} eq "y") { system("$prefs{'SndCmd'} $prefs{'SndFl'}"); }

			if (defined $status_dialog) {
				$status_dialog->{'progressbar'}->configure(0,0,$count);
				while (events_pending Gtk) { main_iteration Gtk; }
			}

			if (defined $account->{'dupecheck'} && $account->{'dupecheck'} eq 'y'){
		  	# check for new mails
				# first check for TOP support
				my $hastop=0;
				print $socket "TOP 1 1\r\n";
				$answer=<$socket>;
				if ($answer=~/^\+OK/){
					$hastop=1;
					while ($answer ne ".\n"){
						$answer=<$socket>;
						$answer=~s/\r//g;
					}
				}
				if ($hastop==1){
					# TOP support found. set statusbar...
					if (defined $status_dialog) {
						$status_dialog->{'progressbar'}->set_format_string("checking for new mails (TOP)");
						while (events_pending Gtk) { main_iteration Gtk; }
					}
					for ($i=1;$i<=$count;$i++){
						# let's check the mails
						print $socket "TOP $i 20\r\n";
						$answer=<$socket>;
						$rawbody="";
						$answer =~ /^\+OK/ or next;
						while ($answer ne ".\n"){
							$answer=<$socket>;
							$answer=~s/\r//g;
							$rawbody=$rawbody.$answer;
						}
						($header)=&parseHeader($rawbody);
						# okay, now lets check if the mail already exists
						if (defined &checkForDupe($conn, $header->{'message-id'}, $account->{'id'})){
							$mails[$i]->{'getit'}='n';
						}	
						if (defined $status_dialog) {
							$status_dialog->{'progressbar'}->set_value($i);
							while (events_pending Gtk) { main_iteration Gtk; }
						}
					}
					# set account dupecheck to no, so it wont be checked in savemessage again
					$account->{'dupecheck'}='y';
					$account->{'dupeworked'}='y';
				} else {
					# no TOP support.. we have to check after the download
					$account->{'dupeworked'}='n';
				}
			} # end dupecheck
			my ($error, $bigmessage);
			for( $i = 1; $i <= $count; $i++ ) {
				if (defined $status_dialog) {
					$percent = $i;
					$status_dialog->{'progressbar'}->set_value($percent);
					$status_dialog->{'progressbar'}->set_format_string("message %v of %u");
					if ($mails[$i]->{'size'}>4096){
						$div=1024;
						$status_dialog->{'mailprogressbar'}->set_format_string("downloaded %v of %u kb");
					} else {
						$div=1;
						$status_dialog->{'mailprogressbar'}->set_format_string("downloaded %v of %u bytes");
					}
					$status_dialog->{'mailprogressbar'}->configure(0,0,$mails[$i]->{'size'}/$div);
					while (events_pending Gtk) { main_iteration Gtk; }
				}
				# only get message if dupecheck is deactivated or the message is no dupe
				if (defined $account->{'dupecheck'} && (($account->{'dupecheck'} eq 'n') || ($account->{'dupecheck'} eq 'y' && $mails[$i]->{'getit'} eq 'y'))){
					print $socket "RETR $i\r\n";
					$answer = <$socket>;
					$answer =~ /^\+OK/ or next;
					$answer = "";  
					$rawbody = "";
					$mailsize=0;
					if ($mails[$i]->{'size'}>4096) { 
					  if (-f "$prefs{'MailDir'}/big") { unlink("$prefs{'MailDir'}/big"); }
					  open(BIG, ">>$prefs{'MailDir'}/big");
					  $bigmessage = 1;
					}
					while ($answer ne ".\n") {
						if ($mails[$i]->{'size'}<4096) {
						$rawbody = $rawbody . $answer;
						} else {
						  print BIG $answer;
					      }
						$answer = <$socket>;
						$mailsize+=length($answer);
					        $answer =~ s/\r//g;
						if (defined $status_dialog) {
							$status_dialog->{'mailprogressbar'}->set_value($mailsize/$div);
							while (events_pending Gtk) { main_iteration Gtk; }
						}
					}
					if (defined $bigmessage and $bigmessage == 1) 
					  { 
					    close BIG;
					    &import_from_mbox(undef, undef, undef, $conn, $prefs{'MailDir'}, "big", "get"); 
					    $bigmessage = 0;  
					    unlink("$prefs{'MailDir'}/big");
					
					  } else {
					  
					$error=&save_message($conn, $rawbody, \%filter, $account);}
				
				      } elsif (defined $account->{'dupecheck'} && $mails[$i]->{'getit'} eq 'n'){
					$error="success";
				
				      } else {
					
					$error=undef;   
				
				      }# end getmessage

				if ((defined $error) and ($account->{'dm'} eq "y")) {
					print $socket "DELE $i\r\n";
					$answer = <$socket>;
				}
				open(TMP,">$prefs{'MailDir'}/.cscmail.refresh");
				print TMP ("1\n");
				close(TMP);
			}
		}
		print $socket "QUIT\r\n";
		close($socket);
	}

}

unlink("$prefs{'MailDir'}/cscget.running");
if ($query) {$query->finish;}
if ($query2) {$query2->finish;}
$conn->disconnect;
