<?php

/**
 * Copyright (c) 2011 ATMAIL. All rights reserved.
 * See http://atmail.com/license.php for license agreement.
 *
 * Author: Sean Pringle sean@staff.atmail.com
 *
 * http://www.rootmanager.com/iphone-ota-configuration/iphone-ota-setup-with-signed-mobileconfig.html
 * openssl smime -sign -in company.mobileconfig -out signed.mobileconfig -signer server.crt -inkey server.key -certfile cert-chain.crt -outform der -nodetach
 */

class iOS_XML_Profile
{
	private $xml;

	/**
	 *
	 */
	function __construct()
	{
		$this->xml = new DOMDocument('1.0', 'utf-8');
		$this->xml->formatOutput = true;
	}

	/**
	 * Generate a DOMNode dictionary
	 */
	private function generateDict($payload)
	{
		$dict = $this->xml->createElement('dict');

		foreach ($payload as $key => $value)
		{
			$dict->appendChild($this->xml->createElement('key', $key));
			if (is_int($value))
			{
				$dict->appendChild($this->xml->createElement('integer', $value));
			}
			else
			if (is_bool($value))
			{
				$dict->appendChild($this->xml->createElement($value ? 'true': 'false'));
			}
			else
			{
				$dict->appendChild($this->xml->createElement('string', $value));
			}
		}
		return $dict;
	}

	/**
	 * Generate an iOS XML configuration profile for the logged in user
	 */
	public function generate($args=array())
	{
		$settings = Zend_Registry::get('UserSettings');
		$userData = Zend_Auth::getInstance()->getStorage()->read();
		$userData = Atmail_Password::processUser($userData);
		
		$serverHost = isset($userData['mailserver_hostname']) && $userData['mailserver_hostname']
			? $userData['mailserver_hostname'] : $_SERVER['SERVER_NAME'];
		
		$dbTables = new dbTables();
		$dbAdapter = Zend_Registry::get('dbAdapter');
		
		// http://manuals.info.apple.com/en_US/Enterprise_Deployment_Guide.pdf

		// UUID can be any string
		$uuid = md5('atmail'.$settings['Account']);

		// XML doc
		$plist = $this->xml->createElement('plist');
		$plist->setAttribute('version', '1.0');

		// defualt string for organization
		$brandname = isset($userData['brandname']) && $userData['brandname']
			? $userData['brandname']: 'Atmail';
		
		if (isset($args['brandname']))
		{
			$brandname = $args['brandname'];
		}


		// future content of PLIST
		$payload = array(
			'PayloadVersion' => 1,
			'PayloadUUID'    => $uuid,
			'PayloadType'    => 'Configuration',
			'PayloadRemovalDisallowed' => false,
			'PayloadIdentifier' => 'atmail.'.$serverHost,
			'PayloadOrganization' => $brandname,
			'PayloadDescription'  => $brandname . ' IMAP, CalDAV, CardDAV',
			'PayloadDisplayName'  => $brandname . ' Mobile Config',
		);
		
		$userMailHost = $settings['MailServer'] && $settings['MailServer'] != 'localhost'
			? $settings['MailServer']: $serverHost;

		if (isset($args['smtpHost']))
		{
			$smtpHost = $args['smtpHost'];
		}
		else
		{
			$smtpHost = $userMailHost;
		}

		$emailIncomingHost = $userMailHost;
		$emailIncomingPort = 143;
		$emailIncomingSSL  = false;
		$emailIncomingAuth = 'EmailAuthPassword';
		$emailIncomingPass = $settings['MailServer'] ? $userData['password']: '';
		$emailOutgoingHost = $smtpHost;
		$emailOutgoingPort = 25;
		$emailOutgoingSSL  = false;
		$emailOutgoingAuth = 'EmailAuthPassword';
		$emailOutgoingPass = $emailIncomingPass;

		// this is not Users.CalDavUrl, which may be localhost for use by PHP
		// must be host name resolvable by the remote client. can be overridden in admin
		$caldavHost = $serverHost;
		$caldavSSL  = false;
		$caldavPort = 8008;
		$caldavPass = $emailIncomingPass;

		$carddavHost = $serverHost;
		$carddavSSL  = false;
		$carddavPort = 8008;
		$carddavPass = $emailIncomingPass;

        // Test if port 8443 is open, if so set caldav and carddav ports to ssl
        $portCheck = `netstat -nltp  | grep 8443 | grep LISTEN`;
        if (!empty($portCheck))
        {
            $caldavPort = 8443;
            $carddavPort = 8443;
        }

        // Test if port 8008 is open, if not set caldav and carddav ports to 80
        $portCheck = `netstat -nltp | grep 8008 | grep LISTEN`;
        if (empty($portCheck))
        {
            $caldavPort = 80;
            $carddavPort = 80;
        }


		// Admin settings
		foreach ($userData as $key => $value)
		{
			if ($key == 'iosOrganization')
			{
				if (!empty($value)) $payload['PayloadOrganization'] = $value;
				continue;
			}
			if ($key == 'iosDisplayName')
			{
				if (!empty($value)) $payload['PayloadDisplayName'] = $value;
				continue;
			}
			if ($key == 'iosDescription')
			{
				if (!empty($value)) $payload['PayloadDescription'] = $value;
				continue;
			}
		}

		// Email Account
		$email = array(
			'PayloadVersion'                   => 1,
			'PayloadUUID'                      => $uuid.'.email',
			'PayloadType'                      => 'com.apple.mail.managed',
			'PayloadIdentifier'                => $payload['PayloadIdentifier'].'.email',
			'PayloadDisplayName'               => 'Email Account',
			'PayloadOrganization'              => $payload['PayloadOrganization'],
			'PayloadDescription'               => 'Configures email account',
			'EmailAddress'                     => $settings['Account'],
			'EmailAccountType'                 => 'EmailTypeIMAP',
			'EmailAccountDescription'          => $payload['PayloadOrganization'].' Email',
			'EmailAccountName'                 => $settings['RealName'],
			'IncomingMailServerHostName'       => $emailIncomingHost,
			'IncomingMailServerPortNumber'     => $emailIncomingPort,
			'IncomingMailServerUseSSL'         => $emailIncomingSSL,
			'IncomingMailServerUsername'       => $settings['Account'],
			'IncomingPassword'                 => $emailIncomingPass,
			'IncomingMailServerAuthentication' => $emailIncomingAuth,
			'OutgoingMailServerHostName'       => $smtpHost,
			'OutgoingMailServerPortNumber'     => $emailOutgoingPort,
			'OutgoingMailServerUseSSL'         => $emailOutgoingSSL,
			'OutgoingMailServerUsername'       => $settings['Account'],
			'OutgoingPassword'                 => $emailOutgoingPass,
			'OutgoingMailServerAuthentication' => $emailOutgoingAuth,
		);
		$emailDict = $this->generateDict($email);

		// PayloadContent array of accounts
		$accounts = $this->xml->createElement('array');
		$accounts->appendChild($emailDict);
		
		// access to DAV stuff via group
		$groupRows = $dbAdapter
			->select()
			->from($dbTables->Groups)
			->where('GroupName = ' . $dbAdapter->quote($userData['Ugroup']))
			->query()
			->fetchAll();
			
		$userGroup = $groupRows && isset($groupRows[0]) ? $groupRows[0]: array();

		if (@$userGroup['CalDAVServer'] == '1')
		{
            $siteBaseUrl = Zend_Registry::get('siteBaseUrl');
            $appBaseUrl = rtrim($siteBaseUrl, '/') . (strpos($siteBaseUrl,'index.php')?'':'/index.php');
            if ($caldavPort == 8443)
            {
                $caldavPrincipal = 'https://' . $serverHost. ':' . $caldavPort . '/principals/users/' . $settings['Account'];
            }
            else if ($caldavPort == 80)
            {
                $caldavPrincipal = 'http://' . $serverHost. ':' . 80 . rtrim(str_replace('index.php', '', $appBaseUrl), '/') . '/dav/server.php/principals/users/' . $settings['Account'];
            }
            else
            {
                $caldavPrincipal = 'http://' . $serverHost. ':' . $caldavPort . '/principals/users/' . $settings['Account'];
            }
            // CalDAV
			$caldav = array(
				'PayloadVersion'           => 1,
				'PayloadUUID'              => $uuid.'.caldav',
				'PayloadType'              => 'com.apple.caldav.account',
				'PayloadIdentifier'        => $payload['PayloadIdentifier'].'.caldav',
				'PayloadDisplayName'       => 'CalDAV Account',
				'PayloadOrganization'      => $payload['PayloadOrganization'],
				'PayloadDescription'       => 'Configures CalDAV account',
				'CalDAVAccountDescription' => $payload['PayloadOrganization'].' CalDAV',
				'CalDAVHostName'           => $caldavHost,
				'CalDAVUsername'           => $userData['CalDavUser'],
				'CalDAVPassword'           => $caldavPass,
				'CalDAVUseSSL'             => $caldavSSL,
				'CalDAVPort'               => $caldavPort,
				'CalDAVPrincipalURL'       => $caldavPrincipal,
			);
			$caldavDict = $this->generateDict($caldav);

			if ($caldavHost)
			{
				$accounts->appendChild($caldavDict);
			}
		}
		
		if (@$userGroup['CardDAVServer'] == '1')
		{
			// Global CardDav
			$carddav = array(
				'PayloadVersion'            => 1,
				'PayloadUUID'               => $uuid.'.carddav',
				'PayloadType'               => 'com.apple.carddav.account',
				'PayloadIdentifier'         => $payload['PayloadIdentifier'].'.carddav',
				'PayloadDisplayName'        => 'CardDAV Account',
				'PayloadOrganization'       => $payload['PayloadOrganization'],
				'PayloadDescription'        => 'Configures CardDAV account',
				'CardDAVAccountDescription' => $payload['PayloadOrganization'].' CardDAV',
				'CardDAVHostName'           => $carddavHost,
				'CardDAVPort'               => $carddavPort,
				'CardDAVUsername'           => $userData['CalDavUser'],
				'CardDAVPassword'           => $carddavPass,
				'CardDAVUseSSL'             => $carddavSSL,
			);
			$carddavDict = $this->generateDict($carddav);
			$accounts->appendChild($carddavDict);
		}
		
		// User custom CardDAV accounts
/*		$abookServers = new Atmail_Abook_Servers(array(
			'Account' => $settings['Account'],
		));

		$carddavAccounts = $abookServers->GetServers();

		foreach ($carddavAccounts as $i => $ca)
		{
			if ($ca['protocol'] != 'carddav') continue;

			$carddav = array(
				'PayloadVersion'           => 1,
				'PayloadUUID'              => $uuid.'.carddav'.$i,
				'PayloadType'              => 'com.apple.carddav.account',
				'PayloadIdentifier'        => $payload['PayloadIdentifier'].'.carddav'.$i,
				'PayloadDisplayName'       => 'CardDAV Account ('.$i.')',
				'PayloadOrganization'      => $payload['PayloadOrganization'],
				'PayloadDescription'       => 'Configures CardDAV account',
				'CardDAVAccountDescription' => $payload['PayloadOrganization'].' Atmail CardDAV ('.$i.')',
				'CardDAVHostName'           => $ca['server'],
				'CardDAVPort'               => $ca['port'],
				'CardDAVUsername'           => $ca['username'],
				'CardDAVPassword'           => $ca['password'],
				'CardDAVPrincipalURL'       => $ca['url'],
				'CardDAVUseSSL'             => false,
			);
			$carddavDict = $this->generateDict($carddav);
			//$accounts->appendChild($carddavDict);
		}
*/
		$topdict = $this->generateDict($payload);
		$topdict->appendChild($this->xml->createElement('key', 'PayloadContent'));
		$topdict->appendChild($accounts);
		$plist->appendChild($topdict);

		$this->xml->appendChild($plist);
		$xml = $this->xml->saveXML();

		// DOMDocument lacks a nice way of setting doctype ?!
		// regex only replaces first match
		$xml = preg_replace('/>/', ">\n".'<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">', $xml, 1);

		return $xml;
	}
}

