#!/usr/local/bin/perl -w

# Newsgrab - The Newsgrabber by Jesper L. Nielsen <lyager@phunkbros.dk>
# Newsrc support added by Roger Knobbe <rogerk+newsgrab@tislabs.com>
#
# Released under the GNU public license.
#
# $Id: newsgrab.pl,v 1.27 2002/04/23 14:37:17 jln Exp $
#

use strict;
use News::NNTPClient;
use News::Newsrc;
use Time::ParseDate;

# Added for authentication.
use Term::ReadKey;

$|=1;	# Set autoflush for progressbar
sub progress_sub($$);
sub xover_fetch($);
sub xpat_fetch($);
sub stat_print;
sub parse_newsgrabrc($);
sub fetch_newsgrabrc(;$);
sub probe_article($);
sub decode_ydec($);
sub decode_uudec($);


# Bind function for handling calls to Carp() in News::NNTPClient
#$SIG{__WARN__} = \&warn_sig;

# ------------------------------------------ global variable initialization ---

my $VERSION = "0.2.2";
my $LIST = 1;
my $NNTP_REGEX = '';
my $NNTP_GROUP = '';
my $NEWSGRAB_RC = $ENV{HOME}."/.newsgrabrc";
my $SERVER = '';
my $RAW = '';
my $SORT = 0;
my $SORT_DATE = 0;
my $IGNORE_RC = 0;
my $VERBOSE = 0;

# Gather parameters
while ($_ = shift(@ARGV)) {
	if (/^-h$/ || /^--help$/) {
		usage_sub();
		next;
	}
	if (/^--version$/) {
		version_sub();
		next;
	}
	if (/^-s$/ || /^--server$/) {
		$SERVER = shift(@ARGV);
		next;
	}
	if (/^-v$/ || /^--verbose$/) {
		$VERBOSE= 1;
		next;
	}
	if (/^-g$/ || /^--group$/) {
		$NNTP_GROUP = shift(@ARGV);
		next;
	}
	if (/^-l$/ || /^--list$/) {
		print "Listing (-l) is now default, use -r to retrieven\n";
		next;
	}
	if (/^-r$/ || /^--retrieve$/) {
		$LIST = 0;
		next;
	}
	if (/^-i$/ || /^--ignore$/) {
		$IGNORE_RC = 1;
		next;
	}
	if (/^-c$/ || /^--conf$/) {
		$NEWSGRAB_RC = shift (@ARGV);
		next;
	}
	if (/^--sort$/) {
		$SORT = 1;
		my $sort_after = shift(@ARGV);
		if ($sort_after eq 'd') {
			$SORT_DATE = 1;
		} else {
			usage();
		}
		next;
	}
	if (/^--raw$/) {
		$RAW = 1;
		next;
	}
	$NNTP_REGEX = $_;
}

# --------------------------------------------------- read newsgrabrc file ---
# Get connectinfo if missing

my $server;
if (!parse_newsgrabrc($NEWSGRAB_RC)) {
	stat_print "Unable to open conf file $NEWSGRAB_RC, specify server.",
		"NOTIFY";
	# Ask for connection info
	print "Server: ";
	$server->{'hostname'}  = <STDIN>;
	chomp $server->{'hostname'};
	
	if (!$server->{'hostname'}) {
		print STDERR "Unable to connect without a hostname\n";
		exit(1);
	}

	$server->{'rc'} = 
		$ENV{HOME}."/.newsrc.newsgrab.".$server->{'hostname'};

	print "Port [119]: ";
	$server->{'port'}  = <STDIN>;
	chomp $server->{'port'};
	if (!$server->{'port'}) {
		# Assign default value
		$server->{'port'} = 119;
	}
	
	print "Username: ";
	$server->{'username'}  = <STDIN>;
	chomp $server->{'username'};
	
	print "Password: ";
	ReadMode('noecho');
	$server->{'password'} = ReadLine(0);
	ReadMode 0;		# Reset readmode
	chomp $server->{'password'};
	print "\n";

} else {
	if (!($server = fetch_newsgrabrc($SERVER))) {
		stat_print "Unable to fetch "
			.($SERVER ? "server with key '$SERVER'" : "default server")
			." from RC file.\n",
			"ERROR";
		exit;
	}
}

# Load newsrc file
my $rc = new News::Newsrc;
stat_print "newsrc", "Reading newsrc ".$server->{'rc'};
if ($rc->load($server->{'rc'})) {
	stat_print("newsrc", 
		"loaded ".$rc->num_groups." group(s) from ".$server->{'rc'});
} else {
	stat_print "newsrc", "no groups in ".$server->{'rc'};
}

# add group to newsrc file, if it doesn't exist.
if ($rc->exists($NNTP_GROUP)) {
	stat_print "newsrc", "$NNTP_GROUP loaded ok";	
} else {
	$rc->add_group($NNTP_GROUP);
}


print "Connecting to ".($NNTP_GROUP ? $NNTP_GROUP." \@ " : "").$server->{'hostname'}.":".$server->{'port'}."\n";

my $connected=1;
my $c = new News::NNTPClient($server->{'hostname'}, $server->{'port'});
if (!$c->ok) {
	stat_print "Unable to connect", "Error";
	exit(1);
}

if ($server->{'username'}) {
	print "Using authentication with username: ".$server->{'username'}."\n";
	$c->authinfo($server->{'username'},$server->{'password'});
	if (!$c->ok) {
		stat_print "Authentication error", "Error";
		exit(1);
	}
}

# ------------------------------------------------------------ main program ---	

# If no group, list all groups on server and EXIT
if (!$NNTP_GROUP) {
	print "No group specified, listing all groups available on the server\n";
	my $newsgroup;
	foreach ($c->list('active')) {
		($newsgroup) = split(/[\t|\s]/);
		print $newsgroup."\n";
	}
	exit(0);
}

# Take all multipart articles, and join them in a hash (one hash key
# presents each complete file)
if ($NNTP_REGEX) {
	print "Finding all subjects in $NNTP_GROUP matching '$NNTP_REGEX'\n";
} else {
	print "Finding all subjects in $NNTP_GROUP\n";
}
print '-'x80;
print "\n";
my ($first, $last) = $c->group($NNTP_GROUP);

# %arts is a collection of multipart messages
my %arts;
my @ordered_keys;
if ($SORT) {
	%arts = xover_fetch($NNTP_REGEX);
	if ($SORT_DATE) {
		@ordered_keys = 
		   sort { $arts{$a}->{'date'} <=> $arts{$a}->{'date'} } keys %arts;
	} else {
		# Default is per key
		@ordered_keys = sort(keys %arts);
	}
} else {
	%arts = xpat_fetch($NNTP_REGEX);
	@ordered_keys = sort(keys %arts);
}

print "\n";

# Now all the multiparted articals have an element in the
# %arts hash, and we can retrieve them, if they are complete
my ($key, $art_no, $parts);
foreach $key (@ordered_keys) {
	# $key   : Multithread article subject

	# All articles for the multithread is located in
	# array $arts{$key}->{'arts'}
	#
	# Let's see if they are all there
	#

	if ($arts{$key}->{'total'} == scalar(keys(%{$arts{$key}->{'arts'}}))) {
		# If we have the same number of articles as the
		# 'total' number.

		$arts{$key}->{'complete'} = 'C';

		# Lightly check if already retrieved
		foreach my $message_no (keys(%{$arts{$key}->{'arts'}})) {
			if ($rc->marked($NNTP_GROUP, 
				$arts{$key}
					->{'arts'}
					->{$message_no}
					->{'message_id'})) {
				# Article was already retrived
				# no need to continue
				$arts{$key}->{'complete'} = 'R';
				last;
			}
				
			
		}
	}

	# Detemine wether to download file, or skip
	# because it's incomplete
	# There 3 the followin states:
	# I: Incomplete (all multipart messages not found)
	# R: Skipping file, coz we've already downloaded (Retrieved) it
	# C: Complete posting

	stat_print $key, $arts{$key}->{'complete'};
	if ($LIST) {
		#Skip if list mode
		next;
	} 
	if ( $arts{$key}->{'complete'} eq 'R') {
		# If already retrieved, skip unles $IGNORE_RC was set
		if (!$IGNORE_RC) {
			next;
		}
	}
	if ($arts{$key}->{'complete'} eq 'I') {
		# Generate incomplete log
		print "SKIPPING: $key\n";
		# Skip if incomplete
		next;
	}

	# If we didn't provide the list option, perform a retriaval of the
	# posting
	my ($file, $mode, @art_lines);
	my @markable;
	my $skipping = 0;

	foreach my $art_no (sort(keys(%{$arts{$key}->{'arts'}}))) {
		my $art = $arts{$key}->{'arts'}->{$art_no};
		my $artnum = $art->{'message_id'};
		next unless $artnum;

		# All articles in @markable will be added to the newsrc file
		push @markable, $artnum;

		if (!$skipping) {
			if (!$connected) {
				$c->connect;
				$c->group($NNTP_GROUP);
				$connected=1;
			}
			@art_lines = $c->body($artnum);
			if ($RAW) {
				# Take care of raw output, and take next;
				stat_print "newsgrab-".$artnum, "Rawwrite";
				open(FP, ">newsgrab-".$artnum) || die;
				print FP @art_lines;
				close (FP);
				next;
			}
			if (!($arts{$key}->{'type'})) {
				# Determine article type
				if (my $type = probe_article(\@art_lines)) {
					$arts{$key}->{'type'} = $type;
				} else {
					stat_print "Unable to probe $key", "Skipping";
					$skipping = 1;
					next;
				}
			}
			if ($arts{$key}->{'type'} eq "ART_YENC") {
				$skipping = decode_ydec(\@art_lines);
				if ($skipping) {
					stat_print "$key", "SKIPPING YDEC ($skipping)";
				}
			} elsif ($arts{$key}->{'type'} eq "ART_UUENC") {
				$skipping = decode_uudec(\@art_lines);
				if ($skipping) {
					stat_print "$key", "SKIPPING UUDEC ($skipping)";
				}
			} else {
				print STDERR "Unable to determine encoding of article: $key\n";
				exit(1);
			}

		}

		# Done fetching, upgrade progress_bar
		progress_sub($art_no, $parts);
	}
	# Mark articles as read in the newsrc file
	$rc->mark_list($NNTP_GROUP, \@markable);
	$rc->save;
}



exit(1);

# -------------------------------------------------------------- functions ---

sub usage_sub {

	print STDERR "Usage: $0 [OPTIONS] [-g group] [match]\n\n";
	print STDERR "  OPTIONS:\n";
	print STDERR "  -h: This help (and quit)\n";
	print STDERR "  -r: Retrive files that match <exp>\n";
	print STDERR "  -i: Ignore what .newsrc says\n";
	print STDERR "  -s: Server to use from the RC file\n";
	print STDERR "  -c: Specify an alternative conf file (default: $NEWSGRAB_RC)\n";
	print STDERR "  --raw: Write article raw to file named 'newsgrab-<MessageID>'\n";
	print STDERR "  --version: Print version information, then quit\n";
	print STDERR "  --sort: Sort output by: 'd' for date\n";
	print STDERR "          (This require more header information to be\n";
	print STDERR "           retrieved, and is therefor slower)\n";
	print STDERR "\n";
	print STDERR "  -g <group>: Group to retrive from (no group lists all)\n";
	print STDERR "  match: Subject must contain this string (default: 'none')\n";
	print STDERR "\n";
	exit(0);
}

sub version_sub {
	print STDERR "NewsGrab Version $VERSION\n";
	exit(0);
}

sub warn_sig {
	print "Got unexpected answer from server ";
	if ($c) {
		print "(Code: ".$c->code.")";
	}
	print "\n";

	
	if ($c && ($c->code >= 200) && ($c->code < 300)) {
		return;
	}
	if ($c && ($c->code >= 500)) {
		print "Error: ".$c->message()."\n";
		$connected = 0;
	} else {
		if (!($c)) {
			# Connection object not created, we was unable to connect
			# to the news server
			print STDERR "Error: Unable to connect to server\n";
		}
		exit(1);
	}
}

sub stat_print_right {
	my ($line, $stat) = @_;

	# line_width is the space the 2 arguments can actually take
	my $column_width = 77;
	my $line_len = ($column_width-(length($stat))); 
	for (my $i = 0; $i < length($line); $i += $line_len) {
		if (!($i)) {
			printf "%s [%s]\n", substr($line, $i, $line_len), $stat;
		} else {
			printf "%s\n", substr($line, $i, $line_len), $stat;

		}
	}
}

sub stat_print {
	my ($line, $stat) = @_;

	# Column determination is such a hastle, lets just
	# print the line without making it so pretty
	printf "[%s] %s\n", $stat, $line;
	return;



	# line_width is the space the 2 arguments can actually take
	# Use COLUMNS as width or 80 chars as default
	my $column_width = ($ENV{COLUMNS} || 80) - 3;
	my $line_len = ($column_width-(length($stat))); 
	for (my $i = 0; $i < length($line); $i += $line_len) {
		if (!($i)) {
			printf "[%s] %s\n", $stat, substr($line, $i, $line_len);
		} else {
			# Remember to add the filling around $stat
			printf " "x(length($stat)+3);
			printf "%s\n", substr($line, $i, $line_len), $stat;

		}
	}
}


sub stat_print_old {
	my ($line, $stat) = @_;

	# line_width is the space the 2 arguments can actually take
	my $column_width = 77;
	my $line_len = ($column_width-(length($stat))); 
	# Cut $line of, if it's too long;
	$line = substr $line, 0, $line_len;
	printf "%-*s [%s]\n", $line_len, $line, $stat;
}


# BLOCK
{

my $last_res;
sub progress_sub($$) {

	return unless $VERBOSE;
	my ($current_no, $total_no) = @_;
	my $cols = 80;

	# First article, initialize values
	if ($current_no == 1) {
		$last_res = 0;
	}

	my $res = ($current_no * $cols) / $total_no;
	#print "now X".($res - $last_res)."\n";
	print "X" x ($res - $last_res);

	# Last article, set newline
	if ($current_no == $total_no) {
		print "x" x ($cols - $res);
		print "$last_res | $res";
		print "\n";
	}
	$last_res = $res;
}
}

# ------------------------------------------ Article Header Fetch Functions ---
# Articales are returned as follows:
#
# $arts{KEY}->{'date'}      : Contains the date of the posting
#                           : (Note: only if the date is actually in the
#                           : subject listing
# $arts{KEY}->{'complete'}  : Multipart complete (C|R|I)
# $arts{KEY}->{'total'}     : Totalt number of messages in mulipart
# $arts{KEY}->{'message'}   : array of message IDs, there doesn't have
#                           : to be a message ID under each array element
#                           : if a message is missing from the multipart
# $arts{KEY}->{'m_count'}   : Is incremented each time an article is added to
#                           : the {'message'} array.
# $arts{KEY}->{'subj_pre'}  : Subject before multipart number
# $arts{KEY}->{'subj_post'} : Subject after multipart number
#
# KEY : A concationation of the subject of the message, excluding the numbers
#       indicting which part of the subject the article is (Cocatenation of
#	{'subj_pre'} and {'subj_post'}).
# 

sub xover_fetch($) {
	my $NNTP_REGEX = shift;
	my %arts;
	foreach my $head ($c->xover($first, $last)) {
		next unless ($head =~ /$NNTP_REGEX/);
	
		# From RFC 2980:
		# Each line of output will be formatted with the article number,
		# followed by each of the headers in the overview database or the
		# article itself (when the data is not available in the overview
		# database) for that article separated by a tab character.  The
		# sequence of fields must be in this order: subject, author, date,
		# message-id, references, byte count, and line count.  Other optional
		# fields may follow line count.  Other optional fields may follow line
		# count.  These fields are specified by examining the response to the
		# LIST OVERVIEW.FMT command.  Where no data exists, a null field must
		# be provided (i.e. the output will have two tab characters adjacent to
		# each other).  Servers should not output fields for articles that have
		# been removed since the XOVER database was created.
	
		my ($mid, $subject, $author, $date, $message_id, 
	    	$refernences, $byte_count, $line_count
	    	) = split(/\t/, $head);
	
		# Check status of the multipost
		if (!($subject =~ /^(.*[\(|\[]{1})([0-9]+)\/([0-9]+)([\)|\]]{1}.*)$/)) {
			next;
		}
		
		next unless ($1 || $4); # Skip, we can't make index
		my $key = "$1$4";
	
		#print "$2:$3|$head\n";
		if ($2 && $3) {
			# initialize
			if (!$arts{$key}) {
				$arts{$key}->{'date'} = parsedate($date);
				$arts{$key}->{'complete'} = 'I';	# Incomplete
				$arts{$key}->{'total'} = $3;
			}
			$arts{$key}->{'arts'}->{scalar($2)}->{'subject'} = $subject;
			$arts{$key}->{'arts'}->{scalar($2)}->{'message_id'} = $mid;
		} else {
			if (!$arts{$key}) {
				$arts{$key}->{'date'} = parsedate($date);
				$arts{$key}->{'complete'} = 'I';	# Incomplete
				$arts{$key}->{'total'} = 1;
			}
			$arts{$key}->{'arts'}->{'1'}->{'subject'} = $subject;
			$arts{$key}->{'arts'}->{'1'}->{'message_id'} = $mid;
		}
	
	}
	return %arts;
}
	
sub xpat_fetch($) {
	my $NNTP_REGEX = shift;
	my %arts;
	foreach my $head ($c->xpat("Subject", $first, $last, '*'.$NNTP_REGEX.'*')) {
		# Attemt to split result from XPAT into the following variables
		# $1: Name of article (Subject line)
		# $2: Part number
		# $3: Number of total parts
		# $4: Possible rest of subject
		#
		# Key for each hash is based on $5 appended to $2
		chomp($head);

		my ($mid, $subject) = split(/ /, $head, 2);
		if (!($subject =~ /^(.*)[\(|\[]{1}([0-9]+)\/([0-9]+)[\)|\]]{1}(.*)$/)) {
			next;
		}
		
		next unless ($1 || $4);	# Skip if we can't make index
		my $key = "$1$4";

		# Our index will be the subject minus the multipart section (meaning
		# beginning part of subject concatenated with the end part of the subject)

		if ($2 && $3) {
			# This is a multipart message
			if (!($arts{$key})) {
				#initialize
				$arts{$key}->{'complete'} = 'I';
				$arts{$key}->{'total'} = $3;
			}
			$arts{$key}->{'arts'}->{scalar($2)}->{'subject'} = $subject;
			$arts{$key}->{'arts'}->{scalar($2)}->{'message_id'} = $mid;
		} else {
			if (!$arts{$key}) {
				#initialize
				$arts{$key}->{'complete'} = 'I';
				$arts{$key}->{'total'} = 1;
			}
			$arts{$key}->{'arts'}->{'1'}->{'subject'} = $subject;
			$arts{$key}->{'arts'}->{'1'}->{'message_id'} = $mid;
		}
	
	}
	return %arts;
}

# ----------------------------------------------------------------------------
# RC Functions

{

my @servers;

#
# Puts all servers in an array, to be popped.. Array contains hashes like:
# $server->{'key'}      = SERVERKEY
#        ->{'hostname'} = HOSTNAME
#        ->{'port'}     = PORT
#        ->{'username'} = USERNAME
#        ->{'password'} = PASSWORD
#        ->{'rc'}       = RC File
#
# Returns number of servers available
#

sub parse_newsgrabrc($) {
	my $newsgrabrc = shift;

	if(open(FP, $newsgrabrc)) {
		stat_print "Success",
			"Opening newsgrabrc: $newsgrabrc";
	} else {
		stat_print "Failed", 
			"Opening newsgrabrc: $newsgrabrc";
		return;
	}

	while (<FP>) {
		next if (/^\s*#/);
		my %server;
		my ($nothing,
		 $name, 
		 $hostname,
		 $port,
		 $username,
		 $password
			) = split /\s/;
		$server{'key'} = $name;
		$server{'hostname'} = $hostname;
		$server{'port'} = ($port || 119);
		$server{'username'} = $username;
		$server{'password'} = $password;
		$server{'rc'} = 
			$ENV{HOME}."/.newsrc.newsgrab.".$hostname;
		push @servers, \%server;
	}
	
	close (FP);
	return scalar(@servers);
}

#
# Returning an element from the %servers hash, containing all servers
# from the newsgrabrc file.
#
# Returns:
# 	%server{'hostname'}
# 	       {'port'}
#	       {'username'}
#	       {'password'}
#

sub fetch_newsgrabrc(;$) {
	$key = shift;
	
	#
	# If a key for the servers was specified
	# return this server ('undef' if not found), or else
	# return the first in line.
	#

	if ($key) {
		foreach my $server (@servers) {
			if ($server->{'key'} =~ /^$key$/) {
				return $server;
			}
		}
		return;
	} else {
		return shift @servers;
	}
}

} # RC Features END

#
# sub probe_article
#
# Probe article checks lines in the article to determine what kind of
# encoding has been used. It returns a sticker that can be attached to the
# article hash.
#
sub probe_article($) {
	my @lines = @{$_[0]};
	while ($_ = shift(@lines)) {
		if (/^=ybegin/) {
			return "ART_YENC";
		}
		if (/^begin\s*\d*\s*.*/) {
			return "ART_UUENC"
		}
	}
	return 0;
}

# UU_decode
# Hmm! uudec doesn't give a filename in each article, we need some
# way to cope with this

{	# decode_uudec

my ($file, $mode);
sub decode_uudec($) {
	my @lines = @{$_[0]};
	while ($_ = shift(@lines)) {
		chomp;
		if(/^begin\s*(\d*)\s*(.*)/) {
			($mode, $file) = ($1, $2);
			if (-e $file) {
				print STDERR "File: '$file' already exists. skipping\n";
				undef $file;
				undef $mode;
				return 1;
			} else {
				open(OUT, "> $file") || die "Couldn't create $file: $!\n";
			}
			next;
		}
		if (/^end/) {
			close (OUT);
			if (!($mode)) {
				stat_print "No mode supplied for file", "Warning";
			} elsif (!($file)) {
				stat_print "No filename to chmod().. Wierd", "Error";
			} else {
				chmod oct($mode), $file;
			}
			# Set $file and $mode to undef, we have reached the end of this file
			undef $file;
			undef $mode;
		}
		# Failsafe.. Check if we have a filename here
		if ($file) {
			next if /[a-z]/;
			next unless int((((ord() - 32) & 077) + 2) / 3) == int(length() / 4);
			my $unpacked = unpack("u", $_); # This catches phony end lines
			if ($unpacked) {
				(print OUT $unpacked) || die "Couldn't write $file: $!\n";
			}
		} 
	}
	return 0;

}
} # decode_uudec

# Ydec decode

sub decode_ydec($) {
	
	my @lines = @{$_[0]};
	my ($ydec_part, $ydec_line, $ydec_size, $ydec_name, $ydec_pcrc, 
		$ydec_begin, $ydec_end);
	while ($_ = shift(@lines)) {
		# Newlines a fakes and should not be decoded
		chomp;
		s/
//g;
		# If we've started decoding $ydec_name will be set
		if (!$ydec_name) {
			# Skip until beginning of yDecoded part
			next unless (/^=ybegin/);
			if (/ part=(\d+)/) {
				$ydec_part = $1;
			}
		
			if (/ size=(\d+)/) {
				$ydec_size = $1;
			} else {
				print STDERR "Mandatory field 'size' missing";
				return 1;
			}
			if (/ line=(\d+)/) {
				$ydec_line = $1;
			}
			if(/ name=(.*)$/) {
				$ydec_name = $1;
				$ydec_name =~ s/\s+$//g;	# Strip wierdo chars
				#print "Found attach ".$ydec_name." of size ".$ydec_size."\n";
			} else {
				print STDERR "Unknown attach name\n";
				return 1;
			}

			# Multipart messages contain more information on
			# the second lin
			if ($ydec_part) {
				$_ = shift(@lines);
				chomp;
				s/^M//g;
				if (/^=ypart/) {
					if (/ begin=(\d+)/) {
						# We need this to check if the size of this message
						# is correct
						$ydec_begin = $1;
					} else {
						print STDERR "No begin field found in part, ignoring\n";
						undef $ydec_part;
					}
					if (/ end=(\d+)/) {
						# We need this to calculate the size of this message
						$ydec_end = $1;
					} else {
						print STDERR "No end field found in part, ignoring";
						undef $ydec_part;
					}
				} else {
					print STDERR "Article described as multipart message, however "
								."it doesn't seem that way\n";
					undef $ydec_part;
				}
			}
			

			# Now make use of the variables
			# If this is a multipart message $ydec_part is defined
			# What we need to do if the $ydec_part is different from 1
			# we need to open the file for appending!
			if (-e $ydec_name) {
				if (defined($ydec_part)) {
					if ($ydec_part != 1) {
						# If we have a multipart message, the file exists
						# and we are not at the first part, we should just
						# open the file as an append. We assume that this is
						# the multipart we were already processing
						#print "Opening $ydec_name for appending\n";
						if (!open(OUT, ">>$ydec_name")) {
							print STDERR "Couldn't open $ydec_name for appending: $!\n";
							return 1;
						}
					} else {
						# File exists, though this is the first part of the file
						# We are probably in the process of overwriting an older 
						# file
						print STDERR "File: '$ydec_name' alread exists. Skipping\n";
						return 1;
					}
				} else {
					# Message is not multipart, still the filename exists.
					# This shouldn't be, we are probably about to overwrite an
					# older message
					print STDERR "File: '$ydec_name' alread exists. Skipping\n";
					return 1;
				}
			} else {
				# File doesn't exist. We open it for writing O' so plain.
				if (!open(OUT, "> $ydec_name")) {
					print STDERR"Couldn't create $ydec_name: $!\n";
					return 1;
				}
			}
			# Set binmode for the open filehandler
			binmode(OUT);
			# Excellent.. We have detirmed all the info for this file we
			# need.. Skip till next line, this should contain the real
			# data
			next;
		}

		# Looking for the end tag
		if (/^=yend/) {
			# We are done.. Check the sanity of article
			# and unset $ydec_name in case that there are more
			# ydecoded files in the same article
			if (/ part=(\d+)/) {
				if ($ydec_part != $1) {
					print STDERR "Part number '$1' different from beginning part '$ydec_part'\n";
					return 1;
				}
			}
			if (/ size=(\d+)/) {
				# Check size, but first calculate it
				my $size;
				if (defined($ydec_part)) {
					$size = ($ydec_end - $ydec_begin + 1);
				} else {
					$size = $ydec_size;
				}
				if ($1 != $size) {
					print STDERR "Size '$1' different from beginning size '$size'\n";
					return 1;
				}
			}
			if (/ pcrc=([0-9a-f]+)/i) {
				if (defined($ydec_pcrc) && ($ydec_pcrc != $1)) {
					print STDERR "CRC '$1' different from beginning CRC '$ydec_pcrc'\n";
					return 1;
				}
			}
			undef $ydec_name;
			# Dont encode the endline, we skip to the next line
			# in search for any more parts
			next;
		}

		# If we got here, we are within an encoded article, an
		# we will take meassures to decode it
		# We decode line by line
		my $decoded_line;
		for (my $i = 0; $i < length; $i++) {
			my $char = substr($_, $i, 1);
			my $code;
			if ($char eq "=") {
				# Got the special char. This means have to take
				# special care of the next one
				$char = substr($_, ++$i, 1);
				$code = ord($char)-64;
			} else {
				$code = ord($char);
			}

			# Decode the char
			$code -= 42;
			$code += 256 if ($code < 0);
			# Cast back to char from ord()
			$decoded_line .= chr($code);
		}
		print OUT $decoded_line;
	}

	close(OUT);
	return 0;
}
