#!/usr/bin/perl

use utf8;
use strict;
use warnings; no warnings qw(once redefine uninitialized);

=head1 NAME

  dump_tickets

Dumps tickets into textfiles

=cut

# FIXME
#BEGIN {
#    unshift @INC, ( $ENV{'POPHOME'} || '@POPHOME@' ) . '/lib'
#		unless $ENV{'KUNDE_NO_PERLPATH'};
#}
use lib qw(/usr/pop/lib);

use Dbase::Globals qw(get_gruppen test_gruppe find_descr);
use Dbase::Help qw(DoFn DoSelect);
use MIME::Parser;
use MIME::Entity;
use Fcntl qw(:flock);

our $BaseDir = "/www/volltextsuche/dump/";
our ($grs, $grc) = get_gruppen ("tickett", "content");
our $status_dead = find_descr (tickets => 'dead', 1);
our $Count = 0;
our $LastRun = '';
our $Now = '';
our @Queues = qw(adm ccm housing incident netz support technik);

our $parser = new MIME::Parser;
$parser->output_to_core (1);

=head1 TIMESTAMP

In der Datei C<lastrun> befindet sich ein timestamp in der Form

  yyyymmddhhmmss

Nur Tickets, die seit diesem Zeitpunkt veraendert wurden werden ge'dumpt.
Gleichzeitig dient diese Datei als Lock: So lange das Script laeuft haelt
es das Lock fuer diese Datei, weitere Instanzen werden daraufhin nicht
anfangen Tickets zu dumpen..

=cut

if (!-e $BaseDir)
{
	mkdir ($BaseDir) or die ("mkdir: $!");
}

if (-e "lastrun")
{
	my $tmp;
	
	open (LR, "< lastrun")
		or die ("open: $!");
	if (!flock (LR, LOCK_SH | LOCK_NB))
	{
		close (LR);
		print STDERR "Lock taken, giving up!\n";
		exit (1);
	}
	
	$tmp = <LR>;
	chomp ($tmp);

	$LastRun = $tmp if ($tmp);

	flock (LR, LOCK_UN);
	close (LR);
}
else
{
	$LastRun = get_timestamp (time () - 3600);
	#$LastRun = "19700101000000";
}

$Now = get_timestamp ();

open (LR, "> lastrun")
	or die ("open: $!");
if (!flock (LR, LOCK_EX | LOCK_NB))
{
	close (LR);
	print STDERR "Lock taken, giving up!\n";
	exit (1);
}

print LR $Now, $/;

# Set autoflush
$| = 1;

print STDERR "Dumping all tickets from $LastRun to $Now\n";

{
	my $queues = join (',', map { "'$_'" } (@Queues));

	DoSelect (sub
	{
		#my ($tid, $tseq, $ttyp, $tinhalt, $tstatus) = @_;
		handle_ticket (@_);
	},
	"SELECT ticketid.ticket FROM ( ticketid, queue ) "
	. "LEFT JOIN ticket ON ticket.id = ticketid.ticket "
	. "WHERE ticketid.timestamp BETWEEN $LastRun AND ($Now - 1) "
	. "AND ticket.id = ticket.ticket "
	. "AND ticket.status <> $status_dead "	# != dead
	. "AND queue.id = ticket.queue "
	. "AND queue.name IN ($queues) "
	. "GROUP BY ticketid.ticket "
	. "ORDER BY ticketid.ticket");
}

=head1 SQL-STATEMETNT

Das Monster-Maessige SQL-Statement

  SELECT ticketid.ticket FROM ticketid 
    LEFT JOIN ticket ON ticket.id = ticketid.ticket
    WHERE ticketid.timestamp BETWEEN $LastRun AND ($Now - 1) 
    AND ticket.id = ticket.ticket
    AND ticket.status <> $status_dead
    AND (ticket.queue = 6 
      OR queue = 31300
      OR queue = 1639
      OR queue = 14951
      OR queue = 570
      OR queue = 24001
      OR queue = 7
      OR queue = 5
      OR queue = 13752
      OR ticket.queue = 7164)
    GROUP BY ticketid.ticket
    ORDER BY ticketid.ticket

Viel Spass beim debuggen..

=cut
    
flock (LR, LOCK_UN);
close (LR);

exit (0);

sub handle_ticket
{
	my $tid = shift;

	my @tickets = ($tid);
	my $where;
	my $subdir;
	my $fh;

	print "Ticket $tid\n";

	DoSelect (sub
	{
		push (@tickets, $_[0]);
	},
	"SELECT id FROM ticket WHERE ticket = $tid AND ticket <> id");

	$where = join (' OR ', map { "ticket = $_" } (@tickets));

	$subdir = int ($tid / 1000) . '/';
	if (!-e "$BaseDir$subdir")
	{
		mkdir ($BaseDir . $subdir) or die ("mkdir: $!");
	}

	open ($fh, "> $BaseDir$subdir$tid.txt") or die ("open: $!");

	my $subject = DoFn("SELECT subject FROM ticket WHERE id = $tid");
	print $fh "Ticket Subject: $subject\n";

	DoSelect (sub
	{
		handle_sequence ($fh, @_);
	},
	"SELECT ticket, seq, typ, inhalt FROM ticketid WHERE $where ORDER BY ticket, seq");

	$Count++;

	if (($Count % 200) == 0)
	{
		print '.';
	}

	if (($Count  % 10000) == 0)
	{
		printf (" %6u\n", $Count);
	}
	
	close ($fh);
}

sub handle_sequence
{
	my ($fh, $etid, $tseq, $ttyp, $tinhalt) = @_;

	return unless (defined ($tinhalt));
	return unless (defined ($ttyp));

	return unless (test_gruppe ("tickett", $ttyp, $grs, $grc));

	$tinhalt =~ s/\r//gs;

	return unless ($tinhalt);

	my $entity = $parser->parse_data ($tinhalt);
	$tinhalt = handle_entity ($entity);
	$entity->purge ();

	return unless ($tinhalt =~ m/[^\s\n\r]/s);

	print $fh "\n-- $etid-$tseq ----------------\n", $tinhalt, "\n";
}

sub handle_entity
{
	my $e = shift;
	my $t = $e->effective_type ();
	my $r = '';

	if (($t =~ m#^text/#i) or ($t =~ m#^message/#i))
	{
		my $hd = $e->head;
		my $bd = $e->bodyhandle;

		if (defined ($bd) and defined ($hd))
		{
			for (qw(From To Cc Subject))
			{
				my $f = $_;
				if ($hd->get ($f))
				{
					$r .= $f . ': ' . $hd->get ($f);
				}
			}
			$r .= "\n";

			$r .= $bd->as_string;
		}
	}
	elsif ($t =~ m#^multipart/#i and 0)
	{
		my @p = $e->parts;
		my $h = $e->head->decode;

		for (qw(From To Cc Subject))
		{
			my $f = $_;
			if ($h->get ($f))
			{
				$r .= $f . ': ' . $h->get ($f);
			}
		}
		$r .= "\n";

		#$r = $e->head->decode->as_string . "\n";
		$r .= handle_entity ($_) for (@p);
	}
		
	return ($r);
}

###
# ALTE FUNKTIONEN
###
sub parse_header
{
	my $head = shift;
	my $retval = {};

	$head =~ s/\n\s+/ /sg;
	#$head =~ s/\s+/ /g;

	while ($head =~ m/^([^:\s\n]+):\s*(.*)$/gm)
	{
		$retval->{lc ($1)} = $2;
	}

	return ($retval);
}

sub handle_mail_format
{
	my $mail = shift;
	my $retval = '';

	$mail =~ s/^\n+//s;
	$mail =~ s/\n+$//s;

	my ($head, $data) = split (m/\n\n+/s, $mail, 2);
	my $head_hash;

	return ('') unless (defined ($data) and $data);
	
	$head_hash = parse_header ($head);

	if (!defined ($head_hash->{'content-type'}))
	{
		# foo
	}
	elsif ($head_hash->{'content-type'} =~ m#^text/#i)
	{
		$retval = "$head\n\n$data\n\n";
	}
	# Content-Type: multipart/signed; micalg=pgp-sha1; protocol="application/pgp-signature"; boundary="tfmLD+Hxjexp/STe"
	elsif ($head_hash->{'content-type'} =~ m#multipart/\w+;.*boundary="([^"]+)"#i)
	{
		my $boundary = quotemeta ($1);
		my @parts = split (m/$boundary/, $data);

		for (@parts)
		{
			$retval .= handle_mail_format ($_);
		}

		if ($retval)
		{
			$retval = "$head\n\n$retval";
		}
	}
	elsif ($head_hash->{'content-type'} =~ m#message/rfc822#i)
	{
		$retval = "$head\n\n$data\n\n";
	}
	else
	{
		#print STDERR "Content-Type: ", $head_hash->{'content-type'}, $/;
	}

	return ($retval);
}



sub get_timestamp
{
	my $t;

	if (@_)
	{
		$t = shift;
	}
	else
	{
		$t = time ();
	}
	
	my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst)
		= localtime ($t);

	$mon++;
	$year += 1900;

	return (sprintf ("%04u%02u%02u%02u%02u%02u", $year, $mon, $mday, $hour, $min, $sec));
}

=head1 AUTOR

Florian Forster, octo@noris.net

=cut
