Autoconfig harmonization
- use $autodiscover_config everywhere - non-443 HTTPS ports in autoconfig etc. - disabling POP service via SRV record - fix display name in Outlook IMAP autodiscover - allow multiple calls to TLSA generator and support Sieve STARTTLS - iOS mobileconfig generatormaster
parent
51660589d4
commit
5abeb313ba
|
@ -5,6 +5,16 @@ if (empty($mailcow_hostname)) {
|
|||
exit();
|
||||
}
|
||||
|
||||
$domain_dot = strpos($_SERVER['HTTP_HOST'], '.');
|
||||
$domain_port = strpos($_SERVER['HTTP_HOST'], ':');
|
||||
if ($domain_port === FALSE) {
|
||||
$domain = substr($_SERVER['HTTP_HOST'], $domain_dot+1);
|
||||
$port = 443;
|
||||
} else {
|
||||
$domain = substr($_SERVER['HTTP_HOST'], $domain_dot+1, $domain_port-$domain_dot-1);
|
||||
$port = substr($_SERVER['HTTP_HOST'], $domain_port+1);
|
||||
}
|
||||
|
||||
header('Content-Type: application/xml');
|
||||
?>
|
||||
<?= '<?xml version="1.0"?>'; ?>
|
||||
|
@ -15,52 +25,59 @@ header('Content-Type: application/xml');
|
|||
<displayShortName>mail server</displayShortName>
|
||||
|
||||
<incomingServer type="imap">
|
||||
<hostname><?= $mailcow_hostname; ?></hostname>
|
||||
<port>993</port>
|
||||
<hostname><?= $autodiscover_config['imap']['server']; ?></hostname>
|
||||
<port><?= $autodiscover_config['imap']['port']; ?></port>
|
||||
<socketType>SSL</socketType>
|
||||
<username>%EMAILADDRESS%</username>
|
||||
<authentication>password-cleartext</authentication>
|
||||
</incomingServer>
|
||||
<incomingServer type="imap">
|
||||
<hostname><?= $mailcow_hostname; ?></hostname>
|
||||
<port>143</port>
|
||||
<hostname><?= $autodiscover_config['imap']['server']; ?></hostname>
|
||||
<port><?= $autodiscover_config['imap']['tlsport']; ?></port>
|
||||
<socketType>STARTTLS</socketType>
|
||||
<username>%EMAILADDRESS%</username>
|
||||
<authentication>password-cleartext</authentication>
|
||||
</incomingServer>
|
||||
|
||||
<?php
|
||||
$records = dns_get_record('_pop3s._tcp.' . $domain, DNS_SRV); // check if POP3 is announced as "not provided" via SRV record
|
||||
if (count($records) == 0 || $records[0]['target'] != '') { ?>
|
||||
<incomingServer type="pop3">
|
||||
<hostname><?= $mailcow_hostname; ?></hostname>
|
||||
<port>995</port>
|
||||
<hostname><?= $autodiscover_config['pop3']['server']; ?></hostname>
|
||||
<port><?= $autodiscover_config['pop3']['port']; ?></port>
|
||||
<socketType>SSL</socketType>
|
||||
<username>%EMAILADDRESS%</username>
|
||||
<authentication>password-cleartext</authentication>
|
||||
</incomingServer>
|
||||
<?php } ?>
|
||||
<?php
|
||||
$records = dns_get_record('_pop3._tcp.' . $domain, DNS_SRV); // check if POP3 is announced as "not provided" via SRV record
|
||||
if (count($records) == 0 || $records[0]['target'] != '') { ?>
|
||||
<incomingServer type="pop3">
|
||||
<hostname><?= $mailcow_hostname; ?></hostname>
|
||||
<port>110</port>
|
||||
<hostname><?= $autodiscover_config['pop3']['server']; ?></hostname>
|
||||
<port><?= $autodiscover_config['pop3']['tlsport']; ?></port>
|
||||
<socketType>STARTTLS</socketType>
|
||||
<username>%EMAILADDRESS%</username>
|
||||
<authentication>password-cleartext</authentication>
|
||||
</incomingServer>
|
||||
<?php } ?>
|
||||
|
||||
<outgoingServer type="smtp">
|
||||
<hostname><?= $mailcow_hostname; ?></hostname>
|
||||
<port>465</port>
|
||||
<hostname><?= $autodiscover_config['smtp']['server']; ?></hostname>
|
||||
<port><?= $autodiscover_config['smtp']['port']; ?></port>
|
||||
<socketType>SSL</socketType>
|
||||
<username>%EMAILADDRESS%</username>
|
||||
<authentication>password-cleartext</authentication>
|
||||
</outgoingServer>
|
||||
|
||||
<outgoingServer type="smtp">
|
||||
<hostname><?= $mailcow_hostname; ?></hostname>
|
||||
<port>587</port>
|
||||
<hostname><?= $autodiscover_config['smtp']['server']; ?></hostname>
|
||||
<port><?= $autodiscover_config['smtp']['tlsport']; ?></port>
|
||||
<socketType>STARTTLS</socketType>
|
||||
<username>%EMAILADDRESS%</username>
|
||||
<authentication>password-cleartext</authentication>
|
||||
</outgoingServer>
|
||||
|
||||
<enable visiturl="https://<?= $mailcow_hostname; ?>/admin.php">
|
||||
<enable visiturl="https://<?= $mailcow_hostname; ?><?php if ($port != 443) echo ':'.$port; ?>/admin.php">
|
||||
<instruction>If you didn't change the password given to you by the administrator or if you didn't change it in a long time, please consider doing that now.</instruction>
|
||||
<instruction lang="de">Sollten Sie das Ihnen durch den Administrator vergebene Passwort noch nicht geändert haben, empfehlen wir dies nun zu tun. Auch ein altes Passwort sollte aus Sicherheitsgründen geändert werden.</instruction>
|
||||
</enable>
|
||||
|
@ -68,6 +85,6 @@ header('Content-Type: application/xml');
|
|||
</emailProvider>
|
||||
|
||||
<webMail>
|
||||
<loginPage url="https://<?= $mailcow_hostname; ?>/SOGo/" />
|
||||
<loginPage url="https://<?= $mailcow_hostname; ?><?php if ($port != 443) echo ':'.$port; ?>/SOGo/" />
|
||||
</webMail>
|
||||
</clientConfig>
|
||||
|
|
|
@ -12,13 +12,14 @@ error_reporting(0);
|
|||
$data = trim(file_get_contents("php://input"));
|
||||
|
||||
// Desktop client needs IMAP, unless it's Outlook 2013 or higher on Windows
|
||||
if (strpos($data, 'autodiscover/outlook/responseschema')) { // desktop client
|
||||
if (strpos($data, 'autodiscover/outlook/responseschema') !== false) { // desktop client
|
||||
$configuration['autodiscoverType'] = 'imap';
|
||||
if ($configuration['useEASforOutlook'] == 'yes' &&
|
||||
// Office for macOS does not support EAS
|
||||
strpos($_SERVER['HTTP_USER_AGENT'], 'Mac') === false &&
|
||||
// Outlook 2013 (version 15) or higher
|
||||
preg_match('/(Outlook|Office).+1[5-9]\./', $_SERVER['HTTP_USER_AGENT'])) {
|
||||
preg_match('/(Outlook|Office).+1[5-9]\./', $_SERVER['HTTP_USER_AGENT'])
|
||||
) {
|
||||
$configuration['autodiscoverType'] = 'activesync';
|
||||
}
|
||||
}
|
||||
|
@ -60,8 +61,28 @@ else {
|
|||
<?php
|
||||
exit(0);
|
||||
}
|
||||
try {
|
||||
$discover = new SimpleXMLElement($data);
|
||||
$email = $discover->Request->EMailAddress;
|
||||
} catch (Exception $e) {
|
||||
$email = $_SERVER['PHP_AUTH_USER'];
|
||||
}
|
||||
|
||||
$username = trim($email);
|
||||
try {
|
||||
$stmt = $pdo->prepare("SELECT `name` FROM `mailbox` WHERE `username`= :username");
|
||||
$stmt->execute(array(':username' => $username));
|
||||
$MailboxData = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
}
|
||||
catch(PDOException $e) {
|
||||
die("Failed to determine name from SQL");
|
||||
}
|
||||
if (!empty($MailboxData['name'])) {
|
||||
$displayname = utf8_encode($MailboxData['name']);
|
||||
}
|
||||
else {
|
||||
$displayname = $email;
|
||||
}
|
||||
|
||||
if ($configuration['autodiscoverType'] == 'imap') {
|
||||
?>
|
||||
|
@ -96,13 +117,13 @@ else {
|
|||
</Protocol>
|
||||
<Protocol>
|
||||
<Type>CalDAV</Type>
|
||||
<Server><?=$configuration['caldav']['server'];?>/SOGo/dav/<?=$email;?>/Calendar</Server>
|
||||
<Server>https://<?=$configuration['caldav']['server'];?><?php if ($configuration['caldav']['port'] != 443) echo ':'.$configuration['caldav']['port']; ?>/SOGo/dav/<?=$email;?>/Calendar</Server>
|
||||
<DomainRequired>off</DomainRequired>
|
||||
<LoginName><?=$email;?></LoginName>
|
||||
</Protocol>
|
||||
<Protocol>
|
||||
<Type>CardDAV</Type>
|
||||
<Server><?=$configuration['carddav']['server'];?>/SOGo/dav/<?=$email;?>/Contacts</Server>
|
||||
<Server>https://<?=$configuration['carddav']['server'];?><?php if ($configuration['caldav']['port'] != 443) echo ':'.$configuration['carddav']['port']; ?>/SOGo/dav/<?=$email;?>/Contacts</Server>
|
||||
<DomainRequired>off</DomainRequired>
|
||||
<LoginName><?=$email;?></LoginName>
|
||||
</Protocol>
|
||||
|
@ -111,21 +132,6 @@ else {
|
|||
<?php
|
||||
}
|
||||
else if ($configuration['autodiscoverType'] == 'activesync') {
|
||||
$username = trim($email);
|
||||
try {
|
||||
$stmt = $pdo->prepare("SELECT `name` FROM `mailbox` WHERE `username`= :username");
|
||||
$stmt->execute(array(':username' => $username));
|
||||
$MailboxData = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
}
|
||||
catch(PDOException $e) {
|
||||
die("Failed to determine name from SQL");
|
||||
}
|
||||
if (!empty($MailboxData['name'])) {
|
||||
$displayname = utf8_encode($MailboxData['name']);
|
||||
}
|
||||
else {
|
||||
$displayname = $email;
|
||||
}
|
||||
?>
|
||||
<Response xmlns="http://schemas.microsoft.com/exchange/autodiscover/mobilesync/responseschema/2006">
|
||||
<Culture>en:en</Culture>
|
||||
|
|
|
@ -62,10 +62,6 @@ function hasMailboxObjectAccess($username, $role, $object) {
|
|||
}
|
||||
return false;
|
||||
}
|
||||
function generate_tlsa_digest($hostname, $port, $starttls = null) {
|
||||
if (!is_valid_domain_name($hostname)) {
|
||||
return "Not a valid hostname";
|
||||
}
|
||||
function pem_to_der($pem_key) {
|
||||
// Need to remove BEGIN/END PUBLIC KEY
|
||||
$lines = explode("\n", trim($pem_key));
|
||||
|
@ -73,6 +69,10 @@ function generate_tlsa_digest($hostname, $port, $starttls = null) {
|
|||
unset($lines[0]);
|
||||
return base64_decode(implode('', $lines));
|
||||
}
|
||||
function generate_tlsa_digest($hostname, $port, $starttls = null) {
|
||||
if (!is_valid_domain_name($hostname)) {
|
||||
return "Not a valid hostname";
|
||||
}
|
||||
|
||||
if (empty($starttls)) {
|
||||
$context = stream_context_create(array("ssl" => array("capture_peer_cert" => true, 'verify_peer' => false, 'allow_self_signed' => true)));
|
||||
|
@ -88,20 +88,24 @@ function generate_tlsa_digest($hostname, $port, $starttls = null) {
|
|||
return $error_nr . ': ' . $error_msg;
|
||||
}
|
||||
$banner = fread($stream, 512 );
|
||||
if (preg_match("/^220/i", $banner)) {
|
||||
if (preg_match("/^220/i", $banner)) { // SMTP
|
||||
fwrite($stream,"HELO tlsa.generator.local\r\n");
|
||||
fread($stream, 512);
|
||||
fwrite($stream,"STARTTLS\r\n");
|
||||
fread($stream, 512);
|
||||
}
|
||||
elseif (preg_match("/imap.+starttls/i", $banner)) {
|
||||
elseif (preg_match("/imap.+starttls/i", $banner)) { // IMAP
|
||||
fwrite($stream,"A1 STARTTLS\r\n");
|
||||
fread($stream, 512);
|
||||
}
|
||||
elseif (preg_match("/^\+OK/", $banner)) {
|
||||
elseif (preg_match("/^\+OK/", $banner)) { // POP3
|
||||
fwrite($stream,"STLS\r\n");
|
||||
fread($stream, 512);
|
||||
}
|
||||
elseif (preg_match("/^OK/m", $banner)) { // Sieve
|
||||
fwrite($stream,"STARTTLS\r\n");
|
||||
fread($stream, 512);
|
||||
}
|
||||
else {
|
||||
return 'Unknown banner: "' . htmlspecialchars(trim($banner)) . '"';
|
||||
}
|
||||
|
|
|
@ -18,31 +18,48 @@ $database_name = getenv('DBNAME');
|
|||
$mailcow_hostname = getenv('MAILCOW_HOSTNAME');
|
||||
|
||||
// Autodiscover settings
|
||||
$https_port = strpos($_SERVER['HTTP_HOST'], ':');
|
||||
if ($https_port === FALSE) {
|
||||
$https_port = 443;
|
||||
} else {
|
||||
$https_port = substr($_SERVER['HTTP_HOST'], $https_port+1);
|
||||
}
|
||||
$autodiscover_config = array(
|
||||
// Enable the autodiscover service for Outlook desktop clients
|
||||
'useEASforOutlook' => 'yes',
|
||||
// General autodiscover service type: "activesync" or "imap"
|
||||
'autodiscoverType' => 'activesync',
|
||||
// Please don't use STARTTLS-enabled service ports here.
|
||||
// Please don't use STARTTLS-enabled service ports in the "port" variable.
|
||||
// The autodiscover service will always point to SMTPS and IMAPS (TLS-wrapped services).
|
||||
// The autoconfig service will additionally announce the STARTTLS-enabled ports, specified in the "tlsport" variable.
|
||||
'imap' => array(
|
||||
'server' => $mailcow_hostname,
|
||||
'port' => getenv('IMAPS_PORT'),
|
||||
'port' => array_pop(explode(':', getenv('IMAPS_PORT'))),
|
||||
'tlsport' => array_pop(explode(':', getenv('IMAP_PORT'))),
|
||||
),
|
||||
'pop3' => array(
|
||||
'server' => $mailcow_hostname,
|
||||
'port' => array_pop(explode(':', getenv('POPS_PORT'))),
|
||||
'tlsport' => array_pop(explode(':', getenv('POP_PORT'))),
|
||||
),
|
||||
'smtp' => array(
|
||||
'server' => $mailcow_hostname,
|
||||
'port' => getenv('SMTPS_PORT'),
|
||||
'port' => array_pop(explode(':', getenv('SMTPS_PORT'))),
|
||||
'tlsport' => array_pop(explode(':', getenv('SUBMISSION_PORT'))),
|
||||
),
|
||||
'activesync' => array(
|
||||
'url' => 'https://'.$mailcow_hostname.'/Microsoft-Server-ActiveSync'
|
||||
'url' => 'https://'.$mailcow_hostname.($https_port == 443 ? '' : ':'.$https_port).'/Microsoft-Server-ActiveSync',
|
||||
),
|
||||
'caldav' => array(
|
||||
'url' => 'https://'.$mailcow_hostname
|
||||
'server' => $mailcow_hostname,
|
||||
'port' => $https_port,
|
||||
),
|
||||
'carddav' => array(
|
||||
'url' => 'https://'.$mailcow_hostname
|
||||
)
|
||||
'server' => $mailcow_hostname,
|
||||
'port' => $https_port,
|
||||
),
|
||||
);
|
||||
unset($https_port);
|
||||
|
||||
// Where to go after adding and editing objects
|
||||
// Can be "form" or "previous"
|
||||
|
|
|
@ -0,0 +1,167 @@
|
|||
<?php
|
||||
require_once 'inc/prerequisites.inc.php';
|
||||
|
||||
if (empty($mailcow_hostname)) {
|
||||
exit();
|
||||
}
|
||||
if (!isset($_SESSION['mailcow_cc_role']) || $_SESSION['mailcow_cc_role'] != 'user') {
|
||||
header("Location: index.php");
|
||||
die("This page is only available to logged-in users, not admins.");
|
||||
}
|
||||
|
||||
header('Content-Type: application/x-apple-aspen-config');
|
||||
header('Content-Disposition: attachment; filename="Mailcow.mobileconfig"');
|
||||
|
||||
$email = $_SESSION['mailcow_cc_username'];
|
||||
$domain = explode('@', $_SESSION['mailcow_cc_username'])[1];
|
||||
$identifier = implode('.', array_reverse(explode('.', $domain))) . '.iphoneprofile.mailcow';
|
||||
|
||||
try {
|
||||
$stmt = $pdo->prepare("SELECT `name` FROM `mailbox` WHERE `username`= :username");
|
||||
$stmt->execute(array(':username' => $email));
|
||||
$MailboxData = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
}
|
||||
catch(PDOException $e) {
|
||||
die("Failed to determine name from SQL");
|
||||
}
|
||||
if (!empty($MailboxData['name'])) {
|
||||
$displayname = utf8_encode($MailboxData['name']);
|
||||
}
|
||||
else {
|
||||
$displayname = $email;
|
||||
}
|
||||
|
||||
echo '<?xml version="1.0" encoding="UTF-8"?>' . "\n";
|
||||
?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>PayloadContent</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>CalDAVAccountDescription</key>
|
||||
<string><?php echo $domain; ?></string>
|
||||
<key>CalDAVHostName</key>
|
||||
<string><?php echo $autodiscover_config['caldav']['server']; ?></string>
|
||||
<key>CalDAVPort</key>
|
||||
<real><?php echo $autodiscover_config['caldav']['port']; ?></real>
|
||||
<key>CalDAVPrincipalURL</key>
|
||||
<string>/SOGo/dav/<?php echo $email; ?></string>
|
||||
<key>CalDAVUseSSL</key>
|
||||
<true/>
|
||||
<key>CalDAVUsername</key>
|
||||
<string><?php echo $email; ?></string>
|
||||
<key>PayloadDescription</key>
|
||||
<string>Configures CalDAV account.</string>
|
||||
<key>PayloadDisplayName</key>
|
||||
<string>CalDAV (<?php echo $domain; ?>)</string>
|
||||
<key>PayloadIdentifier</key>
|
||||
<string><?php echo $identifier; ?>.CalDAV</string>
|
||||
<key>PayloadOrganization</key>
|
||||
<string></string>
|
||||
<key>PayloadType</key>
|
||||
<string>com.apple.caldav.account</string>
|
||||
<key>PayloadUUID</key>
|
||||
<string>FC898573-EBA8-48AF-93BD-BFA0C9778FA7</string>
|
||||
<key>PayloadVersion</key>
|
||||
<integer>1</integer>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>EmailAccountDescription</key>
|
||||
<string><?php echo $domain; ?></string>
|
||||
<key>EmailAccountType</key>
|
||||
<string>EmailTypeIMAP</string>
|
||||
<key>EmailAccountName</key>
|
||||
<string><?php echo $displayname; ?></string>
|
||||
<key>EmailAddress</key>
|
||||
<string><?php echo $email; ?></string>
|
||||
<key>IncomingMailServerAuthentication</key>
|
||||
<string>EmailAuthPassword</string>
|
||||
<key>IncomingMailServerHostName</key>
|
||||
<string><?php echo $autodiscover_config['imap']['server']; ?></string>
|
||||
<key>IncomingMailServerPortNumber</key>
|
||||
<integer><?php echo $autodiscover_config['imap']['port']; ?></integer>
|
||||
<key>IncomingMailServerUseSSL</key>
|
||||
<true/>
|
||||
<key>IncomingMailServerUsername</key>
|
||||
<string><?php echo $email; ?></string>
|
||||
<key>OutgoingMailServerAuthentication</key>
|
||||
<string>EmailAuthPassword</string>
|
||||
<key>OutgoingMailServerHostName</key>
|
||||
<string><?php echo $autodiscover_config['smtp']['server']; ?></string>
|
||||
<key>OutgoingMailServerPortNumber</key>
|
||||
<integer><?php echo $autodiscover_config['smtp']['port']; ?></integer>
|
||||
<key>OutgoingMailServerUseSSL</key>
|
||||
<true/>
|
||||
<key>OutgoingMailServerUsername</key>
|
||||
<string><?php echo $email; ?></string>
|
||||
<key>OutgoingPasswordSameAsIncomingPassword</key>
|
||||
<true/>
|
||||
<key>PayloadDescription</key>
|
||||
<string>Configures email account.</string>
|
||||
<key>PayloadDisplayName</key>
|
||||
<string>IMAP Account (<?php echo $domain; ?>)</string>
|
||||
<key>PayloadIdentifier</key>
|
||||
<string><?php echo $identifier; ?>.email</string>
|
||||
<key>PayloadOrganization</key>
|
||||
<string></string>
|
||||
<key>PayloadType</key>
|
||||
<string>com.apple.mail.managed</string>
|
||||
<key>PayloadUUID</key>
|
||||
<string>00294FBB-1016-413E-87B9-652D856D6875</string>
|
||||
<key>PayloadVersion</key>
|
||||
<integer>1</integer>
|
||||
<key>PreventAppSheet</key>
|
||||
<false/>
|
||||
<key>PreventMove</key>
|
||||
<false/>
|
||||
<key>SMIMEEnabled</key>
|
||||
<false/>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>CardDAVAccountDescription</key>
|
||||
<string><?php echo $domain; ?></string>
|
||||
<key>CardDAVHostName</key>
|
||||
<string><?php echo $autodiscover_config['carddav']['server']; ?></string>
|
||||
<key>CardDAVPort</key>
|
||||
<integer><?php echo $autodiscover_config['carddav']['port']; ?></integer>
|
||||
<key>CardDAVPrincipalURL</key>
|
||||
<string>/SOGo/dav/<?php echo $email; ?></string>
|
||||
<key>CardDAVUseSSL</key>
|
||||
<true/>
|
||||
<key>CardDAVUsername</key>
|
||||
<string><?php echo $email; ?></string>
|
||||
<key>PayloadDescription</key>
|
||||
<string>Configures CardDAV accounts</string>
|
||||
<key>PayloadDisplayName</key>
|
||||
<string>CardDAV (<?php echo $domain; ?>)</string>
|
||||
<key>PayloadIdentifier</key>
|
||||
<string><?php echo $identifier; ?>.carddav</string>
|
||||
<key>PayloadOrganization</key>
|
||||
<string></string>
|
||||
<key>PayloadType</key>
|
||||
<string>com.apple.carddav.account</string>
|
||||
<key>PayloadUUID</key>
|
||||
<string>0797EF2B-B1F1-4BC7-ABCD-4580862252B4</string>
|
||||
<key>PayloadVersion</key>
|
||||
<integer>1</integer>
|
||||
</dict>
|
||||
</array>
|
||||
<key>PayloadDescription</key>
|
||||
<string>IMAP, CalDAV, CardDAV</string>
|
||||
<key>PayloadDisplayName</key>
|
||||
<string><?php echo $domain; ?> Mailcow</string>
|
||||
<key>PayloadIdentifier</key>
|
||||
<string><?php echo $identifier; ?></string>
|
||||
<key>PayloadOrganization</key>
|
||||
<string></string>
|
||||
<key>PayloadRemovalDisallowed</key>
|
||||
<false/>
|
||||
<key>PayloadType</key>
|
||||
<string>Configuration</string>
|
||||
<key>PayloadUUID</key>
|
||||
<string>5EE248C5-ACCB-42D8-9199-8F8ED08D5624</string>
|
||||
<key>PayloadVersion</key>
|
||||
<integer>1</integer>
|
||||
</dict>
|
||||
</plist>
|
Loading…
Reference in New Issue