#!/usr/bin/perl
#/* ========================================
# * ███╗   ███╗██████╗ ██╗ █████╗ ██╗
# * ████╗ ████║██╔══██╗██║██╔══██╗██║
# * ██╔████╔██║██║  ██║██║███████║██║
# * ██║╚██╔╝██║██║  ██║██║██╔══██║██║
# * ██║ ╚═╝ ██║██████╔╝██║██║  ██║███████╗
# * ╚═╝     ╚═╝╚═════╝ ╚═╝╚═╝  ╚═╝╚══════╝
# * ========================================
# * mDial - Omni-Channel Contact Centre Suite.
# * Initially Written by Martin McCarthy.
# * Contributions welcome.
# * Active: 2020 - 2023.
# *
# * This software is licensed under AGPLv2.
# * You can find more information here;
# * https://www.gnu.org/licenses/agpl-3.0.en.html
# * A copy of the license is also shipped with this build.
# *
# * Important note: this software is provided to you free of charge.
# * If you paid for this software, you were ripped off.
# *
# * This project is a fork of the awesome FOSS project, ViCiDial.
# * ViCiDial is copyrighted by Matt Florell and the ViCiDial Group
# * under the AGPLv2 license.
# *
# * You can find out more about ViCiDial;
# * Web: https://www.vicidial.com/
# * Email: Matt Florell <vicidial@gmail.com>
# * IRC: Libera.Chat - ##vicidial
# *
# * Bug reports, feature requests and patches welcome!
# * ======================================== */
$DB           = 0;
$DBX          = 0;
$VERBOSE      = 1;
$TEST         = 0;
$PATHconf     = '/etc/astguiclient.conf';
$PATHarchive  = '/home/archive/RECORDINGS';
$PATHmonitor  = '/var/spool/asterisk/monitorDONE';
$PATHlogs     = '/var/log/astguiclient';
$URLArchive   = '/archive/RECORDINGS';
$ServerIP     = '127.0.0.1';
$DoMove       = 0;
$DeleteAfter  = 0;
$CompareSizes = 1;
$FileLimit    = 10000;
$MP3          = 1;                                # Default to MP3 cause reasons
$OGG          = 0;
$GSM          = 0;
$WAV          = 0;
$FTPmove =
  1;  # Copy processed files to FTP directory so other scripts can do things too
my $DBhost         = 'localhost';
my $DBname         = 'asterisk';
my $DBuser         = 'cron';
my $DBpass         = '1234';
my $DBport         = '3306';
my $CLIDB_host     = 0;
my $CLIDB_name     = 0;
my $CLIDB_user     = 0;
my $CLIDB_pass     = 0;
my $CLIDB_port     = 0;
my $CLIPATHmonitor = 0;
my $CLIPATHarchive = 0;
my $CLIURLArchive  = 0;
my $CLIServerIP    = 0;
my $CLIPATHconf    = 0;
use warnings;
use DBI;
use File::Basename;
use Scalar::Util qw(looks_like_number);
use File::Copy   qw(move copy);
$| = 1;    # flush buffer after each print so things dont look like they've hung

sub trim {
    my $string = shift;
    $string =~ s/^\s+//;
    $string =~ s/\s+$//;
    return $string;
}

sub getviciarg {
    my $return  = '0';      # Default to boolean false on return
    my $value   = '';       # return value
    my $arg     = shift;    # Get variable to look for
    my $argtype = 'flag'
      ;   # By default just check if the argument exists and return boolean true
    if (@_) {
        if ( lc( $_[0] ) eq 'value' ) { $argtype = 'value'; }
    }     # If we are returning a value, set that option here
    if ( @ARGV && length( $ARGV[0] ) > 1 ) {
        foreach my $a (@ARGV) {
            if ( $a =~ /$arg/i ) {
                my @CLIarg = split( /$arg=/, $a );
                if ( $CLIarg[1] ) {
                    $value = $CLIarg[1];
                    $value =~ s/\/$| |\r|\n|\t//gi
                      ;    # Remove whitespace and special sauce
                    $return = 2;    # Has a value set
                }
                else {
                    $return = 1;    # Only a flag, no value set
                }
            }
        }
    }
    if ( $argtype eq 'value' ) {
        return $value;    # If value requested, return the value of the variable
    }
    else {
        return $return;   # returns 0 for boolean false, 1 = flag, 2 = has value
    }
}

sub debugoutput {
    my $debugline = shift;
    my $debugdie  = 0;
    if (@_)
    {    # If we have a second parameter, it's the debugdie option so grab it
        $debugdie = shift;
        if ( !looks_like_number($debugdie) ) {
            $debugdie = 0;
        }    # 0 = don't exit, 1 = exit, everything else = garbage
    }
    if ( $DB == 1 and $debugdie == 0 ) {
        print "$debugline\n";
    }
    elsif ( $DB == 1 and $debugdie == 1 ) {
        die("$debugline\n")
          ;    # Evidently it was a critical error, so we die on output
    }
}

sub debugxoutput {
    if ( $DBX == 1 ) { debugoutput(@_); }
}    # Same as above, but for DebugX

sub verboseoutput {    # Gives verbose output if it's on
    my $verboseline = shift;
    my $newLine     = 1;       # Add a newline by default
    if (@_) {    # If we have a second parameter, it's the newline option
        $newLine = shift;
    }
    if ( $VERBOSE == 1 ) {
        if   ( $newLine == 1 ) { print "$verboseline\n"; }
        else                   { print "$verboseline"; }
    }
}

sub loadconfig
{    # Parse the config file if it's preasent, skipping options from above
    debugxoutput("--- loadconfig START");
    my $configFile = shift;
    if ( -e $configFile ) {
        open( CONF, "$configFile" );
        @conf = <CONF>;
        close(CONF);
        $i = 0;
        foreach (@conf) {
            $line = $conf[$i];
            $line =~ s/ |>|\n|\r|\t|\#.*|;.*//gi;
            if ( ( $line =~ /^VARDB_server/ ) && ( $CLIDB_host < 1 ) ) {
                $DBhost = $line;
                $DBhost =~ s/.*=//gi;
            }
            if ( ( $line =~ /^VARDB_database/ ) && ( $CLIDB_name < 1 ) ) {
                $DBname = $line;
                $DBname =~ s/.*=//gi;
            }
            if ( ( $line =~ /^VARDB_user/ ) && ( $CLIDB_user < 1 ) ) {
                $DBuser = $line;
                $DBuser =~ s/.*=//gi;
            }
            if ( ( $line =~ /^VARDB_pass/ ) && ( $CLIDB_pass < 1 ) ) {
                $DBpass = $line;
                $DBpass =~ s/.*=//gi;
            }
            if ( ( $line =~ /^VARDB_port/ ) && ( $CLIDB_port < 1 ) ) {
                $DBport = $line;
                $DBport =~ s/.*=//gi;
            }
            if ( ( $line =~ /^PATHDONEmonitor/ ) && ( $CLIPATHmonitor < 1 ) ) {
                $PATHmonitor = $line;
                $PATHmonitor =~ s/.*=//gi;
            }
            if ( ( $line =~ /^PATHlogs/ ) ) {
                $PATHlogs = $line;
                $PATHlogs =~ s/.*=//gi;
            }
            if ( ( $line =~ /^VARserver_ip/ ) ) {
                $ServerIP = $line;
                $ServerIP =~ s/.*=//gi;
            }
            $i++;
        }
    }
    else { print "Config file not found at: $configFile\n"; }
    debugxoutput("--- loadconfig STOP");
}

sub findRecordingID {    # Find the recording_id for the file and return it
    debugxoutput("--- findRecordingID START");
    my $filename    = shift;
    my $recordingID = '-1';
    my $startTime   = '-1';
    my $sth         = $dbhVD->prepare(
'SELECT recording_id, date(start_time) FROM recording_log WHERE filename = ?'
    ) or die "Recording ID prepare failed: $dbh->errstr()";
    $sth->execute($filename)
      or die "Recording ID execution failed: $dbh->errstr()";
    my $sthRows = $sth->rows;
    if ( $sthRows >= 1 ) {
        my @row = $sth->fetchrow_array;
        $recordingID = $row[0];
        $startTime   = $row[1];
    }
    return ( $recordingID, $startTime );
    debugxoutput("--- findRecordingID STOP");
}

sub updateRecordingID {
    debugxoutput("--- updateRecordingID START");
    my $recordingID  = shift;
    my $recordingURL = shift;
    my $sql = 'update recording_log set location=? where recording_id=?;';
    $dbhVD->do( $sql, undef, $recordingURL, $recordingID );
    return 0;
    debugxoutput("--- updateRecordingID STOP");
}
$args = "";
if ( length( $ARGV[0] ) > 1 ) {
    $i = 0;
    while ( $#ARGV >= $i ) {
        $args = "$args $ARGV[$i]";
        $i++;
    }
    if ( $args =~ /--help/i ) {
        loadconfig($PATHconf);
        print "\n\nViciDial Local Archive\n\n";
        print "allowed run time options:\n";
        print "  [--debug] = debug\n";
        print "  [--debugX] = debug extended\n";
        print "  [--quiet] = Be quiet, default is to be verbose\n";
        print "  [--domove] = Move files instead of copying to archive\n";
        print "  [--deleteafter] = Delete file after copying\n";
        print "  [--dontcompare] = Don't compare file size after copy/move\n";
        print "  [--mp3] = Process MP3 recordings, DEFAULT\n";
        print "  [--ogg] = Process OGG recordings\n";
        print "  [--wav] = Process WAV recordings\n";
        print "  [--gsm] = Process GSM recordings\n";
        print "  [--filelimit=$FileLimit] = Max number of files to process\n";
        print "  [--noftpmove] = Do not copy files to FTP directory\n";
        print "  [--astconffile=$PATHconf] = ViciDial configuration file\n";
        print
          "  [--monitordir=$PATHmonitor] = Directory of ViciDial recordings\n";
        print
          "  [--archivedir=$PATHarchive] = Directory for the local archive\n";
        print
"  [--archiveurl=$URLArchive] = URL to add to end of local server IP\n";
        print "  [--archivehost=$ServerIP] = Host/IP to use in URL creation\n";
        print "  [--dbhost=$DBhost] = Database Host\n";
        print "  [--dbname=$DBname] = Database Name\n";
        print "  [--dbuser=$DBuser] = Database User\n";
        print "  [--dbpass=$DBpass] = Database Pass\n";
        print "  [--dbport=$DBport] = Database Port\n";
        exit;
    }
    else {
        if ( getviciarg('--debugX') ) {
            $DBX     = 1;
            $DB      = 1;
            $VERBOSE = 1;
            print "\n\nViciDial Local Archive\n\n";
            print "\n----- DEBUG Extended -----\n\n";
        }
        if ( $DB == 0 && getviciarg('--debug') ) {
            $DB      = 1;
            $VERBOSE = 1;
            print "\n\nViciDial Local Archive\n\n";
            print "\n----- DEBUG Normal -----\n\n";
        }
        if ( getviciarg('--domove') ) {
            $DoMove = 1;
            debugoutput(" CLI Transfer Method  :      Move");
        }
        if ( $VERBOSE == 1 && $DB == 0 && getviciarg('--quiet') ) {
            $VERBOSE = 0;
            debugoutput(" CLI Verbose          :      Yes");
        }
        if ( $DoMove == 0 && getviciarg('--deleteafter') ) {
            $DeleteAfter = 1;
            debugoutput(" CLI Delete After     :      Yes");
        }
        if ( getviciarg('--dontcompare') ) {
            $CompareSizes = 0;
            debugoutput(" CLI Compare Sizes    :      No");
        }
        if ( getviciarg('--noftpmove') ) {
            $FTPmove = 0;
            debugoutput(" CLI Move to FTP dir  :      No");
        }
        if ( getviciarg('--astconffile') == 2 ) {
            $PATHconf    = getviciarg( '--astconffile', 'value' );
            $CLIPATHconf = 1;
            debugoutput(" CLI Vici conf file   :      $PATHconf");
        }
        if ( getviciarg('--monitordir') == 2 ) {
            $PATHmonitor    = getviciarg( '--monitordir', 'value' );
            $CLIPATHmonitor = 1;
            debugoutput(" CLI monitor dir      :      $PATHmonitor");
        }
        if ( getviciarg('--archivedir') == 2 ) {
            $PATHarchive    = getviciarg( '--archivedir', 'value' );
            $CLIPATHarchive = 1;
            debugoutput(" CLI archive dir      :      $PATHarchive");
        }
        if ( getviciarg('--archiveurl') == 2 ) {
            $URLArchive    = getviciarg( '--archiveurl', 'value' );
            $CLIURLArchive = 1;
            debugoutput(" CLI archive dir      :      $PATHarchive");
        }
        if ( getviciarg('--archivehost') == 2 ) {
            $ServerIP    = getviciarg( '--archivehost', 'value' );
            $CLIServerIP = 1;
            debugoutput(" CLI archive dir      :      $PATHarchive");
        }
        if ( getviciarg('--filelimit') == 2 ) {
            $FileLimit      = getviciarg( '--filelimit', 'value' );
            $CLIPATHarchive = 1;
            debugoutput(" CLI file limit       :      $FileLimit");
        }
        if ( getviciarg('--wav') ) {
            $WAV = 1;
            $MP3 = 0;
            $GSM = 0;
            $OGG = 0;
        }
        if ( getviciarg('--ogg') ) {
            $WAV = 0;
            $MP3 = 0;
            $GSM = 0;
            $OGG = 1;
        }
        if ( getviciarg('--gsm') ) {
            $WAV = 0;
            $MP3 = 0;
            $GSM = 1;
            $OGG = 0;
        }
        if ( getviciarg('--dbhost') == 2 ) {
            $DBhost     = getviciarg( '--dbhost', 'value' );
            $CLIDB_host = 1;
            debugoutput(" CLI Database Host    :      $DBhost");
        }
        if ( getviciarg('--dbname') == 2 ) {
            $DBname     = getviciarg( '--dbname', 'value' );
            $CLIDB_name = 1;
            debugoutput(" CLI Database Name    :      $DBname");
        }
        if ( getviciarg('--dbuser') == 2 ) {
            $DBuser     = getviciarg( '--dbuser', 'value' );
            $CLIDB_user = 1;
            debugoutput(" CLI Database User    :      $DBuser");
        }
        if ( getviciarg('--dbpass') == 2 ) {
            $DBpass     = getviciarg( '--dbpass', 'value' );
            $CLIDB_pass = 1;
            debugoutput(" CLI Database Password:      $DBpass");
        }
        if ( getviciarg('--dbport') == 2 ) {
            my $DBPORTtmp = getviciarg( '--dbport', 'value' );
            if ( looks_like_number($DBPORTtmp) ) {
                if ( $DBPORTtmp < 65535 && $DBPORTtmp > 1024 ) {
                    $DBport     = $DBPORTtmp;
                    $CLIDB_port = 1;
                    debugoutput(" CLI Database Port    :      $DBport");
                }
            }
        }
    }
}
loadconfig($PATHconf);
if ( $DB == 1 ) {
    if   ( $MP3 == 1 ) { debugoutput(" MP3 processing       :      Yes"); }
    else               { debugoutput(" MP3 processing       :      No"); }
    if   ( $WAV == 1 ) { debugoutput(" WAV processing       :      Yes"); }
    else               { debugoutput(" WAV processing       :      No"); }
    if   ( $OGG == 1 ) { debugoutput(" OGG processing       :      Yes"); }
    else               { debugoutput(" OGG processing       :      No"); }
    if   ( $GSM == 1 ) { debugoutput(" GSM processing       :      Yes"); }
    else               { debugoutput(" GSM processing       :      No"); }

    if ( $CLIPATHconf == 0 ) {
        debugoutput(" ViciDIal Conf file   :      $PATHconf");
    }
    if ( $CLIPATHmonitor == 0 ) {
        debugoutput(" Monitor Dir          :      $PATHmonitor");
    }
    if ( $CLIPATHarchive == 0 ) {
        debugoutput(" Archive Dir          :      $PATHarchive");
    }
    if ( $CLIURLArchive == 0 ) {
        debugoutput(" Archive URL          :      $URLArchive");
    }
    if ( $CLIServerIP == 0 ) {
        debugoutput(" Archive Host         :      $ServerIP");
    }
    if ( $CLIDB_host == 0 ) {
        debugoutput(" Database Host        :      $DBhost");
    }
    if ( $CLIDB_name == 0 ) {
        debugoutput(" Database Name        :      $DBname");
    }
    if ( $CLIDB_user == 0 ) {
        debugoutput(" Database User        :      $DBuser");
    }
    if ( $CLIDB_pass == 0 ) {
        debugoutput(" Database Pass        :      $DBpass");
    }
    if ( $CLIDB_port == 0 ) {
        debugoutput(" Database Port        :      $DBport");
    }
    if ( $DoMove == 0 ) {
        debugoutput(" Transfer Method      :      Copy");
        if ( $DeleteAfter == 0 ) {
            debugoutput(" Delete After         :      No");
        }
        if ( $FTPmove == 1 ) {
            debugoutput(" Move to FTP dir      :      Yes");
        }
    }
    if ( $CompareSizes == 1 ) { debugoutput(" Compare File Sizes  :      No"); }
}
verboseoutput("ViciDial Local Archive");
$RUNNING_FILE = basename($0);
my $grepout =
  `/bin/ps ax | grep $RUNNING_FILE | grep -v grep | grep -v /bin/sh`;
my $grepnum = 0;
$grepnum++ while ( $grepout =~ m/\n/g );
if ( $grepnum > 1 ) {
    die("\nI am not alone! Another $0 is running! Exiting...\n");
}
if ( $DB < 1 && $VERBOSE < 1 ) {
    use IO::Handle;
    open OUTPUT, '>>', "$PATHlogs/audio_3_archive.log" or die $!;
    open ERROR,  '>>', "$PATHlogs/audio_3_archive.log" or die $!;
    STDOUT->fdopen( \*OUTPUT, 'w' ) or die $!;
    STDERR->fdopen( \*ERROR,  'w' ) or die $!;
}
$dbhVD =
  DBI->connect( "DBI:mysql:$DBname:$DBhost:$DBport", "$DBuser", "$DBpass" )
  or die "Couldn't connect to database: " . DBI->errstr;
if ( !-d $PATHarchive ) { die "Archive directory not found at $PATHarchive\n"; }
$dir2   = "$PATHmonitor";
$FTPdir = "$PATHmonitor/FTP";
if ( $MP3 > 0 ) { $dir2 = "$PATHmonitor/MP3"; }
if ( $GSM > 0 ) { $dir2 = "$PATHmonitor/GSM"; }
if ( $OGG > 0 ) { $dir2 = "$PATHmonitor/OGG"; }
verboseoutput( "Processing $dir2...", 0 );
$CTfile = 0;
opendir( DIR, "$dir2" ) or die "Can't open $dir2: $!";

while ( defined( my $file = readdir DIR ) && $CTfile < $FileLimit ) {
    next if ( $file =~ m/^\./ );    # Don't bother with files beginning with a .
    $files[$CTfile][0] = $file;
    $files[$CTfile][1] =
      -s "$dir2/$file";    # Store filesize so we can check it later for writes
    $CTfile++;
}
closedir(DIR);
verboseoutput("  found $CTfile files.");
sleep 3;                   # Wait so we can check for writes later
$fileCount = 0;
while ( $fileCount < $CTfile ) {
    debugoutput("Processing file $fileCount: $dir2/$files[$fileCount][0]");
    my $file = $files[$fileCount][0];
    my $filePreSize =
      $files[$fileCount][1];    # Size of file when directory was listed
    my $fileSize = -s "$dir2/$file";    # Size of file as it exists now
    my ( $filename, $path, $suffix ) = fileparse( "$dir2/$file", '\.[^\.]*' );
    my $basename = $filename;
    $basename =~ s/-all//;
    my ( $recordingID, $recordingDate ) = findRecordingID($basename);

    if ( $recordingID == '-1' ) {
        verboseoutput("  File $file not found in database");
        $fileCount++;
        next;    # Force loop
    }
    elsif ( $filePreSize == $fileSize )
    {            # File sizes match, so it's not been written to
        verboseoutput(
"  File $fileCount: $file, Size: $filePreSize, ID: $recordingID... ",
            0
        );
    }
    else {
        verboseoutput(
"  File $fileCount: $file has changed size from $filePreSize to $fileSize, skipping."
        );
        $fileCount++;
        next;    # Force loop
    }
    if ( !-d "$PATHarchive/$recordingDate" ) {
        mkdir "$PATHarchive/$recordingDate";
    }
    if ( -f "$dir2/$file" ) {
        if ( $DoMove == 1 ) {
            move( "$dir2/$file", "$PATHarchive/$recordingDate/$file" );
            verboseoutput( "moved...", 0 );
        }
        else {
            copy( "$dir2/$file", "$PATHarchive/$recordingDate/$file" );
            verboseoutput( "copied...", 0 );
            if ( $FTPmove == 1 && -d $FTPdir ) {
                move( "$dir2/$file", "$FTPdir/$file" );
            }
            else {
                debugoutput("  FTP directory doesn't exist at $FTPdir!?");
            }
        }
        $fileSize = -s "$PATHarchive/$recordingDate/$file";
        if ( !-f "$PATHarchive/$recordingDate/$file" ) {
            die(
" ERROR! File $file was not found at $PATHarchive/$recordingDate as expected! Drive full?\n"
            );
        }
        elsif ( $CompareSizes == 1 && $filePreSize != $fileSize ) {
            die(
"File $file was not the same size after copying/moving! Drive full?\n"
            );
        }
        elsif ( $DoMove == 0 && $DeleteAfter == 1 ) {
            unlink("$dir2/$file");
        }
    }
    else {
        verboseoutput("File $dir2/$file not found! skipping...");
        $fileCount++;
        next;    # Force loop
    }
    verboseoutput( " updating DB... ", 0 );
    my $newURL = "http://$ServerIP/$URLArchive/$recordingDate/$file";
    updateRecordingID( $recordingID, $newURL );
    verboseoutput("done.");
    $fileCount++;
}
