<?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\PaxFax\Controller;

use OCP\AppFramework\ApiController;
use OCP\IRequest;
use OCP\AppFramework\Http\DataResponse;
use OCP\AppFramework\OCSController;
use OCP\IUserSession;
use OCP\AppFramework\Controller;
use OCP\Files\IAppData;
use OCA\PaxFax\Service\PaxfaxService;
use OCP\AppFramework\App;
use OCP\Files\NotPermittedException;
use OCP\Files\Folder;
use OC\Files\Filesystem;
use OC\Files\View;
use \ReflectionClass;
use OCP\Notification;
use OCP\Notification\INotification;
use OCP\Notification\IManager;
use OCP\Notification\IAction;
use \DateTime;

use Phaxio;
use Phaxio\OperationResult;
use Phaxio\Error\AuthenticationException;
use Phaxio\Error\NotFoundException;
use Phaxio\Error\InvalidRequestException;
use Phaxio\Error\RateLimitException;
use Phaxio\Error\APIConnectionException;
use Phaxio\Error\GeneralException;


class AuthorApiController extends ApiController {

    private $service;
    private $userId;
    private $folder;
    private $filesystem;
    private $view;
    private $userSession;

    public function __construct($appName, IRequest $request, IUserSession $userSession, PaxfaxService $service, Folder $folder, Filesystem $filesystem, $userId, View $view) {
        parent::__construct(
                $appName,
                $request,
                'PUT, POST, GET, DELETE, PATCH',
                'Authorization, Content-Type, Accept',
                1728000);

        $this->service = $service;
        $this->userId = $userId;
        $this->folder = $folder;
        $this->filesystem = $filesystem;
        $this->view = $view;
        $this->userSession = $userSession;
    }

    /**
     * @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 isValidCallbackRequest($token, $url = null, $postParameters = null, $uploadedFiles = null, $signature = null) {

	if (!$url) {
	    $url = $_SERVER['REQUEST_SCHEME'] . "://" . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
	}

	if (!$postParameters) {
	    $postParameters = $_REQUEST;
	}

	if (!$uploadedFiles) {
	    $uploadedFiles = $_FILES;
	}

	if (!$signature) {
	    $signature = $_SERVER['HTTP_X_PHAXIO_SIGNATURE'];
	}

	// Sort the array by keys
	ksort($postParameters);

	// Append the data array to the url string, with no delimiters
	foreach ($postParameters as $key => $value) {
		 $url .= $key . $value;
	}

	foreach ($uploadedFiles as $key => $value) {
		 $url .= $key . sha1_file($value['tmp_name']);
	}

	$hmac = hash_hmac("sha1", $url, $token);
	return $signature == $hmac;
    }

    /**
     * @NoAdminRequired
     * @NoCSRFRequired
     */
    public function receivefaxphaxio() {

       $phaxiosignature = $_SERVER['HTTP_X_PHAXIO_SIGNATURE'];

       $thisapicred = $this->service->getapicredentials($this->userId);
       $phaxiowhtoken = $thisapicred[2];
       $phaxiorecURL = $thisapicred[3];

       // Verify Phaxio's signature
       $signverify = $this->isValidCallbackRequest($phaxiowhtoken, $phaxiorecURL, null, null, $phaxiosignature);

       if ($signverify) {

           $fileContent = file_get_contents($_FILES['file']['tmp_name']);
           $fileNameinit = $_FILES['file']['name'];

           $fldate = date("Y-m-d_H-i-s_").gettimeofday()["usec"];

           $gmtind = "UTC " . date('P');
           $flmsdateinit = date("Y-m-d  H:i:s");
           $flmsdate = $flmsdateinit . " " . $gmtind;

           $fileNamesec = array_reverse(explode(".", $fileNameinit));
           $filenameext = $fileNamesec[0];
           array_shift($fileNamesec);

           $fileName = implode("", $fileNamesec);

           $faxid = str_replace("Fax-", "", $fileName);

           $apiMode = 'live';

           $apiKeys[$apiMode] = $thisapicred[0];
           $apiSecrets[$apiMode] = $thisapicred[1];

           $apiHost = 'https://api.phaxio.com/v2.1/';

           $phaxio = new Phaxio($apiKeys[$apiMode], $apiSecrets[$apiMode], $apiHost);


           try {
                      $phaxioresultreq = $phaxio->doRequest("GET", 'faxes/' . $faxid);

                      $fromnmbrtoarr = $this->object_to_array($phaxioresultreq);

                      $phaxiofromraw = $fromnmbrtoarr['data']['from_number'];
                      $phaxiotoraw  = $fromnmbrtoarr['data']['to_number'];
                      $phaxiofromnumber = str_replace("+", "", $phaxiofromraw);
                      $phaxiotonumber = str_replace("+", "", $phaxiotoraw);
                      $errortype = 'there are no errors';

           } catch (InvalidRequestException $e) {
                      $phaxiofromnumber = 'null';
                      $errortype = 'invalid request error';
           } catch (AuthenticationException $e) {
                      $phaxiofromnumber = 'null';
                      $errortype = 'authentication error';
           } catch (APIConnectionException $e) {
                      $phaxiofromnumber = 'null';
                      $errortype = 'API connection error';
           } catch (RateLimitException $e) {
                      $phaxiofromnumber = 'null';
                      $errortype = 'rate limit error';
           } catch (NotFoundException $e) {
                      $phaxiofromnumber = 'null';
                      $errortype = 'not found error';
           } catch (GeneralException $e) {
                      $phaxiofromnumber = 'null';
                      $errortype = 'undefined error';
           }

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

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

           $targetfile = "/Pax_Fax/faxes_received/" . $fileName . "_" . $phaxiofromnumber . "_" . $phaxiotonumber  . "_" . $fldate . "." . $filenameext;

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

           $target->putContent($fileContent);

           // Move failed received faxes to the 'faxes_received_failed' folder
           if ($filenameext == '') {

               $newtargetfl =  "/Pax_Fax/faxes_received_failed/" . $fileName . "_" . $phaxiofromnumber . "_" . $phaxiotonumber . "_" . $fldate . "." . $filenameext;
               $targetact = $this->folder->newFile($newtargetfl);

               $targetact->putContent($fileContent);

               $failedfl = "/Pax_Fax/faxes_received/" . $fileName . "_" . $phaxiofromnumber . "_" . $phaxiotonumber . "_" . $fldate . "." . $filenameext;
               $removefailed = $this->filesystem->unlink($failedfl);
           }

           // Send notifications
           $nameofhost = exec("hostname");
           $getnextnotify = $thisapicred[4];
           $useremailaddr = $thisapicred[5];

           if ($filenameext != '') {
               $targetflname = $targetfile;
               $targettrim = "/Pax_Fax/faxes_received/";
               $validfaxparam = "fax";
               $setsubject = "New fax received";
           } else {
               $targetflname = $newtargetfl;
               $targettrim = "/Pax_Fax/faxes_received_failed/";
               $validfaxparam = "failed fax";
               $setsubject = "New failed fax received";
           }

           if ($useremailaddr != '') {

               $subject = $setsubject;
               $message = "Hello! <br><br> You have received a new ".$validfaxparam." on ".$flmsdate." .<br> The new ".$validfaxparam." file is '".$targetflname."' . <br><br>____________<br><br> Yours, <br> Pax Fax <br> A fax application for Nextcloud <br> Host: '".$nameofhost."' <br>";

               $messagefin = chunk_split(base64_encode($message));

               $headers = "MIME-Version: 1.0" . "\r\n";
               $headers .= "Content-type: text/html; charset=UTF-8" . "\r\n";
               $headers .= "Content-Transfer-Encoding: base64" . "\r\n";

               // Set the email sender
               $headers .= "From: " . $useremailaddr . "\r\n";
               $headers .= "Reply-To: " . $useremailaddr . "\r\n";

               mail($useremailaddr, $subject, $messagefin, $headers);
           }

           if ($getnextnotify != 0 ) {

               $notify = exec("php ./occ notification:generate ".$this->userId." 'Pax Fax has received a new fax !' -l 'The new fax can be found in the \"".$targettrim."\" folder.'");
          }

       } else { return "access denied"; }

    }

}