Page MenuHomestyx hydra

No OneTemporary

diff --git a/conf/default.conf.php b/conf/default.conf.php
index be32c7b456..302d3ea45d 100644
--- a/conf/default.conf.php
+++ b/conf/default.conf.php
@@ -1,143 +1,149 @@
<?php
/*
* Copyright 2011 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
return array(
// The root URI which Phabricator is installed on.
// Example: "http://phabricator.example.com/"
'phabricator.base-uri' => null,
// The Conduit URI for API access to this install. Normally this is just
// the 'base-uri' plus "/api/" (e.g. "http://phabricator.example.com/api/"),
// but make sure you specify 'https' if you have HTTPS configured.
'phabricator.conduit-uri' => null,
'phabricator.csrf-key' => '0b7ec0592e0a2829d8b71df2fa269b2c6172eca3',
'phabricator.version' => 'UNSTABLE',
// The default PHID for users who haven't uploaded a profile image. It should
// be 50x50px.
'user.default-profile-image-phid' => 'PHID-FILE-f57aaefce707fc4060ef',
// When email is sent, try to hand it off to the MTA immediately. The only
// reason to disable this is if your MTA infrastructure is completely
// terrible. If you disable this option, you must run the 'metamta_mta.php'
// daemon or mail won't be handed off to the MTA.
'metamta.send-immediately' => true,
-
+
// "Reply-To" email address to use for no-reply emails.
'metamta.noreply' => 'noreply@example.com',
+ 'metamta.mail-adapter' =>
+ 'PhabricatorMailImplementationPHPMailerLiteAdapter',
+
+ 'amazon-ses.access-key' => null,
+ 'amazon-ses.secret-key' => null,
+
// -- Access Control -------------------------------------------------------- //
// Phabricator users have one of three access levels: "anyone", "verified",
// or "admin". "anyone" means every user, including users who do not have
// accounts or are not logged into the system. "verified" is users who have
// accounts, are logged in, and have satisfied whatever verification steps
// the configuration requires (e.g., email verification and/or manual
// approval). "admin" is verified users with the "administrator" flag set.
// These configuration options control which access level is required to read
// data from Phabricator (e.g., view revisions and comments in Differential)
// and write data to Phabricator (e.g., upload files and create diffs). By
// default they are both set to "verified", meaning only verified user
// accounts can interact with the system in any meaningful way.
// If you are configuring an install for an open source project, you may
// want to reduce the "phabricator.read-access" requirement to "anyone". This
// will allow anyone to browse Phabricator content, even without logging in.
// Alternatively, you could raise the "phabricator.write-access" requirement
// to "admin", effectively creating a read-only install.
// Controls the minimum access level required to read data from Phabricator
// (e.g., view revisions in Differential). Allowed values are "anyone",
// "verified", or "admin". Note that "anyone" includes users who are not
// logged in! You should leave this at 'verified' unless you want your data
// to be publicly readable (e.g., you are developing open source software).
'phabricator.read-access' => 'verified',
// Controls the minimum access level required to write data to Phabricator
// (e.g., create new revisions in Differential). Allowed values are
// "verified" or "admin". Setting this to "admin" will effectively create a
// read-only install.
'phabricator.write-access' => 'verified',
// -- DarkConsole ----------------------------------------------------------- //
// DarkConsole is a administrative debugging/profiling tool built into
// Phabricator. You can leave it disabled unless you're developing against
// Phabricator.
// Determines whether or not DarkConsole is available. DarkConsole exposes
// some data like queries and stack traces, so you should be careful about
// turning it on in production (although users can not normally see it, even
// if the deployment configuration enables it).
'darkconsole.enabled' => true,
// Always enable DarkConsole, even for logged out users. This potentially
// exposes sensitive information to users, so make sure untrusted users can
// not access an install running in this mode. You should definitely leave
// this off in production. It is only really useful for using DarkConsole
// utilties to debug or profile logged-out pages. You must set
// 'darkconsole.enabled' to use this option.
'darkconsole.always-on' => false,
// -- MySQL --------------------------------------------------------------- //
// The username to use when connecting to MySQL.
'mysql.user' => 'root',
// The password to use when connecting to MySQL.
'mysql.pass' => '',
// The MySQL server to connect to.
'mysql.host' => 'localhost',
// -- Facebook ------------------------------------------------------------ //
// Can users use Facebook credentials to login to Phabricator?
'facebook.auth-enabled' => false,
// The Facebook "Application ID" to use for Facebook API access.
'facebook.application-id' => null,
// The Facebook "Application Secret" to use for Facebook API access.
'facebook.application-secret' => null,
// -- Recaptcha ------------------------------------------------------------- //
// Is Recaptcha enabled? If disabled, captchas will not appear.
'recaptcha.enabled' => false,
// Your Recaptcha public key, obtained from Recaptcha.
'recaptcha.public-key' => null,
// Your Recaptcha private key, obtained from Recaptcha.
'recaptcha.private-key' => null,
);
diff --git a/externals/amazon-ses/ses.php b/externals/amazon-ses/ses.php
new file mode 100644
index 0000000000..f6ccfa6014
--- /dev/null
+++ b/externals/amazon-ses/ses.php
@@ -0,0 +1,703 @@
+<?php
+/**
+*
+* Copyright (c) 2011, Dan Myers.
+* Parts copyright (c) 2008, Donovan Schonknecht.
+* All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions are met:
+*
+* - Redistributions of source code must retain the above copyright notice,
+* this list of conditions and the following disclaimer.
+* - Redistributions in binary form must reproduce the above copyright
+* notice, this list of conditions and the following disclaimer in the
+* documentation and/or other materials provided with the distribution.
+*
+* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+* POSSIBILITY OF SUCH DAMAGE.
+*
+* This is a modified BSD license (the third clause has been removed).
+* The BSD license may be found here:
+* http://www.opensource.org/licenses/bsd-license.php
+*
+* Amazon Simple Email Service is a trademark of Amazon.com, Inc. or its affiliates.
+*
+* SimpleEmailService is based on Donovan Schonknecht's Amazon S3 PHP class, found here:
+* http://undesigned.org.za/2007/10/22/amazon-s3-php-class
+*
+*/
+
+/**
+* Amazon SimpleEmailService PHP class
+*
+* @link http://sourceforge.net/projects/php-aws-ses/
+* version 0.8.1
+*
+*/
+class SimpleEmailService
+{
+ protected $__accessKey; // AWS Access key
+ protected $__secretKey; // AWS Secret key
+ protected $__host;
+
+ public function getAccessKey() { return $this->__accessKey; }
+ public function getSecretKey() { return $this->__secretKey; }
+ public function getHost() { return $this->__host; }
+
+ protected $__verifyHost = 1;
+ protected $__verifyPeer = 1;
+
+ // verifyHost and verifyPeer determine whether curl verifies ssl certificates.
+ // It may be necessary to disable these checks on certain systems.
+ // These only have an effect if SSL is enabled.
+ public function verifyHost() { return $this->__verifyHost; }
+ public function enableVerifyHost($enable = true) { $this->__verifyHost = $enable; }
+
+ public function verifyPeer() { return $this->__verifyPeer; }
+ public function enableVerifyPeer($enable = true) { $this->__verifyPeer = $enable; }
+
+ /**
+ * Constructor
+ *
+ * @param string $accessKey Access key
+ * @param string $secretKey Secret key
+ * @return void
+ */
+ public function __construct($accessKey = null, $secretKey = null, $host = 'email.us-east-1.amazonaws.com') {
+ if ($accessKey !== null && $secretKey !== null) {
+ $this->setAuth($accessKey, $secretKey);
+ }
+ $this->__host = $host;
+ }
+
+ /**
+ * Set AWS access key and secret key
+ *
+ * @param string $accessKey Access key
+ * @param string $secretKey Secret key
+ * @return void
+ */
+ public function setAuth($accessKey, $secretKey) {
+ $this->__accessKey = $accessKey;
+ $this->__secretKey = $secretKey;
+ }
+
+ /**
+ * Lists the email addresses that have been verified and can be used as the 'From' address
+ *
+ * @return An array containing two items: a list of verified email addresses, and the request id.
+ */
+ public function listVerifiedEmailAddresses() {
+ $rest = new SimpleEmailServiceRequest($this, 'GET');
+ $rest->setParameter('Action', 'ListVerifiedEmailAddresses');
+
+ $rest = $rest->getResponse();
+ if($rest->error === false && $rest->code !== 200) {
+ $rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status');
+ }
+ if($rest->error !== false) {
+ $this->__triggerError('listVerifiedEmailAddresses', $rest->error);
+ return false;
+ }
+
+ $response = array();
+ if(!isset($rest->body)) {
+ return $response;
+ }
+
+ $addresses = array();
+ foreach($rest->body->ListVerifiedEmailAddressesResult->VerifiedEmailAddresses->member as $address) {
+ $addresses[] = (string)$address;
+ }
+
+ $response['Addresses'] = $addresses;
+ $response['RequestId'] = (string)$rest->body->ResponseMetadata->RequestId;
+
+ return $response;
+ }
+
+ /**
+ * Requests verification of the provided email address, so it can be used
+ * as the 'From' address when sending emails through SimpleEmailService.
+ *
+ * After submitting this request, you should receive a verification email
+ * from Amazon at the specified address containing instructions to follow.
+ *
+ * @param string email The email address to get verified
+ * @return The request id for this request.
+ */
+ public function verifyEmailAddress($email) {
+ $rest = new SimpleEmailServiceRequest($this, 'POST');
+ $rest->setParameter('Action', 'VerifyEmailAddress');
+ $rest->setParameter('EmailAddress', $email);
+
+ $rest = $rest->getResponse();
+ if($rest->error === false && $rest->code !== 200) {
+ $rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status');
+ }
+ if($rest->error !== false) {
+ $this->__triggerError('verifyEmailAddress', $rest->error);
+ return false;
+ }
+
+ $response['RequestId'] = (string)$rest->body->ResponseMetadata->RequestId;
+ return $response;
+ }
+
+ /**
+ * Removes the specified email address from the list of verified addresses.
+ *
+ * @param string email The email address to remove
+ * @return The request id for this request.
+ */
+ public function deleteVerifiedEmailAddress($email) {
+ $rest = new SimpleEmailServiceRequest($this, 'DELETE');
+ $rest->setParameter('Action', 'DeleteVerifiedEmailAddress');
+ $rest->setParameter('EmailAddress', $email);
+
+ $rest = $rest->getResponse();
+ if($rest->error === false && $rest->code !== 200) {
+ $rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status');
+ }
+ if($rest->error !== false) {
+ $this->__triggerError('deleteVerifiedEmailAddress', $rest->error);
+ return false;
+ }
+
+ $response['RequestId'] = (string)$rest->body->ResponseMetadata->RequestId;
+ return $response;
+ }
+
+ /**
+ * Retrieves information on the current activity limits for this account.
+ * See http://docs.amazonwebservices.com/ses/latest/APIReference/API_GetSendQuota.html
+ *
+ * @return An array containing information on this account's activity limits.
+ */
+ public function getSendQuota() {
+ $rest = new SimpleEmailServiceRequest($this, 'GET');
+ $rest->setParameter('Action', 'GetSendQuota');
+
+ $rest = $rest->getResponse();
+ if($rest->error === false && $rest->code !== 200) {
+ $rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status');
+ }
+ if($rest->error !== false) {
+ $this->__triggerError('getSendQuota', $rest->error);
+ return false;
+ }
+
+ $response = array();
+ if(!isset($rest->body)) {
+ return $response;
+ }
+
+ $response['Max24HourSend'] = (string)$rest->body->GetSendQuotaResult->Max24HourSend;
+ $response['MaxSendRate'] = (string)$rest->body->GetSendQuotaResult->MaxSendRate;
+ $response['SentLast24Hours'] = (string)$rest->body->GetSendQuotaResult->SentLast24Hours;
+ $response['RequestId'] = (string)$rest->body->ResponseMetadata->RequestId;
+
+ return $response;
+ }
+
+ /**
+ * Retrieves statistics for the last two weeks of activity on this account.
+ * See http://docs.amazonwebservices.com/ses/latest/APIReference/API_GetSendStatistics.html
+ *
+ * @return An array of activity statistics. Each array item covers a 15-minute period.
+ */
+ public function getSendStatistics() {
+ $rest = new SimpleEmailServiceRequest($this, 'GET');
+ $rest->setParameter('Action', 'GetSendStatistics');
+
+ $rest = $rest->getResponse();
+ if($rest->error === false && $rest->code !== 200) {
+ $rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status');
+ }
+ if($rest->error !== false) {
+ $this->__triggerError('getSendStatistics', $rest->error);
+ return false;
+ }
+
+ $response = array();
+ if(!isset($rest->body)) {
+ return $response;
+ }
+
+ $datapoints = array();
+ foreach($rest->body->GetSendStatisticsResult->SendDataPoints->member as $datapoint) {
+ $p = array();
+ $p['Bounces'] = (string)$datapoint->Bounces;
+ $p['Complaints'] = (string)$datapoint->Complaints;
+ $p['DeliveryAttempts'] = (string)$datapoint->DeliveryAttempts;
+ $p['Rejects'] = (string)$datapoint->Rejects;
+ $p['Timestamp'] = (string)$datapoint->Timestamp;
+
+ $datapoints[] = $p;
+ }
+
+ $response['SendDataPoints'] = $datapoints;
+ $response['RequestId'] = (string)$rest->body->ResponseMetadata->RequestId;
+
+ return $response;
+ }
+
+
+ /**
+ * Given a SimpleEmailServiceMessage object, submits the message to the service for sending.
+ *
+ * @return An array containing the unique identifier for this message and a separate request id.
+ * Returns false if the provided message is missing any required fields.
+ */
+ public function sendEmail($sesMessage) {
+ if(!$sesMessage->validate()) {
+ return false;
+ }
+
+ $rest = new SimpleEmailServiceRequest($this, 'POST');
+ $rest->setParameter('Action', 'SendEmail');
+
+ $i = 1;
+ foreach($sesMessage->to as $to) {
+ $rest->setParameter('Destination.ToAddresses.member.'.$i, $to);
+ $i++;
+ }
+
+ if(is_array($sesMessage->cc)) {
+ $i = 1;
+ foreach($sesMessage->cc as $cc) {
+ $rest->setParameter('Destination.CcAddresses.member.'.$i, $cc);
+ $i++;
+ }
+ }
+
+ if(is_array($sesMessage->bcc)) {
+ $i = 1;
+ foreach($sesMessage->bcc as $bcc) {
+ $rest->setParameter('Destination.BccAddresses.member.'.$i, $bcc);
+ $i++;
+ }
+ }
+
+ if(is_array($sesMessage->replyto)) {
+ $i = 1;
+ foreach($sesMessage->replyto as $replyto) {
+ $rest->setParameter('ReplyToAddresses.member.'.$i, $replyto);
+ $i++;
+ }
+ }
+
+ $rest->setParameter('Source', $sesMessage->from);
+
+ if($sesMessage->returnpath != null) {
+ $rest->setParameter('ReturnPath', $sesMessage->returnpath);
+ }
+
+ if($sesMessage->subject != null && strlen($sesMessage->subject) > 0) {
+ $rest->setParameter('Message.Subject.Data', $sesMessage->subject);
+ if($sesMessage->subjectCharset != null && strlen($sesMessage->subjectCharset) > 0) {
+ $rest->setParameter('Message.Subject.Charset', $sesMessage->subjectCharset);
+ }
+ }
+
+
+ if($sesMessage->messagetext != null && strlen($sesMessage->messagetext) > 0) {
+ $rest->setParameter('Message.Body.Text.Data', $sesMessage->messagetext);
+ if($sesMessage->messageTextCharset != null && strlen($sesMessage->messageTextCharset) > 0) {
+ $rest->setParameter('Message.Body.Text.Charset', $sesMessage->messageTextCharset);
+ }
+ }
+
+ if($sesMessage->messagehtml != null && strlen($sesMessage->messagehtml) > 0) {
+ $rest->setParameter('Message.Body.Html.Data', $sesMessage->messagehtml);
+ if($sesMessage->messageHtmlCharset != null && strlen($sesMessage->messageHtmlCharset) > 0) {
+ $rest->setParameter('Message.Body.Html.Charset', $sesMessage->messageHtmlCharset);
+ }
+ }
+
+ $rest = $rest->getResponse();
+ if($rest->error === false && $rest->code !== 200) {
+ $rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status');
+ }
+ if($rest->error !== false) {
+ $this->__triggerError('sendEmail', $rest->error);
+ return false;
+ }
+
+ $response['MessageId'] = (string)$rest->body->SendEmailResult->MessageId;
+ $response['RequestId'] = (string)$rest->body->ResponseMetadata->RequestId;
+ return $response;
+ }
+
+ /**
+ * Trigger an error message
+ *
+ * @internal Used by member functions to output errors
+ * @param array $error Array containing error information
+ * @return string
+ */
+ public function __triggerError($functionname, $error)
+ {
+ if($error == false) {
+ trigger_error(sprintf("SimpleEmailService::%s(): Encountered an error, but no description given", $functionname), E_USER_WARNING);
+ }
+ else if(isset($error['curl']) && $error['curl'])
+ {
+ trigger_error(sprintf("SimpleEmailService::%s(): %s %s", $functionname, $error['code'], $error['message']), E_USER_WARNING);
+ }
+ else if(isset($error['Error']))
+ {
+ $e = $error['Error'];
+ $message = sprintf("SimpleEmailService::%s(): %s - %s: %s\nRequest Id: %s\n", $functionname, $e['Type'], $e['Code'], $e['Message'], $error['RequestId']);
+ trigger_error($message, E_USER_WARNING);
+ }
+ }
+
+ /**
+ * Callback handler for 503 retries.
+ *
+ * @internal Used by SimpleDBRequest to call the user-specified callback, if set
+ * @param $attempt The number of failed attempts so far
+ * @return The retry delay in microseconds, or 0 to stop retrying.
+ */
+ public function __executeServiceTemporarilyUnavailableRetryDelay($attempt)
+ {
+ if(is_callable($this->__serviceUnavailableRetryDelayCallback)) {
+ $callback = $this->__serviceUnavailableRetryDelayCallback;
+ return $callback($attempt);
+ }
+ return 0;
+ }
+}
+
+final class SimpleEmailServiceRequest
+{
+ private $ses, $verb, $parameters = array();
+ public $response;
+
+ /**
+ * Constructor
+ *
+ * @param string $ses The SimpleEmailService object making this request
+ * @param string $action action
+ * @param string $verb HTTP verb
+ * @return mixed
+ */
+ function __construct($ses, $verb) {
+ $this->ses = $ses;
+ $this->verb = $verb;
+ $this->response = new STDClass;
+ $this->response->error = false;
+ }
+
+ /**
+ * Set request parameter
+ *
+ * @param string $key Key
+ * @param string $value Value
+ * @param boolean $replace Whether to replace the key if it already exists (default true)
+ * @return void
+ */
+ public function setParameter($key, $value, $replace = true) {
+ if(!$replace && isset($this->parameters[$key]))
+ {
+ $temp = (array)($this->parameters[$key]);
+ $temp[] = $value;
+ $this->parameters[$key] = $temp;
+ }
+ else
+ {
+ $this->parameters[$key] = $value;
+ }
+ }
+
+ /**
+ * Get the response
+ *
+ * @return object | false
+ */
+ public function getResponse() {
+
+ $params = array();
+ foreach ($this->parameters as $var => $value)
+ {
+ if(is_array($value))
+ {
+ foreach($value as $v)
+ {
+ $params[] = $var.'='.$this->__customUrlEncode($v);
+ }
+ }
+ else
+ {
+ $params[] = $var.'='.$this->__customUrlEncode($value);
+ }
+ }
+
+ sort($params, SORT_STRING);
+
+ // must be in format 'Sun, 06 Nov 1994 08:49:37 GMT'
+ $date = gmdate('D, d M Y H:i:s e');
+
+ $query = implode('&', $params);
+
+ $headers = array();
+ $headers[] = 'Date: '.$date;
+ $headers[] = 'Host: '.$this->ses->getHost();
+
+ $auth = 'AWS3-HTTPS AWSAccessKeyId='.$this->ses->getAccessKey();
+ $auth .= ',Algorithm=HmacSHA256,Signature='.$this->__getSignature($date);
+ $headers[] = 'X-Amzn-Authorization: '.$auth;
+
+ $url = 'https://'.$this->ses->getHost().'/';
+
+ // Basic setup
+ $curl = curl_init();
+ curl_setopt($curl, CURLOPT_USERAGENT, 'SimpleEmailService/php');
+
+ curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, ($this->ses->verifyHost() ? 1 : 0));
+ curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, ($this->ses->verifyPeer() ? 1 : 0));
+
+ // Request types
+ switch ($this->verb) {
+ case 'GET':
+ $url .= '?'.$query;
+ break;
+ case 'POST':
+ curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $this->verb);
+ curl_setopt($curl, CURLOPT_POSTFIELDS, $query);
+ $headers[] = 'Content-Type: application/x-www-form-urlencoded';
+ break;
+ case 'DELETE':
+ $url .= '?'.$query;
+ curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'DELETE');
+ break;
+ default: break;
+ }
+ curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
+ curl_setopt($curl, CURLOPT_HEADER, false);
+
+ curl_setopt($curl, CURLOPT_URL, $url);
+ curl_setopt($curl, CURLOPT_RETURNTRANSFER, false);
+ curl_setopt($curl, CURLOPT_WRITEFUNCTION, array(&$this, '__responseWriteCallback'));
+ curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true);
+
+ // Execute, grab errors
+ if (curl_exec($curl)) {
+ $this->response->code = curl_getinfo($curl, CURLINFO_HTTP_CODE);
+ } else {
+ $this->response->error = array(
+ 'curl' => true,
+ 'code' => curl_errno($curl),
+ 'message' => curl_error($curl),
+ 'resource' => $this->resource
+ );
+ }
+
+ @curl_close($curl);
+
+ // Parse body into XML
+ if ($this->response->error === false && isset($this->response->body)) {
+ $this->response->body = simplexml_load_string($this->response->body);
+
+ // Grab SES errors
+ if (!in_array($this->response->code, array(200, 201, 202, 204))
+ && isset($this->response->body->Error)) {
+ $error = $this->response->body->Error;
+ $output = array();
+ $output['curl'] = false;
+ $output['Error'] = array();
+ $output['Error']['Type'] = (string)$error->Type;
+ $output['Error']['Code'] = (string)$error->Code;
+ $output['Error']['Message'] = (string)$error->Message;
+ $output['RequestId'] = (string)$this->response->body->RequestId;
+
+ $this->response->error = $output;
+ unset($this->response->body);
+ }
+ }
+
+ return $this->response;
+ }
+
+ /**
+ * CURL write callback
+ *
+ * @param resource &$curl CURL resource
+ * @param string &$data Data
+ * @return integer
+ */
+ private function __responseWriteCallback(&$curl, &$data) {
+ $this->response->body .= $data;
+ return strlen($data);
+ }
+
+ /**
+ * Contributed by afx114
+ * URL encode the parameters as per http://docs.amazonwebservices.com/AWSECommerceService/latest/DG/index.html?Query_QueryAuth.html
+ * PHP's rawurlencode() follows RFC 1738, not RFC 3986 as required by Amazon. The only difference is the tilde (~), so convert it back after rawurlencode
+ * See: http://www.morganney.com/blog/API/AWS-Product-Advertising-API-Requires-a-Signed-Request.php
+ *
+ * @param string $var String to encode
+ * @return string
+ */
+ private function __customUrlEncode($var) {
+ return str_replace('%7E', '~', rawurlencode($var));
+ }
+
+ /**
+ * Generate the auth string using Hmac-SHA256
+ *
+ * @internal Used by SimpleDBRequest::getResponse()
+ * @param string $string String to sign
+ * @return string
+ */
+ private function __getSignature($string) {
+ return base64_encode(hash_hmac('sha256', $string, $this->ses->getSecretKey(), true));
+ }
+}
+
+
+final class SimpleEmailServiceMessage {
+
+ // these are public for convenience only
+ // these are not to be used outside of the SimpleEmailService class!
+ public $to, $cc, $bcc, $replyto;
+ public $from, $returnpath;
+ public $subject, $messagetext, $messagehtml;
+ public $subjectCharset, $messageTextCharset, $messageHtmlCharset;
+
+ function __construct() {
+ $to = array();
+ $cc = array();
+ $bcc = array();
+ $replyto = array();
+
+ $from = null;
+ $returnpath = null;
+
+ $subject = null;
+ $messagetext = null;
+ $messagehtml = null;
+
+ $subjectCharset = null;
+ $messageTextCharset = null;
+ $messageHtmlCharset = null;
+ }
+
+
+ /**
+ * addTo, addCC, addBCC, and addReplyTo have the following behavior:
+ * If a single address is passed, it is appended to the current list of addresses.
+ * If an array of addresses is passed, that array is merged into the current list.
+ */
+ function addTo($to) {
+ if(!is_array($to)) {
+ $this->to[] = $to;
+ }
+ else {
+ $this->to = array_merge($this->to, $to);
+ }
+ }
+
+ function addCC($cc) {
+ if(!is_array($cc)) {
+ $this->cc[] = $cc;
+ }
+ else {
+ $this->cc = array_merge($this->cc, $cc);
+ }
+ }
+
+ function addBCC($bcc) {
+ if(!is_array($bcc)) {
+ $this->bcc[] = $bcc;
+ }
+ else {
+ $this->bcc = array_merge($this->bcc, $bcc);
+ }
+ }
+
+ function addReplyTo($replyto) {
+ if(!is_array($replyto)) {
+ $this->replyto[] = $replyto;
+ }
+ else {
+ $this->replyto = array_merge($this->replyto, $replyto);
+ }
+ }
+
+ function setFrom($from) {
+ $this->from = $from;
+ }
+
+ function setReturnPath($returnpath) {
+ $this->returnpath = $returnpath;
+ }
+
+ function setSubject($subject) {
+ $this->subject = $subject;
+ }
+
+ function setSubjectCharset($charset) {
+ $this->subjectCharset = $charset;
+ }
+
+ function setMessageFromString($text, $html = null) {
+ $this->messagetext = $text;
+ $this->messagehtml = $html;
+ }
+
+ function setMessageFromFile($textfile, $htmlfile = null) {
+ if(file_exists($textfile) && is_file($textfile) && is_readable($textfile)) {
+ $this->messagetext = file_get_contents($textfile);
+ }
+ if(file_exists($htmlfile) && is_file($htmlfile) && is_readable($htmlfile)) {
+ $this->messagehtml = file_get_contents($htmlfile);
+ }
+ }
+
+ function setMessageFromURL($texturl, $htmlurl = null) {
+ $this->messagetext = file_get_contents($texturl);
+ if($htmlurl !== null) {
+ $this->messagehtml = file_get_contents($htmlurl);
+ }
+ }
+
+ function setMessageCharset($textCharset, $htmlCharset = null) {
+ $this->messageTextCharset = $textCharset;
+ $this->messageHtmlCharset = $htmlCharset;
+ }
+
+ /**
+ * Validates whether the message object has sufficient information to submit a request to SES.
+ * This does not guarantee the message will arrive, nor that the request will succeed;
+ * instead, it makes sure that no required fields are missing.
+ *
+ * This is used internally before attempting a SendEmail or SendRawEmail request,
+ * but it can be used outside of this file if verification is desired.
+ * May be useful if e.g. the data is being populated from a form; developers can generally
+ * use this function to verify completeness instead of writing custom logic.
+ *
+ * @return boolean
+ */
+ public function validate() {
+ if(count($this->to) == 0)
+ return false;
+ if($this->from == null || strlen($this->from) == 0)
+ return false;
+ if($this->messagetext == null)
+ return false;
+ return true;
+ }
+}
diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php
index 8dd50530f0..5f80b68b39 100644
--- a/src/__phutil_library_map__.php
+++ b/src/__phutil_library_map__.php
@@ -1,396 +1,398 @@
<?php
/**
* This file is automatically generated. Use 'phutil_mapper.php' to rebuild it.
* @generated
*/
phutil_register_library_map(array(
'class' =>
array(
'Aphront400Response' => 'aphront/response/400',
'Aphront404Response' => 'aphront/response/404',
'AphrontAjaxResponse' => 'aphront/response/ajax',
'AphrontApplicationConfiguration' => 'aphront/applicationconfiguration',
'AphrontController' => 'aphront/controller',
'AphrontDatabaseConnection' => 'storage/connection/base',
'AphrontDefaultApplicationConfiguration' => 'aphront/default/configuration',
'AphrontDefaultApplicationController' => 'aphront/default/controller',
'AphrontDialogResponse' => 'aphront/response/dialog',
'AphrontDialogView' => 'view/dialog',
'AphrontErrorView' => 'view/form/error',
'AphrontException' => 'aphront/exception/base',
'AphrontFileResponse' => 'aphront/response/file',
'AphrontFormCheckboxControl' => 'view/form/control/checkbox',
'AphrontFormControl' => 'view/form/control/base',
'AphrontFormDividerControl' => 'view/form/control/divider',
'AphrontFormFileControl' => 'view/form/control/file',
'AphrontFormMarkupControl' => 'view/form/control/markup',
'AphrontFormPasswordControl' => 'view/form/control/password',
'AphrontFormRecaptchaControl' => 'view/form/control/recaptcha',
'AphrontFormSelectControl' => 'view/form/control/select',
'AphrontFormStaticControl' => 'view/form/control/static',
'AphrontFormSubmitControl' => 'view/form/control/submit',
'AphrontFormTextAreaControl' => 'view/form/control/textarea',
'AphrontFormTextControl' => 'view/form/control/text',
'AphrontFormTokenizerControl' => 'view/form/control/tokenizer',
'AphrontFormView' => 'view/form/base',
'AphrontMySQLDatabaseConnection' => 'storage/connection/mysql',
'AphrontNullView' => 'view/null',
'AphrontPageView' => 'view/page/base',
'AphrontPanelView' => 'view/layout/panel',
'AphrontQueryConnectionException' => 'storage/exception/connection',
'AphrontQueryConnectionLostException' => 'storage/exception/connectionlost',
'AphrontQueryCountException' => 'storage/exception/count',
'AphrontQueryDuplicateKeyException' => 'storage/exception/duplicatekey',
'AphrontQueryException' => 'storage/exception/base',
'AphrontQueryObjectMissingException' => 'storage/exception/objectmissing',
'AphrontQueryParameterException' => 'storage/exception/parameter',
'AphrontQueryRecoverableException' => 'storage/exception/recoverable',
'AphrontRedirectException' => 'aphront/exception/redirect',
'AphrontRedirectResponse' => 'aphront/response/redirect',
'AphrontRequest' => 'aphront/request',
'AphrontRequestFailureView' => 'view/page/failure',
'AphrontResponse' => 'aphront/response/base',
'AphrontSideNavView' => 'view/layout/sidenav',
'AphrontTableView' => 'view/control/table',
'AphrontURIMapper' => 'aphront/mapper',
'AphrontView' => 'view/base',
'AphrontWebpageResponse' => 'aphront/response/webpage',
'CelerityAPI' => 'infrastructure/celerity/api',
'CelerityResourceController' => 'infrastructure/celerity/controller',
'CelerityResourceMap' => 'infrastructure/celerity/map',
'CelerityStaticResourceResponse' => 'infrastructure/celerity/response',
'ConduitAPIMethod' => 'applications/conduit/method/base',
'ConduitAPIRequest' => 'applications/conduit/protocol/request',
'ConduitAPI_conduit_connect_Method' => 'applications/conduit/method/conduit/connect',
'ConduitAPI_differential_creatediff_Method' => 'applications/conduit/method/differential/creatediff',
'ConduitAPI_differential_createrevision_Method' => 'applications/conduit/method/differential/createrevision',
'ConduitAPI_differential_find_Method' => 'applications/conduit/method/differential/find',
'ConduitAPI_differential_parsecommitmessage_Method' => 'applications/conduit/method/differential/parsecommitmessage',
'ConduitAPI_differential_setdiffproperty_Method' => 'applications/conduit/method/differential/setdiffproperty',
'ConduitAPI_differential_updaterevision_Method' => 'applications/conduit/method/differential/updaterevision',
'ConduitAPI_file_upload_Method' => 'applications/conduit/method/file/upload',
'ConduitAPI_user_find_Method' => 'applications/conduit/method/user/find',
'ConduitException' => 'applications/conduit/protocol/exception',
'DarkConsole' => 'aphront/console/api',
'DarkConsoleController' => 'aphront/console/controller',
'DarkConsoleCore' => 'aphront/console/core',
'DarkConsoleErrorLogPlugin' => 'aphront/console/plugin/errorlog',
'DarkConsoleErrorLogPluginAPI' => 'aphront/console/plugin/errorlog/api',
'DarkConsolePlugin' => 'aphront/console/plugin/base',
'DarkConsoleRequestPlugin' => 'aphront/console/plugin/request',
'DarkConsoleServicesPlugin' => 'aphront/console/plugin/services',
'DarkConsoleServicesPluginAPI' => 'aphront/console/plugin/services/api',
'DarkConsoleXHProfPlugin' => 'aphront/console/plugin/xhprof',
'DarkConsoleXHProfPluginAPI' => 'aphront/console/plugin/xhprof/api',
'DifferentialAction' => 'applications/differential/constants/action',
'DifferentialAddCommentView' => 'applications/differential/view/addcomment',
'DifferentialCCWelcomeMail' => 'applications/differential/mail/ccwelcome',
'DifferentialChangeType' => 'applications/differential/constants/changetype',
'DifferentialChangeset' => 'applications/differential/storage/changeset',
'DifferentialChangesetDetailView' => 'applications/differential/view/changesetdetailview',
'DifferentialChangesetListView' => 'applications/differential/view/changesetlistview',
'DifferentialChangesetParser' => 'applications/differential/parser/changeset',
'DifferentialChangesetViewController' => 'applications/differential/controller/changesetview',
'DifferentialComment' => 'applications/differential/storage/comment',
'DifferentialCommentEditor' => 'applications/differential/editor/comment',
'DifferentialCommentMail' => 'applications/differential/mail/comment',
'DifferentialCommentPreviewController' => 'applications/differential/controller/commentpreview',
'DifferentialCommentSaveController' => 'applications/differential/controller/commentsave',
'DifferentialCommitMessage' => 'applications/differential/parser/commitmessage',
'DifferentialCommitMessageParserException' => 'applications/differential/parser/commitmessage/exception',
'DifferentialController' => 'applications/differential/controller/base',
'DifferentialDAO' => 'applications/differential/storage/base',
'DifferentialDiff' => 'applications/differential/storage/diff',
'DifferentialDiffContentMail' => 'applications/differential/mail/diffcontent',
'DifferentialDiffCreateController' => 'applications/differential/controller/diffcreate',
'DifferentialDiffProperty' => 'applications/differential/storage/diffproperty',
'DifferentialDiffTableOfContentsView' => 'applications/differential/view/difftableofcontents',
'DifferentialDiffViewController' => 'applications/differential/controller/diffview',
'DifferentialHunk' => 'applications/differential/storage/hunk',
'DifferentialInlineComment' => 'applications/differential/storage/inlinecomment',
'DifferentialInlineCommentEditController' => 'applications/differential/controller/inlinecommentedit',
'DifferentialInlineCommentPreviewController' => 'applications/differential/controller/inlinecommentpreview',
'DifferentialInlineCommentView' => 'applications/differential/view/inlinecomment',
'DifferentialLintStatus' => 'applications/differential/constants/lintstatus',
'DifferentialMail' => 'applications/differential/mail/base',
'DifferentialMarkupEngineFactory' => 'applications/differential/parser/markup',
'DifferentialNewDiffMail' => 'applications/differential/mail/newdiff',
'DifferentialReviewRequestMail' => 'applications/differential/mail/reviewrequest',
'DifferentialRevision' => 'applications/differential/storage/revision',
'DifferentialRevisionCommentListView' => 'applications/differential/view/revisioncommentlist',
'DifferentialRevisionCommentView' => 'applications/differential/view/revisioncomment',
'DifferentialRevisionControlSystem' => 'applications/differential/constants/revisioncontrolsystem',
'DifferentialRevisionDetailView' => 'applications/differential/view/revisiondetail',
'DifferentialRevisionEditController' => 'applications/differential/controller/revisionedit',
'DifferentialRevisionEditor' => 'applications/differential/editor/revision',
'DifferentialRevisionListController' => 'applications/differential/controller/revisionlist',
'DifferentialRevisionListData' => 'applications/differential/data/revisionlist',
'DifferentialRevisionStatus' => 'applications/differential/constants/revisionstatus',
'DifferentialRevisionUpdateHistoryView' => 'applications/differential/view/revisionupdatehistory',
'DifferentialRevisionViewController' => 'applications/differential/controller/revisionview',
'DifferentialUnitStatus' => 'applications/differential/constants/unitstatus',
'Javelin' => 'infrastructure/javelin/api',
'LiskDAO' => 'storage/lisk/dao',
'Phabricator404Controller' => 'applications/base/controller/404',
'PhabricatorAuthController' => 'applications/auth/controller/base',
'PhabricatorConduitAPIController' => 'applications/conduit/controller/api',
'PhabricatorConduitConnectionLog' => 'applications/conduit/storage/connectionlog',
'PhabricatorConduitConsoleController' => 'applications/conduit/controller/console',
'PhabricatorConduitController' => 'applications/conduit/controller/base',
'PhabricatorConduitDAO' => 'applications/conduit/storage/base',
'PhabricatorConduitLogController' => 'applications/conduit/controller/log',
'PhabricatorConduitMethodCallLog' => 'applications/conduit/storage/methodcalllog',
'PhabricatorController' => 'applications/base/controller/base',
'PhabricatorDirectoryCategory' => 'applications/directory/storage/category',
'PhabricatorDirectoryCategoryDeleteController' => 'applications/directory/controller/categorydelete',
'PhabricatorDirectoryCategoryEditController' => 'applications/directory/controller/categoryedit',
'PhabricatorDirectoryCategoryListController' => 'applications/directory/controller/categorylist',
'PhabricatorDirectoryController' => 'applications/directory/controller/base',
'PhabricatorDirectoryDAO' => 'applications/directory/storage/base',
'PhabricatorDirectoryItem' => 'applications/directory/storage/item',
'PhabricatorDirectoryItemDeleteController' => 'applications/directory/controller/itemdelete',
'PhabricatorDirectoryItemEditController' => 'applications/directory/controller/itemedit',
'PhabricatorDirectoryItemListController' => 'applications/directory/controller/itemlist',
'PhabricatorDirectoryMainController' => 'applications/directory/controller/main',
'PhabricatorDraft' => 'applications/draft/storage/draft',
'PhabricatorDraftDAO' => 'applications/draft/storage/base',
'PhabricatorEmailLoginController' => 'applications/auth/controller/email',
'PhabricatorEmailTokenController' => 'applications/auth/controller/emailtoken',
'PhabricatorEnv' => 'infrastructure/env',
'PhabricatorFacebookAuthController' => 'applications/auth/controller/facebookauth',
'PhabricatorFacebookAuthDiagnosticsController' => 'applications/auth/controller/facebookauth/diagnostics',
'PhabricatorFile' => 'applications/files/storage/file',
'PhabricatorFileController' => 'applications/files/controller/base',
'PhabricatorFileDAO' => 'applications/files/storage/base',
'PhabricatorFileListController' => 'applications/files/controller/list',
'PhabricatorFileStorageBlob' => 'applications/files/storage/storageblob',
'PhabricatorFileURI' => 'applications/files/uri',
'PhabricatorFileUploadController' => 'applications/files/controller/upload',
'PhabricatorFileViewController' => 'applications/files/controller/view',
'PhabricatorLiskDAO' => 'applications/base/storage/lisk',
'PhabricatorLoginController' => 'applications/auth/controller/login',
'PhabricatorLogoutController' => 'applications/auth/controller/logout',
'PhabricatorMailImplementationAdapter' => 'applications/metamta/adapter/base',
+ 'PhabricatorMailImplementationAmazonSESAdapter' => 'applications/metamta/adapter/amazonses',
'PhabricatorMailImplementationPHPMailerLiteAdapter' => 'applications/metamta/adapter/phpmailerlite',
'PhabricatorMetaMTAController' => 'applications/metamta/controller/base',
'PhabricatorMetaMTADAO' => 'applications/metamta/storage/base',
'PhabricatorMetaMTAListController' => 'applications/metamta/controller/list',
'PhabricatorMetaMTAMail' => 'applications/metamta/storage/mail',
'PhabricatorMetaMTAMailingList' => 'applications/metamta/storage/mailinglist',
'PhabricatorMetaMTAMailingListEditController' => 'applications/metamta/controller/mailinglistedit',
'PhabricatorMetaMTAMailingListsController' => 'applications/metamta/controller/mailinglists',
'PhabricatorMetaMTASendController' => 'applications/metamta/controller/send',
'PhabricatorMetaMTAViewController' => 'applications/metamta/controller/view',
'PhabricatorObjectHandle' => 'applications/phid/handle',
'PhabricatorObjectHandleData' => 'applications/phid/handle/data',
'PhabricatorPHID' => 'applications/phid/storage/phid',
'PhabricatorPHIDAllocateController' => 'applications/phid/controller/allocate',
'PhabricatorPHIDController' => 'applications/phid/controller/base',
'PhabricatorPHIDDAO' => 'applications/phid/storage/base',
'PhabricatorPHIDListController' => 'applications/phid/controller/list',
'PhabricatorPHIDLookupController' => 'applications/phid/controller/lookup',
'PhabricatorPHIDType' => 'applications/phid/storage/type',
'PhabricatorPHIDTypeEditController' => 'applications/phid/controller/typeedit',
'PhabricatorPHIDTypeListController' => 'applications/phid/controller/typelist',
'PhabricatorPeopleController' => 'applications/people/controller/base',
'PhabricatorPeopleEditController' => 'applications/people/controller/edit',
'PhabricatorPeopleListController' => 'applications/people/controller/list',
'PhabricatorPeopleProfileController' => 'applications/people/controller/profile',
'PhabricatorStandardPageView' => 'view/page/standard',
'PhabricatorTypeaheadCommonDatasourceController' => 'applications/typeahead/controller/common',
'PhabricatorTypeaheadDatasourceController' => 'applications/typeahead/controller/base',
'PhabricatorUser' => 'applications/people/storage/user',
'PhabricatorUserDAO' => 'applications/people/storage/base',
'PhabricatorUserSettingsController' => 'applications/people/controller/settings',
'PhabricatorXHProfController' => 'applications/xhprof/controller/base',
'PhabricatorXHProfProfileController' => 'applications/xhprof/controller/profile',
'PhabricatorXHProfProfileSymbolView' => 'applications/xhprof/view/symbol',
'PhabricatorXHProfProfileTopLevelView' => 'applications/xhprof/view/toplevel',
),
'function' =>
array(
'_qsprintf_check_scalar_type' => 'storage/qsprintf',
'_qsprintf_check_type' => 'storage/qsprintf',
'celerity_generate_unique_node_id' => 'infrastructure/celerity/api',
'celerity_register_resource_map' => 'infrastructure/celerity/map',
'javelin_render_tag' => 'infrastructure/javelin/markup',
'phabricator_format_relative_time' => 'view/utils',
'phabricator_format_timestamp' => 'view/utils',
'phabricator_format_units_generic' => 'view/utils',
'qsprintf' => 'storage/qsprintf',
'queryfx' => 'storage/queryfx',
'queryfx_all' => 'storage/queryfx',
'queryfx_one' => 'storage/queryfx',
'require_celerity_resource' => 'infrastructure/celerity/api',
'vqsprintf' => 'storage/qsprintf',
'vqueryfx' => 'storage/queryfx',
'vqueryfx_all' => 'storage/queryfx',
'xsprintf_query' => 'storage/qsprintf',
),
'requires_class' =>
array(
'Aphront400Response' => 'AphrontResponse',
'Aphront404Response' => 'AphrontResponse',
'AphrontAjaxResponse' => 'AphrontResponse',
'AphrontDefaultApplicationConfiguration' => 'AphrontApplicationConfiguration',
'AphrontDefaultApplicationController' => 'AphrontController',
'AphrontDialogResponse' => 'AphrontResponse',
'AphrontDialogView' => 'AphrontView',
'AphrontErrorView' => 'AphrontView',
'AphrontFileResponse' => 'AphrontResponse',
'AphrontFormCheckboxControl' => 'AphrontFormControl',
'AphrontFormControl' => 'AphrontView',
'AphrontFormDividerControl' => 'AphrontFormControl',
'AphrontFormFileControl' => 'AphrontFormControl',
'AphrontFormMarkupControl' => 'AphrontFormControl',
'AphrontFormPasswordControl' => 'AphrontFormControl',
'AphrontFormRecaptchaControl' => 'AphrontFormControl',
'AphrontFormSelectControl' => 'AphrontFormControl',
'AphrontFormStaticControl' => 'AphrontFormControl',
'AphrontFormSubmitControl' => 'AphrontFormControl',
'AphrontFormTextAreaControl' => 'AphrontFormControl',
'AphrontFormTextControl' => 'AphrontFormControl',
'AphrontFormTokenizerControl' => 'AphrontFormControl',
'AphrontFormView' => 'AphrontView',
'AphrontMySQLDatabaseConnection' => 'AphrontDatabaseConnection',
'AphrontNullView' => 'AphrontView',
'AphrontPageView' => 'AphrontView',
'AphrontPanelView' => 'AphrontView',
'AphrontQueryConnectionException' => 'AphrontQueryException',
'AphrontQueryConnectionLostException' => 'AphrontQueryRecoverableException',
'AphrontQueryCountException' => 'AphrontQueryException',
'AphrontQueryDuplicateKeyException' => 'AphrontQueryException',
'AphrontQueryObjectMissingException' => 'AphrontQueryException',
'AphrontQueryParameterException' => 'AphrontQueryException',
'AphrontQueryRecoverableException' => 'AphrontQueryException',
'AphrontRedirectException' => 'AphrontException',
'AphrontRedirectResponse' => 'AphrontResponse',
'AphrontRequestFailureView' => 'AphrontView',
'AphrontSideNavView' => 'AphrontView',
'AphrontTableView' => 'AphrontView',
'AphrontWebpageResponse' => 'AphrontResponse',
'CelerityResourceController' => 'AphrontController',
'ConduitAPI_conduit_connect_Method' => 'ConduitAPIMethod',
'ConduitAPI_differential_creatediff_Method' => 'ConduitAPIMethod',
'ConduitAPI_differential_createrevision_Method' => 'ConduitAPIMethod',
'ConduitAPI_differential_find_Method' => 'ConduitAPIMethod',
'ConduitAPI_differential_parsecommitmessage_Method' => 'ConduitAPIMethod',
'ConduitAPI_differential_setdiffproperty_Method' => 'ConduitAPIMethod',
'ConduitAPI_differential_updaterevision_Method' => 'ConduitAPIMethod',
'ConduitAPI_file_upload_Method' => 'ConduitAPIMethod',
'ConduitAPI_user_find_Method' => 'ConduitAPIMethod',
'DarkConsoleController' => 'PhabricatorController',
'DarkConsoleErrorLogPlugin' => 'DarkConsolePlugin',
'DarkConsoleRequestPlugin' => 'DarkConsolePlugin',
'DarkConsoleServicesPlugin' => 'DarkConsolePlugin',
'DarkConsoleXHProfPlugin' => 'DarkConsolePlugin',
'DifferentialAddCommentView' => 'AphrontView',
'DifferentialCCWelcomeMail' => 'DifferentialReviewRequestMail',
'DifferentialChangeset' => 'DifferentialDAO',
'DifferentialChangesetDetailView' => 'AphrontView',
'DifferentialChangesetListView' => 'AphrontView',
'DifferentialChangesetViewController' => 'DifferentialController',
'DifferentialComment' => 'DifferentialDAO',
'DifferentialCommentMail' => 'DifferentialMail',
'DifferentialCommentPreviewController' => 'DifferentialController',
'DifferentialCommentSaveController' => 'DifferentialController',
'DifferentialController' => 'PhabricatorController',
'DifferentialDAO' => 'PhabricatorLiskDAO',
'DifferentialDiff' => 'DifferentialDAO',
'DifferentialDiffContentMail' => 'DifferentialMail',
'DifferentialDiffCreateController' => 'DifferentialController',
'DifferentialDiffProperty' => 'DifferentialDAO',
'DifferentialDiffTableOfContentsView' => 'AphrontView',
'DifferentialDiffViewController' => 'DifferentialController',
'DifferentialHunk' => 'DifferentialDAO',
'DifferentialInlineComment' => 'DifferentialDAO',
'DifferentialInlineCommentEditController' => 'DifferentialController',
'DifferentialInlineCommentPreviewController' => 'DifferentialController',
'DifferentialInlineCommentView' => 'AphrontView',
'DifferentialNewDiffMail' => 'DifferentialReviewRequestMail',
'DifferentialReviewRequestMail' => 'DifferentialMail',
'DifferentialRevision' => 'DifferentialDAO',
'DifferentialRevisionCommentListView' => 'AphrontView',
'DifferentialRevisionCommentView' => 'AphrontView',
'DifferentialRevisionDetailView' => 'AphrontView',
'DifferentialRevisionEditController' => 'DifferentialController',
'DifferentialRevisionListController' => 'DifferentialController',
'DifferentialRevisionUpdateHistoryView' => 'AphrontView',
'DifferentialRevisionViewController' => 'DifferentialController',
'Phabricator404Controller' => 'PhabricatorController',
'PhabricatorAuthController' => 'PhabricatorController',
'PhabricatorConduitAPIController' => 'PhabricatorConduitController',
'PhabricatorConduitConnectionLog' => 'PhabricatorConduitDAO',
'PhabricatorConduitConsoleController' => 'PhabricatorConduitController',
'PhabricatorConduitController' => 'PhabricatorController',
'PhabricatorConduitDAO' => 'PhabricatorLiskDAO',
'PhabricatorConduitLogController' => 'PhabricatorConduitController',
'PhabricatorConduitMethodCallLog' => 'PhabricatorConduitDAO',
'PhabricatorController' => 'AphrontController',
'PhabricatorDirectoryCategory' => 'PhabricatorDirectoryDAO',
'PhabricatorDirectoryCategoryDeleteController' => 'PhabricatorDirectoryController',
'PhabricatorDirectoryCategoryEditController' => 'PhabricatorDirectoryController',
'PhabricatorDirectoryCategoryListController' => 'PhabricatorDirectoryController',
'PhabricatorDirectoryController' => 'PhabricatorController',
'PhabricatorDirectoryDAO' => 'PhabricatorLiskDAO',
'PhabricatorDirectoryItem' => 'PhabricatorDirectoryDAO',
'PhabricatorDirectoryItemDeleteController' => 'PhabricatorDirectoryController',
'PhabricatorDirectoryItemEditController' => 'PhabricatorDirectoryController',
'PhabricatorDirectoryItemListController' => 'PhabricatorDirectoryController',
'PhabricatorDirectoryMainController' => 'PhabricatorDirectoryController',
'PhabricatorDraft' => 'PhabricatorDraftDAO',
'PhabricatorDraftDAO' => 'PhabricatorLiskDAO',
'PhabricatorEmailLoginController' => 'PhabricatorAuthController',
'PhabricatorEmailTokenController' => 'PhabricatorAuthController',
'PhabricatorFacebookAuthController' => 'PhabricatorAuthController',
'PhabricatorFacebookAuthDiagnosticsController' => 'PhabricatorAuthController',
'PhabricatorFile' => 'PhabricatorFileDAO',
'PhabricatorFileController' => 'PhabricatorController',
'PhabricatorFileDAO' => 'PhabricatorLiskDAO',
'PhabricatorFileListController' => 'PhabricatorFileController',
'PhabricatorFileStorageBlob' => 'PhabricatorFileDAO',
'PhabricatorFileUploadController' => 'PhabricatorFileController',
'PhabricatorFileViewController' => 'PhabricatorFileController',
'PhabricatorLiskDAO' => 'LiskDAO',
'PhabricatorLoginController' => 'PhabricatorAuthController',
'PhabricatorLogoutController' => 'PhabricatorAuthController',
+ 'PhabricatorMailImplementationAmazonSESAdapter' => 'PhabricatorMailImplementationAdapter',
'PhabricatorMailImplementationPHPMailerLiteAdapter' => 'PhabricatorMailImplementationAdapter',
'PhabricatorMetaMTAController' => 'PhabricatorController',
'PhabricatorMetaMTADAO' => 'PhabricatorLiskDAO',
'PhabricatorMetaMTAListController' => 'PhabricatorMetaMTAController',
'PhabricatorMetaMTAMail' => 'PhabricatorMetaMTADAO',
'PhabricatorMetaMTAMailingList' => 'PhabricatorMetaMTADAO',
'PhabricatorMetaMTAMailingListEditController' => 'PhabricatorMetaMTAController',
'PhabricatorMetaMTAMailingListsController' => 'PhabricatorMetaMTAController',
'PhabricatorMetaMTASendController' => 'PhabricatorMetaMTAController',
'PhabricatorMetaMTAViewController' => 'PhabricatorMetaMTAController',
'PhabricatorPHID' => 'PhabricatorPHIDDAO',
'PhabricatorPHIDAllocateController' => 'PhabricatorPHIDController',
'PhabricatorPHIDController' => 'PhabricatorController',
'PhabricatorPHIDDAO' => 'PhabricatorLiskDAO',
'PhabricatorPHIDListController' => 'PhabricatorPHIDController',
'PhabricatorPHIDLookupController' => 'PhabricatorPHIDController',
'PhabricatorPHIDType' => 'PhabricatorPHIDDAO',
'PhabricatorPHIDTypeEditController' => 'PhabricatorPHIDController',
'PhabricatorPHIDTypeListController' => 'PhabricatorPHIDController',
'PhabricatorPeopleController' => 'PhabricatorController',
'PhabricatorPeopleEditController' => 'PhabricatorPeopleController',
'PhabricatorPeopleListController' => 'PhabricatorPeopleController',
'PhabricatorPeopleProfileController' => 'PhabricatorPeopleController',
'PhabricatorStandardPageView' => 'AphrontPageView',
'PhabricatorTypeaheadCommonDatasourceController' => 'PhabricatorTypeaheadDatasourceController',
'PhabricatorTypeaheadDatasourceController' => 'PhabricatorController',
'PhabricatorUser' => 'PhabricatorUserDAO',
'PhabricatorUserDAO' => 'PhabricatorLiskDAO',
'PhabricatorUserSettingsController' => 'PhabricatorPeopleController',
'PhabricatorXHProfController' => 'PhabricatorController',
'PhabricatorXHProfProfileController' => 'PhabricatorXHProfController',
'PhabricatorXHProfProfileSymbolView' => 'AphrontView',
'PhabricatorXHProfProfileTopLevelView' => 'AphrontView',
),
'requires_interface' =>
array(
),
));
diff --git a/src/applications/metamta/adapter/amazonses/PhabricatorMailImplementationAmazonSESAdapter.php b/src/applications/metamta/adapter/amazonses/PhabricatorMailImplementationAmazonSESAdapter.php
new file mode 100644
index 0000000000..aa73909f11
--- /dev/null
+++ b/src/applications/metamta/adapter/amazonses/PhabricatorMailImplementationAmazonSESAdapter.php
@@ -0,0 +1,94 @@
+<?php
+
+/*
+ * Copyright 2011 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+class PhabricatorMailImplementationAmazonSESAdapter
+ extends PhabricatorMailImplementationAdapter {
+
+ private $message;
+ private $isHTML;
+
+ public function __construct() {
+ $root = phutil_get_library_root('phabricator');
+ $root = dirname($root);
+ require_once $root.'/externals/amazon-ses/ses.php';
+ $this->message = newv('SimpleEmailServiceMessage', array());
+ }
+
+ public function setFrom($email) {
+ $this->message->setFrom($email);
+ return $this;
+ }
+
+ public function addReplyTo($email) {
+ $this->message->addReplyTo($email);
+ return $this;
+ }
+
+ public function addTos(array $emails) {
+ foreach ($emails as $email) {
+ $this->message->addTo($email);
+ }
+ return $this;
+ }
+
+ public function addCCs(array $emails) {
+ foreach ($emails as $email) {
+ $this->message->addCC($email);
+ }
+ return $this;
+ }
+
+ public function addHeader($header_name, $header_value) {
+ // SES does not currently support custom headers.
+ return $this;
+ }
+
+ public function setBody($body) {
+ $this->body = $body;
+ return $this;
+ }
+
+ public function setSubject($subject) {
+ $this->message->setSubject($subject);
+ return $this;
+ }
+
+ public function setIsHTML($is_html) {
+ $this->isHTML = true;
+ return $this;
+ }
+
+ public function hasValidRecipients() {
+ return true;
+ }
+
+ public function send() {
+ if ($this->isHTML) {
+ $this->message->setMessageFromString($this->body, $this->body);
+ } else {
+ $this->message->setMessageFromString($this->body);
+ }
+
+ $key = PhabricatorEnv::getEnvConfig('amazon-ses.access-key');
+ $secret = PhabricatorEnv::getEnvConfig('amazon-ses.secret-key');
+
+ $service = new SimpleEmailService($key, $secret);
+ return $service->sendEmail($this->message);
+ }
+
+}
diff --git a/src/applications/metamta/storage/mail/__init__.php b/src/applications/metamta/adapter/amazonses/__init__.php
similarity index 55%
copy from src/applications/metamta/storage/mail/__init__.php
copy to src/applications/metamta/adapter/amazonses/__init__.php
index 715dad61dd..5fb8d3710c 100644
--- a/src/applications/metamta/storage/mail/__init__.php
+++ b/src/applications/metamta/adapter/amazonses/__init__.php
@@ -1,17 +1,16 @@
<?php
/**
* This file is automatically generated. Lint this module to rebuild it.
* @generated
*/
-phutil_require_module('phabricator', 'applications/metamta/adapter/phpmailerlite');
-phutil_require_module('phabricator', 'applications/metamta/storage/base');
-phutil_require_module('phabricator', 'applications/phid/handle/data');
+phutil_require_module('phabricator', 'applications/metamta/adapter/base');
phutil_require_module('phabricator', 'infrastructure/env');
+phutil_require_module('phutil', 'moduleutils');
phutil_require_module('phutil', 'utils');
-phutil_require_source('PhabricatorMetaMTAMail.php');
+phutil_require_source('PhabricatorMailImplementationAmazonSESAdapter.php');
diff --git a/src/applications/metamta/storage/mail/PhabricatorMetaMTAMail.php b/src/applications/metamta/storage/mail/PhabricatorMetaMTAMail.php
index 6c76198c6c..720d40502b 100644
--- a/src/applications/metamta/storage/mail/PhabricatorMetaMTAMail.php
+++ b/src/applications/metamta/storage/mail/PhabricatorMetaMTAMail.php
@@ -1,258 +1,261 @@
<?php
/*
* Copyright 2011 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* See #394445 for an explanation of why this thing even exists.
*/
class PhabricatorMetaMTAMail extends PhabricatorMetaMTADAO {
const STATUS_QUEUE = 'queued';
const STATUS_SENT = 'sent';
const STATUS_FAIL = 'fail';
const MAX_RETRIES = 250;
const RETRY_DELAY = 5;
protected $parameters;
protected $status;
protected $message;
protected $retryCount;
protected $nextRetry;
protected $relatedPHID;
public function __construct() {
$this->status = self::STATUS_QUEUE;
$this->retryCount = 0;
$this->nextRetry = time();
$this->parameters = array();
parent::__construct();
}
public function getConfiguration() {
return array(
self::CONFIG_SERIALIZATION => array(
'parameters' => self::SERIALIZATION_JSON,
),
) + parent::getConfiguration();
}
protected function setParam($param, $value) {
$this->parameters[$param] = $value;
return $this;
}
protected function getParam($param) {
return idx($this->parameters, $param);
}
public function getSubject() {
return $this->getParam('subject');
}
public function addTos(array $phids) {
$this->setParam('to', $phids);
return $this;
}
public function addCCs(array $phids) {
$this->setParam('cc', $phids);
return $this;
}
public function addHeader($name, $value) {
$this->parameters['headers'][$name] = $value;
return $this;
}
public function setFrom($from) {
$this->setParam('from', $from);
return $this;
}
public function setReplyTo($reply_to) {
$this->setParam('reply-to', $reply_to);
return $this;
}
public function setSubject($subject) {
$this->setParam('subject', $subject);
return $this;
}
public function setBody($body) {
$this->setParam('body', $body);
return $this;
}
public function setIsHTML($html) {
$this->setParam('is-html', $html);
return $this;
}
public function getSimulatedFailureCount() {
return nonempty($this->getParam('simulated-failures'), 0);
}
public function setSimulatedFailureCount($count) {
$this->setParam('simulated-failures', $count);
return $this;
}
public function save() {
$try_send = (PhabricatorEnv::getEnvConfig('metamta.send-immediately')) &&
(!$this->getID());
$ret = parent::save();
if ($try_send) {
- $mailer = new PhabricatorMailImplementationPHPMailerLiteAdapter();
+ $class_name = PhabricatorEnv::getEnvConfig('metamta.mail-adapter');
+ PhutilSymbolLoader::loadClass($class_name);
+ $mailer = newv($class_name, array());
$this->sendNow($force_send = false, $mailer);
}
return $ret;
}
public function sendNow(
$force_send = false,
PhabricatorMailImplementationAdapter $mailer) {
if (!$force_send) {
if ($this->getStatus() != self::STATUS_QUEUE) {
throw new Exception("Trying to send an already-sent mail!");
}
if (time() < $this->getNextRetry()) {
throw new Exception("Trying to send an email before next retry!");
}
}
try {
$parameters = $this->parameters;
$phids = array();
foreach ($parameters as $key => $value) {
switch ($key) {
case 'from':
case 'to':
case 'cc':
if (!is_array($value)) {
$value = array($value);
}
foreach (array_filter($value) as $phid) {
$phids[] = $phid;
}
break;
}
}
$handles = id(new PhabricatorObjectHandleData($phids))
->loadHandles();
foreach ($this->parameters as $key => $value) {
switch ($key) {
case 'from':
$mailer->setFrom($handles[$value]->getEmail());
break;
case 'reply-to':
$mailer->addReplyTo($value);
break;
case 'to':
$emails = array();
foreach ($value as $phid) {
$emails[] = $handles[$phid]->getEmail();
}
$mailer->addTos($emails);
break;
case 'cc':
$emails = array();
foreach ($value as $phid) {
$emails[] = $handles[$phid]->getEmail();
}
$mailer->addCCs($emails);
break;
case 'headers':
foreach ($value as $header_key => $header_value) {
$mailer->addHeader($header_key, $header_value);
}
break;
case 'body':
$mailer->setBody($value);
break;
case 'subject':
$mailer->setSubject($value);
break;
case 'is-html':
if ($value) {
$mailer->setIsHTML(true);
}
break;
default:
// Just discard.
}
}
$mailer->addHeader('X-Mail-Transport-Agent', 'MetaMTA');
} catch (Exception $ex) {
$this->setStatus(self::STATUS_FAIL);
$this->setMessage($ex->getMessage());
$this->save();
return;
}
if ($this->getRetryCount() < $this->getSimulatedFailureCount()) {
$ok = false;
$error = 'Simulated failure.';
} else {
try {
$ok = $mailer->send();
+ $error = null;
} catch (Exception $ex) {
$ok = false;
$error = $ex->getMessage();
}
}
if (!$ok) {
$this->setMessage($error);
if ($this->getRetryCount() > self::MAX_RETRIES) {
$this->setStatus(self::STATUS_FAIL);
} else {
$this->setRetryCount($this->getRetryCount() + 1);
$next_retry = time() + ($this->getRetryCount() * self::RETRY_DELAY);
$this->setNextRetry($next_retry);
}
} else {
$this->setStatus(self::STATUS_SENT);
}
$this->save();
}
public static function getReadableStatus($status_code) {
static $readable = array(
self::STATUS_QUEUE => "Queued for Delivery",
self::STATUS_FAIL => "Delivery Failed",
self::STATUS_SENT => "Sent",
);
$status_code = coalesce($status_code, '?');
return idx($readable, $status_code, $status_code);
}
}
diff --git a/src/applications/metamta/storage/mail/__init__.php b/src/applications/metamta/storage/mail/__init__.php
index 715dad61dd..8e7330cba4 100644
--- a/src/applications/metamta/storage/mail/__init__.php
+++ b/src/applications/metamta/storage/mail/__init__.php
@@ -1,17 +1,17 @@
<?php
/**
* This file is automatically generated. Lint this module to rebuild it.
* @generated
*/
-phutil_require_module('phabricator', 'applications/metamta/adapter/phpmailerlite');
phutil_require_module('phabricator', 'applications/metamta/storage/base');
phutil_require_module('phabricator', 'applications/phid/handle/data');
phutil_require_module('phabricator', 'infrastructure/env');
+phutil_require_module('phutil', 'symbols');
phutil_require_module('phutil', 'utils');
phutil_require_source('PhabricatorMetaMTAMail.php');

File Metadata

Mime Type
text/x-diff
Expires
Mon, Jun 9, 6:55 PM (3 h, 18 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
140133
Default Alt Text
(66 KB)

Event Timeline