#!/usr/bin/perl
#
# LMS version 1.3-cvs
#
#  (C) 2001-2004 LMS Developers
#
#  Please, see the doc/AUTHORS for more information about authors!
#
#  This program is free software; you can redistribute it and/or modify
#  it under the terms of the GNU General Public License Version 2 as
#  published by the Free Software Foundation.
#
#  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.
#
#  $Id: lms-rtparser,v 1.15 2004/04/02 18:06:30 alec Exp $

#TODO - reply to a sender on a new ticket

use strict;
use DBI;
use Config::IniFiles;
use Getopt::Long;
use vars qw($configfile $help $version $queue $debug);
use POSIX qw(strftime);
use File::Copy;
use MIME::Parser;
use Data::Dumper;
use Sys::Hostname;

$ENV{'PATH'}='/sbin:/usr/sbin:/usr/local/sbin:/bin:/usr/bin:/usr/local/bin';

sub basename($) { my @tmp = split '/',$_[0]; return pop @tmp }

my $hostname = hostname || 'example.com';

my $save_path = '/home/admins/baseciq/public_html/devel/lms/bin/attach';

my $_version = '1.3-cvs';

my %options = (
	"--config-file|C=s"     =>      \$configfile,
	"--help|h"              =>      \$help,
	"--version|v"           =>      \$version,
	"--debug|d"             =>      \$debug,
	"--queue|q=s"		=>	\$queue
);

Getopt::Long::config("no_ignore_case");
GetOptions(%options);

if($help)
{
	print STDERR <<EOF;
lms-mgc, version $_version
(C) 2001-2004 LMS Developers

-C, --config-file=/etc/lms/lms.ini
		alternate config file (default: /etc/lms/lms.ini);
-h, --help	print this help and exit;
-v, --version	print version info and exit;
-d, --debug	print out debug information, do not log any messages into
		system;
-q, --queue	queue ID (it means, QUEUE ID, numeric! NOT NAME! also
		it's required to run!)
				
EOF
	exit 0;
}							

if($version)
{
	print STDERR <<EOF;
lms-mgc, version $_version
(C) 2001-2004 LMS Developers

EOF
	exit 0;
}

if(!$configfile)
{
	$configfile = "/etc/lms/lms.ini";
}

if(! -r $configfile)
{
	print STDERR "Fatal error: Unable to read configuration file $configfile, exiting.\n";
	exit 1;
}

my $ini = new Config::IniFiles -file => $configfile;
my $dbtype = $ini->val('database', 'type') || 'mysql';
my $dbhost = $ini->val('database', 'host') || 'localhost';
my $dbuser = $ini->val('database', 'user') || 'root';
my $dbpasswd = $ini->val('database', 'password') || '';
my $dbname = $ini->val('database', 'database') || 'lms';

# very ugly code, but we really need tempdir..
# 
my $tmpdir = (defined $ini->val('rt', 'tmp_dir') && ! ($ini->val('rt', 'tmp_dir') eq '')) || (defined $ENV{'TMP'} && ! ($ENV{'TMP'} eq '') ? $ENV{'TMP'} : '/tmp');

my $parser = new MIME::Parser;

# TODO - FIXME - better handling of temporary dir - we should use sth simillar to mktemp();

$parser->decode_headers(1);
$parser->extract_uuencode(1);
$parser->output_dir($tmpdir);

my $entity = $parser->parse(\*STDIN);
my $headers = $entity->head;
my $mh_from = $headers->get('From');
my $mh_to = $headers->get('To');
my $mh_msgid = $headers->get('Message-ID');
my $mh_replyto = $headers->get('Reply-To');
my $mh_subject = $headers->get('Subject');
my $mh_references = $headers->get('References');
my $mailheaders = $headers->as_string;
my $body;
my $mailbody;
my @attachments;

#chomp $mh_from;

#$mh_from =~ s/^.* (<.+\@.+>)$/\1/g;

#print $mh_from;
#print "\n";
#die;

# Taken from pl.comp.lang.perl FAQ - http://www.kt.agh.edu.pl/other/perl/faq/5.html#6

if($entity->mime_type =~ m|multipart/|i) # if we deal with multipart message...
{
	for(my $partnum = 0; $partnum < $entity->parts; $partnum++)
	{
		if(($body = $entity->parts($partnum))->mime_type =~ m|text/|i && $mailbody eq '') # if we have empty body now.
		{
			$body = $entity->parts($partnum);
			$mailbody = $body->as_string;
		}
		else
		{
			# pchnijmy index encji do tablicy z zacznikami
			push @attachments, $partnum;
		}
	}
}
else
{
	$body = $entity->bodyhandle;
	$mailbody = $body->as_string;
}

chomp $mh_from;
chomp $mh_subject;
chomp $mh_msgid;
chomp $mailbody;
chomp $mailheaders;
chomp $mh_replyto;
chomp $mh_references;

$mailbody =~ s/\\/\\\\/g;
$mailbody =~ s/\'/\\\'/g;
$mailheaders =~ s/\\/\\\\/g;
$mailheaders =~ s/\'/\\\'/g;
$mh_from =~ s/\\/\\\\/g;
$mh_from =~ s/\'/\\\'/g;
$mh_msgid =~ s/\\/\\\\/g;
$mh_msgid =~ s/\'/\\\'/g;
$mh_subject =~ s/\\/\\\\/g;
$mh_subject =~ s/\'/\\\'/g;
$mh_replyto =~ s/\\/\\\\/g;
$mh_replyto =~ s/\'/\\\'/g;
$mh_references =~ s/\\/\\\\/g;
$mh_references =~ s/\'/\\\'/g;

if($mh_subject eq '')
{
	$mh_subject = '(brak tematu)';
}

my $dbase;
my $utsfmt;

if($dbtype eq "mysql")
{
	$dbase = DBI->connect("DBI:mysql:database=$dbname;host=$dbhost","$dbuser","$dbpasswd", { RaiseError => 1 });
	$utsfmt = "UNIX_TIMESTAMP()";
}
elsif($dbtype eq "postgres")
{
	$dbase = DBI->connect("DBI:Pg:dbname=$dbname;host=$dbhost","$dbuser","$dbpasswd", { RaiseError => 1 });
	$utsfmt = "EXTRACT(EPOCH FROM CURRENT_TIMESTAMP(0))";
}
elsif($dbtype eq "sqlite")
{
	$dbase = DBI->connect("DBI:SQLite:dbname=$dbname;host=$dbhost","$dbuser","$dbpasswd", { RaiseError => 1 });
	$utsfmt = "strftime('%s','now')";	
}
else
{
	print STDERR "Fatal error: unsupported database type: $dbtype, exiting.\n";
	exit 1;
}

# for security, fetch timestamp from database.
my $dbq = $dbase->prepare("SELECT $utsfmt AS timestamp");
$dbq->execute();
my $row = $dbq->fetchrow_hashref();
my $timestamp = $row->{'timestamp'};

# before we create new ticket try to find references...

my $prev_tid = 0;
$queue = 0 if($queue eq '');
	
# TODO - consider using references and In-Reply-To:
#
# no because: somebody would like to make new request while replying with new subject (without ticketdid)

if( $mh_subject =~ /\[RT#[0-9]{6,}\]/ )
{
	$prev_tid = $mh_subject;
	$prev_tid =~ s/.*\[RT#([0-9]{6,})\].*/\1/;
	$prev_tid = sprintf('%d',$prev_tid);
	$dbq = $dbase->prepare("SELECT * FROM rttickets WHERE id = $prev_tid AND queueid = $queue");
	$dbq->execute();
	if(!($row = $dbq->fetchrow_hashref()))
	{
		$prev_tid = 0;
	}
}

my $ticket_id;
my $rt_msgid;

if(! $prev_tid) # generate new ticket if previous not found
{
	my $fromemail = $mh_from;
	my $reqadminid = 0;
	my $reqcustid = 0;
	$fromemail =~ s/^.* <(.+\@.+)>$/\1/g;
	
	# find adminid
	
	$dbq = $dbase->prepare("SELECT id FROM admins WHERE email = '$fromemail'");
	$dbq->execute();
	if(my $row = $dbq->fetchrow_hashref())
	{
		$reqadminid = $row->{'id'};
	}

	$dbq = $dbase->prepare("SELECT id FROM users WHERE email = '$fromemail'");
	$dbq->execute();
	if(my $row = $dbq->fetchrow_hashref())
	{
		$reqcustid = $row->{'id'};
	}
	
	$dbq = $dbase->prepare("INSERT INTO rttickets (queueid, requestor, requestorcustid, requestoradminid, subject, createtime) VALUES ($queue, '$mh_from', $reqcustid, $reqadminid,'$mh_subject', $timestamp)");
	$dbq->execute();
	
	$dbq = $dbase->prepare("SELECT id FROM rttickets WHERE queueid = '$queue' AND requestor = '$mh_from' AND subject = '$mh_subject' AND createtime = $timestamp");
	
	$dbq->execute();
	$row = $dbq->fetchrow_hashref();
	$ticket_id = $row->{'id'};

	$dbq = $dbase->prepare("INSERT INTO rtmessages (ticketid, mailfrom, subject, messageid, headers, body, createtime) VALUES ($ticket_id, '$mh_from', '$mh_subject', '$mh_msgid', '$mailheaders', '$mailbody', $timestamp)");	
	$dbq->execute();

	# i think that this expr should be enought to fetch id of previously inserted message
	
	$dbq = $dbase->prepare("SELECT id FROM rtmessages WHERE ticketid = $ticket_id AND messageid = '$mh_msgid' AND createtime = $timestamp");
	$dbq->execute();
	$row = $dbq->fetchrow_hashref();
	$rt_msgid = $row->{'id'};	
	
	my $replymail = MIME::Entity->build(
		'Type' => "text/plain",
		'Charset' => "ISO-8859-2",
		'From' => "LMS RT System <parser\@netx.waw.pl>",
		'Encoding' => "quoted-printable",
		'Subject' => "[RT#".sprintf("%06d",$ticket_id)."] Potwierdzenie przyjcia zgoszenia o temacie '".$mh_subject."'",
		'To' => $mh_replyto,
		'References' => $mh_references.' '.$mh_msgid,
		'Data' => [
			"Uprzejmie informujemy e Pastwa zgoszenie zostao zarejestrowane w naszym\n",
			"systemie. Zgoszeniu zosta przydzielony numer: #".sprintf("%06d",$ticket_id)."\n",
			"\n",
			"W przypadku jakiejkolwiek korespondencji zwizanej z Pastwa zgoszeniem, prosimy\n",
			"umieci w polu tematu wiadomoci nastpujcy cig znakw: [RT#".sprintf("%06d",$ticket_id)."]\n",
			"\n",
		],
		'Message-ID' => '<confirm.'.$ticket_id.'.'.$queue.'.'.$timestamp.'@rtsystem.'.$hostname.'>',
		'In-Reply-To' => $mh_msgid,
		'X-Mailer' => 'LMS/RT v.'.$_version
	);
	
	# TODO - is sendmail via pipe is correct way?
	
	open SENDMAIL, "|/usr/lib/sendmail -t -oi -oem"
		or die "$0: open sendmail: $!\n";
	$replymail->print(\*SENDMAIL);
	close SENDMAIL;
	die "sendmail failed" if ($? >> 255);
	
}
else
{
	my @reftab = split(' ',$mh_references);
	my $lastref = $reftab[(scalar @reftab)-1];
	my $inreplytoid = 0;
	$dbq = $dbase->prepare("SELECT id FROM rtmessages WHERE messageid = '$lastref'");
	$dbq->execute();
	if($row = $dbq->fetchrow_hashref())
	{
		$inreplytoid = $row->{'id'};
	}
	$dbq = $dbase->prepare("INSERT INTO rtmessages (ticketid, mailfrom, subject, messageid, replyto, headers, body, inreplyto, createtime) VALUES ($prev_tid, '$mh_from', '$mh_subject', '$mh_msgid', '$mh_replyto', '$mailheaders', '$mailbody', $inreplytoid, $timestamp)");
	$dbq->execute();
	$dbq = $dbase->prepare("SELECT id FROM rtmessages WHERE ticketid = $prev_tid AND messageid = '$mh_msgid' AND createtime = $timestamp");
	$dbq->execute();
	$row = $dbq->fetchrow_hashref();
	$rt_msgid = $row->{'id'};
	
	$ticket_id = $prev_tid;
	
}
if(scalar @attachments)
{
	mkdir($save_path.'/'.sprintf('%06d',$ticket_id));
	mkdir($save_path.'/'.sprintf('%06d',$ticket_id).'/'.sprintf('%06d',$rt_msgid));
	foreach my $partnum (@attachments)
	{
		$body = $entity->parts($partnum);					
		my $filename = $body->bodyhandle->path;
		my $content_type = $body->mime_type;
		copy($filename, $save_path.'/'.sprintf('%06d',$ticket_id).'/'.sprintf('%06d',$rt_msgid));
		$dbq = $dbase->prepare("INSERT INTO rtattachments (messageid, filename, contenttype) VALUES ($rt_msgid, '".basename($filename)."', '$content_type')");
		$dbq->execute();
	}
}
$parser->filer->purge;			# cleanup
$dbq->finish();
$dbase->disconnect();
