<?php
/**
 * @copyright 2021 Double Bastion LLC <www.doublebastion.com>
 *
 * @author Double Bastion LLC
 *
 * @license GNU AGPL version 3 or any later version
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
 * License as published by the Free Software Foundation; either
 * version 3 of the License, or any later version.
 *
 * 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 AFFERO GENERAL PUBLIC LICENSE for more details.
 *
 * You should have received a copy of the GNU Affero General Public
 * License along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

declare(strict_types=1);

namespace OCA\SMSRelentless\Controller;

use OCP\IRequest;
use OCP\AppFramework\Controller;
use OCA\SMSRelentless\Service\SmsrelentlessService;
use OCP\AppFramework\App;
use OC\Http\Client\Client;
use OCP\Files\SimpleFS\ISimpleFile;
use OCP\Files\SimpleFS\ISimpleFolder;
use OCP\IL10N;
use OCP\Files\File;
use OCP\Files\Folder;
use OCP\Files\IRootFolder;
use OCP\IConfig;
use OC\Files\Filesystem;
use OC\Files\View;
use \ReflectionClass;
use \FilesystemIterator;
use \DateTime;
use \DateInterval;
use OCP\AppFramework\Http\DataResponse;
use OCP\Files\NotFoundException;
use OCP\Files\NotPermittedException;
use Plivo\RestClient;
use OCP\Share\IManager;
use OCP\Constants;
use OCP\IDBConnection;
use OCP\IUserManager;
use OCP\IUserSession;
use OC\URLGenerator;
use OCP\Share\IShare;

class SmsrelentlessController extends Controller {

    private $service;
    private $config;
    private $folder;
    private $filesystem;
    private $view;
    private $shareManager;
    private $connection;
    private $userManager;
    private $userSession;
    private $urlGenerator;
    private $rootFolder;

    public function __construct($appName, IRequest $request, SmsrelentlessService $service, IConfig $config, Folder $folder, Filesystem $filesystem, View $view, IManager $shareManager, IDBConnection $connection, IUserManager $userManager, IUserSession $userSession, URLGenerator $urlGenerator, IRootFolder $rootFolder) {

        parent::__construct($appName, $request);
        $this->service = $service;
        $this->config = $config;
        $this->folder = $folder;
        $this->filesystem = $filesystem;
        $this->view = $view;
	$this->shareManager = $shareManager;
        $this->connection = $connection;
        $this->userManager = $userManager;
        $this->userSession = $userSession;
        $this->urlGenerator = $urlGenerator;
        $this->rootFolder = $rootFolder;
    }


    /**
     * @NoAdminRequired
     */
    public function object_to_array($obj) {
        if (is_object($obj)) $obj = (array)$this->dismount($obj);
        if (is_array($obj)) {
           $new = array();
           foreach($obj as $key => $val) {
               $new[$key] = $this->object_to_array($val);
           }
        }
        else $new = $obj;
        return $new;
    }


    /**
     * @NoAdminRequired
     */
    public function dismount($object) {
        $reflectionClass = new ReflectionClass(get_class($object));
        $array = array();
        foreach ($reflectionClass->getProperties() as $property) {
           $property->setAccessible(true);
           $array[$property->getName()] = $property->getValue($object);
           $property->setAccessible(false);
        }
        return $array;
    }


    /**
     * @NoAdminRequired
     */
    public function getappdirectory() {
        $apprelpath = $this->urlGenerator->linkTo('sms_relentless', 'COPYING.txt');
        $apprelpatharr = explode("/", $apprelpath);
        $currentappdir = $apprelpatharr[1];
        return $currentappdir;
    }


    /**
     * @NoAdminRequired
     */
    public function createMessageId() {
             // Create a random string to use as message id for messages that don't have it
	     $keypassin = substr(sha1((string) mt_rand()), 0, 32);
	     $keysaltin = openssl_random_pseudo_bytes(24);
	     $keyLengthin = 32;
	     $iterationin = 50;
	     $generated_keyin = openssl_pbkdf2($keypassin, $keysaltin, $keyLengthin, $iterationin, 'sha256');
	     $ctdMessageId = "generated-id-" . bin2hex($generated_keyin);
             return $ctdMessageId;
    }


    /**
     * @NoAdminRequired
     */
    public function getbalancetel() {

        $telsmsapicred = $this->service->getapicredentials($this->userSession->getUser()->getUID(), 'telnyx');

        $telapikey = $telsmsapicred[0];
        $ch = curl_init();
        $headerstel = array("Content-Type: application/json", "Accept: application/json", "Authorization: Bearer ".$telapikey);

        curl_setopt($ch, CURLOPT_URL, "https://api.telnyx.com/v2/balance");
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch, CURLOPT_HTTPHEADER, $headerstel);
        $responsetel = curl_exec($ch);
        $recdatatel = json_decode($responsetel, TRUE);
        $telbalresponse = $recdatatel['data']['balance'];
        $currentbalancetel = round(floatval($telbalresponse), 3);
        curl_close($ch);

        return $currentbalancetel;
    }


    /**
     * @NoAdminRequired
     */
    public function getbalancenex() {

        $smsapicred = $this->service->getapicredentials($this->userSession->getUser()->getUID(), 'plivo');
        $smsapikey = $smsapicred[5];
        $smsapisecret = $smsapicred[6];

        if ($smsapikey == '' || $smsapisecret == '') {
            $currentbalancenex = "N/A";
        } else {
            $getmesdata = "https://".$smsapikey.":".$smsapisecret."@api.plivo.com/v1/Account/".$smsapikey."/";
            $mesdata = file_get_contents($getmesdata);
            $datainit = json_decode($mesdata);
            $balancenex = $datainit->cash_credits;
            $currentbalancenex = round(floatval($balancenex), 3);
        }
        return $currentbalancenex;
    }


    /**
     * @NoAdminRequired
     */
    public function getbalancetwil() {

        $smsapicred = $this->service->getapicredentials($this->userSession->getUser()->getUID(), 'twilio');

        $smsapisid = $smsapicred[15];
        $smsapitoken = $smsapicred[16];

        if ($smsapisid == '' || $smsapitoken == '') {
            $currentbalancetwil = "N/A";
        } else {

            $twilbalance = json_decode(file_get_contents("https://".$smsapisid.":".$smsapitoken."@api.twilio.com/2010-04-01/Accounts/".$smsapisid."/Balance.json"));
            $balancetwil = $twilbalance->balance;

            $currentbalancetwil = round(floatval($balancetwil), 3);
        }
        return $currentbalancetwil;
    }


    /**
     * @NoAdminRequired
     */
    public function getbalanceflow() {

        $currentbalanceflow = 'n/a';
        return $currentbalanceflow;
    }


    /**
     * @NoAdminRequired
     */
    public function getsmsnumbers() {

        return $this->service->getsmsnumbers($this->userSession->getUser()->getUID());
    }


    /**
     * @NoAdminRequired
     */
    public function refreshavailablenumbers() {

        return $this->service->refreshavailablenumbers($this->userSession->getUser()->getUID());
    }


    /**
     * @NoAdminRequired
     */
    public function cleantempdir() {

        // Create the temporary folder if it doesn't exist
        if ($this->folder->nodeExists('SMS_Relentless/temp_files') == false) {
            $this->folder->newFolder('SMS_Relentless/temp_files');
        }

        $gettempdir = $this->folder->get("/SMS_Relentless/temp_files");
        $fileSystemIterator = $gettempdir->getDirectoryListing();

        $dirfiles = [];
        foreach ($fileSystemIterator as $fileInfo){
                 $dirfiles[] = $fileInfo->getName();
        }

        foreach ($dirfiles as $key => $indfile) {
                 $tempfile = "/SMS_Relentless/temp_files/" . $indfile;
                 $userFolder = $this->rootFolder->getUserFolder($this->userSession->getUser()->getUID());
                 $removetmpfile = $userFolder->get($tempfile)->delete();
        }
     }


    /**
     * @NoAdminRequired
     */
    public function cleanmultrecdir() {

        // Create the temporary folder if it doesn't exist
        if ($this->folder->nodeExists('SMS_Relentless/multiple_recipients') == false) {
            $this->folder->newFolder('SMS_Relentless/multiple_recipients');
        }

        $gettempdir = $this->folder->get("/SMS_Relentless/multiple_recipients");
        $fileSystemIterator = $gettempdir->getDirectoryListing();

        $dirfiles = [];
        foreach ($fileSystemIterator as $fileInfo){
                 $dirfiles[] = $fileInfo->getName();
        }

        foreach ($dirfiles as $key => $indfile) {
                 $tempfile = "/SMS_Relentless/multiple_recipients/" . $indfile;
                 $userFolder = $this->rootFolder->getUserFolder($this->userSession->getUser()->getUID());
                 $removetmpfile = $userFolder->get($tempfile)->delete();
        }
     }


    /**
     * @NoAdminRequired
     */
    public function uploadNumbersFile($uploadfileforsms) {

        // Create the temporary folder if it doesn't exist
        if ($this->folder->nodeExists('SMS_Relentless/multiple_recipients') == false) {
            $this->folder->newFolder('SMS_Relentless/multiple_recipients');
        }

        // First delete any file that has been previously uploaded
        $gettempdir = $this->folder->get("/SMS_Relentless/multiple_recipients");
        $fileSystemIterator = $gettempdir->getDirectoryListing();

        $dirfiles = [];
        foreach ($fileSystemIterator as $fileInfo){
                 $dirfiles[] = $fileInfo->getName();
        }

        foreach ($dirfiles as $key => $indfile) {
                 $tempfile = "/SMS_Relentless/multiple_recipients/" . $indfile;
                 $userFolder = $this->rootFolder->getUserFolder($this->userSession->getUser()->getUID());
                 $removetmpfile = $userFolder->get($tempfile)->delete();
        }

        // Upload the new file
        $fileContent = file_get_contents($_FILES['uploadfileforsms']['tmp_name']);
        $fileName = $_FILES['uploadfileforsms']['name'];

        $targetfile = "/SMS_Relentless/multiple_recipients/" . $fileName;

        $target = $this->folder->newFile($targetfile);
        $target->putContent($fileContent);

        // Extract the phone numbers from the file
        $numberarraysec = str_replace(array(";", "|", "\r\n", "\r", "\n", "\t"), ",", $fileContent);
        $numberarraytert = preg_replace("/[^0-9,]/", "", $numberarraysec);
        $numberarrayfourth = explode(",", $numberarraytert);
        $numberarrayfifth = array_filter(array_map('trim', $numberarrayfourth));
        $numberarray = array_unique($numberarrayfifth);

        return $numberarray;
    }


    /**
     * @NoAdminRequired
     */
    public function uploadfile($uploadfileformms) {

           $fileContent = file_get_contents($_FILES['uploadfileformms']['tmp_name']);
           $fileName = $_FILES['uploadfileformms']['name'];
           $fileSizeinit = $_FILES['uploadfileformms']['size'];
           $fileSize = $fileSizeinit / 1024;

           if ($this->folder->nodeExists('SMS_Relentless/temp_files') == false) {
               $this->folder->newFolder('SMS_Relentless/temp_files');
           }

           $targetfile = "/SMS_Relentless/temp_files/" . $fileName;

           $target = $this->folder->newFile($targetfile);
           $target->putContent($fileContent);

           // Get the cumulative files size of the uploaded files
           $gettempdir = $this->folder->get("/SMS_Relentless/temp_files");
           $fileSystemIterator = $gettempdir->getDirectoryListing();

           $dirfiles = [];
           foreach ($fileSystemIterator as $fileInfo){
                    $dirfiles[] = $fileInfo->getName();
           }

           $totalflsizeinit = 0;
           foreach ($dirfiles as $key => $indfile) {
                    $fileSizeinit = $this->filesystem->filesize("/SMS_Relentless/temp_files/" . $indfile);
                    $mbSize = round($fileSizeinit / 1024, 4);
                    $totalflsizeinit += $mbSize;
           }

           $totalflsize = round($totalflsizeinit, 4);

           return $totalflsize;
    }


    /**
     * @NoAdminRequired
     */
    public function pickfile($path) {

           if ($this->folder->nodeExists('SMS_Relentless/temp_files') == false) {
               $this->folder->newFolder('SMS_Relentless/temp_files');
           }

           $fltgt = $this->folder->get($path);

           $fileContent = $fltgt->getContent();

           $patharr = explode("/", $path);

           $revarr = array_reverse($patharr);

           $relflpath = "/SMS_Relentless/temp_files/" . $revarr[0]; 

           $target = $this->folder->newFile($relflpath);

           $target->putContent($fileContent);

           $fileSizeinit = $this->filesystem->filesize($relflpath);
           $pkfilesize = round($fileSizeinit / 1024, 4);

           // Get the cumulative files size of the uploaded files
           $targetdir = $this->folder->get("/SMS_Relentless/temp_files");
           $fileSystemIterator = $targetdir->getDirectoryListing();

           $dirfiles = [];
           foreach ($fileSystemIterator as $fileInfo){
                    $dirfiles[] = $fileInfo->getName();
           }

           $totalflsizeinit = 0;
           foreach ($dirfiles as $key => $indfile) {
                    $fileSizeinit = $this->filesystem->filesize("/SMS_Relentless/temp_files/" . $indfile);
                    $mbSize = round($fileSizeinit / 1024, 4);
                    $totalflsizeinit += $mbSize;
           }

           $totalflsize = round($totalflsizeinit, 4);

           $pickresult = [$totalflsize, $pkfilesize];

           return $pickresult;
    }


    /**
     * @NoAdminRequired
     */
    public function removeupfile($removedfilename) {

           $tempfile = "/SMS_Relentless/temp_files/" . $removedfilename;
           $userFolder = $this->rootFolder->getUserFolder($this->userSession->getUser()->getUID());
           $removetmpfile = $userFolder->get($tempfile)->delete();

           // Get the cumulative files size of the uploaded files
           $gettempdir = $this->folder->get("/SMS_Relentless/temp_files");
           $fileSystemIterator = $gettempdir->getDirectoryListing();

           $dirfiles = [];
           foreach ($fileSystemIterator as $fileInfo) {
                    $dirfiles[] = $fileInfo->getName();
           }

           $totalflsizeinit = 0;
           foreach ($dirfiles as $key => $indfile) {
                    $fileSizeinit = $this->filesystem->filesize("/SMS_Relentless/temp_files/" . $indfile);
                    $mbSize = round($fileSizeinit / 1024, 4);
                    $totalflsizeinit += $mbSize;
           }

           $totalflsize = round($totalflsizeinit, 4);

           return $totalflsize;
    }


    /**
     * @NoAdminRequired
     */
    public function sendsmstel($receiversPhoneNbs, $fromsender, $waitinterval, $sentsmstext, $ismms, $mmsfiles) {

         $telsmsapicred = $this->service->getapicredentials($this->userSession->getUser()->getUID(), 'telnyx');
         $telnyxkey = $telsmsapicred[0];
         $teldelrecurl = $telsmsapicred[3];
         $messagingprofid = $telsmsapicred[4];
         $addDisplName = $telsmsapicred[24];

         // Get the Display Name of the current user
         $crtuser = $this->userManager->get($this->userSession->getUser()->getUID());
         $displayname = $crtuser->getDisplayName();

         if ($addDisplName == 1) {
             $sentsmstext = $displayname . ": " . $sentsmstext;
         }

         \Telnyx\Telnyx::setApiKey($telnyxkey);

         $microinterval = $waitinterval * 1000;

         foreach ($receiversPhoneNbs as $keytel => $tonumber) {

             usleep($microinterval);

             $messagedate = date("Y-m-d H:i:s");

             if ($ismms == 0) {

                 if (preg_match('/[A-Za-z]+/', $fromsender)) {
                     $message = \Telnyx\Message::Create(["from" => $fromsender, "to" => $tonumber, "text" => $sentsmstext, "webhook_url" => $teldelrecurl, "messaging_profile_id" => $messagingprofid]);
                 } else {
                     $message = \Telnyx\Message::Create(["from" => $fromsender, "to" => $tonumber, "text" => $sentsmstext, "webhook_url" => $teldelrecurl]);
                 }

                 $messagetexttel = $sentsmstext;

             } else {

                 $mediaURLarr = [];
                 $includedMediaFiles = '';

                 for ($p = 0; $p < count($mmsfiles); $p++ ) {

                      $userroot = $this->view->getRoot();
                      $filetoshare = $userroot . "/SMS_Relentless/temp_files/".$mmsfiles[$p]."";

                      $flsharetarget = $this->folder->newFile($filetoshare);

	              $share = $this->shareManager->newShare();
	              $share->setNode($flsharetarget);
	              $share->setPermissions(Constants::PERMISSION_READ);
                      $share->setShareType(IShare::TYPE_LINK);
	              $share->setSharedBy($this->userSession->getUser()->getUID());
                      $expirydate = DateTime::createFromFormat('Y-m-d H:i:s', $messagedate);
                      $expirydate->add(new \DateInterval('P1D'));
                      $share->setExpirationDate($expirydate);
                      $shared = $this->shareManager->createShare($share);
                      $shareToken = $shared->getToken();

                      $hostnm = $_SERVER['REQUEST_SCHEME'] . "://" . $_SERVER['HTTP_HOST'];

                      $mediaURLarr[] = $hostnm . "/s/" . $shareToken . "/download/" . $mmsfiles[$p];

                      $includedMediaFiles .= $hostnm . "/s/" . $shareToken . "/download/" . $mmsfiles[$p] . "<br><br>";
                 }

                 if (preg_match('/[A-Za-z]+/', $fromsender)) {
                     $message = \Telnyx\Message::Create(["from" => $fromsender, "to" => $tonumber, "text" => $sentsmstext, "webhook_url" => $teldelrecurl, "messaging_profile_id" => $messagingprofid, "subject" => "MMS", "media_urls" => $mediaURLarr]);
                 } else {
                     $message = \Telnyx\Message::Create(["from" => $fromsender, "to" => $tonumber, "text" => $sentsmstext, "webhook_url" => $teldelrecurl, "subject" => "MMS", "media_urls" => $mediaURLarr]);
                 }

                 $messagetexttel = $sentsmstext . "<br><br><br>--- File(s) included in MMS ---<br><br>" . $includedMediaFiles;
             }

             if ($message) {
                 if (isset($message['id'])) { $messageid = $message['id']; } else { $messageid = $this->createMessageId(); }
             } else { $messageid = $this->createMessageId(); }

             $messagefrom = "Telnyx: " . $fromsender;
             $messageto = $tonumber;
             $messagenetwork = null;
             $messageprice = null;
             $messagestatus = $message['to'][0]['status'];
             $messagedelivery = null;

             $sentmessagearr = [$messageid, $messagedate, $messagefrom, $messageto, $messagenetwork, $messageprice, $messagestatus, $messagedelivery, $messagetexttel];

             $this->service->insertsentsms($this->userSession->getUser()->getUID(), $displayname, $sentmessagearr);
         }
         return $displayname;
    }


    /**
     * @NoAdminRequired
     */
    public function sendsmsnex($receiversPhoneNbs, $fromsender, $waitinterval, $sentsmstext, $ismms, $mmsfiles) {

         $plsmsapicred = $this->service->getapicredentials($this->userSession->getUser()->getUID(), 'plivo');

         $smsapikey = $plsmsapicred[5];
         $smsapisecret = $plsmsapicred[6];
         $smsapideliveryrecurl = $plsmsapicred[8];
         $addDisplName = $plsmsapicred[24];

         // Get the Display Name of the current user
         $crtuser = $this->userManager->get($this->userSession->getUser()->getUID());
         $displayname = $crtuser->getDisplayName();

         if ($addDisplName == 1) {
             $sentsmstext = $displayname . ": " . $sentsmstext;
         }

         $microinterval = $waitinterval * 1000;

         foreach ($receiversPhoneNbs as $keynex => $tonumber) {

             usleep($microinterval);

             $messagedatepl = date("Y-m-d H:i:s");

             if ($ismms == 0) {

                 $client = new RestClient($smsapikey, $smsapisecret);
                 $response = $client->messages->create($fromsender,[$tonumber],$sentsmstext,["url" => $smsapideliveryrecurl]);
                 $messagetextpl = $sentsmstext;
	         $messageidinit = $response->getmessageUuid(0);
                 $messageid = $messageidinit[0];

                 if (property_exists($response, 'error')) { 
                     $messagestatus = "Error: " . $response->error;
                 } else { $messagestatus = 'The message has been accepted for delivery.'; }

             } else {

                 $mediaURLarr = [];
                 $includedMediaFiles = '';

                 for ($p = 0; $p < count($mmsfiles); $p++ ) {

                      $userroot = $this->view->getRoot();
                      $filetoshare = $userroot . "/SMS_Relentless/temp_files/".$mmsfiles[$p]."";

                      $flsharetarget = $this->folder->newFile($filetoshare);

	              $share = $this->shareManager->newShare();
	              $share->setNode($flsharetarget);
	              $share->setPermissions(Constants::PERMISSION_READ);
                      $share->setShareType(IShare::TYPE_LINK);
	              $share->setSharedBy($this->userSession->getUser()->getUID());
                      $expirydate = DateTime::createFromFormat('Y-m-d H:i:s', $messagedatepl);
                      $expirydate->add(new \DateInterval('P1D'));
                      $share->setExpirationDate($expirydate);
                      $shared = $this->shareManager->createShare($share);
                      $shareToken = $shared->getToken();

                      $hostnm = $_SERVER['REQUEST_SCHEME'] . "://" . $_SERVER['HTTP_HOST'];

                      $mediaURLarr[] = $hostnm . "/s/" . $shareToken . "/download/" . $mmsfiles[$p];

                      $includedMediaFiles .= $hostnm . "/s/" . $shareToken . "/download/" . $mmsfiles[$p] . "<br><br>";
                 }

		 $datatosendpl = ["src" => $fromsender, "dst" => $tonumber, "text" => $sentsmstext, "url" => $smsapideliveryrecurl, "type" => "mms", "media_urls" => $mediaURLarr];
		 $postedparamspl = json_encode($datatosendpl);

		 $chpl = curl_init();
		 curl_setopt($chpl, CURLOPT_URL, 'https://'.$smsapikey.':'.$smsapisecret.'@api.plivo.com/v1/Account/'.$smsapikey.'/Message/');
		 curl_setopt($chpl, CURLOPT_HTTPHEADER, array("Content-Type: application/json"));
		 curl_setopt($chpl, CURLOPT_TIMEOUT, 300);
		 curl_setopt($chpl, CURLOPT_RETURNTRANSFER, 1);
		 curl_setopt($chpl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
		 curl_setopt($chpl, CURLOPT_POST, 1);
		 curl_setopt($chpl, CURLOPT_POSTFIELDS, $postedparamspl);
		 $resultpl = curl_exec ($chpl);
		 $statusCodepl = curl_getinfo($chpl, CURLINFO_HTTP_CODE);
		 curl_close ($chpl);

		 $decresultpl = json_decode($resultpl);

                 if ($decresultpl) {
                     if (property_exists($decresultpl, 'message_uuid')) {
                         $messageidinit = $decresultpl->message_uuid;
                         $messageid = $messageidinit[0];
                     } else { $messageid = $this->createMessageId(); }
                 } else { $messageid = $this->createMessageId(); }

	         if (in_array($statusCodepl, [200, 201, 202, 203, 204, 205, 206])) {

                     if (property_exists($decresultpl, 'error')) {
                         $messagestatus = "Error: " . $decresultpl->error;
                     } else { $messagestatus = 'The message has been accepted for delivery.'; }

                 } else { $messagestatus = 'An error occurred while trying to send the message.'; }

                 $messagetextpl = $sentsmstext . "<br><br><br>--- File(s) included in MMS ---<br><br>" . $includedMediaFiles;
             }

             if (preg_match('/[A-Za-z]+/', $fromsender)) {
                 $messagefrom = "Plivo: " . $fromsender;
             } else { $messagefrom = "Plivo: +" . $fromsender; }

             $messageto = $tonumber;
             $messagenetwork = '';
             $messageprice = '';

             $messagedelivery = '';

             $sentmessagearr = [$messageid, $messagedatepl, $messagefrom, $messageto, $messagenetwork, $messageprice, $messagestatus, $messagedelivery, $messagetextpl];

             $this->service->insertsentsms($this->userSession->getUser()->getUID(), $displayname, $sentmessagearr);
         }
         return $displayname;
    }


    /**
     * @NoAdminRequired
     */
    public function sendsmstwil($receiversPhoneNbs, $fromsender, $waitinterval, $sentsmstext, $ismms, $mmsfiles) {

         $twsmsapicred = $this->service->getapicredentials($this->userSession->getUser()->getUID(), 'twilio');

         $sid = $twsmsapicred[15];
         $token = $twsmsapicred[16];
         $smsapirecurltw = $twsmsapicred[18];
         $addDisplName = $twsmsapicred[24];

         // Get the Display Name of the current user
         $crtuser = $this->userManager->get($this->userSession->getUser()->getUID());
         $displayname = $crtuser->getDisplayName();

         if ($addDisplName == 1) {
             $sentsmstext = $displayname . ": " . $sentsmstext;
         }

         $microinterval = $waitinterval * 1000;

         foreach ($receiversPhoneNbs as $keytwil => $tonumbertw) {

             usleep($microinterval);

             $messagedatetw = date("Y-m-d H:i:s");

             if ($ismms == 0) {

                 $datatoposttw = [["To" => $tonumbertw, "From" => $fromsender, "Body" => $sentsmstext, "StatusCallback" => $smsapirecurltw]];
                 $sentsmstextfintw = $sentsmstext;

             } else {

                 $mediaURLs = [];
                 $includedMediaFiles = '';

                 for ($p = 0; $p < count($mmsfiles); $p++ ) {

                      $userroot = $this->view->getRoot();
                      $filetoshare = $userroot . "/SMS_Relentless/temp_files/".$mmsfiles[$p]."";

                      $flsharetarget = $this->folder->newFile($filetoshare);

	              $share = $this->shareManager->newShare();
	              $share->setNode($flsharetarget);
	              $share->setPermissions(Constants::PERMISSION_READ);
                      $share->setShareType(IShare::TYPE_LINK);
	              $share->setSharedBy($this->userSession->getUser()->getUID());
                      $expirydate = DateTime::createFromFormat('Y-m-d H:i:s', $messagedatetw);
                      $expirydate->add(new \DateInterval('P1D'));
                      $share->setExpirationDate($expirydate);
                      $shared = $this->shareManager->createShare($share);
                      $shareToken = $shared->getToken();

                      $hostnm = $_SERVER['REQUEST_SCHEME'] . "://" . $_SERVER['HTTP_HOST'];

                      $mediaURLs[] = $hostnm . "/s/" . $shareToken . "/download/" . $mmsfiles[$p];

                      $includedMediaFiles .= $hostnm . "/s/" . $shareToken . "/download/" . $mmsfiles[$p] . "<br><br>";
                 }

                 $datatoposttw = [["To" => $tonumbertw, "From" => $fromsender, "Body" => $sentsmstext, "StatusCallback" => $smsapirecurltw]];

                 for ($m = 0; $m < count($mediaURLs); $m++) {
                      array_push($datatoposttw, ["MediaUrl" => $mediaURLs[$m]]);
                 }

                 $sentsmstextfintw = $sentsmstext . "<br><br><br>--- File(s) included in MMS ---<br><br>" . $includedMediaFiles;
             }

             $postedsendingfl = implode('&', array_map('http_build_query', $datatoposttw));

	     $chtw = curl_init();
	     curl_setopt($chtw, CURLOPT_URL, 'https://api.twilio.com/2010-04-01/Accounts/'.$sid.'/Messages.json');
	     curl_setopt($chtw, CURLOPT_TIMEOUT, 300);
	     curl_setopt($chtw, CURLOPT_RETURNTRANSFER, 1);
	     curl_setopt($chtw, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
             curl_setopt($chtw, CURLOPT_USERPWD, "$sid:$token");
	     curl_setopt($chtw, CURLOPT_POST, 1);
             curl_setopt($chtw, CURLOPT_POSTFIELDS, $postedsendingfl);

	     $resulttw = curl_exec ($chtw);
	     $statusCodetw = curl_getinfo($chtw, CURLINFO_HTTP_CODE);
	     curl_close ($chtw);

             $decresulttw = json_decode($resulttw);

             if ($decresulttw) {
                 if (property_exists($decresulttw, 'sid')) { $messageidtw = $decresulttw->sid; } else { $messageidtw = $this->createMessageId(); }
             } else { $messageidtw = $this->createMessageId(); }

	     if (in_array($statusCodetw, [200, 201, 202, 203, 204, 205, 206])) {
                 $messagestatustw = 'The message has been accepted for delivery.';
             } else {
                 $messagestatustw = 'An error occurred while trying to send the message.';
             }

             $messagefromtw = "Twilio: " . $fromsender;

             $messagenetworktw = '';
             $messagepricetw = '';
             $messagedeliverytw = '';

             $sentmessagearr = [$messageidtw, $messagedatetw, $messagefromtw, $tonumbertw, $messagenetworktw, $messagepricetw, $messagestatustw, $messagedeliverytw, $sentsmstextfintw];

             $this->service->insertsentsms($this->userSession->getUser()->getUID(), $displayname, $sentmessagearr);
         }
         return $displayname;
    }


    /**
     * @NoAdminRequired
     */
    public function sendsmsflow($receiversPhoneNbs, $fromsender, $waitinterval, $sentsmstext, $ismms, $mmsfiles) {

         $flsmsapicred = $this->service->getapicredentials($this->userSession->getUser()->getUID(), 'flowroute');

         $flowapikey = $flsmsapicred[20];
         $flowapisecret = $flsmsapicred[21];
         $flowdelrecurl = $flsmsapicred[23];
         $addDisplName = $flsmsapicred[24];

         // Get the Display Name of the current user
         $crtuser = $this->userManager->get($this->userSession->getUser()->getUID());
         $displayname = $crtuser->getDisplayName();

         if ($addDisplName == 1) {
             $sentsmstext = $displayname . ": " . $sentsmstext;
         }

         $sentsmstextproc = str_replace('"','\\"', $sentsmstext);

         $microinterval = $waitinterval * 1000;

         foreach ($receiversPhoneNbs as $keyflow => $tonumberfl) {

             usleep($microinterval);

             $messagedatefl = date("Y-m-d H:i:s");

             if ($ismms == 0) {

                 $messagetextfinfl = $sentsmstext;
                 $postedparamsfl = json_encode(["to" => $tonumberfl, "from" => $fromsender, "body" => $sentsmstextproc, "dlr_callback" => $flowdelrecurl]);

             } else {

		 $mediaurlsarr = [];
		 $includedMediaFiles = '';

		 for ($p = 0; $p < count($mmsfiles); $p++ ) {

		      $userroot = $this->view->getRoot();
		      $filetoshare = $userroot . "/SMS_Relentless/temp_files/".$mmsfiles[$p]."";

		      $flsharetarget = $this->folder->newFile($filetoshare);

		      $share = $this->shareManager->newShare();
		      $share->setNode($flsharetarget);
		      $share->setPermissions(Constants::PERMISSION_READ);
                      $share->setShareType(IShare::TYPE_LINK);
		      $share->setSharedBy($this->userSession->getUser()->getUID());
                      $expirydate = DateTime::createFromFormat('Y-m-d H:i:s', $messagedatefl);
                      $expirydate->add(new \DateInterval('P1D'));
                      $share->setExpirationDate($expirydate);
		      $shared = $this->shareManager->createShare($share);
		      $shareToken = $shared->getToken();

                      $hostnm = $_SERVER['REQUEST_SCHEME'] . "://" . $_SERVER['HTTP_HOST'];

		      $mediaurlsarr[] = $hostnm . "/s/" . $shareToken . "/download/" . $mmsfiles[$p];

                      $includedMediaFiles .= $hostnm . "/s/" . $shareToken . "/download/" . $mmsfiles[$p] . "<br><br>";
		 }

                 $messagetextfinfl = $sentsmstext . "<br><br><br>--- File(s) included in MMS ---<br><br>" . $includedMediaFiles;

                 $postedparamsfl = json_encode(["to" => $tonumberfl, "from" => $fromsender, "body" => $sentsmstextproc, "dlr_callback" => $flowdelrecurl, "media_urls" => $mediaurlsarr]);
             }

	     $chfl = curl_init();
	     curl_setopt($chfl, CURLOPT_URL, 'https://'.$flowapikey.':'.$flowapisecret.'@api.flowroute.com/v2.1/messages');
	     curl_setopt($chfl, CURLOPT_HTTPHEADER, array("Content-Type: application/vnd.api+json"));
	     curl_setopt($chfl, CURLOPT_TIMEOUT, 300);
	     curl_setopt($chfl, CURLOPT_RETURNTRANSFER, 1);
	     curl_setopt($chfl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
	     curl_setopt($chfl, CURLOPT_POST, 1);
             curl_setopt($chfl, CURLOPT_POSTFIELDS, $postedparamsfl);
	     $resultfl = curl_exec ($chfl);
	     $statusCode = curl_getinfo($chfl, CURLINFO_HTTP_CODE);
	     curl_close ($chfl);

             $decresultfl = json_decode($resultfl);

             if ($decresultfl) {
                 if (isset($decresultfl->data->id)) { 
                     $messageidfl = $decresultfl->data->id;
                 } else { $messageidfl = $this->createMessageId(); }
             } else { $messageidfl = $this->createMessageId(); }

	     if (in_array($statusCode, [200, 201, 202, 203, 204, 205, 206])) {
                 $messagestatusfl = 'The message has been accepted for delivery.'; 
             } else { 
                 $messagestatusfl = 'An error occurred while trying to send the message.'; 
             }

             $messagefromfl = "Flowroute: " . $fromsender;
             $messagetofl = $tonumberfl;
             $messagenetworkfl = '';
             $messagepricefl = '';
             $messagedeliveryfl = '';

             $sentmessagearr = [$messageidfl, $messagedatefl, $messagefromfl, $messagetofl, $messagenetworkfl, $messagepricefl, $messagestatusfl, $messagedeliveryfl, $messagetextfinfl];

             $this->service->insertsentsms($this->userSession->getUser()->getUID(), $displayname, $sentmessagearr);
         }
         return $displayname;
    }


    /**
     * @NoAdminRequired
     */
    public function saveoldrecrows($oldrecRows) {

           // Create the folder for removed messages if it doesn't exist
           if ($this->folder->nodeExists('SMS_Relentless/removed_received_messages') == false) {
               $this->folder->newFolder('SMS_Relentless/removed_received_messages');
           }
           $savecheck = 0;

           if (count($oldrecRows) > 1) {

               $msfileContent = implode("", $oldrecRows);
               $delrowsdate = date("Y-m-d_H-i-s");
               $msfileName = "Received_Messages_Deleted_On_" . $delrowsdate . ".csv";

               $targetfile = "/SMS_Relentless/removed_received_messages/" . $msfileName;

               $target = $this->folder->newFile($targetfile);
               $target->putContent($msfileContent);

               if ($this->filesystem->file_get_contents($targetfile) != '') {
                   $savecheck = 1;
               }
           }

           return $savecheck;
    }


    /**
     * @NoAdminRequired
     */
    public function saveoldsentrows($oldsentRows) {

           // Create the folder for removed messages if it doesn't exist
           if ($this->folder->nodeExists('SMS_Relentless/removed_sent_messages') == false) {
               $this->folder->newFolder('SMS_Relentless/removed_sent_messages');
           }
           $savesentcheck = 0;

           if (count($oldsentRows) > 1) {
               $sntfileContent = implode("", $oldsentRows);

               $delsentrowsdate = date("Y-m-d_H-i-s");
               $sntfileName = "Sent_Messages_Deleted_On_" . $delsentrowsdate . ".csv";

               $snttargetfile = "/SMS_Relentless/removed_sent_messages/" . $sntfileName;

               $snttarget = $this->folder->newFile($snttargetfile);
               $snttarget->putContent($sntfileContent);

               if ($this->filesystem->file_get_contents($snttargetfile) != '') {
                   $savesentcheck = 1;
               }
           }

           return $savesentcheck;
    }


    /**
     * @NoAdminRequired
     */
    public function getreceivedtable() {
           return $this->service->getreceivedtable($this->userSession->getUser()->getUID());
    }

    /**
     * @NoAdminRequired
     */
    public function getreceivedtablefordel() {
           return $this->service->getreceivedtablefordel($this->userSession->getUser()->getUID());
    }

    /**
     * @NoAdminRequired
     */
    public function removerecrows($recmessagedbIDs) {

           // Get the Display Name of the current user
           $crtuserdel = $this->userManager->get($this->userSession->getUser()->getUID());
           $userDelDspName = $crtuserdel->getDisplayName();

           return $this->service->removerecrows($this->userSession->getUser()->getUID(), $userDelDspName, $recmessagedbIDs);
    }

    /**
     * @NoAdminRequired
     */
    public function getsenttable() {
           return $this->service->getsenttable($this->userSession->getUser()->getUID());
    }

    /**
     * @NoAdminRequired
     */
    public function getsenttablefordel() {
           return $this->service->getsenttablefordel($this->userSession->getUser()->getUID());
    }

    /**
     * @NoAdminRequired
     */
    public function removesentrows($sentmessagedbIDs) {

           // Get the Display Name of the current user
           $crtuserstdel = $this->userManager->get($this->userSession->getUser()->getUID());
           $userstDelDspName = $crtuserstdel->getDisplayName();

           return $this->service->removesentrows($this->userSession->getUser()->getUID(), $userstDelDspName, $sentmessagedbIDs);
    }

    /**
     * @NoAdminRequired
     */
    public function getconversations() {
           return $this->service->getconversations($this->userSession->getUser()->getUID());
    }

    /**
     * @NoAdminRequired
     */
    public function archiveconv($conversationId) {

           // Get the Display Name of the current user
           $crtusergt = $this->userManager->get($this->userSession->getUser()->getUID());
           $userDspNameArch = $crtusergt->getDisplayName();

           return $this->service->archiveconv($this->userSession->getUser()->getUID(), $userDspNameArch, $conversationId);
    }

    /**
     * @NoAdminRequired
     */
    public function unarchiveconv($conversationId) {

           // Get the Display Name of the current user
           $crtusergtun = $this->userManager->get($this->userSession->getUser()->getUID());
           $userDspNameUnarch = $crtusergtun->getDisplayName();

           return $this->service->unarchiveconv($this->userSession->getUser()->getUID(), $userDspNameUnarch, $conversationId);
    }

    /**
     * @NoAdminRequired
     */
    public function saveconvdescription($convDescription, $convId) {

           // Get the Display Name of the current user
           $crtuserdesc = $this->userManager->get($this->userSession->getUser()->getUID());
           $userDspNameDesc = $crtuserdesc->getDisplayName();

           return $this->service->saveconvdescription($this->userSession->getUser()->getUID(), $userDspNameDesc, $convDescription, $convId);
    }

    /**
     * @NoAdminRequired
     */
    public function saveconvtag($convTag, $convId) {

           // Get the Display Name of the current user
           $crtusertag = $this->userManager->get($this->userSession->getUser()->getUID());
           $userDspNameTag = $crtusertag->getDisplayName();

           return $this->service->saveconvtag($this->userSession->getUser()->getUID(), $userDspNameTag, $convTag, $convId);
    }

    /**
     * @NoAdminRequired
     */
    public function saveconvflag($convFlag, $convId) {

           // Get the Display Name of the current user
           $crtuserflag = $this->userManager->get($this->userSession->getUser()->getUID());
           $userDspNameFlag = $crtuserflag->getDisplayName();

           return $this->service->saveconvflag($this->userSession->getUser()->getUID(), $userDspNameFlag, $convFlag, $convId);
    }

    /**
     * @NoAdminRequired
     */
    public function removeconvmsgs($conversationId) {
           return $this->service->removeconvmsgs($this->userSession->getUser()->getUID(), $conversationId);
    }

    /**
     * @NoAdminRequired
     */
    public function getgroupedtable() {
           return $this->service->getgroupedtable($this->userSession->getUser()->getUID());
    }

    /**
     * @NoAdminRequired
     */
    public function getactivitytable($interval) {

           // Get the Display Name of the current user
           $crtuser = $this->userManager->get($this->userSession->getUser()->getUID());
           $displayname = $crtuser->getDisplayName();

           return $this->service->getactivitytable($this->userSession->getUser()->getUID(), $displayname, $interval);
    }

    /**
     * @NoAdminRequired
     */
    public function getindactivity($interval, $indusrdspnm) {

           // Get the Display Name of the current user
           $crtuser = $this->userManager->get($this->userSession->getUser()->getUID());
           $displayname = $crtuser->getDisplayName();

           return $this->service->getindactivity($this->userSession->getUser()->getUID(), $displayname, $interval, $indusrdspnm);
    }

    /**
     * @NoAdminRequired
     */
    public function savedisplayname($authorDisplayname, $from) {
           return $this->service->savedisplayname($this->userSession->getUser()->getUID(), $authorDisplayname, $from);
    }

    /**
     * @NoAdminRequired
     */
    public function getmsgsperpgnewmsgarchnb() {
           return $this->service->getmsgsperpgnewmsgarchnb($this->userSession->getUser()->getUID());
    }

    /**
     * @NoAdminRequired
     */
    public function getnewmsgindicator() {
           return $this->service->getnewmsgindicator($this->userSession->getUser()->getUID());
    }

    /**
     * @NoAdminRequired
     */
    public function getdelrecsettings() {
           return $this->service->getdelrecsettings($this->userSession->getUser()->getUID());
    }

    public function updatenumberrestrictions($savedByDsplname, $phoneNumber, $groups, $users) {
           return $this->service->updatenumberrestrictions($this->userSession->getUser()->getUID(), $savedByDsplname, $phoneNumber, $groups, $users);
    }

    public function updatekeysallowedusers($groups, $users, $groupsdel, $usersdel, $provider) {
           return $this->service->updatekeysallowedusers($this->userSession->getUser()->getUID(), $groups, $users, $groupsdel, $usersdel, $provider);
    }

    public function removenumberrestrictions($phoneNumber) {
           return $this->service->removenumberrestrictions($this->userSession->getUser()->getUID(), $phoneNumber);
    }

    /**
     * @NoAdminRequired
     */
    public function updateautoreplies($savedByDsplname, $phoneNumber, $daysOfWeek, $dailyStart, $dailyEnd, $vacationStart, $vacationEnd, $messageText) {
           return $this->service->updateautoreplies($this->userSession->getUser()->getUID(), $savedByDsplname, $phoneNumber, $daysOfWeek, $dailyStart, $dailyEnd, $vacationStart, $vacationEnd, $messageText);
    }

    /**
     * @NoAdminRequired
     */
    public function removeautoreplies($phoneNumber) {
           return $this->service->removeautoreplies($this->userSession->getUser()->getUID(), $phoneNumber);
    }

    /**
     * @NoAdminRequired
     */
     public function getadminornot($userId) {
           return $this->service->getadminornot($this->userSession->getUser()->getUID());
     }

    /**
     * @NoAdminRequired
     */
    public function getsettings() {
           return $this->service->getsettings($this->userSession->getUser()->getUID());
    }

    public function getadminsettings() {
           return $this->service->getadminsettings($this->userSession->getUser()->getUID());
    }

    /**
     * @NoAdminRequired
     */
    public function getautoreplyconf() {

           // Get the available phone numbers for the current user (the restricted phone numbers are excluded)
           $availphonenmbrs = $this->getsmsnumbers($this->userSession->getUser()->getUID());

           // Get the display name of the current user
           $usrid = $this->userSession->getUser()->getUID();
           $getusrdnm = $this->connection->prepare('SELECT `uid`, `name`, `value` FROM `*PREFIX*accounts_data` WHERE `uid` = ? AND `name` = ?');
	   $getusrdnmres = $getusrdnm->execute([$usrid, 'displayname']);
	   $getusrdnmdata = $getusrdnmres->fetch();
	   $userDisplayNm = $getusrdnmdata['value'];
	   $getusrdnmres->closeCursor();

           // Get the auto-replies for the available phone numbers
           $getautorpl = $this->connection->prepare('SELECT `saved_by_dsplname`, `phone_number`, `days_of_week`, `daily_start`, `daily_end`, `vacation_start`, `vacation_end`, 
                                                    `message_text` FROM `*PREFIX*sms_relent_autorply`');
	   $getautorplres = $getautorpl->execute();
           $autorplconf = [];
	   while ($acdatausrdnadm = $getautorplres->fetch()) {
                  $acdatausrdnadm['days_of_week'] = htmlspecialchars($acdatausrdnadm['days_of_week'], ENT_QUOTES);
                  $acdatausrdnadm['message_text'] = htmlspecialchars($acdatausrdnadm['message_text'], ENT_QUOTES);
                  $autorplconf[] = $acdatausrdnadm;
           }
	   $getautorplres->closeCursor();

           if ($autorplconf) {

               $autoreplyconf = [];
               foreach ($autorplconf as $arkey => $arvalue) {
                        if (in_array($arvalue['phone_number'], $availphonenmbrs)) {
                            $autoreplyconf[] = $arvalue;
                        }
               }

           } else { $autoreplyconf = ''; }

           $autoreplyfdb = ['userdisplayname' => $userDisplayNm, 'phonenumbers' => $availphonenmbrs, 'autoreplies' => $autoreplyconf];

           return $autoreplyfdb;
    }

    /**
     * @NoAdminRequired
     */
    public function getgroupedpernumber($phoneNumber) {
           return $this->service->getgroupedpernumber($this->userSession->getUser()->getUID(), $phoneNumber);
    }

    /**
     * @NoAdminRequired
     */
    public function getgroupedforreply($phoneNmbrFrom, $phoneNmbrTo) {
           return $this->service->getgroupedforreply($this->userSession->getUser()->getUID(), $phoneNmbrFrom, $phoneNmbrTo);
    }

    /**
     * @NoAdminRequired
     */
    public function updatesettings($telapiUrlRec, $telapiUrl, $nexapiUrlRec, $nexapiUrl, $twilapiUrlRec, $twilapiUrl, $flowapiUrlRec, $flowapiUrl, $messagesperpage, $getNotify, $notificationEmail, $getsmsinemail, $showDisplayNames, $addDisplayNames, $msgCheckInterval, $archivedConvNmbr) {
           return $this->service->updatesettings($this->userSession->getUser()->getUID(), $telapiUrlRec, $telapiUrl, $nexapiUrlRec, $nexapiUrl, $twilapiUrlRec, $twilapiUrl, $flowapiUrlRec, $flowapiUrl, $messagesperpage, $getNotify, $notificationEmail, $getsmsinemail, $showDisplayNames, $addDisplayNames, $msgCheckInterval, $archivedConvNmbr);
    }

    public function updateadminsettings($telapiKey, $telPubKey, $telapiUrlRec, $telapiUrl, $messagingProfileId, $nexapiKey, $nexapiSecret, $nexapiUrlRec, $nexapiUrl, $telSenderName, $nexSenderName, $twilapiKey, $twilapiSecret, $twilapiUrlRec, $twilapiUrl, $twilSenderName, $flowapiKey, $flowapiSecret, $flowapiUrlRec, $flowapiUrl, $showAllMessages) {
           return $this->service->updateadminsettings($this->userSession->getUser()->getUID(), $telapiKey, $telPubKey, $telapiUrlRec, $telapiUrl, $messagingProfileId, $nexapiKey, $nexapiSecret, $nexapiUrlRec, $nexapiUrl, $telSenderName, $nexSenderName, $twilapiKey, $twilapiSecret, $twilapiUrlRec, $twilapiUrl, $twilSenderName, $flowapiKey, $flowapiSecret, $flowapiUrlRec, $flowapiUrl, $showAllMessages);
    }

    public function updatepersadmnsettings($messagesperpage, $getNotify, $notificationEmail, $getsmsinemail, $showDisplayNames, $addDisplayNames, $msgCheckInterval, $archivedConvNmbr) {
           return $this->service->updatepersadmnsettings($this->userSession->getUser()->getUID(), $messagesperpage, $getNotify, $notificationEmail, $getsmsinemail, $showDisplayNames, $addDisplayNames, $msgCheckInterval, $archivedConvNmbr);
    }
}
