Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Merge pull request #48 from iron-io/feature-email-example

Feature email example
  • Loading branch information...
commit 4e0836e50786cb041b3a879b0f95d5d1594cb9d5 2 parents bb186c1 + f788887
@treeder treeder authored
Showing with 5,822 additions and 1 deletion.
  1. +27 −0 php/EmailSender.php
  2. +47 −0 php/MasterSlaveEmailer.php
  3. +70 −0 php/workers/email_worker/emailWorker.php
  4. +362 −0 php/workers/email_worker/lib/IronCache.class.php
  5. +329 −0 php/workers/email_worker/lib/IronCore.class.php
  6. +2,532 −0 php/workers/email_worker/lib/class.phpmailer.php
  7. +818 −0 php/workers/email_worker/lib/class.smtp.php
  8. +76 −0 php/workers/master_email_worker/MasterEmailWorker.php
  9. +329 −0 php/workers/master_email_worker/lib/IronCore.class.php
  10. +303 −0 php/workers/master_email_worker/lib/IronMQ.class.php
  11. +627 −0 php/workers/master_email_worker/lib/IronWorker.class.php
  12. +2 −1  ruby/_config.yml
  13. +13 −0 ruby_ng/email_worker/README.md
  14. +87 −0 ruby_ng/email_worker/email_worker.rb
  15. +5 −0 ruby_ng/email_worker/email_worker.worker
  16. +26 −0 ruby_ng/email_worker/single_email_sender.rb
  17. +14 −0 ruby_ng/master_email_worker/README.md
  18. +19 −0 ruby_ng/master_email_worker/master_email_sender.rb
  19. +81 −0 ruby_ng/master_email_worker/master_email_worker.rb
  20. +4 −0 ruby_ng/master_email_worker/master_email_worker.worker
  21. +11 −0 ruby_ng/twilio_worker/README.md
  22. +19 −0 ruby_ng/twilio_worker/single_twilio_sender.rb
  23. +17 −0 ruby_ng/twilio_worker/twilio_worker.rb
  24. +4 −0 ruby_ng/twilio_worker/twilio_worker.worker
View
27 php/EmailSender.php
@@ -0,0 +1,27 @@
+<?php
+include("../IronCore.class.php");
+include("../IronWorker.class.php");
+
+$name = "emailWorker.php";
+
+$iw = new IronWorker('config.ini');
+
+//uploading worker
+$iw->upload(dirname(__FILE__)."/workers/email_worker", 'emailWorker.php', $name);
+
+
+$payload = array(
+ 'host' => 'smtp.gmail.com',
+ 'port' => 587,
+ 'username' => 'username',
+ 'password' => 'passw',
+ 'from' => 'from@mail.com',
+ 'to' => 'sample@mail.com',
+ 'subject' => "Title",
+ 'body' => "Hey it's a body"
+);
+
+//queueing task
+$task_id = $iw->postTask($name, $payload);
+
+
View
47 php/MasterSlaveEmailer.php
@@ -0,0 +1,47 @@
+<?php
+include("../IronCore.class.php");
+include("../IronWorker.class.php");
+include("../IronMQ.class.php");
+$name = "MasterSlaveMailer-php";
+
+$iw = new IronWorker('config.ini');
+
+//parsing config to get token and project_id
+$data = @parse_ini_file('config.ini', true);
+
+//uploading worker
+$iw->upload(dirname(__FILE__)."/workers/master_email_worker", 'MasterEmailWorker.php', $name);
+
+
+
+$payload = array(
+ 'host' => 'smtp.gmail.com',
+ 'port' => 587,
+ 'username' => 'username',
+ 'password' => 'pass',
+ 'from' => 'from@mail.com',
+ 'token' => $data['iron_worker']['token'],
+ 'project_id' => $data['iron_worker']['project_id']
+);
+
+$ironmq = new IronMQ(array(
+ 'token' => $data['iron_worker']['token'],
+ 'project_id' => $data['iron_worker']['project_id']
+));
+
+//filing queue with emails
+for ($i = 0; $i < 20;$i++) {
+ $ironmq->postMessage('mail',$i.'sample@email.com');
+}
+
+$task_id = $iw->postTask($name, $payload);
+echo "task_id = $task_id \n";
+
+// Wait for task finish
+$details = $iw->waitFor($task_id);
+print_r($details);
+
+$log = $iw->getLog($task_id);
+echo "Task log:\n $log\n";
+
+
View
70 php/workers/email_worker/emailWorker.php
@@ -0,0 +1,70 @@
+<?php
+include("./lib/IronCore.class.php");
+require_once dirname(__FILE__) . "/lib/IronCache.class.php";
+require_once dirname(__FILE__) . "/lib/class.phpmailer.php";
+require_once dirname(__FILE__) . "/lib/class.smtp.php";
+
+function init_mail($payload)
+{
+ $mail = new PHPMailer();
+ $mail->IsSMTP();
+ $mail->SMTPDebug = 0; // debugging: 1 = errors and messages, 2 = messages only
+ $mail->SMTPAuth = true; // authentication enabled
+ $mail->SMTPSecure = 'ssl'; // secure transfer enabled
+ $mail->Host = $payload->host;
+ $mail->Port = $payload->port;
+ $mail->Username = $payload->username;
+ $mail->Password = $payload->password;
+ return $mail;
+}
+
+function send_mail($to, $from, $subject, $body,$mail)
+{
+ $mail->SetFrom($from, 'Best Company');
+ $mail->Subject = $subject;
+ $mail->MsgHTML($body);
+ $mail->AddAddress($to, "Dear User");
+ $mail->Send();
+}
+
+function update_message_status($payload, $email)
+{
+ echo("Updating status\n");
+ //Ping your api
+ echo("pinging api\n");
+ file_get_contents('http://google.com/?email='.urlencode($email));
+ if (!empty($payload->token) && !empty($payload->project_id))
+ {
+ //Or update date of last email in iron_cache
+ echo("setting iron_cache\n");
+ $cache = new IronCache(array(
+ 'token' => $payload->token,
+ 'project_id' => $payload->project_id
+ ));
+ $res = $cache->putItem('mail',$email, date("D M d, Y G:i"));
+ print_r($res);
+ }
+}
+
+$args = getArgs();
+print_r($args);
+$payload = $args['payload'];
+$mail = init_mail($payload);
+echo("Sending email\n");
+
+//what we received array of emails or single email
+if(is_array($payload->to))
+{
+foreach($payload->to as $email)
+ {
+ //array
+ send_mail($email, $payload->from, $payload->subject, $payload->body,$mail);
+ update_message_status($payload, $email);
+ }
+} else {
+ //single email
+ send_mail($payload->to, $payload->from, $payload->subject, $payload->body,$mail);
+ update_message_status($payload, $payload->to);
+}
+
+?>
View
362 php/workers/email_worker/lib/IronCache.class.php
@@ -0,0 +1,362 @@
+<?php
+/**
+ * PHP client for IronCache
+ *
+ * @link https://github.com/iron-io/iron_cache_php
+ * @link http://www.iron.io/products/cache
+ * @link http://dev.iron.io/
+ * @version 0.0.1
+ * @package IronCache
+ * @copyright Feel free to copy, steal, take credit for, or whatever you feel like doing with this code. ;)
+ */
+
+
+class IronCache_Item {
+ private $value;
+ private $expires_in;
+ private $replace;
+ private $add;
+
+ const max_expires_in = 2592000;
+
+ /**
+ * Create a new item.
+ *
+ * @param array|string $item
+ * An array of item properties or a string of the item value.
+ * Fields in item array:
+ * Required:
+ * - value: string - The item data, as a string.
+ * Optional:
+ * - expires_in: integer - How long in seconds to keep the item on the cache before it is deleted. Default is 604,800 seconds (7 days). Maximum is 2,592,000 seconds (30 days).
+ * - replace: boolean - Will only work if key already exists.
+ * - add: boolean - Will only work if key does not exist.
+ */
+ function __construct($item) {
+ if(is_string($item) || is_integer($item)) {
+ $this->setValue($item);
+ } elseif(is_array($item)) {
+ $this->setValue($item['value']);
+ if(array_key_exists("replace", $item)) {
+ $this->setReplace($item['replace']);
+ }
+ if(array_key_exists("add", $item)) {
+ $this->setAdd($item['add']);
+ }
+ if(array_key_exists("expires_in", $item)) {
+ $this->setExpiresIn($item['expires_in']);
+ }
+ }
+ }
+
+ public function setValue($value) {
+ if(empty($value)) {
+ throw new InvalidArgumentException("Please specify a value");
+ } else {
+ $this->value = $value;
+ }
+ }
+
+ public function getValue() {
+ return $this->value;
+ }
+
+ public function setReplace($replace) {
+ $this->replace = $replace;
+ }
+
+ public function getReplace() {
+ return $this->replace;
+ }
+
+ public function setAdd($add) {
+ $this->add = $add;
+ }
+
+ public function getAdd() {
+ return $this->add;
+ }
+
+ public function setExpiresIn($expires_in) {
+ if($expires_in > self::max_expires_in) {
+ throw new InvalidArgumentException("Expires In can't be greater than ".self::max_expires_in.".");
+ } else {
+ $this->expires_in = $expires_in;
+ }
+ }
+
+ public function getExpiresIn(){
+ return $this->expires_in;
+ }
+
+ public function asArray() {
+ $array = array();
+ $array['value'] = $this->getValue();
+ if($this->getExpiresIn() != null) {
+ $array['expires_in'] = $this->getExpiresIn();
+ }
+ if($this->getReplace() != null) {
+ $array['replace'] = $this->getReplace();
+ }
+ if($this->getAdd() != null) {
+ $array['add'] = $this->getAdd();
+ }
+ return $array;
+ }
+}
+
+class IronCache extends IronCore{
+ protected $client_version = '0.0.1';
+ protected $client_name = 'iron_cache_php';
+ protected $product_name = 'iron_cache';
+ protected $default_values = array(
+ 'protocol' => 'https',
+ 'host' => 'cache-aws-us-east-1.iron.io',
+ 'port' => '443',
+ 'api_version' => '1',
+ );
+
+ private $cache_name;
+
+ /**
+ * @param string|array $config_file_or_options
+ * Array of options or name of config file.
+ * Fields in options array or in config:
+ *
+ * Required:
+ * - token
+ * - project_id
+ * Optional:
+ * - protocol
+ * - host
+ * - port
+ * - api_version
+ * @param string|null $cache_name set default cache name
+ */
+ function __construct($config_file_or_options = null, $cache_name = null){
+ $this->getConfigData($config_file_or_options);
+ $this->url = "{$this->protocol}://{$this->host}:{$this->port}/{$this->api_version}/";
+ $this->setCacheName($cache_name);
+ }
+
+ /**
+ * Switch active project
+ *
+ * @param string $project_id Project ID
+ * @throws InvalidArgumentException
+ */
+ public function setProjectId($project_id) {
+ if (!empty($project_id)){
+ $this->project_id = $project_id;
+ }
+ if (empty($this->project_id)){
+ throw new InvalidArgumentException("Please set project_id");
+ }
+ }
+
+ /**
+ * Set default cache name
+ *
+ * @param string $cache_name name of cache
+ * @throws InvalidArgumentException
+ */
+ public function setCacheName($cache_name) {
+ if (!empty($cache_name)){
+ $this->cache_name = $cache_name;
+ }
+
+ }
+
+ public function getCaches($page = 0){
+ $url = "projects/{$this->project_id}/caches";
+ $params = array();
+ if($page > 0) {
+ $params['page'] = $page;
+ }
+ $this->setJsonHeaders();
+ return self::json_decode($this->apiCall(self::GET, $url, $params));
+ }
+
+ /**
+ * Get information about cache.
+ * Also returns cache size.
+ *
+ * @param string $cache
+ * @return mixed
+ */
+ public function getCache($cache) {
+ $cache = self::encodeCache($cache);
+ $url = "projects/{$this->project_id}/caches/$cache";
+ $this->setJsonHeaders();
+ return self::json_decode($this->apiCall(self::GET, $url));
+ }
+
+ /**
+ * Push a item on the cache at 'key'
+ *
+ * Examples:
+ * <code>
+ * $cache->postItem("test_cache", 'default', "Hello world");
+ * </code>
+ * <code>
+ * $cache->putItem("test_cache", 'default', array(
+ * "value" => "Test Item",
+ * 'expires_in' => 2*24*3600, # 2 days
+ * "replace" => true
+ * ));
+ * </code>
+ *
+ * @param string $cache Name of the cache.
+ * @param string $key Item key.
+ * @param array|string $item
+ *
+ * @return mixed
+ */
+ public function putItem($cache, $key, $item) {
+ $cache = self::encodeCache($cache);
+ $key = self::encodeKey($key);
+ $itm = new IronCache_Item($item);
+ $req = $itm->asArray();
+ $url = "projects/{$this->project_id}/caches/$cache/items/$key";
+
+ $this->setJsonHeaders();
+ $res = $this->apiCall(self::PUT, $url, $req);
+ return self::json_decode($res);
+ }
+
+ /**
+ * Get item from cache by key
+ *
+ * @param string $cache Cache name
+ * @param string $key Cache key
+ * @return mixed|null single item or null
+ * @throws Http_Exception
+ */
+ public function getItem($cache, $key) {
+ $cache = self::encodeCache($cache);
+ $key = self::encodeKey($key);
+ $url = "projects/{$this->project_id}/caches/$cache/items/$key";
+
+ $this->setJsonHeaders();
+ try {
+ $res = $this->apiCall(self::GET, $url);
+ }catch (Http_Exception $e){
+ if ($e->getCode() == Http_Exception::NOT_FOUND){
+ return null;
+ }else{
+ throw $e;
+ }
+ }
+ return self::json_decode($res);
+ }
+
+ public function deleteItem($cache, $key) {
+ $cache = self::encodeCache($cache);
+ $key = self::encodeKey($key);
+ $url = "projects/{$this->project_id}/caches/$cache/items/$key";
+
+ $this->setJsonHeaders();
+ return self::json_decode($this->apiCall(self::DELETE, $url));
+ }
+
+ /**
+ * Atomically increments the value for key by amount.
+ * Can be used for both increment and decrement by passing a negative value.
+ * The value must exist and must be an integer.
+ * The number is treated as an unsigned 64-bit integer.
+ * The usual overflow rules apply when adding, but subtracting from 0 always yields 0.
+ *
+ * @param string $cache
+ * @param string $key
+ * @param int $amount Change by this value
+ * @return mixed|void
+ */
+ public function incrementItem($cache, $key, $amount = 1){
+ $cache = self::encodeCache($cache);
+ $key = self::encodeKey($key);
+ $url = "projects/{$this->project_id}/caches/$cache/items/$key/increment";
+ $params = array(
+ 'amount' => $amount
+ );
+ $this->setJsonHeaders();
+ return self::json_decode($this->apiCall(self::POST, $url, $params));
+ }
+
+
+ /**
+ * Shortcut for getItem($cache, $key)
+ * Please set $cache name before use by setCacheName() method
+ *
+ * @param string $key
+ * @return mixed|null
+ * @throws InvalidArgumentException
+ */
+ public function get($key){
+ return $this->getItem($this->cache_name, $key);
+ }
+
+ /**
+ * Shortcut for postItem($cache, $key, $item)
+ * Please set $cache name before use by setCacheName() method
+ *
+ * @param string $key
+ * @param array|string $item
+ * @return mixed
+ * @throws InvalidArgumentException
+ */
+ public function put($key, $item){
+ return $this->putItem($this->cache_name, $key, $item);
+ }
+
+ /**
+ * Shortcut for deleteItem($cache, $key)
+ * Please set $cache name before use by setCacheName() method
+ *
+ * @param string $key
+ * @return mixed|void
+ * @throws InvalidArgumentException
+ */
+ public function delete($key){
+ return $this->deleteItem($this->cache_name, $key);
+ }
+
+ /**
+ * Shortcut for incrementItem($cache, $key, $amount)
+ * Please set $cache name before use by setCacheName() method
+ *
+ * @param string $key
+ * @param int $amount
+ * @return mixed|void
+ * @throws InvalidArgumentException
+ */
+ public function increment($key, $amount = 1){
+ return $this->incrementItem($this->cache_name, $key, $amount);
+ }
+
+ /* PRIVATE FUNCTIONS */
+
+ private static function encodeCache($cache){
+ if (empty($cache)){
+ throw new InvalidArgumentException('Please set $cache variable');
+ }
+ return rawurlencode($cache);
+ }
+
+ private static function encodeKey($key){
+ if (empty($key)){
+ throw new InvalidArgumentException('Please set $key variable');
+ }
+ return rawurlencode($key);
+ }
+
+
+ private function setJsonHeaders(){
+ $this->setCommonHeaders();
+ }
+
+ private function setPostHeaders(){
+ $this->setCommonHeaders();
+ $this->headers['Content-Type'] ='multipart/form-data';
+ }
+
+}
View
329 php/workers/email_worker/lib/IronCore.class.php
@@ -0,0 +1,329 @@
+<?php
+/**
+ * Core functionality for Iron.io products
+ *
+ * @link https://github.com/iron-io/iron_core_php
+ * @link http://www.iron.io/
+ * @link http://dev.iron.io/
+ * @version 0.0.2
+ * @package IronCore
+ * @copyright BSD 2-Clause License. See LICENSE file.
+ */
+
+class IronCore{
+ protected $core_version = '0.0.1';
+
+ // should be overridden by child class
+ protected $client_version = null;
+ protected $client_name = null;
+ protected $product_name = null;
+ protected $default_values = null;
+
+ const HTTP_OK = 200;
+ const HTTP_CREATED = 201;
+ const HTTP_ACCEPTED = 202;
+
+ const POST = 'POST';
+ const PUT = 'PUT';
+ const GET = 'GET';
+ const DELETE = 'DELETE';
+
+ const header_accept = "application/json";
+ const header_accept_encoding = "gzip, deflate";
+
+ protected $url;
+ protected $token;
+ protected $api_version;
+ protected $version;
+ protected $project_id;
+ protected $headers;
+ protected $protocol;
+ protected $host;
+ protected $port;
+
+ public $max_retries = 5;
+ public $debug_enabled = false;
+ public $ssl_verifypeer = true;
+
+
+ protected static function dateRfc3339($timestamp = 0) {
+ if ($timestamp instanceof DateTime) {
+ $timestamp = $timestamp->getTimestamp();
+ }
+ if (!$timestamp) {
+ $timestamp = time();
+ }
+ return gmdate('c', $timestamp);
+ }
+
+ protected static function json_decode($response){
+ $data = json_decode($response);
+ if (function_exists('json_last_error')){
+ $json_error = json_last_error();
+ if($json_error != JSON_ERROR_NONE) {
+ throw new JSON_Exception($json_error);
+ }
+ }elseif($data === null){
+ throw new JSON_Exception("Common JSON error");
+ }
+ return $data;
+ }
+
+
+ protected static function homeDir(){
+ if ($home_dir = getenv('HOME')){
+ // *NIX
+ return $home_dir.DIRECTORY_SEPARATOR;
+ }else{
+ // Windows
+ return getenv('HOMEDRIVE').getenv('HOMEPATH').DIRECTORY_SEPARATOR;
+ }
+ }
+
+ protected function debug($var_name, $variable){
+ if ($this->debug_enabled){
+ echo "{$var_name}: ".var_export($variable,true)."\n";
+ }
+ }
+
+ protected function userAgent(){
+ return "{$this->client_name}-{$this->client_version} (iron_core-{$this->core_version})";
+ }
+
+ /**
+ * Load configuration
+ *
+ * @param array|string|null $config_file_or_options
+ * array of options or name of config file
+ * @return array
+ * @throws InvalidArgumentException
+ */
+ protected function getConfigData($config_file_or_options){
+ if(is_string($config_file_or_options)){
+ if (!file_exists($config_file_or_options)){
+ throw new InvalidArgumentException("Config file $config_file_or_options not found");
+ }
+ $this->loadConfigFile($config_file_or_options);
+ }elseif(is_array($config_file_or_options)){
+ $this->loadFromHash($config_file_or_options);
+ }
+
+ $this->loadConfigFile('iron.ini');
+ $this->loadConfigFile('iron.json');
+
+ $this->loadFromEnv(strtoupper($this->product_name));
+ $this->loadFromEnv('IRON');
+
+ $this->loadConfigFile(self::homeDir() . '.iron.ini');
+ $this->loadConfigFile(self::homeDir() . '.iron.json');
+
+ $this->loadFromHash($this->default_values);
+
+ if (empty($this->token) || empty($this->project_id)){
+ throw new InvalidArgumentException("token or project_id not found in any of the available sources");
+ }
+ }
+
+
+ protected function loadFromHash($options){
+ if (empty($options)) return;
+ $this->setVarIfValue('token', $options);
+ $this->setVarIfValue('project_id', $options);
+ $this->setVarIfValue('protocol', $options);
+ $this->setVarIfValue('host', $options);
+ $this->setVarIfValue('port', $options);
+ $this->setVarIfValue('api_version', $options);
+ }
+
+ protected function loadFromEnv($prefix){
+ $this->setVarIfValue('token', getenv($prefix. "_TOKEN"));
+ $this->setVarIfValue('project_id', getenv($prefix. "_PROJECT_ID"));
+ $this->setVarIfValue('protocol', getenv($prefix. "_SCHEME"));
+ $this->setVarIfValue('host', getenv($prefix. "_HOST"));
+ $this->setVarIfValue('port', getenv($prefix. "_PORT"));
+ $this->setVarIfValue('api_version', getenv($prefix. "_API_VERSION"));
+ }
+
+ protected function setVarIfValue($key, $options_or_value){
+ if (!empty($this->$key)) return;
+ if (is_array($options_or_value)){
+ if (!empty($options_or_value[$key])){
+ $this->$key = $options_or_value[$key];
+ }
+ }else{
+ if (!empty($options_or_value)){
+ $this->$key = $options_or_value;
+ }
+ }
+ }
+
+ protected function loadConfigFile($file){
+ if (!file_exists($file)) return;
+ $data = @parse_ini_file($file, true);
+ if ($data === false){
+ $data = json_decode(file_get_contents($file), true);
+ }
+ if (!is_array($data)){
+ throw new InvalidArgumentException("Config file $file not parsed");
+ };
+
+ if (!empty($data[$this->product_name])) $this->loadFromHash($data[$this->product_name]);
+ if (!empty($data['iron'])) $this->loadFromHash($data['iron']);
+ $this->loadFromHash($data);
+ }
+
+ protected function apiCall($type, $url, $params = array(), $raw_post_data = null){
+ $url = "{$this->url}$url";
+
+ $s = curl_init();
+ if (! isset($params['oauth'])) {
+ $params['oauth'] = $this->token;
+ }
+ switch ($type) {
+ case self::DELETE:
+ $url .= '?' . http_build_query($params);
+ curl_setopt($s, CURLOPT_URL, $url);
+ curl_setopt($s, CURLOPT_CUSTOMREQUEST, self::DELETE);
+ break;
+ case self::PUT:
+ curl_setopt($s, CURLOPT_URL, $url);
+ curl_setopt($s, CURLOPT_CUSTOMREQUEST, self::PUT);
+ curl_setopt($s, CURLOPT_POSTFIELDS, json_encode($params));
+ break;
+ case self::POST:
+ curl_setopt($s, CURLOPT_URL, $url);
+ curl_setopt($s, CURLOPT_POST, true);
+ if ($raw_post_data){
+ curl_setopt($s, CURLOPT_POSTFIELDS, $raw_post_data);
+ }else{
+ curl_setopt($s, CURLOPT_POSTFIELDS, json_encode($params));
+ }
+ break;
+ case self::GET:
+ $url .= '?' . http_build_query($params);
+ curl_setopt($s, CURLOPT_URL, $url);
+ break;
+ }
+ $this->debug('apiCall full Url', $url);
+ curl_setopt($s, CURLOPT_SSL_VERIFYPEER, $this->ssl_verifypeer);
+ curl_setopt($s, CURLOPT_RETURNTRANSFER, true);
+ curl_setopt($s, CURLOPT_HTTPHEADER, $this->compiledHeaders());
+ return $this->callWithRetries($s);
+ }
+
+ protected function callWithRetries($s){
+ for ($retry = 0; $retry < $this->max_retries; $retry++){
+ $_out = curl_exec($s);
+ $status = curl_getinfo($s, CURLINFO_HTTP_CODE);
+ switch ($status) {
+ case self::HTTP_OK:
+ case self::HTTP_CREATED:
+ case self::HTTP_ACCEPTED:
+ curl_close($s);
+ return $_out;
+ case Http_Exception::INTERNAL_ERROR:
+ if (strpos($_out, "EOF") !== false){
+ self::waitRandomInterval($retry);
+ }else{
+ curl_close($s);
+ $this->reportHttpError($status, $_out);
+ }
+ break;
+ case Http_Exception::SERVICE_UNAVAILABLE:
+ self::waitRandomInterval($retry);
+ break;
+ default:
+ curl_close($s);
+ $this->reportHttpError($status, $_out);
+ }
+ }
+ curl_close($s);
+ return $this->reportHttpError(503, "Service unavailable");
+ }
+
+ protected function reportHttpError($status, $text){
+ throw new Http_Exception("http error: {$status} | {$text}", $status);
+ }
+
+ /**
+ * Wait for a random time between 0 and (4^currentRetry * 100) milliseconds
+ *
+ * @static
+ * @param int $retry currentRetry number
+ */
+ protected static function waitRandomInterval($retry){
+ $max_delay = pow(4, $retry)*100*1000;
+ usleep(rand(0, $max_delay));
+ }
+
+ protected function compiledHeaders(){
+ # Set default headers if no headers set.
+ if ($this->headers == null){
+ $this->setCommonHeaders();
+ }
+
+ $headers = array();
+ foreach ($this->headers as $k => $v){
+ $headers[] = "$k: $v";
+ }
+ return $headers;
+ }
+
+ protected function setCommonHeaders(){
+ $this->headers = array(
+ 'Authorization' => "OAuth {$this->token}",
+ 'User-Agent' => $this->userAgent(),
+ 'Content-Type' => 'application/json',
+ 'Accept' => self::header_accept,
+ 'Accept-Encoding' => self::header_accept_encoding
+ );
+ }
+
+}
+
+/**
+ * The Http_Exception class represents an HTTP response status that is not 200 OK.
+ */
+class Http_Exception extends Exception{
+ const NOT_MODIFIED = 304;
+ const BAD_REQUEST = 400;
+ const NOT_FOUND = 404;
+ const NOT_ALLOWED = 405;
+ const CONFLICT = 409;
+ const PRECONDITION_FAILED = 412;
+ const INTERNAL_ERROR = 500;
+ const SERVICE_UNAVAILABLE = 503;
+}
+
+/**
+ * The JSON_Exception class represents an failures of decoding json strings.
+ */
+class JSON_Exception extends Exception {
+ public $error = null;
+ public $error_code = JSON_ERROR_NONE;
+
+ function __construct($error_code) {
+ $this->error_code = $error_code;
+ switch($error_code) {
+ case JSON_ERROR_DEPTH:
+ $this->error = 'Maximum stack depth exceeded.';
+ break;
+ case JSON_ERROR_CTRL_CHAR:
+ $this->error = "Unexpected control characted found.";
+ break;
+ case JSON_ERROR_SYNTAX:
+ $this->error = "Syntax error, malformed JSON";
+ break;
+ default:
+ $this->error = $error_code;
+ break;
+
+ }
+ parent::__construct();
+ }
+
+ function __toString() {
+ return $this->error;
+ }
+}
+
View
2,532 php/workers/email_worker/lib/class.phpmailer.php
@@ -0,0 +1,2532 @@
+<?php
+/*~ class.phpmailer.php
+.---------------------------------------------------------------------------.
+| Software: PHPMailer - PHP email class |
+| Version: 5.2.1 |
+| Site: https://code.google.com/a/apache-extras.org/p/phpmailer/ |
+| ------------------------------------------------------------------------- |
+| Admin: Jim Jagielski (project admininistrator) |
+| Authors: Andy Prevost (codeworxtech) codeworxtech@users.sourceforge.net |
+| : Marcus Bointon (coolbru) coolbru@users.sourceforge.net |
+| : Jim Jagielski (jimjag) jimjag@gmail.com |
+| Founder: Brent R. Matzelle (original founder) |
+| Copyright (c) 2010-2012, Jim Jagielski. All Rights Reserved. |
+| Copyright (c) 2004-2009, Andy Prevost. All Rights Reserved. |
+| Copyright (c) 2001-2003, Brent R. Matzelle |
+| ------------------------------------------------------------------------- |
+| License: Distributed under the Lesser General Public License (LGPL) |
+| http://www.gnu.org/copyleft/lesser.html |
+| This program is distributed in the hope that it will be useful - WITHOUT |
+| ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
+| FITNESS FOR A PARTICULAR PURPOSE. |
+'---------------------------------------------------------------------------'
+*/
+
+/**
+ * PHPMailer - PHP email transport class
+ * NOTE: Requires PHP version 5 or later
+ * @package PHPMailer
+ * @author Andy Prevost
+ * @author Marcus Bointon
+ * @author Jim Jagielski
+ * @copyright 2010 - 2012 Jim Jagielski
+ * @copyright 2004 - 2009 Andy Prevost
+ * @version $Id: class.phpmailer.php 450 2010-06-23 16:46:33Z coolbru $
+ * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
+ */
+
+if (version_compare(PHP_VERSION, '5.0.0', '<') ) exit("Sorry, this version of PHPMailer will only run on PHP version 5 or greater!\n");
+
+class PHPMailer {
+
+ /////////////////////////////////////////////////
+ // PROPERTIES, PUBLIC
+ /////////////////////////////////////////////////
+
+ /**
+ * Email priority (1 = High, 3 = Normal, 5 = low).
+ * @var int
+ */
+ public $Priority = 3;
+
+ /**
+ * Sets the CharSet of the message.
+ * @var string
+ */
+ public $CharSet = 'iso-8859-1';
+
+ /**
+ * Sets the Content-type of the message.
+ * @var string
+ */
+ public $ContentType = 'text/plain';
+
+ /**
+ * Sets the Encoding of the message. Options for this are
+ * "8bit", "7bit", "binary", "base64", and "quoted-printable".
+ * @var string
+ */
+ public $Encoding = '8bit';
+
+ /**
+ * Holds the most recent mailer error message.
+ * @var string
+ */
+ public $ErrorInfo = '';
+
+ /**
+ * Sets the From email address for the message.
+ * @var string
+ */
+ public $From = 'root@localhost';
+
+ /**
+ * Sets the From name of the message.
+ * @var string
+ */
+ public $FromName = 'Root User';
+
+ /**
+ * Sets the Sender email (Return-Path) of the message. If not empty,
+ * will be sent via -f to sendmail or as 'MAIL FROM' in smtp mode.
+ * @var string
+ */
+ public $Sender = '';
+
+ /**
+ * Sets the Subject of the message.
+ * @var string
+ */
+ public $Subject = '';
+
+ /**
+ * Sets the Body of the message. This can be either an HTML or text body.
+ * If HTML then run IsHTML(true).
+ * @var string
+ */
+ public $Body = '';
+
+ /**
+ * Sets the text-only body of the message. This automatically sets the
+ * email to multipart/alternative. This body can be read by mail
+ * clients that do not have HTML email capability such as mutt. Clients
+ * that can read HTML will view the normal Body.
+ * @var string
+ */
+ public $AltBody = '';
+
+ /**
+ * Stores the complete compiled MIME message body.
+ * @var string
+ * @access protected
+ */
+ protected $MIMEBody = '';
+
+ /**
+ * Stores the complete compiled MIME message headers.
+ * @var string
+ * @access protected
+ */
+ protected $MIMEHeader = '';
+
+ /**
+ * Stores the complete sent MIME message (Body and Headers)
+ * @var string
+ * @access protected
+ */
+ protected $SentMIMEMessage = '';
+
+ /**
+ * Sets word wrapping on the body of the message to a given number of
+ * characters.
+ * @var int
+ */
+ public $WordWrap = 0;
+
+ /**
+ * Method to send mail: ("mail", "sendmail", or "smtp").
+ * @var string
+ */
+ public $Mailer = 'mail';
+
+ /**
+ * Sets the path of the sendmail program.
+ * @var string
+ */
+ public $Sendmail = '/usr/sbin/sendmail';
+
+ /**
+ * Path to PHPMailer plugins. Useful if the SMTP class
+ * is in a different directory than the PHP include path.
+ * @var string
+ */
+ public $PluginDir = '';
+
+ /**
+ * Sets the email address that a reading confirmation will be sent.
+ * @var string
+ */
+ public $ConfirmReadingTo = '';
+
+ /**
+ * Sets the hostname to use in Message-Id and Received headers
+ * and as default HELO string. If empty, the value returned
+ * by SERVER_NAME is used or 'localhost.localdomain'.
+ * @var string
+ */
+ public $Hostname = '';
+
+ /**
+ * Sets the message ID to be used in the Message-Id header.
+ * If empty, a unique id will be generated.
+ * @var string
+ */
+ public $MessageID = '';
+
+ /////////////////////////////////////////////////
+ // PROPERTIES FOR SMTP
+ /////////////////////////////////////////////////
+
+ /**
+ * Sets the SMTP hosts. All hosts must be separated by a
+ * semicolon. You can also specify a different port
+ * for each host by using this format: [hostname:port]
+ * (e.g. "smtp1.example.com:25;smtp2.example.com").
+ * Hosts will be tried in order.
+ * @var string
+ */
+ public $Host = 'localhost';
+
+ /**
+ * Sets the default SMTP server port.
+ * @var int
+ */
+ public $Port = 25;
+
+ /**
+ * Sets the SMTP HELO of the message (Default is $Hostname).
+ * @var string
+ */
+ public $Helo = '';
+
+ /**
+ * Sets connection prefix.
+ * Options are "", "ssl" or "tls"
+ * @var string
+ */
+ public $SMTPSecure = '';
+
+ /**
+ * Sets SMTP authentication. Utilizes the Username and Password variables.
+ * @var bool
+ */
+ public $SMTPAuth = false;
+
+ /**
+ * Sets SMTP username.
+ * @var string
+ */
+ public $Username = '';
+
+ /**
+ * Sets SMTP password.
+ * @var string
+ */
+ public $Password = '';
+
+ /**
+ * Sets the SMTP server timeout in seconds.
+ * This function will not work with the win32 version.
+ * @var int
+ */
+ public $Timeout = 10;
+
+ /**
+ * Sets SMTP class debugging on or off.
+ * @var bool
+ */
+ public $SMTPDebug = false;
+
+ /**
+ * Prevents the SMTP connection from being closed after each mail
+ * sending. If this is set to true then to close the connection
+ * requires an explicit call to SmtpClose().
+ * @var bool
+ */
+ public $SMTPKeepAlive = false;
+
+ /**
+ * Provides the ability to have the TO field process individual
+ * emails, instead of sending to entire TO addresses
+ * @var bool
+ */
+ public $SingleTo = false;
+
+ /**
+ * If SingleTo is true, this provides the array to hold the email addresses
+ * @var bool
+ */
+ public $SingleToArray = array();
+
+ /**
+ * Provides the ability to change the line ending
+ * @var string
+ */
+ public $LE = "\n";
+
+ /**
+ * Used with DKIM DNS Resource Record
+ * @var string
+ */
+ public $DKIM_selector = 'phpmailer';
+
+ /**
+ * Used with DKIM DNS Resource Record
+ * optional, in format of email address 'you@yourdomain.com'
+ * @var string
+ */
+ public $DKIM_identity = '';
+
+ /**
+ * Used with DKIM DNS Resource Record
+ * @var string
+ */
+ public $DKIM_passphrase = '';
+
+ /**
+ * Used with DKIM DNS Resource Record
+ * optional, in format of email address 'you@yourdomain.com'
+ * @var string
+ */
+ public $DKIM_domain = '';
+
+ /**
+ * Used with DKIM DNS Resource Record
+ * optional, in format of email address 'you@yourdomain.com'
+ * @var string
+ */
+ public $DKIM_private = '';
+
+ /**
+ * Callback Action function name
+ * the function that handles the result of the send email action. Parameters:
+ * bool $result result of the send action
+ * string $to email address of the recipient
+ * string $cc cc email addresses
+ * string $bcc bcc email addresses
+ * string $subject the subject
+ * string $body the email body
+ * @var string
+ */
+ public $action_function = ''; //'callbackAction';
+
+ /**
+ * Sets the PHPMailer Version number
+ * @var string
+ */
+ public $Version = '5.2.1';
+
+ /**
+ * What to use in the X-Mailer header
+ * @var string
+ */
+ public $XMailer = '';
+
+ /////////////////////////////////////////////////
+ // PROPERTIES, PRIVATE AND PROTECTED
+ /////////////////////////////////////////////////
+
+ protected $smtp = NULL;
+ protected $to = array();
+ protected $cc = array();
+ protected $bcc = array();
+ protected $ReplyTo = array();
+ protected $all_recipients = array();
+ protected $attachment = array();
+ protected $CustomHeader = array();
+ protected $message_type = '';
+ protected $boundary = array();
+ protected $language = array();
+ protected $error_count = 0;
+ protected $sign_cert_file = '';
+ protected $sign_key_file = '';
+ protected $sign_key_pass = '';
+ protected $exceptions = false;
+
+ /////////////////////////////////////////////////
+ // CONSTANTS
+ /////////////////////////////////////////////////
+
+ const STOP_MESSAGE = 0; // message only, continue processing
+ const STOP_CONTINUE = 1; // message?, likely ok to continue processing
+ const STOP_CRITICAL = 2; // message, plus full stop, critical error reached
+
+ /////////////////////////////////////////////////
+ // METHODS, VARIABLES
+ /////////////////////////////////////////////////
+
+ /**
+ * Constructor
+ * @param boolean $exceptions Should we throw external exceptions?
+ */
+ public function __construct($exceptions = false) {
+ $this->exceptions = ($exceptions == true);
+ }
+
+ /**
+ * Sets message type to HTML.
+ * @param bool $ishtml
+ * @return void
+ */
+ public function IsHTML($ishtml = true) {
+ if ($ishtml) {
+ $this->ContentType = 'text/html';
+ } else {
+ $this->ContentType = 'text/plain';
+ }
+ }
+
+ /**
+ * Sets Mailer to send message using SMTP.
+ * @return void
+ */
+ public function IsSMTP() {
+ $this->Mailer = 'smtp';
+ }
+
+ /**
+ * Sets Mailer to send message using PHP mail() function.
+ * @return void
+ */
+ public function IsMail() {
+ $this->Mailer = 'mail';
+ }
+
+ /**
+ * Sets Mailer to send message using the $Sendmail program.
+ * @return void
+ */
+ public function IsSendmail() {
+ if (!stristr(ini_get('sendmail_path'), 'sendmail')) {
+ $this->Sendmail = '/var/qmail/bin/sendmail';
+ }
+ $this->Mailer = 'sendmail';
+ }
+
+ /**
+ * Sets Mailer to send message using the qmail MTA.
+ * @return void
+ */
+ public function IsQmail() {
+ if (stristr(ini_get('sendmail_path'), 'qmail')) {
+ $this->Sendmail = '/var/qmail/bin/sendmail';
+ }
+ $this->Mailer = 'sendmail';
+ }
+
+ /////////////////////////////////////////////////
+ // METHODS, RECIPIENTS
+ /////////////////////////////////////////////////
+
+ /**
+ * Adds a "To" address.
+ * @param string $address
+ * @param string $name
+ * @return boolean true on success, false if address already used
+ */
+ public function AddAddress($address, $name = '') {
+ return $this->AddAnAddress('to', $address, $name);
+ }
+
+ /**
+ * Adds a "Cc" address.
+ * Note: this function works with the SMTP mailer on win32, not with the "mail" mailer.
+ * @param string $address
+ * @param string $name
+ * @return boolean true on success, false if address already used
+ */
+ public function AddCC($address, $name = '') {
+ return $this->AddAnAddress('cc', $address, $name);
+ }
+
+ /**
+ * Adds a "Bcc" address.
+ * Note: this function works with the SMTP mailer on win32, not with the "mail" mailer.
+ * @param string $address
+ * @param string $name
+ * @return boolean true on success, false if address already used
+ */
+ public function AddBCC($address, $name = '') {
+ return $this->AddAnAddress('bcc', $address, $name);
+ }
+
+ /**
+ * Adds a "Reply-to" address.
+ * @param string $address
+ * @param string $name
+ * @return boolean
+ */
+ public function AddReplyTo($address, $name = '') {
+ return $this->AddAnAddress('Reply-To', $address, $name);
+ }
+
+ /**
+ * Adds an address to one of the recipient arrays
+ * Addresses that have been added already return false, but do not throw exceptions
+ * @param string $kind One of 'to', 'cc', 'bcc', 'ReplyTo'
+ * @param string $address The email address to send to
+ * @param string $name
+ * @return boolean true on success, false if address already used or invalid in some way
+ * @access protected
+ */
+ protected function AddAnAddress($kind, $address, $name = '') {
+ if (!preg_match('/^(to|cc|bcc|Reply-To)$/', $kind)) {
+ $this->SetError($this->Lang('Invalid recipient array').': '.$kind);
+ if ($this->exceptions) {
+ throw new phpmailerException('Invalid recipient array: ' . $kind);
+ }
+ if ($this->SMTPDebug) {
+ echo $this->Lang('Invalid recipient array').': '.$kind;
+ }
+ return false;
+ }
+ $address = trim($address);
+ $name = trim(preg_replace('/[\r\n]+/', '', $name)); //Strip breaks and trim
+ if (!self::ValidateAddress($address)) {
+ $this->SetError($this->Lang('invalid_address').': '. $address);
+ if ($this->exceptions) {
+ throw new phpmailerException($this->Lang('invalid_address').': '.$address);
+ }
+ if ($this->SMTPDebug) {
+ echo $this->Lang('invalid_address').': '.$address;
+ }
+ return false;
+ }
+ if ($kind != 'Reply-To') {
+ if (!isset($this->all_recipients[strtolower($address)])) {
+ array_push($this->$kind, array($address, $name));
+ $this->all_recipients[strtolower($address)] = true;
+ return true;
+ }
+ } else {
+ if (!array_key_exists(strtolower($address), $this->ReplyTo)) {
+ $this->ReplyTo[strtolower($address)] = array($address, $name);
+ return true;
+ }
+ }
+ return false;
+}
+
+/**
+ * Set the From and FromName properties
+ * @param string $address
+ * @param string $name
+ * @return boolean
+ */
+ public function SetFrom($address, $name = '', $auto = 1) {
+ $address = trim($address);
+ $name = trim(preg_replace('/[\r\n]+/', '', $name)); //Strip breaks and trim
+ if (!self::ValidateAddress($address)) {
+ $this->SetError($this->Lang('invalid_address').': '. $address);
+ if ($this->exceptions) {
+ throw new phpmailerException($this->Lang('invalid_address').': '.$address);
+ }
+ if ($this->SMTPDebug) {
+ echo $this->Lang('invalid_address').': '.$address;
+ }
+ return false;
+ }
+ $this->From = $address;
+ $this->FromName = $name;
+ if ($auto) {
+ if (empty($this->ReplyTo)) {
+ $this->AddAnAddress('Reply-To', $address, $name);
+ }
+ if (empty($this->Sender)) {
+ $this->Sender = $address;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Check that a string looks roughly like an email address should
+ * Static so it can be used without instantiation
+ * Tries to use PHP built-in validator in the filter extension (from PHP 5.2), falls back to a reasonably competent regex validator
+ * Conforms approximately to RFC2822
+ * @link http://www.hexillion.com/samples/#Regex Original pattern found here
+ * @param string $address The email address to check
+ * @return boolean
+ * @static
+ * @access public
+ */
+ public static function ValidateAddress($address) {
+ if (function_exists('filter_var')) { //Introduced in PHP 5.2
+ if(filter_var($address, FILTER_VALIDATE_EMAIL) === FALSE) {
+ return false;
+ } else {
+ return true;
+ }
+ } else {
+ return preg_match('/^(?:[\w\!\#\$\%\&\'\*\+\-\/\=\?\^\`\{\|\}\~]+\.)*[\w\!\#\$\%\&\'\*\+\-\/\=\?\^\`\{\|\}\~]+@(?:(?:(?:[a-zA-Z0-9_](?:[a-zA-Z0-9_\-](?!\.)){0,61}[a-zA-Z0-9_-]?\.)+[a-zA-Z0-9_](?:[a-zA-Z0-9_\-](?!$)){0,61}[a-zA-Z0-9_]?)|(?:\[(?:(?:[01]?\d{1,2}|2[0-4]\d|25[0-5])\.){3}(?:[01]?\d{1,2}|2[0-4]\d|25[0-5])\]))$/', $address);
+ }
+ }
+
+ /////////////////////////////////////////////////
+ // METHODS, MAIL SENDING
+ /////////////////////////////////////////////////
+
+ /**
+ * Creates message and assigns Mailer. If the message is
+ * not sent successfully then it returns false. Use the ErrorInfo
+ * variable to view description of the error.
+ * @return bool
+ */
+ public function Send() {
+ try {
+ if(!$this->PreSend()) return false;
+ return $this->PostSend();
+ } catch (phpmailerException $e) {
+ $this->SentMIMEMessage = '';
+ $this->SetError($e->getMessage());
+ if ($this->exceptions) {
+ throw $e;
+ }
+ return false;
+ }
+ }
+
+ protected function PreSend() {
+ try {
+ $mailHeader = "";
+ if ((count($this->to) + count($this->cc) + count($this->bcc)) < 1) {
+ throw new phpmailerException($this->Lang('provide_address'), self::STOP_CRITICAL);
+ }
+
+ // Set whether the message is multipart/alternative
+ if(!empty($this->AltBody)) {
+ $this->ContentType = 'multipart/alternative';
+ }
+
+ $this->error_count = 0; // reset errors
+ $this->SetMessageType();
+ //Refuse to send an empty message
+ if (empty($this->Body)) {
+ throw new phpmailerException($this->Lang('empty_message'), self::STOP_CRITICAL);
+ }
+
+ $this->MIMEHeader = $this->CreateHeader();
+ $this->MIMEBody = $this->CreateBody();
+
+ // To capture the complete message when using mail(), create
+ // an extra header list which CreateHeader() doesn't fold in
+ if ($this->Mailer == 'mail') {
+ if (count($this->to) > 0) {
+ $mailHeader .= $this->AddrAppend("To", $this->to);
+ } else {
+ $mailHeader .= $this->HeaderLine("To", "undisclosed-recipients:;");
+ }
+ $mailHeader .= $this->HeaderLine('Subject', $this->EncodeHeader($this->SecureHeader(trim($this->Subject))));
+ // if(count($this->cc) > 0) {
+ // $mailHeader .= $this->AddrAppend("Cc", $this->cc);
+ // }
+ }
+
+ // digitally sign with DKIM if enabled
+ if ($this->DKIM_domain && $this->DKIM_private) {
+ $header_dkim = $this->DKIM_Add($this->MIMEHeader, $this->EncodeHeader($this->SecureHeader($this->Subject)), $this->MIMEBody);
+ $this->MIMEHeader = str_replace("\r\n", "\n", $header_dkim) . $this->MIMEHeader;
+ }
+
+ $this->SentMIMEMessage = sprintf("%s%s\r\n\r\n%s",$this->MIMEHeader,$mailHeader,$this->MIMEBody);
+ return true;
+
+ } catch (phpmailerException $e) {
+ $this->SetError($e->getMessage());
+ if ($this->exceptions) {
+ throw $e;
+ }
+ return false;
+ }
+ }
+
+ protected function PostSend() {
+ try {
+ // Choose the mailer and send through it
+ switch($this->Mailer) {
+ case 'sendmail':
+ return $this->SendmailSend($this->MIMEHeader, $this->MIMEBody);
+ case 'smtp':
+ return $this->SmtpSend($this->MIMEHeader, $this->MIMEBody);
+ case 'mail':
+ return $this->MailSend($this->MIMEHeader, $this->MIMEBody);
+ default:
+ return $this->MailSend($this->MIMEHeader, $this->MIMEBody);
+ }
+
+ } catch (phpmailerException $e) {
+ $this->SetError($e->getMessage());
+ if ($this->exceptions) {
+ throw $e;
+ }
+ if ($this->SMTPDebug) {
+ echo $e->getMessage()."\n";
+ }
+ return false;
+ }
+ }
+
+ /**
+ * Sends mail using the $Sendmail program.
+ * @param string $header The message headers
+ * @param string $body The message body
+ * @access protected
+ * @return bool
+ */
+ protected function SendmailSend($header, $body) {
+ if ($this->Sender != '') {
+ $sendmail = sprintf("%s -oi -f %s -t", escapeshellcmd($this->Sendmail), escapeshellarg($this->Sender));
+ } else {
+ $sendmail = sprintf("%s -oi -t", escapeshellcmd($this->Sendmail));
+ }
+ if ($this->SingleTo === true) {
+ foreach ($this->SingleToArray as $key => $val) {
+ if(!@$mail = popen($sendmail, 'w')) {
+ throw new phpmailerException($this->Lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
+ }
+ fputs($mail, "To: " . $val . "\n");
+ fputs($mail, $header);
+ fputs($mail, $body);
+ $result = pclose($mail);
+ // implement call back function if it exists
+ $isSent = ($result == 0) ? 1 : 0;
+ $this->doCallback($isSent, $val, $this->cc, $this->bcc, $this->Subject, $body);
+ if($result != 0) {
+ throw new phpmailerException($this->Lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
+ }
+ }
+ } else {
+ if(!@$mail = popen($sendmail, 'w')) {
+ throw new phpmailerException($this->Lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
+ }
+ fputs($mail, $header);
+ fputs($mail, $body);
+ $result = pclose($mail);
+ // implement call back function if it exists
+ $isSent = ($result == 0) ? 1 : 0;
+ $this->doCallback($isSent, $this->to, $this->cc, $this->bcc, $this->Subject, $body);
+ if($result != 0) {
+ throw new phpmailerException($this->Lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Sends mail using the PHP mail() function.
+ * @param string $header The message headers
+ * @param string $body The message body
+ * @access protected
+ * @return bool
+ */
+ protected function MailSend($header, $body) {
+ $toArr = array();
+ foreach($this->to as $t) {
+ $toArr[] = $this->AddrFormat($t);
+ }
+ $to = implode(', ', $toArr);
+
+ if (empty($this->Sender)) {
+ $params = "-oi ";
+ } else {
+ $params = sprintf("-oi -f %s", $this->Sender);
+ }
+ if ($this->Sender != '' and !ini_get('safe_mode')) {
+ $old_from = ini_get('sendmail_from');
+ ini_set('sendmail_from', $this->Sender);
+ if ($this->SingleTo === true && count($toArr) > 1) {
+ foreach ($toArr as $key => $val) {
+ $rt = @mail($val, $this->EncodeHeader($this->SecureHeader($this->Subject)), $body, $header, $params);
+ // implement call back function if it exists
+ $isSent = ($rt == 1) ? 1 : 0;
+ $this->doCallback($isSent, $val, $this->cc, $this->bcc, $this->Subject, $body);
+ }
+ } else {
+ $rt = @mail($to, $this->EncodeHeader($this->SecureHeader($this->Subject)), $body, $header, $params);
+ // implement call back function if it exists
+ $isSent = ($rt == 1) ? 1 : 0;
+ $this->doCallback($isSent, $to, $this->cc, $this->bcc, $this->Subject, $body);
+ }
+ } else {
+ if ($this->SingleTo === true && count($toArr) > 1) {
+ foreach ($toArr as $key => $val) {
+ $rt = @mail($val, $this->EncodeHeader($this->SecureHeader($this->Subject)), $body, $header, $params);
+ // implement call back function if it exists
+ $isSent = ($rt == 1) ? 1 : 0;
+ $this->doCallback($isSent, $val, $this->cc, $this->bcc, $this->Subject, $body);
+ }
+ } else {
+ $rt = @mail($to, $this->EncodeHeader($this->SecureHeader($this->Subject)), $body, $header, $params);
+ // implement call back function if it exists
+ $isSent = ($rt == 1) ? 1 : 0;
+ $this->doCallback($isSent, $to, $this->cc, $this->bcc, $this->Subject, $body);
+ }
+ }
+ if (isset($old_from)) {
+ ini_set('sendmail_from', $old_from);
+ }
+ if(!$rt) {
+ throw new phpmailerException($this->Lang('instantiate'), self::STOP_CRITICAL);
+ }
+ return true;
+ }
+
+ /**
+ * Sends mail via SMTP using PhpSMTP
+ * Returns false if there is a bad MAIL FROM, RCPT, or DATA input.
+ * @param string $header The message headers
+ * @param string $body The message body
+ * @uses SMTP
+ * @access protected
+ * @return bool
+ */
+ protected function SmtpSend($header, $body) {
+ require_once $this->PluginDir . 'class.smtp.php';
+ $bad_rcpt = array();
+
+ if(!$this->SmtpConnect()) {
+ throw new phpmailerException($this->Lang('smtp_connect_failed'), self::STOP_CRITICAL);
+ }
+ $smtp_from = ($this->Sender == '') ? $this->From : $this->Sender;
+ if(!$this->smtp->Mail($smtp_from)) {
+ throw new phpmailerException($this->Lang('from_failed') . $smtp_from, self::STOP_CRITICAL);
+ }
+
+ // Attempt to send attach all recipients
+ foreach($this->to as $to) {
+ if (!$this->smtp->Recipient($to[0])) {
+ $bad_rcpt[] = $to[0];
+ // implement call back function if it exists
+ $isSent = 0;
+ $this->doCallback($isSent, $to[0], '', '', $this->Subject, $body);
+ } else {
+ // implement call back function if it exists
+ $isSent = 1;
+ $this->doCallback($isSent, $to[0], '', '', $this->Subject, $body);
+ }
+ }
+ foreach($this->cc as $cc) {
+ if (!$this->smtp->Recipient($cc[0])) {
+ $bad_rcpt[] = $cc[0];
+ // implement call back function if it exists
+ $isSent = 0;
+ $this->doCallback($isSent, '', $cc[0], '', $this->Subject, $body);
+ } else {
+ // implement call back function if it exists
+ $isSent = 1;
+ $this->doCallback($isSent, '', $cc[0], '', $this->Subject, $body);
+ }
+ }
+ foreach($this->bcc as $bcc) {
+ if (!$this->smtp->Recipient($bcc[0])) {
+ $bad_rcpt[] = $bcc[0];
+ // implement call back function if it exists
+ $isSent = 0;
+ $this->doCallback($isSent, '', '', $bcc[0], $this->Subject, $body);
+ } else {
+ // implement call back function if it exists
+ $isSent = 1;
+ $this->doCallback($isSent, '', '', $bcc[0], $this->Subject, $body);
+ }
+ }
+
+
+ if (count($bad_rcpt) > 0 ) { //Create error message for any bad addresses
+ $badaddresses = implode(', ', $bad_rcpt);
+ throw new phpmailerException($this->Lang('recipients_failed') . $badaddresses);
+ }
+ if(!$this->smtp->Data($header . $body)) {
+ throw new phpmailerException($this->Lang('data_not_accepted'), self::STOP_CRITICAL);
+ }
+ if($this->SMTPKeepAlive == true) {
+ $this->smtp->Reset();
+ }
+ return true;
+ }
+
+ /**
+ * Initiates a connection to an SMTP server.
+ * Returns false if the operation failed.
+ * @uses SMTP
+ * @access public
+ * @return bool
+ */
+ public function SmtpConnect() {
+ if(is_null($this->smtp)) {
+ $this->smtp = new SMTP();
+ }
+
+ $this->smtp->do_debug = $this->SMTPDebug;
+ $hosts = explode(';', $this->Host);
+ $index = 0;
+ $connection = $this->smtp->Connected();
+
+ // Retry while there is no connection
+ try {
+ while($index < count($hosts) && !$connection) {
+ $hostinfo = array();
+ if (preg_match('/^(.+):([0-9]+)$/', $hosts[$index], $hostinfo)) {
+ $host = $hostinfo[1];
+ $port = $hostinfo[2];
+ } else {
+ $host = $hosts[$index];
+ $port = $this->Port;
+ }
+
+ $tls = ($this->SMTPSecure == 'tls');
+ $ssl = ($this->SMTPSecure == 'ssl');
+
+ if ($this->smtp->Connect(($ssl ? 'ssl://':'').$host, $port, $this->Timeout)) {
+
+ $hello = ($this->Helo != '' ? $this->Helo : $this->ServerHostname());
+ $this->smtp->Hello($hello);
+
+ if ($tls) {
+ if (!$this->smtp->StartTLS()) {
+ throw new phpmailerException($this->Lang('tls'));
+ }
+
+ //We must resend HELO after tls negotiation
+ $this->smtp->Hello($hello);
+ }
+
+ $connection = true;
+ if ($this->SMTPAuth) {
+ if (!$this->smtp->Authenticate($this->Username, $this->Password)) {
+ throw new phpmailerException($this->Lang('authenticate'));
+ }
+ }
+ }
+ $index++;
+ if (!$connection) {
+ throw new phpmailerException($this->Lang('connect_host'));
+ }
+ }
+ } catch (phpmailerException $e) {
+ $this->smtp->Reset();
+ if ($this->exceptions) {
+ throw $e;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Closes the active SMTP session if one exists.
+ * @return void
+ */
+ public function SmtpClose() {
+ if(!is_null($this->smtp)) {
+ if($this->smtp->Connected()) {
+ $this->smtp->Quit();
+ $this->smtp->Close();
+ }
+ }
+ }
+
+ /**
+ * Sets the language for all class error messages.
+ * Returns false if it cannot load the language file. The default language is English.
+ * @param string $langcode ISO 639-1 2-character language code (e.g. Portuguese: "br")
+ * @param string $lang_path Path to the language file directory
+ * @access public
+ */
+ function SetLanguage($langcode = 'en', $lang_path = 'language/') {
+ //Define full set of translatable strings
+ $PHPMAILER_LANG = array(
+ 'provide_address' => 'You must provide at least one recipient email address.',
+ 'mailer_not_supported' => ' mailer is not supported.',
+ 'execute' => 'Could not execute: ',
+ 'instantiate' => 'Could not instantiate mail function.',
+ 'authenticate' => 'SMTP Error: Could not authenticate.',
+ 'from_failed' => 'The following From address failed: ',
+ 'recipients_failed' => 'SMTP Error: The following recipients failed: ',
+ 'data_not_accepted' => 'SMTP Error: Data not accepted.',
+ 'connect_host' => 'SMTP Error: Could not connect to SMTP host.',
+ 'file_access' => 'Could not access file: ',
+ 'file_open' => 'File Error: Could not open file: ',
+ 'encoding' => 'Unknown encoding: ',
+ 'signing' => 'Signing Error: ',
+ 'smtp_error' => 'SMTP server error: ',
+ 'empty_message' => 'Message body empty',
+ 'invalid_address' => 'Invalid address',
+ 'variable_set' => 'Cannot set or reset variable: '
+ );
+ //Overwrite language-specific strings. This way we'll never have missing translations - no more "language string failed to load"!
+ $l = true;
+ if ($langcode != 'en') { //There is no English translation file
+ $l = @include $lang_path.'phpmailer.lang-'.$langcode.'.php';
+ }
+ $this->language = $PHPMAILER_LANG;
+ return ($l == true); //Returns false if language not found
+ }
+
+ /**
+ * Return the current array of language strings
+ * @return array
+ */
+ public function GetTranslations() {
+ return $this->language;
+ }
+
+ /////////////////////////////////////////////////
+ // METHODS, MESSAGE CREATION
+ /////////////////////////////////////////////////
+
+ /**
+ * Creates recipient headers.
+ * @access public
+ * @return string
+ */
+ public function AddrAppend($type, $addr) {
+ $addr_str = $type . ': ';
+ $addresses = array();
+ foreach ($addr as $a) {
+ $addresses[] = $this->AddrFormat($a);
+ }
+ $addr_str .= implode(', ', $addresses);
+ $addr_str .= $this->LE;
+
+ return $addr_str;
+ }
+
+ /**
+ * Formats an address correctly.
+ * @access public
+ * @return string
+ */
+ public function AddrFormat($addr) {
+ if (empty($addr[1])) {
+ return $this->SecureHeader($addr[0]);
+ } else {
+ return $this->EncodeHeader($this->SecureHeader($addr[1]), 'phrase') . " <" . $this->SecureHeader($addr[0]) . ">";
+ }
+ }
+
+ /**
+ * Wraps message for use with mailers that do not
+ * automatically perform wrapping and for quoted-printable.
+ * Original written by philippe.
+ * @param string $message The message to wrap
+ * @param integer $length The line length to wrap to
+ * @param boolean $qp_mode Whether to run in Quoted-Printable mode
+ * @access public
+ * @return string
+ */
+ public function WrapText($message, $length, $qp_mode = false) {
+ $soft_break = ($qp_mode) ? sprintf(" =%s", $this->LE) : $this->LE;
+ // If utf-8 encoding is used, we will need to make sure we don't
+ // split multibyte characters when we wrap
+ $is_utf8 = (strtolower($this->CharSet) == "utf-8");
+
+ $message = $this->FixEOL($message);
+ if (substr($message, -1) == $this->LE) {
+ $message = substr($message, 0, -1);
+ }
+
+ $line = explode($this->LE, $message);
+ $message = '';
+ for ($i = 0 ;$i < count($line); $i++) {
+ $line_part = explode(' ', $line[$i]);
+ $buf = '';
+ for ($e = 0; $e<count($line_part); $e++) {
+ $word = $line_part[$e];
+ if ($qp_mode and (strlen($word) > $length)) {
+ $space_left = $length - strlen($buf) - 1;
+ if ($e != 0) {
+ if ($space_left > 20) {
+ $len = $space_left;
+ if ($is_utf8) {
+ $len = $this->UTF8CharBoundary($word, $len);
+ } elseif (substr($word, $len - 1, 1) == "=") {
+ $len--;
+ } elseif (substr($word, $len - 2, 1) == "=") {
+ $len -= 2;
+ }
+ $part = substr($word, 0, $len);
+ $word = substr($word, $len);
+ $buf .= ' ' . $part;
+ $message .= $buf . sprintf("=%s", $this->LE);
+ } else {
+ $message .= $buf . $soft_break;
+ }
+ $buf = '';
+ }
+ while (strlen($word) > 0) {
+ $len = $length;
+ if ($is_utf8) {
+ $len = $this->UTF8CharBoundary($word, $len);
+ } elseif (substr($word, $len - 1, 1) == "=") {
+ $len--;
+ } elseif (substr($word, $len - 2, 1) == "=") {
+ $len -= 2;
+ }
+ $part = substr($word, 0, $len);
+ $word = substr($word, $len);
+
+ if (strlen($word) > 0) {
+ $message .= $part . sprintf("=%s", $this->LE);
+ } else {
+ $buf = $part;
+ }
+ }
+ } else {
+ $buf_o = $buf;
+ $buf .= ($e == 0) ? $word : (' ' . $word);
+
+ if (strlen($buf) > $length and $buf_o != '') {
+ $message .= $buf_o . $soft_break;
+ $buf = $word;
+ }
+ }
+ }
+ $message .= $buf . $this->LE;
+ }
+
+ return $message;
+ }
+
+ /**
+ * Finds last character boundary prior to maxLength in a utf-8
+ * quoted (printable) encoded string.
+ * Original written by Colin Brown.
+ * @access public
+ * @param string $encodedText utf-8 QP text
+ * @param int $maxLength find last character boundary prior to this length
+ * @return int
+ */
+ public function UTF8CharBoundary($encodedText, $maxLength) {
+ $foundSplitPos = false;
+ $lookBack = 3;
+ while (!$foundSplitPos) {
+ $lastChunk = substr($encodedText, $maxLength - $lookBack, $lookBack);
+ $encodedCharPos = strpos($lastChunk, "=");
+ if ($encodedCharPos !== false) {
+ // Found start of encoded character byte within $lookBack block.
+ // Check the encoded byte value (the 2 chars after the '=')
+ $hex = substr($encodedText, $maxLength - $lookBack + $encodedCharPos + 1, 2);
+ $dec = hexdec($hex);
+ if ($dec < 128) { // Single byte character.
+ // If the encoded char was found at pos 0, it will fit
+ // otherwise reduce maxLength to start of the encoded char
+ $maxLength = ($encodedCharPos == 0) ? $maxLength :
+ $maxLength - ($lookBack - $encodedCharPos);
+ $foundSplitPos = true;
+ } elseif ($dec >= 192) { // First byte of a multi byte character
+ // Reduce maxLength to split at start of character
+ $maxLength = $maxLength - ($lookBack - $encodedCharPos);
+ $foundSplitPos = true;
+ } elseif ($dec < 192) { // Middle byte of a multi byte character, look further back
+ $lookBack += 3;
+ }
+ } else {
+ // No encoded character found
+ $foundSplitPos = true;
+ }
+ }
+ return $maxLength;
+ }
+
+
+ /**
+ * Set the body wrapping.
+ * @access public
+ * @return void
+ */
+ public function SetWordWrap() {
+ if($this->WordWrap < 1) {
+ return;
+ }
+
+ switch($this->message_type) {
+ case 'alt':
+ case 'alt_inline':
+ case 'alt_attach':
+ case 'alt_inline_attach':
+ $this->AltBody = $this->WrapText($this->AltBody, $this->WordWrap);
+ break;
+ default:
+ $this->Body = $this->WrapText($this->Body, $this->WordWrap);
+ break;
+ }
+ }
+
+ /**
+ * Assembles message header.
+ * @access public
+ * @return string The assembled header
+ */
+ public function CreateHeader() {
+ $result = '';
+
+ // Set the boundaries
+ $uniq_id = md5(uniqid(time()));
+ $this->boundary[1] = 'b1_' . $uniq_id;
+ $this->boundary[2] = 'b2_' . $uniq_id;
+ $this->boundary[3] = 'b3_' . $uniq_id;
+
+ $result .= $this->HeaderLine('Date', self::RFCDate());
+ if($this->Sender == '') {
+ $result .= $this->HeaderLine('Return-Path', trim($this->From));
+ } else {
+ $result .= $this->HeaderLine('Return-Path', trim($this->Sender));
+ }
+
+ // To be created automatically by mail()
+ if($this->Mailer != 'mail') {
+ if ($this->SingleTo === true) {
+ foreach($this->to as $t) {
+ $this->SingleToArray[] = $this->AddrFormat($t);
+ }
+ } else {
+ if(count($this->to) > 0) {
+ $result .= $this->AddrAppend('To', $this->to);
+ } elseif (count($this->cc) == 0) {
+ $result .= $this->HeaderLine('To', 'undisclosed-recipients:;');
+ }
+ }
+ }
+
+ $from = array();
+ $from[0][0] = trim($this->From);
+ $from[0][1] = $this->FromName;
+ $result .= $this->AddrAppend('From', $from);
+
+ // sendmail and mail() extract Cc from the header before sending
+ if(count($this->cc) > 0) {
+ $result .= $this->AddrAppend('Cc', $this->cc);
+ }
+
+ // sendmail and mail() extract Bcc from the header before sending
+ if((($this->Mailer == 'sendmail') || ($this->Mailer == 'mail')) && (count($this->bcc) > 0)) {
+ $result .= $this->AddrAppend('Bcc', $this->bcc);
+ }
+
+ if(count($this->ReplyTo) > 0) {
+ $result .= $this->AddrAppend('Reply-To', $this->ReplyTo);
+ }
+
+ // mail() sets the subject itself
+ if($this->Mailer != 'mail') {
+ $result .= $this->HeaderLine('Subject', $this->EncodeHeader($this->SecureHeader($this->Subject)));
+ }
+
+ if($this->MessageID != '') {
+ $result .= $this->HeaderLine('Message-ID', $this->MessageID);
+ } else {
+ $result .= sprintf("Message-ID: <%s@%s>%s", $uniq_id, $this->ServerHostname(), $this->LE);
+ }
+ $result .= $this->HeaderLine('X-Priority', $this->Priority);
+ if($this->XMailer) {
+ $result .= $this->HeaderLine('X-Mailer', $this->XMailer);
+ } else {
+ $result .= $this->HeaderLine('X-Mailer', 'PHPMailer '.$this->Version.' (http://code.google.com/a/apache-extras.org/p/phpmailer/)');
+ }
+
+ if($this->ConfirmReadingTo != '') {
+ $result .= $this->HeaderLine('Disposition-Notification-To', '<' . trim($this->ConfirmReadingTo) . '>');
+ }
+
+ // Add custom headers
+ for($index = 0; $index < count($this->CustomHeader); $index++) {
+ $result .= $this->HeaderLine(trim($this->CustomHeader[$index][0]), $this->EncodeHeader(trim($this->CustomHeader[$index][1])));
+ }
+ if (!$this->sign_key_file) {
+ $result .= $this->HeaderLine('MIME-Version', '1.0');
+ $result .= $this->GetMailMIME();
+ }
+
+ return $result;
+ }
+
+ /**
+ * Returns the message MIME.
+ * @access public
+ * @return string
+ */
+ public function GetMailMIME() {
+ $result = '';
+ switch($this->message_type) {
+ case 'plain':
+ $result .= $this->HeaderLine('Content-Transfer-Encoding', $this->Encoding);
+ $result .= $this->TextLine('Content-Type: '.$this->ContentType.'; charset="'.$this->CharSet.'"');
+ break;
+ case 'inline':
+ $result .= $this->HeaderLine('Content-Type', 'multipart/related;');
+ $result .= $this->TextLine("\tboundary=\"" . $this->boundary[1] . '"');
+ break;
+ case 'attach':
+ case 'inline_attach':
+ case 'alt_attach':
+ case 'alt_inline_attach':
+