Guest User

mailwizz-postal

a guest
Feb 13th, 2020
158
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
PHP 93.46 KB | None | 0 0
  1. <?php defined('MW_PATH') || exit('No direct script access allowed');
  2.  
  3. /**
  4.  * DswhController
  5.  *
  6.  * Delivery Servers Web Hooks (DSWH) handler
  7.  *
  8.  * @package MailWizz EMA
  9.  * @author Serban George Cristian <cristian.serban@mailwizz.com>
  10.  * @link https://www.mailwizz.com/
  11.  * @copyright MailWizz EMA (https://www.mailwizz.com)
  12.  * @license https://www.mailwizz.com/license/
  13.  * @since 1.3.4.8
  14.  */
  15.  
  16. class DswhController extends Controller
  17. {
  18.     /**
  19.      * @inheritdoc
  20.      */
  21.     public function init()
  22.     {
  23.         set_time_limit(0);
  24.         ini_set('memory_limit', -1);
  25.         parent::init();
  26.        
  27.         /* because posting too fast sometimes can lead to dupes */
  28.         usleep(rand(100000, 3000000)); // 0.1 => 3 sec
  29.     }
  30.  
  31.     /**
  32.      * Entry point
  33.      * @param $id
  34.      */
  35.     public function actionIndex($id)
  36.     {
  37.         $server = DeliveryServer::model()->findByPk((int)$id);
  38.        
  39.         if (empty($server)) {
  40.             Yii::app()->end();
  41.         }
  42.        
  43.         $map = array(
  44.             'mandrill-web-api'     => array($this, 'processMandrill'),
  45.             'amazon-ses-web-api'   => array($this, 'processAmazonSes'),
  46.             'mailgun-web-api'      => array($this, 'processMailgun'),
  47.             'sendgrid-web-api'     => array($this, 'processSendgrid'),
  48.             'leadersend-web-api'   => array($this, 'processLeadersend'),
  49.             'elasticemail-web-api' => array($this, 'processElasticemail'),
  50.             'dyn-web-api'          => array($this, 'processDyn'),
  51.             'sparkpost-web-api'    => array($this, 'processSparkpost'),
  52.             'mailjet-web-api'      => array($this, 'processMailjet'),
  53.             'sendinblue-web-api'   => array($this, 'processSendinblue'),
  54.             'tipimail-web-api'     => array($this, 'processTipimail'),
  55.             'pepipost-web-api'     => array($this, 'processPepipost'),
  56.             'postmark-web-api'     => array($this, 'processPostmark')
  57.         );
  58.  
  59.         $map = (array)Yii::app()->hooks->applyFilters('dswh_process_map', $map, $server, $this);
  60.         if (isset($map[$server->type]) && is_callable($map[$server->type])) {
  61.             call_user_func_array($map[$server->type], array($server, $this));
  62.         }
  63.  
  64.         Yii::app()->end();
  65.     }
  66.  
  67.     /**
  68.      * Process DRH's GreenArrow
  69.      */
  70.     public function actionDrh()
  71.     {
  72.         $request = Yii::app()->request;
  73.         if (!count($request->getPost(null))) {
  74.             Yii::app()->end();
  75.         }
  76.  
  77.         $event = $request->getPost('event_type');
  78.        
  79.         // header name: X-GreenArrow-Click-Tracking-ID
  80.         // header value: [CAMPAIGN_UID]|[SUBSCRIBER_UID]
  81.         $cs = explode('|', $request->getPost('click_tracking_id'));
  82.  
  83.         if (empty($event) || empty($cs) || count($cs) != 2) {
  84.             $this->end('OK');
  85.         }
  86.  
  87.         list($campaignUid, $subscriberUid) = $cs;
  88.  
  89.         $campaign = Campaign::model()->findByAttributes(array(
  90.             'campaign_uid' => $campaignUid
  91.         ));
  92.         if (empty($campaign)) {
  93.             $this->end('OK');
  94.         }
  95.  
  96.         $subscriber = ListSubscriber::model()->findByAttributes(array(
  97.             'list_id'          => $campaign->list_id,
  98.             'subscriber_uid'   => $subscriberUid,
  99.             'status'           => ListSubscriber::STATUS_CONFIRMED,
  100.         ));
  101.  
  102.         if (empty($subscriber)) {
  103.             $this->end('OK');
  104.         }
  105.        
  106.         if (stripos($event, 'bounce') !== false) {
  107.  
  108.             $count = CampaignBounceLog::model()->countByAttributes(array(
  109.                 'campaign_id'   => $campaign->campaign_id,
  110.                 'subscriber_id' => $subscriber->subscriber_id,
  111.             ));
  112.            
  113.             if (!empty($count)) {
  114.                 $this->end('OK');
  115.             }
  116.            
  117.             $bounceLog = new CampaignBounceLog();
  118.             $bounceLog->campaign_id   = $campaign->campaign_id;
  119.             $bounceLog->subscriber_id = $subscriber->subscriber_id;
  120.             $bounceLog->message       = $request->getPost('bounce_text');
  121.             $bounceLog->bounce_type   = $request->getPost('bounce_type') == 'h' ? CampaignBounceLog::BOUNCE_HARD : CampaignBounceLog::BOUNCE_SOFT;
  122.             $bounceLog->save();
  123.  
  124.             if ($bounceLog->bounce_type == CampaignBounceLog::BOUNCE_HARD) {
  125.                 $subscriber->addToBlacklist($bounceLog->message);
  126.             }
  127.  
  128.             $this->end('OK');
  129.         }
  130.  
  131.         if ($event == 'scomp') {
  132.            
  133.             if (Yii::app()->options->get('system.cron.process_feedback_loop_servers.subscriber_action', 'unsubscribe') == 'delete') {
  134.                 $subscriber->delete();
  135.                 $this->end('OK');
  136.             }
  137.  
  138.             $subscriber->saveStatus(ListSubscriber::STATUS_UNSUBSCRIBED);
  139.  
  140.             $count = CampaignTrackUnsubscribe::model()->countByAttributes(array(
  141.                 'campaign_id'   => $campaign->campaign_id,
  142.                 'subscriber_id' => $subscriber->subscriber_id,
  143.             ));
  144.  
  145.             if (empty($count)) {
  146.                 $trackUnsubscribe = new CampaignTrackUnsubscribe();
  147.                 $trackUnsubscribe->campaign_id   = $campaign->campaign_id;
  148.                 $trackUnsubscribe->subscriber_id = $subscriber->subscriber_id;
  149.                 $trackUnsubscribe->note          = 'Abuse complaint!';
  150.                 $trackUnsubscribe->ip_address    = Yii::app()->request->userHostAddress;
  151.                 $trackUnsubscribe->user_agent    = StringHelper::truncateLength(Yii::app()->request->userAgent, 255);
  152.                 $trackUnsubscribe->save(false);
  153.             }
  154.            
  155.             // since 1.4.4 - complaints go into their own tables
  156.             $count = CampaignComplainLog::model()->countByAttributes(array(
  157.                 'campaign_id'   => $campaign->campaign_id,
  158.                 'subscriber_id' => $subscriber->subscriber_id,
  159.             ));
  160.            
  161.             if (empty($count)) {
  162.                 $complaintLog = new CampaignComplainLog();
  163.                 $complaintLog->campaign_id = $campaign->campaign_id;
  164.                 $complaintLog->subscriber_id = $subscriber->subscriber_id;
  165.                 $complaintLog->message = 'Abuse complaint via DRH!';
  166.                 $complaintLog->save(false);
  167.             }
  168.             //
  169.            
  170.             $this->end('OK');
  171.         }
  172.  
  173.         if ($event == 'engine_unsub') {
  174.            
  175.             $subscriber->saveStatus(ListSubscriber::STATUS_UNSUBSCRIBED);
  176.  
  177.             $count = CampaignTrackUnsubscribe::model()->countByAttributes(array(
  178.                 'campaign_id'   => $campaign->campaign_id,
  179.                 'subscriber_id' => $subscriber->subscriber_id,
  180.             ));
  181.  
  182.             if (empty($count)) {
  183.                 $trackUnsubscribe = new CampaignTrackUnsubscribe();
  184.                 $trackUnsubscribe->campaign_id   = $campaign->campaign_id;
  185.                 $trackUnsubscribe->subscriber_id = $subscriber->subscriber_id;
  186.                 $trackUnsubscribe->note          = 'Unsubscribed via Web Hook!';
  187.                 $trackUnsubscribe->ip_address    = Yii::app()->request->userHostAddress;
  188.                 $trackUnsubscribe->user_agent    = StringHelper::truncateLength(Yii::app()->request->userAgent, 255);
  189.                 $trackUnsubscribe->save(false);
  190.             }
  191.  
  192.             $this->end('OK');
  193.         }
  194.  
  195.         $this->end('OK');
  196.     }
  197.  
  198.     /**
  199.      * Process Postal
  200.      */
  201.     public function actionPostal()
  202.     {
  203.         $event = file_get_contents("php://input");
  204.         if (empty($event)) {
  205.             Yii::app()->end();
  206.         }
  207.         $event = CJSON::decode($event);
  208.  
  209.         if (empty($event) || !is_array($event)) {
  210.             $event = array();
  211.         }
  212.        
  213.         if (in_array($event['event'], array('MessageDeliveryFailed', 'MessageDelayed', 'MessageHeld'))) {
  214.            
  215.             $messageId = isset($event['payload']['message']['message_id']) ? $event['payload']['message']['message_id'] : '';
  216.             if (!$messageId) {
  217.                 Yii::app()->end();
  218.             }
  219.            
  220.             $criteria = new CDbCriteria();
  221.             $criteria->addCondition('`email_message_id` = :email_message_id AND `status` = :status');
  222.             $criteria->params = array(
  223.                 'email_message_id' => (string)$messageId,
  224.                 'status'           => CampaignDeliveryLog::STATUS_SUCCESS,
  225.             );
  226.            
  227.             $deliveryLog = CampaignDeliveryLog::model()->find($criteria);
  228.             if (empty($deliveryLog)) {
  229.                 $deliveryLog = CampaignDeliveryLogArchive::model()->find($criteria);
  230.             }
  231.            
  232.             if (empty($deliveryLog)) {
  233.                 Yii::app()->end();
  234.             }
  235.  
  236.             $campaign = Campaign::model()->findByPk($deliveryLog->campaign_id);
  237.             if (empty($campaign)) {
  238.                 Yii::app()->end();
  239.             }
  240.  
  241.             $subscriber = ListSubscriber::model()->findByAttributes(array(
  242.                 'list_id'          => $campaign->list_id,
  243.                 'subscriber_id'    => $deliveryLog->subscriber_id,
  244.                 'status'           => ListSubscriber::STATUS_CONFIRMED,
  245.             ));
  246.  
  247.             if (empty($subscriber)) {
  248.                 Yii::app()->end();
  249.             }
  250.  
  251.             $count = CampaignBounceLog::model()->countByAttributes(array(
  252.                 'campaign_id'   => $campaign->campaign_id,
  253.                 'subscriber_id' => $subscriber->subscriber_id,
  254.             ));
  255.  
  256.             if (!empty($count)) {
  257.                 Yii::app()->end();
  258.             }
  259.  
  260.             $message    = !empty($event['payload']['details']) ? $event['payload']['details'] : 'BOUNCED BACK';
  261.             $bounceType = CampaignBounceLog::BOUNCE_INTERNAL;
  262.            
  263.             if (!empty($event['payload']['status'])) {
  264.                 if (stripos($event['payload']['status'], 'hard') !== false) {
  265.                     $bounceType = CampaignBounceLog::BOUNCE_HARD;
  266.                 } elseif (stripos($event['payload']['status'], 'soft') !== false) {
  267.                     $bounceType = CampaignBounceLog::BOUNCE_SOFT;
  268.                 }
  269.             }
  270.            
  271.             $bounceLog = new CampaignBounceLog();
  272.             $bounceLog->campaign_id     = $campaign->campaign_id;
  273.             $bounceLog->subscriber_id   = $subscriber->subscriber_id;
  274.             $bounceLog->message         = $message;
  275.             $bounceLog->bounce_type     = $bounceType;
  276.             $bounceLog->save();
  277.  
  278.             if ($bounceLog->bounce_type === CampaignBounceLog::BOUNCE_HARD) {
  279.                 $subscriber->addToBlacklist($bounceLog->message);
  280.             }
  281.            
  282.             Yii::app()->end();
  283.         }
  284.        
  285.         if ($event['event'] == 'MessageBounced') {
  286.            
  287.             $messageId = !empty($event['payload']['original_message']['message_id']) ? $event['payload']['original_message']['message_id'] : '';
  288.             if (!$messageId) {
  289.                 Yii::app()->end();
  290.             }
  291.  
  292.             $criteria = new CDbCriteria();
  293.             $criteria->addCondition('`email_message_id` = :email_message_id AND `status` = :status');
  294.             $criteria->params = array(
  295.                 'email_message_id' => (string)$messageId,
  296.                 'status'           => CampaignDeliveryLog::STATUS_SUCCESS,
  297.             );
  298.  
  299.             $deliveryLog = CampaignDeliveryLog::model()->find($criteria);
  300.             if (empty($deliveryLog)) {
  301.                 $deliveryLog = CampaignDeliveryLogArchive::model()->find($criteria);
  302.             }
  303.  
  304.             if (empty($deliveryLog)) {
  305.                 Yii::app()->end();
  306.             }
  307.  
  308.             $campaign = Campaign::model()->findByPk($deliveryLog->campaign_id);
  309.             if (empty($campaign)) {
  310.                 Yii::app()->end();
  311.             }
  312.  
  313.             $subscriber = ListSubscriber::model()->findByAttributes(array(
  314.                 'list_id'          => $campaign->list_id,
  315.                 'subscriber_id'    => $deliveryLog->subscriber_id,
  316.                 'status'           => ListSubscriber::STATUS_CONFIRMED,
  317.             ));
  318.  
  319.             if (empty($subscriber)) {
  320.                 Yii::app()->end();
  321.             }
  322.  
  323.             $count = CampaignBounceLog::model()->countByAttributes(array(
  324.                 'campaign_id'   => $campaign->campaign_id,
  325.                 'subscriber_id' => $subscriber->subscriber_id,
  326.             ));
  327.  
  328.             if (!empty($count)) {
  329.                 Yii::app()->end();
  330.             }
  331.            
  332.             // it still unclear how we should handle these
  333.             // https://github.com/atech/postal/issues/253
  334.             $message    = 'BOUNCED BACK';
  335.             $bounceType = CampaignBounceLog::BOUNCE_INTERNAL;
  336.            
  337.             $bounceLog = new CampaignBounceLog();
  338.             $bounceLog->campaign_id     = $campaign->campaign_id;
  339.             $bounceLog->subscriber_id   = $subscriber->subscriber_id;
  340.             $bounceLog->message         = $message;
  341.             $bounceLog->bounce_type     = $bounceType;
  342.             $bounceLog->save();
  343.  
  344.             Yii::app()->end();
  345.         }
  346.     }
  347.  
  348.     /**
  349.      * Process Postmastery
  350.      */
  351.     public function actionPostmastery()
  352.     {
  353.         $events = file_get_contents("php://input");
  354.         if (empty($events)) {
  355.             Yii::app()->end();
  356.         }
  357.  
  358.         $events = CJSON::decode($events);
  359.  
  360.         if (empty($events) || !is_array($events)) {
  361.             Yii::app()->end();
  362.         }
  363.  
  364.         foreach ($events as $event) {
  365.  
  366.             if (empty($event['type']) || empty($event['header_Message-Id'])) {
  367.                 continue;
  368.             }
  369.            
  370.             $event['header_Message-Id'] = str_replace(array('<', '>'), '', $event['header_Message-Id']);
  371.             $messageId = $event['header_Message-Id'];
  372.  
  373.             $criteria = new CDbCriteria();
  374.             $criteria->addCondition('`email_message_id` = :email_message_id AND `status` = :status');
  375.             $criteria->params = array(
  376.                 'email_message_id' => (string)$messageId,
  377.                 'status'           => CampaignDeliveryLog::STATUS_SUCCESS,
  378.             );
  379.  
  380.             $deliveryLog = CampaignDeliveryLog::model()->find($criteria);
  381.             if (empty($deliveryLog)) {
  382.                 $deliveryLog = CampaignDeliveryLogArchive::model()->find($criteria);
  383.             }
  384.  
  385.             if (empty($deliveryLog)) {
  386.                 continue;
  387.             }
  388.  
  389.             $campaign = Campaign::model()->findByPk($deliveryLog->campaign_id);
  390.             if (empty($campaign)) {
  391.                 continue;
  392.             }
  393.  
  394.             $subscriber = ListSubscriber::model()->findByAttributes(array(
  395.                 'list_id'          => $campaign->list_id,
  396.                 'subscriber_id'    => $deliveryLog->subscriber_id,
  397.                 'status'           => ListSubscriber::STATUS_CONFIRMED,
  398.             ));
  399.  
  400.             if (empty($subscriber)) {
  401.                 continue;
  402.             }
  403.  
  404.             // bounces
  405.             if (in_array($event['type'], array('b', 'rb', 'rs')) && !empty($event['bounceCat'])) {
  406.  
  407.                 $count = CampaignBounceLog::model()->countByAttributes(array(
  408.                     'campaign_id'   => $campaign->campaign_id,
  409.                     'subscriber_id' => $subscriber->subscriber_id,
  410.                 ));
  411.  
  412.                 if (!empty($count)) {
  413.                     continue;
  414.                 }
  415.  
  416.                 $bounceLog = new CampaignBounceLog();
  417.                 $bounceLog->campaign_id    = $campaign->campaign_id;
  418.                 $bounceLog->subscriber_id  = $subscriber->subscriber_id;
  419.                 $bounceLog->message        = !empty($event['dsnDiag']) ? $event['dsnDiag'] : 'BOUNCED BACK';
  420.                 $bounceLog->bounce_type    = CampaignBounceLog::BOUNCE_INTERNAL;
  421.  
  422.                 if (in_array($event['bounceCat'], array('bad-mailbox', 'inactive-mailbox', 'bad-domain'))) {
  423.                     $bounceLog->bounce_type = CampaignBounceLog::BOUNCE_HARD;
  424.                 } elseif (in_array($event['bounceCat'], array('quota-issues', 'no-answer-from-host', 'relaying-issues', 'routing-errors'))) {
  425.                     $bounceLog->bounce_type = CampaignBounceLog::BOUNCE_SOFT;
  426.                 }
  427.  
  428.                 $bounceLog->save();
  429.  
  430.                 if ($bounceLog->bounce_type == CampaignBounceLog::BOUNCE_HARD) {
  431.                     $subscriber->addToBlacklist($bounceLog->message);
  432.                 }
  433.  
  434.                 continue;
  435.             }
  436.  
  437.             // FBL
  438.             if (in_array($event['type'], array('f'))) {
  439.  
  440.                 if (Yii::app()->options->get('system.cron.process_feedback_loop_servers.subscriber_action', 'unsubscribe') == 'delete') {
  441.                     $subscriber->delete();
  442.                     continue;
  443.                 }
  444.  
  445.                 $subscriber->saveStatus(ListSubscriber::STATUS_UNSUBSCRIBED);
  446.  
  447.                 $count = CampaignTrackUnsubscribe::model()->countByAttributes(array(
  448.                     'campaign_id'   => $campaign->campaign_id,
  449.                     'subscriber_id' => $subscriber->subscriber_id,
  450.                 ));
  451.  
  452.                 if (empty($count)) {
  453.                     $trackUnsubscribe = new CampaignTrackUnsubscribe();
  454.                     $trackUnsubscribe->campaign_id   = $campaign->campaign_id;
  455.                     $trackUnsubscribe->subscriber_id = $subscriber->subscriber_id;
  456.                     $trackUnsubscribe->note          = 'Abuse complaint!';
  457.                     $trackUnsubscribe->ip_address    = Yii::app()->request->userHostAddress;
  458.                     $trackUnsubscribe->user_agent    = StringHelper::truncateLength(Yii::app()->request->userAgent, 255);
  459.                     $trackUnsubscribe->save(false);
  460.                 }
  461.  
  462.                 $count = CampaignComplainLog::model()->countByAttributes(array(
  463.                     'campaign_id'   => $campaign->campaign_id,
  464.                     'subscriber_id' => $subscriber->subscriber_id,
  465.                 ));
  466.  
  467.                 if (empty($count)) {
  468.                     $complaintLog = new CampaignComplainLog();
  469.                     $complaintLog->campaign_id   = $campaign->campaign_id;
  470.                     $complaintLog->subscriber_id = $subscriber->subscriber_id;
  471.                     $complaintLog->message       = 'Abuse complaint via Postmastery!';
  472.                     $complaintLog->save(false);
  473.                 }
  474.  
  475.                 continue;
  476.             }
  477.         }
  478.     }
  479.    
  480.     /**
  481.      * Process NewsMan
  482.      */
  483.     public function actionNewsman()
  484.     {
  485.         $events = Yii::app()->request->getPost('newsman_events');
  486.         if (empty($events)) {
  487.             Yii::app()->end();
  488.         }
  489.         $events = CJSON::decode($events);
  490.  
  491.         if (empty($events) || !is_array($events)) {
  492.             $events = array();
  493.         }
  494.        
  495.         foreach ($events as $event) {
  496.            
  497.             $messageId = !empty($event['data']['send_id']) ? $event['data']['send_id'] : '';
  498.             if (empty($messageId)) {
  499.                 continue;
  500.             }
  501.  
  502.             $criteria = new CDbCriteria();
  503.             $criteria->addCondition('`email_message_id` = :email_message_id AND `status` = :status');
  504.             $criteria->params = array(
  505.                 'email_message_id' => (string)$messageId,
  506.                 'status'           => CampaignDeliveryLog::STATUS_SUCCESS,
  507.             );
  508.  
  509.             $deliveryLog = CampaignDeliveryLog::model()->find($criteria);
  510.             if (empty($deliveryLog)) {
  511.                 $deliveryLog = CampaignDeliveryLogArchive::model()->find($criteria);
  512.             }
  513.            
  514.             if (empty($deliveryLog)) {
  515.                 continue;
  516.             }
  517.  
  518.             $campaign = Campaign::model()->findByPk($deliveryLog->campaign_id);
  519.             if (empty($campaign)) {
  520.                 continue;
  521.             }
  522.  
  523.             $subscriber = ListSubscriber::model()->findByAttributes(array(
  524.                 'list_id'          => $campaign->list_id,
  525.                 'subscriber_id'    => $deliveryLog->subscriber_id,
  526.                 'status'           => ListSubscriber::STATUS_CONFIRMED,
  527.             ));
  528.  
  529.             if (empty($subscriber)) {
  530.                 continue;
  531.             }
  532.            
  533.             if (in_array($event['type'], array('spam', 'unsub'))) {
  534.  
  535.                 if ($event['type'] == 'spam' && Yii::app()->options->get('system.cron.process_feedback_loop_servers.subscriber_action', 'unsubscribe') == 'delete') {
  536.                     $subscriber->delete();
  537.                     continue;
  538.                 }
  539.  
  540.                 $subscriber->saveStatus(ListSubscriber::STATUS_UNSUBSCRIBED);
  541.  
  542.                 $count = CampaignTrackUnsubscribe::model()->countByAttributes(array(
  543.                     'campaign_id'   => $campaign->campaign_id,
  544.                     'subscriber_id' => $subscriber->subscriber_id,
  545.                 ));
  546.  
  547.                 if (empty($count)) {
  548.                     $trackUnsubscribe = new CampaignTrackUnsubscribe();
  549.                     $trackUnsubscribe->campaign_id   = $campaign->campaign_id;
  550.                     $trackUnsubscribe->subscriber_id = $subscriber->subscriber_id;
  551.                     $trackUnsubscribe->note          = 'Unsubscribed via Web Hook!';
  552.                     $trackUnsubscribe->ip_address    = Yii::app()->request->userHostAddress;
  553.                     $trackUnsubscribe->user_agent    = StringHelper::truncateLength(Yii::app()->request->userAgent, 255);
  554.                     $trackUnsubscribe->save(false);
  555.                 }
  556.  
  557.                 // since 1.4.4 - complaints go into their own tables
  558.                 if ($event['type'] == 'spam') {
  559.  
  560.                     $count = CampaignComplainLog::model()->countByAttributes(array(
  561.                         'campaign_id'   => $campaign->campaign_id,
  562.                         'subscriber_id' => $subscriber->subscriber_id,
  563.                     ));
  564.  
  565.                     if (empty($count)) {
  566.                         $complaintLog = new CampaignComplainLog();
  567.                         $complaintLog->campaign_id   = $campaign->campaign_id;
  568.                         $complaintLog->subscriber_id = $subscriber->subscriber_id;
  569.                         $complaintLog->message       = 'Abuse complaint via NewsMan!';
  570.                         $complaintLog->save(false);
  571.                     }
  572.                 }
  573.  
  574.                 continue;
  575.             }
  576.            
  577.             if (in_array($event['type'], array('bounce', 'reject'))) {
  578.                 $count = CampaignBounceLog::model()->countByAttributes(array(
  579.                     'campaign_id'   => $campaign->campaign_id,
  580.                     'subscriber_id' => $subscriber->subscriber_id,
  581.                 ));
  582.  
  583.                 if (!empty($count)) {
  584.                     continue;
  585.                 }
  586.  
  587.                 $bounceLog = new CampaignBounceLog();
  588.                 $bounceLog->campaign_id   = $campaign->campaign_id;
  589.                 $bounceLog->subscriber_id = $subscriber->subscriber_id;
  590.                 $bounceLog->bounce_type   = CampaignBounceLog::BOUNCE_INTERNAL;
  591.                 $bounceLog->message       = !empty($event['data']['meta']['subject']) ? $event['data']['meta']['subject'] : 'BOUNCED BACK';
  592.                
  593.                 if ($event['type'] == 'reject') {
  594.                     $bounceLog->save();
  595.                     continue;
  596.                 }
  597.                
  598.                 if (strpos($event['data']['meta']['reason'], 'soft') !== false) {
  599.                     $bounceLog->bounce_type = CampaignBounceLog::BOUNCE_SOFT;
  600.                 } else {
  601.                     $bounceLog->bounce_type = CampaignBounceLog::BOUNCE_HARD;
  602.                 }
  603.  
  604.                 $bounceLog->save();
  605.  
  606.                 if ($bounceLog->bounce_type == CampaignBounceLog::BOUNCE_HARD) {
  607.                     $subscriber->addToBlacklist($bounceLog->message);
  608.                 }
  609.                
  610.                 continue;
  611.             }
  612.         }
  613.     }
  614.  
  615.     /**
  616.      * Process mandrill
  617.      */
  618.     public function processMandrill()
  619.     {
  620.         if (!MW_COMPOSER_SUPPORT) {
  621.             Yii::app()->end();
  622.         }
  623.  
  624.         $request = Yii::app()->request;
  625.         $mandrillEvents = $request->getPost('mandrill_events');
  626.  
  627.         if (empty($mandrillEvents)) {
  628.             Yii::app()->end();
  629.         }
  630.  
  631.         $mandrillEvents = CJSON::decode($mandrillEvents);
  632.         if (empty($mandrillEvents) || !is_array($mandrillEvents)) {
  633.             $mandrillEvents = array();
  634.         }
  635.  
  636.         foreach ($mandrillEvents as $evt) {
  637.            
  638.             if (!empty($evt['type']) && $evt['type'] == 'blacklist' && !empty($evt['action']) && $evt['action'] == 'add') {
  639.                 if (!empty($evt['reject']['email'])) {
  640.                     EmailBlacklist::addToBlacklist($evt['reject']['email'], (!empty($evt['reject']['detail']) ? $evt['reject']['detail'] : null));
  641.                 }
  642.                 continue;
  643.             }
  644.  
  645.             if (empty($evt['msg']) || !is_array($evt['msg'])) {
  646.                 continue;
  647.             }
  648.  
  649.             $msgData = $evt['msg'];
  650.             $event   = !empty($evt['event']) ? $evt['event'] : null;
  651.  
  652.             $globalMetaData    = !empty($msgData['metadata']) && is_array($msgData['metadata']) ? $msgData['metadata'] : array();
  653.             $recipientMetaData = !empty($msgData['recipient_metadata']) && is_array($msgData['recipient_metadata']) ? $msgData['recipient_metadata'] : array();
  654.             $metaData          = array_merge($globalMetaData, $recipientMetaData);
  655.  
  656.             if (empty($metaData['campaign_uid']) || empty($metaData['subscriber_uid'])) {
  657.                 continue;
  658.             }
  659.  
  660.             $campaignUid   = trim($metaData['campaign_uid']);
  661.             $subscriberUid = trim($metaData['subscriber_uid']);
  662.  
  663.             $campaign = Campaign::model()->findByUid($campaignUid);
  664.             if (empty($campaign)) {
  665.                 continue;
  666.             }
  667.  
  668.             $subscriber = ListSubscriber::model()->findByAttributes(array(
  669.                 'list_id'           => $campaign->list_id,
  670.                 'subscriber_uid'    => $subscriberUid,
  671.                 'status'            => ListSubscriber::STATUS_CONFIRMED,
  672.             ));
  673.  
  674.             if (empty($subscriber)) {
  675.                 continue;
  676.             }
  677.            
  678.             $returnReason = array();
  679.             if (!empty($msgData['diag'])) {
  680.                 $returnReason[] = $msgData['diag'];
  681.             }
  682.             if (!empty($msgData['bounce_description'])) {
  683.                 $returnReason[] = $msgData['bounce_description'];
  684.             }
  685.             $returnReason = implode(" ", $returnReason);
  686.  
  687.             if (in_array($event, array('hard_bounce', 'soft_bounce'))) {
  688.  
  689.                 $count = CampaignBounceLog::model()->countByAttributes(array(
  690.                     'campaign_id'   => $campaign->campaign_id,
  691.                     'subscriber_id' => $subscriber->subscriber_id,
  692.                 ));
  693.                
  694.                 if (!empty($count)) {
  695.                     continue;
  696.                 }
  697.                
  698.                 $bounceLog = new CampaignBounceLog();
  699.                 $bounceLog->campaign_id     = $campaign->campaign_id;
  700.                 $bounceLog->subscriber_id   = $subscriber->subscriber_id;
  701.                 $bounceLog->message         = $returnReason;
  702.                 $bounceLog->bounce_type     = $event == 'soft_bounce' ? CampaignBounceLog::BOUNCE_SOFT : CampaignBounceLog::BOUNCE_HARD;
  703.                 $bounceLog->save();
  704.  
  705.                 if ($bounceLog->bounce_type == CampaignBounceLog::BOUNCE_HARD) {
  706.                     $subscriber->addToBlacklist($bounceLog->message);
  707.                 }
  708.  
  709.                 continue;
  710.             }
  711.  
  712.             if (in_array($event, array('reject', 'blacklist'))) {
  713.                 $subscriber->addToBlacklist($returnReason);
  714.                 continue;
  715.             }
  716.  
  717.             if (in_array($event, array('spam', 'unsub'))) {
  718.                
  719.                 if ($event == 'spam' && Yii::app()->options->get('system.cron.process_feedback_loop_servers.subscriber_action', 'unsubscribe') == 'delete') {
  720.                     $subscriber->delete();
  721.                     continue;
  722.                 }
  723.  
  724.                 $subscriber->saveStatus(ListSubscriber::STATUS_UNSUBSCRIBED);
  725.  
  726.                 $count = CampaignTrackUnsubscribe::model()->countByAttributes(array(
  727.                     'campaign_id'   => $campaign->campaign_id,
  728.                     'subscriber_id' => $subscriber->subscriber_id,
  729.                 ));
  730.                
  731.                 if (empty($count)) {
  732.                     $trackUnsubscribe = new CampaignTrackUnsubscribe();
  733.                     $trackUnsubscribe->campaign_id   = $campaign->campaign_id;
  734.                     $trackUnsubscribe->subscriber_id = $subscriber->subscriber_id;
  735.                     $trackUnsubscribe->note          = 'Unsubscribed via Web Hook!';
  736.                     $trackUnsubscribe->ip_address    = Yii::app()->request->userHostAddress;
  737.                     $trackUnsubscribe->user_agent    = StringHelper::truncateLength(Yii::app()->request->userAgent, 255);
  738.                     $trackUnsubscribe->save(false);    
  739.                 }
  740.                
  741.                 // since 1.4.4 - complaints go into their own tables
  742.                 if ($event == 'spam') {
  743.                    
  744.                     $count = CampaignComplainLog::model()->countByAttributes(array(
  745.                         'campaign_id'   => $campaign->campaign_id,
  746.                         'subscriber_id' => $subscriber->subscriber_id,
  747.                     ));
  748.                    
  749.                     if (empty($count)) {
  750.                         $complaintLog = new CampaignComplainLog();
  751.                         $complaintLog->campaign_id   = $campaign->campaign_id;
  752.                         $complaintLog->subscriber_id = $subscriber->subscriber_id;
  753.                         $complaintLog->message       = 'Abuse complaint via Mandrill!';
  754.                         $complaintLog->save(false);
  755.                     }
  756.                 }
  757.  
  758.                 continue;
  759.             }
  760.         }
  761.  
  762.         Yii::app()->end();
  763.     }
  764.  
  765.     /**
  766.      * Process Amazon SES
  767.      */
  768.     public function processAmazonSes($server)
  769.     {
  770.         if (!version_compare(PHP_VERSION, '5.5', '>=')) {
  771.             Yii::app()->end();
  772.         }
  773.        
  774.         $message   = call_user_func(array('\Aws\Sns\Message', 'fromRawPostData'));
  775.         $className = '\Aws\Sns\MessageValidator';
  776.         $validator = new $className(array($this, '_amazonFetchRemote'));
  777.         try {
  778.             $validator->validate($message);
  779.         } catch (Exception $e) {
  780.             Yii::log($e->getMessage(), CLogger::LEVEL_ERROR);
  781.             Yii::app()->end();
  782.         }
  783.        
  784.         if ($message['Type'] === 'SubscriptionConfirmation') {
  785.            
  786.             try {
  787.  
  788.                 $types  = DeliveryServer::getTypesMapping();
  789.                 $type   = $types[$server->type];
  790.                 $server = DeliveryServer::model($type)->findByPk((int)$server->server_id);
  791.                 $result = $server->getSnsClient()->confirmSubscription(array(
  792.                     'TopicArn'  => $message['TopicArn'],
  793.                     'Token'     => $message['Token'],
  794.                 ));
  795.                 if (stripos($result->get('SubscriptionArn'), 'pending') === false) {
  796.                     $server->subscription_arn = $result->get('SubscriptionArn');
  797.                     $server->save(false);
  798.                 }
  799.                 Yii::app()->end();
  800.  
  801.             } catch (Exception $e) {}
  802.            
  803.             $className = '\Guzzle\Http\Client';
  804.             $client    = new $className();
  805.             $client->get($message['SubscribeURL'])->send();
  806.             Yii::app()->end();
  807.         }
  808.  
  809.         if ($message['Type'] !== 'Notification') {
  810.             Yii::app()->end();
  811.         }
  812.  
  813.         $data = new CMap((array)CJSON::decode($message['Message']));
  814.         if (!$data->itemAt('notificationType') || $data->itemAt('notificationType') == 'AmazonSnsSubscriptionSucceeded' || !$data->itemAt('mail')) {
  815.             Yii::app()->end();
  816.         }
  817.  
  818.         $mailMessage = $data->itemAt('mail');
  819.         if (empty($mailMessage['messageId'])) {
  820.             Yii::app()->end();
  821.         }
  822.         $messageId = $mailMessage['messageId'];
  823.  
  824.         $criteria = new CDbCriteria();
  825.         $criteria->addCondition('`email_message_id` = :email_message_id AND `status` = :status');
  826.         $criteria->params = array(
  827.             'email_message_id' => (string)$messageId,
  828.             'status'           => CampaignDeliveryLog::STATUS_SUCCESS,
  829.         );
  830.  
  831.         $deliveryLog = CampaignDeliveryLog::model()->find($criteria);
  832.         if (empty($deliveryLog)) {
  833.             $deliveryLog = CampaignDeliveryLogArchive::model()->find($criteria);
  834.         }
  835.  
  836.         if (empty($deliveryLog)) {
  837.             Yii::app()->end();
  838.         }
  839.  
  840.         $campaign = Campaign::model()->findByPk($deliveryLog->campaign_id);
  841.         if (empty($campaign)) {
  842.             Yii::app()->end();
  843.         }
  844.  
  845.         $subscriber = ListSubscriber::model()->findByAttributes(array(
  846.             'list_id'          => $campaign->list_id,
  847.             'subscriber_id'    => $deliveryLog->subscriber_id,
  848.             'status'           => ListSubscriber::STATUS_CONFIRMED,
  849.         ));
  850.  
  851.         if (empty($subscriber)) {
  852.             Yii::app()->end();
  853.         }
  854.  
  855.         if ($data->itemAt('notificationType') == 'Bounce' && ($bounce = $data->itemAt('bounce'))) {
  856.  
  857.             $count = CampaignBounceLog::model()->countByAttributes(array(
  858.                 'campaign_id'   => $campaign->campaign_id,
  859.                 'subscriber_id' => $subscriber->subscriber_id,
  860.             ));
  861.            
  862.             if (!empty($count)) {
  863.                 Yii::app()->end();
  864.             }
  865.            
  866.             $bounceLog = new CampaignBounceLog();
  867.             $bounceLog->campaign_id     = $campaign->campaign_id;
  868.             $bounceLog->subscriber_id   = $subscriber->subscriber_id;
  869.             $bounceLog->message         = !empty($bounce['bouncedRecipients'][0]['diagnosticCode']) ? $bounce['bouncedRecipients'][0]['diagnosticCode'] : 'BOUNCED BACK';
  870.             $bounceLog->bounce_type     = $bounce['bounceType'] !== 'Permanent' ? CampaignBounceLog::BOUNCE_SOFT : CampaignBounceLog::BOUNCE_HARD;
  871.             $bounceLog->save();
  872.  
  873.             if ($bounceLog->bounce_type === CampaignBounceLog::BOUNCE_HARD) {
  874.                 $subscriber->addToBlacklist($bounceLog->message);
  875.             }
  876.             Yii::app()->end();
  877.         }
  878.  
  879.         if ($data->itemAt('notificationType') == 'Complaint' && ($complaint = $data->itemAt('complaint'))) {
  880.            
  881.             if (Yii::app()->options->get('system.cron.process_feedback_loop_servers.subscriber_action', 'unsubscribe') == 'delete') {
  882.                 $subscriber->delete();
  883.                 Yii::app()->end();
  884.             }
  885.  
  886.             $subscriber->saveStatus(ListSubscriber::STATUS_UNSUBSCRIBED);
  887.            
  888.             $count = CampaignTrackUnsubscribe::model()->countByAttributes(array(
  889.                 'campaign_id'   => $campaign->campaign_id,
  890.                 'subscriber_id' => $subscriber->subscriber_id,
  891.             ));
  892.            
  893.             if (empty($count)) {
  894.                 $trackUnsubscribe = new CampaignTrackUnsubscribe();
  895.                 $trackUnsubscribe->campaign_id   = $campaign->campaign_id;
  896.                 $trackUnsubscribe->subscriber_id = $subscriber->subscriber_id;
  897.                 $trackUnsubscribe->note          = 'Abuse complaint!';
  898.                 $trackUnsubscribe->ip_address    = Yii::app()->request->userHostAddress;
  899.                 $trackUnsubscribe->user_agent    = StringHelper::truncateLength(Yii::app()->request->userAgent, 255);
  900.                 $trackUnsubscribe->save(false);
  901.             }
  902.  
  903.             // since 1.4.4 - complaints go into their own tables
  904.             $count = CampaignComplainLog::model()->countByAttributes(array(
  905.                 'campaign_id'   => $campaign->campaign_id,
  906.                 'subscriber_id' => $subscriber->subscriber_id,
  907.             ));
  908.            
  909.             if (empty($count)) {
  910.                 $complaintLog = new CampaignComplainLog();
  911.                 $complaintLog->campaign_id   = $campaign->campaign_id;
  912.                 $complaintLog->subscriber_id = $subscriber->subscriber_id;
  913.                 $complaintLog->message       = 'Abuse complaint via Amazon SES!';
  914.                 $complaintLog->save(false);
  915.             }
  916.             //
  917.  
  918.             Yii::app()->end();
  919.         }
  920.  
  921.         Yii::app()->end();
  922.     }
  923.  
  924.     /**
  925.      * Helper for \Aws\Sns\MessageValidator because otherwise it uses file_get_contents to fetch remote data
  926.      * and this might be disabled oin many hosts
  927.      *
  928.      * @param $url
  929.      * @return string
  930.      */
  931.     public function _amazonFetchRemote($url)
  932.     {
  933.         $content = AppInitHelper::simpleCurlGet($url);
  934.         return !empty($content['message']) ? $content['message'] : '';
  935.     }
  936.  
  937.     /**
  938.      * Process Mailgun
  939.      */
  940.     public function processMailgun()
  941.     {
  942.         if (!version_compare(PHP_VERSION, '5.5', '>=')) {
  943.             Yii::app()->end();
  944.         }
  945.  
  946.         $request  = Yii::app()->request;
  947.         $event    = $request->getPost('event');
  948.         $metaData = $request->getPost('metadata');
  949.  
  950.         if (empty($metaData) || empty($event)) {
  951.             Yii::app()->end();
  952.         }
  953.  
  954.         $metaData = CJSON::decode($metaData);
  955.         if (empty($metaData['campaign_uid']) || empty($metaData['subscriber_uid'])) {
  956.             Yii::app()->end();
  957.         }
  958.  
  959.         $campaign = Campaign::model()->findByAttributes(array(
  960.             'campaign_uid' => $metaData['campaign_uid']
  961.         ));
  962.         if (empty($campaign)) {
  963.             Yii::app()->end();
  964.         }
  965.  
  966.         $subscriber = ListSubscriber::model()->findByAttributes(array(
  967.             'list_id'          => $campaign->list_id,
  968.             'subscriber_uid'   => $metaData['subscriber_uid'],
  969.             'status'           => ListSubscriber::STATUS_CONFIRMED,
  970.         ));
  971.  
  972.         if (empty($subscriber)) {
  973.             Yii::app()->end();
  974.         }
  975.  
  976.         if ($event == 'bounced') {
  977.  
  978.             $count = CampaignBounceLog::model()->countByAttributes(array(
  979.                 'campaign_id'   => $campaign->campaign_id,
  980.                 'subscriber_id' => $subscriber->subscriber_id,
  981.             ));
  982.  
  983.             if (!empty($count)) {
  984.                 Yii::app()->end();
  985.             }
  986.  
  987.             $bounceLog = new CampaignBounceLog();
  988.             $bounceLog->campaign_id   = $campaign->campaign_id;
  989.             $bounceLog->subscriber_id = $subscriber->subscriber_id;
  990.             $bounceLog->message       = $request->getPost('notification', $request->getPost('error', $request->getPost('code', '')));
  991.             $bounceLog->bounce_type   = CampaignBounceLog::BOUNCE_HARD;
  992.             $bounceLog->save();
  993.  
  994.             $subscriber->addToBlacklist($bounceLog->message);
  995.  
  996.             Yii::app()->end();
  997.         }
  998.  
  999.         if ($event == 'dropped') {
  1000.  
  1001.             $count = CampaignBounceLog::model()->countByAttributes(array(
  1002.                 'campaign_id'   => $campaign->campaign_id,
  1003.                 'subscriber_id' => $subscriber->subscriber_id,
  1004.             ));
  1005.  
  1006.             if (!empty($count)) {
  1007.                 Yii::app()->end();
  1008.             }
  1009.  
  1010.             $bounceLog = new CampaignBounceLog();
  1011.             $bounceLog->campaign_id   = $campaign->campaign_id;
  1012.             $bounceLog->subscriber_id = $subscriber->subscriber_id;
  1013.             $bounceLog->message       = $request->getPost('description', $request->getPost('error', $request->getPost('reason', '')));
  1014.             $bounceLog->bounce_type   = $request->getPost('reason') != 'hardfail' ? CampaignBounceLog::BOUNCE_SOFT : CampaignBounceLog::BOUNCE_HARD;
  1015.             $bounceLog->save();
  1016.  
  1017.             if ($bounceLog->bounce_type == CampaignBounceLog::BOUNCE_HARD) {
  1018.                 $subscriber->addToBlacklist($bounceLog->message);
  1019.             }
  1020.  
  1021.             Yii::app()->end();
  1022.         }
  1023.  
  1024.         if ($event == 'complained') {
  1025.            
  1026.             if (Yii::app()->options->get('system.cron.process_feedback_loop_servers.subscriber_action', 'unsubscribe') == 'delete') {
  1027.                 $subscriber->delete();
  1028.                 Yii::app()->end();
  1029.             }
  1030.  
  1031.             $subscriber->saveStatus(ListSubscriber::STATUS_UNSUBSCRIBED);
  1032.            
  1033.             $count = CampaignTrackUnsubscribe::model()->countByAttributes(array(
  1034.                 'campaign_id'   => $campaign->campaign_id,
  1035.                 'subscriber_id' => $subscriber->subscriber_id,
  1036.             ));
  1037.            
  1038.             if (empty($count)) {
  1039.                 $trackUnsubscribe = new CampaignTrackUnsubscribe();
  1040.                 $trackUnsubscribe->campaign_id   = $campaign->campaign_id;
  1041.                 $trackUnsubscribe->subscriber_id = $subscriber->subscriber_id;
  1042.                 $trackUnsubscribe->note          = 'Abuse complaint!';
  1043.                 $trackUnsubscribe->ip_address    = Yii::app()->request->userHostAddress;
  1044.                 $trackUnsubscribe->user_agent    = StringHelper::truncateLength(Yii::app()->request->userAgent, 255);
  1045.                 $trackUnsubscribe->save(false);
  1046.             }
  1047.  
  1048.             // since 1.4.4 - complaints go into their own tables
  1049.             $count = CampaignComplainLog::model()->countByAttributes(array(
  1050.                 'campaign_id'   => $campaign->campaign_id,
  1051.                 'subscriber_id' => $subscriber->subscriber_id,
  1052.             ));
  1053.  
  1054.             if (empty($count)) {
  1055.                 $complaintLog = new CampaignComplainLog();
  1056.                 $complaintLog->campaign_id   = $campaign->campaign_id;
  1057.                 $complaintLog->subscriber_id = $subscriber->subscriber_id;
  1058.                 $complaintLog->message       = 'Abuse complaint via Mailgun!';
  1059.                 $complaintLog->save(false);
  1060.             }
  1061.             //
  1062.  
  1063.             Yii::app()->end();
  1064.         }
  1065.  
  1066.         Yii::app()->end();
  1067.     }
  1068.  
  1069.     /**
  1070.      * Process Sendgrid
  1071.      */
  1072.     public function processSendgrid()
  1073.     {
  1074.         if (!version_compare(PHP_VERSION, '5.6', '>=')) {
  1075.             Yii::app()->end();
  1076.         }
  1077.  
  1078.         $events = file_get_contents("php://input");
  1079.         if (empty($events)) {
  1080.             Yii::app()->end();
  1081.         }
  1082.  
  1083.         $events = CJSON::decode($events);
  1084.         if (empty($events) || !is_array($events)) {
  1085.             $events = array();
  1086.         }
  1087.  
  1088.         foreach ($events as $evt) {
  1089.            
  1090.             if (empty($evt['event']) || !in_array($evt['event'], array('dropped' , 'bounce', 'spamreport'))) {
  1091.                 continue;
  1092.             }
  1093.  
  1094.             if (empty($evt['campaign_uid']) || empty($evt['subscriber_uid'])) {
  1095.                 continue;
  1096.             }
  1097.  
  1098.             $campaignUid   = trim($evt['campaign_uid']);
  1099.             $subscriberUid = trim($evt['subscriber_uid']);
  1100.  
  1101.             $campaign = Campaign::model()->findByUid($campaignUid);
  1102.             if (empty($campaign)) {
  1103.                 continue;
  1104.             }
  1105.  
  1106.             $subscriber = ListSubscriber::model()->findByAttributes(array(
  1107.                 'list_id'           => $campaign->list_id,
  1108.                 'subscriber_uid'    => $subscriberUid,
  1109.                 'status'            => ListSubscriber::STATUS_CONFIRMED,
  1110.             ));
  1111.  
  1112.             if (empty($subscriber)) {
  1113.                 continue;
  1114.             }
  1115.            
  1116.             // https://sendgrid.com/docs/API_Reference/Webhooks/event.html
  1117.             if (in_array($evt['event'], array('dropped'))) {
  1118.  
  1119.                 $count = CampaignBounceLog::model()->countByAttributes(array(
  1120.                     'campaign_id'   => $campaign->campaign_id,
  1121.                     'subscriber_id' => $subscriber->subscriber_id,
  1122.                 ));
  1123.                
  1124.                 if (!empty($count)) {
  1125.                     continue;
  1126.                 }
  1127.                
  1128.                 $bounceLog = new CampaignBounceLog();
  1129.                 $bounceLog->campaign_id   = $campaign->campaign_id;
  1130.                 $bounceLog->subscriber_id = $subscriber->subscriber_id;
  1131.                 $bounceLog->message       = !empty($evt['reason']) ? $evt['reason'] : $evt['event'];
  1132.                 $bounceLog->message       = !empty($bounceLog->message) ? $bounceLog->message : 'Internal Bounce';
  1133.                 $bounceLog->bounce_type   = CampaignBounceLog::BOUNCE_INTERNAL;
  1134.                 $bounceLog->save();
  1135.                
  1136.                 continue;
  1137.             }
  1138.  
  1139.             if (in_array($evt['event'], array('bounce'))) {
  1140.  
  1141.                 $count = CampaignBounceLog::model()->countByAttributes(array(
  1142.                     'campaign_id'   => $campaign->campaign_id,
  1143.                     'subscriber_id' => $subscriber->subscriber_id,
  1144.                 ));
  1145.  
  1146.                 if (!empty($count)) {
  1147.                     continue;
  1148.                 }
  1149.                
  1150.                 $bounceLog = new CampaignBounceLog();
  1151.                 $bounceLog->campaign_id   = $campaign->campaign_id;
  1152.                 $bounceLog->subscriber_id = $subscriber->subscriber_id;
  1153.                 $bounceLog->message       = isset($evt['reason']) ? $evt['reason'] : 'BOUNCED BACK';
  1154.                 $bounceLog->bounce_type   = CampaignBounceLog::BOUNCE_HARD;
  1155.                 $bounceLog->save();
  1156.  
  1157.                 if ($bounceLog->bounce_type == CampaignBounceLog::BOUNCE_HARD) {
  1158.                     $subscriber->addToBlacklist($bounceLog->message);
  1159.                 }
  1160.  
  1161.                 continue;
  1162.             }
  1163.  
  1164.             if (in_array($evt['event'], array('spamreport'))) {
  1165.                
  1166.                 if ($evt['event'] == 'spamreport' && Yii::app()->options->get('system.cron.process_feedback_loop_servers.subscriber_action', 'unsubscribe') == 'delete') {
  1167.                     $subscriber->delete();
  1168.                     continue;
  1169.                 }
  1170.  
  1171.                 $subscriber->saveStatus(ListSubscriber::STATUS_UNSUBSCRIBED);
  1172.  
  1173.                 $count = CampaignTrackUnsubscribe::model()->countByAttributes(array(
  1174.                     'campaign_id'   => $campaign->campaign_id,
  1175.                     'subscriber_id' => $subscriber->subscriber_id,
  1176.                 ));
  1177.  
  1178.                 if (empty($count)) {
  1179.                     $trackUnsubscribe = new CampaignTrackUnsubscribe();
  1180.                     $trackUnsubscribe->campaign_id   = $campaign->campaign_id;
  1181.                     $trackUnsubscribe->subscriber_id = $subscriber->subscriber_id;
  1182.                     $trackUnsubscribe->note          = 'Unsubscribed via Web Hook!';
  1183.                     $trackUnsubscribe->ip_address    = Yii::app()->request->userHostAddress;
  1184.                     $trackUnsubscribe->user_agent    = StringHelper::truncateLength(Yii::app()->request->userAgent, 255);
  1185.                     $trackUnsubscribe->save(false);
  1186.                 }
  1187.                
  1188.                 // since 1.4.4 - complaints go into their own tables
  1189.                 $count = CampaignComplainLog::model()->countByAttributes(array(
  1190.                     'campaign_id'   => $campaign->campaign_id,
  1191.                     'subscriber_id' => $subscriber->subscriber_id,
  1192.                 ));
  1193.  
  1194.                 if (empty($count)) {
  1195.                     $complaintLog = new CampaignComplainLog();
  1196.                     $complaintLog->campaign_id   = $campaign->campaign_id;
  1197.                     $complaintLog->subscriber_id = $subscriber->subscriber_id;
  1198.                     $complaintLog->message       = 'Abuse complaint via SendGrid!';
  1199.                     $complaintLog->save(false);
  1200.                 }
  1201.                 //
  1202.  
  1203.                 continue;
  1204.             }
  1205.         }
  1206.  
  1207.         Yii::app()->end();
  1208.     }
  1209.  
  1210.     /**
  1211.      * Process LeaderSend
  1212.      */
  1213.     public function processLeadersend()
  1214.     {
  1215.         $request = Yii::app()->request;
  1216.         $events  = $request->getPost('leadersend_events');
  1217.  
  1218.         if (empty($events)) {
  1219.             Yii::app()->end();
  1220.         }
  1221.  
  1222.         $events = CJSON::decode($events);
  1223.         if (empty($events) || !is_array($events)) {
  1224.             $events = array();
  1225.         }
  1226.  
  1227.         foreach ($events as $evt) {
  1228.             if (empty($evt['msg']) || empty($evt['msg']['id'])) {
  1229.                 continue;
  1230.             }
  1231.            
  1232.             if (empty($evt['event']) || !in_array($evt['event'], array('spam', 'soft_bounce', 'hard_bounce', 'reject'))) {
  1233.                 continue;
  1234.             }
  1235.  
  1236.             $messageId = $evt['msg']['id'];
  1237.  
  1238.             $criteria = new CDbCriteria();
  1239.             $criteria->addCondition('`email_message_id` = :email_message_id AND `status` = :status');
  1240.             $criteria->params = array(
  1241.                 'email_message_id' => (string)$messageId,
  1242.                 'status'           => CampaignDeliveryLog::STATUS_SUCCESS,
  1243.             );
  1244.  
  1245.             $deliveryLog = CampaignDeliveryLog::model()->find($criteria);
  1246.             if (empty($deliveryLog)) {
  1247.                 $deliveryLog = CampaignDeliveryLogArchive::model()->find($criteria);
  1248.             }
  1249.            
  1250.             if (empty($deliveryLog)) {
  1251.                 continue;
  1252.             }
  1253.  
  1254.             $campaign = Campaign::model()->findByPk($deliveryLog->campaign_id);
  1255.             if (empty($campaign)) {
  1256.                 continue;
  1257.             }
  1258.  
  1259.             $subscriber = ListSubscriber::model()->findByAttributes(array(
  1260.                 'list_id'          => $campaign->list_id,
  1261.                 'subscriber_id'    => $deliveryLog->subscriber_id,
  1262.                 'status'           => ListSubscriber::STATUS_CONFIRMED,
  1263.             ));
  1264.  
  1265.             if (empty($subscriber)) {
  1266.                 continue;
  1267.             }
  1268.  
  1269.             if (in_array($evt['event'], array('soft_bounce', 'hard_bounce'))) {
  1270.  
  1271.                 $count = CampaignBounceLog::model()->countByAttributes(array(
  1272.                     'campaign_id'   => $campaign->campaign_id,
  1273.                     'subscriber_id' => $subscriber->subscriber_id,
  1274.                 ));
  1275.  
  1276.                 if (!empty($count)) {
  1277.                     continue;
  1278.                 }
  1279.                
  1280.                 $bounceLog = new CampaignBounceLog();
  1281.                 $bounceLog->campaign_id     = $campaign->campaign_id;
  1282.                 $bounceLog->subscriber_id   = $subscriber->subscriber_id;
  1283.                 $bounceLog->message         = !empty($evt['msg']['delivery_report']) ? $evt['msg']['delivery_report'] : 'BOUNCED BACK';
  1284.                 $bounceLog->bounce_type     = $evt['event'] == 'soft_bounce' ? CampaignBounceLog::BOUNCE_SOFT : CampaignBounceLog::BOUNCE_HARD;
  1285.                 $bounceLog->save();
  1286.  
  1287.                 if ($bounceLog->bounce_type == CampaignBounceLog::BOUNCE_HARD) {
  1288.                     $subscriber->addToBlacklist($bounceLog->message);
  1289.                 }
  1290.                 continue;
  1291.             }
  1292.  
  1293.             if ($evt['event'] == 'spam') {
  1294.                
  1295.                 if (Yii::app()->options->get('system.cron.process_feedback_loop_servers.subscriber_action', 'unsubscribe') == 'delete') {
  1296.                     $subscriber->delete();
  1297.                     continue;
  1298.                 }
  1299.  
  1300.                 $subscriber->saveStatus(ListSubscriber::STATUS_UNSUBSCRIBED);
  1301.  
  1302.                 $count = CampaignTrackUnsubscribe::model()->countByAttributes(array(
  1303.                     'campaign_id'   => $campaign->campaign_id,
  1304.                     'subscriber_id' => $subscriber->subscriber_id,
  1305.                 ));
  1306.  
  1307.                 if (empty($count)) {
  1308.                     $trackUnsubscribe = new CampaignTrackUnsubscribe();
  1309.                     $trackUnsubscribe->campaign_id   = $campaign->campaign_id;
  1310.                     $trackUnsubscribe->subscriber_id = $subscriber->subscriber_id;
  1311.                     $trackUnsubscribe->note          = 'Unsubscribed via Web Hook!';
  1312.                     $trackUnsubscribe->ip_address    = Yii::app()->request->userHostAddress;
  1313.                     $trackUnsubscribe->user_agent    = StringHelper::truncateLength(Yii::app()->request->userAgent, 255);
  1314.                     $trackUnsubscribe->save(false);
  1315.                 }
  1316.  
  1317.                 // since 1.4.4 - complaints go into their own tables
  1318.                 $count = CampaignComplainLog::model()->countByAttributes(array(
  1319.                     'campaign_id'   => $campaign->campaign_id,
  1320.                     'subscriber_id' => $subscriber->subscriber_id,
  1321.                 ));
  1322.  
  1323.                 if (empty($count)) {
  1324.                     $complaintLog = new CampaignComplainLog();
  1325.                     $complaintLog->campaign_id   = $campaign->campaign_id;
  1326.                     $complaintLog->subscriber_id = $subscriber->subscriber_id;
  1327.                     $complaintLog->message       = 'Abuse complaint via Leadersend!';
  1328.                     $complaintLog->save(false);
  1329.                 }
  1330.                 //
  1331.  
  1332.                 continue;
  1333.             }
  1334.  
  1335.             if ($evt['event'] == 'reject') {
  1336.                 $subscriber->addToBlacklist(!empty($evt['msg']['delivery_report']) ? $evt['msg']['delivery_report'] : 'BOUNCED BACK');
  1337.                 continue;
  1338.             }
  1339.         }
  1340.  
  1341.         Yii::app()->end();
  1342.     }
  1343.  
  1344.     /**
  1345.      * Process EE
  1346.      */
  1347.     public function processElasticemail()
  1348.     {
  1349.         $request     = Yii::app()->request;
  1350.         $category    = trim($request->getQuery('category'));
  1351.         $messageId   = trim($request->getQuery('messageid'));
  1352.         $status      = trim($request->getQuery('status'));
  1353.  
  1354.         if (empty($messageId) || empty($category)) {
  1355.             Yii::app()->end();
  1356.         }
  1357.  
  1358.         $criteria = new CDbCriteria();
  1359.         $criteria->addCondition('`email_message_id` = :email_message_id AND `status` = :status');
  1360.         $criteria->params = array(
  1361.             'email_message_id' => (string)$messageId,
  1362.             'status'           => CampaignDeliveryLog::STATUS_SUCCESS,
  1363.         );
  1364.  
  1365.         $deliveryLog = CampaignDeliveryLog::model()->find($criteria);
  1366.         if (empty($deliveryLog)) {
  1367.             $deliveryLog = CampaignDeliveryLogArchive::model()->find($criteria);
  1368.         }
  1369.  
  1370.         if (empty($deliveryLog)) {
  1371.             Yii::app()->end();
  1372.         }
  1373.  
  1374.         $campaign = Campaign::model()->findByPk($deliveryLog->campaign_id);
  1375.         if (empty($campaign)) {
  1376.             Yii::app()->end();
  1377.         }
  1378.  
  1379.         $subscriber = ListSubscriber::model()->findByAttributes(array(
  1380.             'list_id'          => $campaign->list_id,
  1381.             'subscriber_id'    => $deliveryLog->subscriber_id,
  1382.             'status'           => ListSubscriber::STATUS_CONFIRMED,
  1383.         ));
  1384.  
  1385.         if (empty($subscriber)) {
  1386.             Yii::app()->end();
  1387.         }
  1388.        
  1389.         // All categories:
  1390.         // https://elasticemail.com/support/delivery/http-web-notification
  1391.         if ($status == 'AbuseReport') {
  1392.            
  1393.             if (Yii::app()->options->get('system.cron.process_feedback_loop_servers.subscriber_action', 'unsubscribe') == 'delete') {
  1394.                 $subscriber->delete();
  1395.                 Yii::app()->end();
  1396.             }
  1397.  
  1398.             $subscriber->saveStatus(ListSubscriber::STATUS_UNSUBSCRIBED);
  1399.  
  1400.             $count = CampaignTrackUnsubscribe::model()->countByAttributes(array(
  1401.                 'campaign_id'   => $campaign->campaign_id,
  1402.                 'subscriber_id' => $subscriber->subscriber_id,
  1403.             ));
  1404.  
  1405.             if (empty($count)) {
  1406.                 $trackUnsubscribe = new CampaignTrackUnsubscribe();
  1407.                 $trackUnsubscribe->campaign_id   = $campaign->campaign_id;
  1408.                 $trackUnsubscribe->subscriber_id = $subscriber->subscriber_id;
  1409.                 $trackUnsubscribe->note          = 'Unsubscribed via Web Hook!';
  1410.                 $trackUnsubscribe->ip_address    = Yii::app()->request->userHostAddress;
  1411.                 $trackUnsubscribe->user_agent    = StringHelper::truncateLength(Yii::app()->request->userAgent, 255);
  1412.                 $trackUnsubscribe->save(false);
  1413.             }
  1414.            
  1415.             // since 1.4.4 - complaints go into their own tables
  1416.             $count = CampaignComplainLog::model()->countByAttributes(array(
  1417.                 'campaign_id'   => $campaign->campaign_id,
  1418.                 'subscriber_id' => $subscriber->subscriber_id,
  1419.             ));
  1420.  
  1421.             if (empty($count)) {
  1422.                 $complaintLog = new CampaignComplainLog();
  1423.                 $complaintLog->campaign_id   = $campaign->campaign_id;
  1424.                 $complaintLog->subscriber_id = $subscriber->subscriber_id;
  1425.                 $complaintLog->message       = 'Abuse complaint via ElasticEmail!';
  1426.                 $complaintLog->save(false);
  1427.             }
  1428.             //
  1429.  
  1430.             Yii::app()->end();
  1431.         }
  1432.        
  1433.         if ($status == 'Unsubscribed') {
  1434.            
  1435.             $subscriber->saveStatus(ListSubscriber::STATUS_UNSUBSCRIBED);
  1436.  
  1437.             $count = CampaignTrackUnsubscribe::model()->countByAttributes(array(
  1438.                 'campaign_id'   => $campaign->campaign_id,
  1439.                 'subscriber_id' => $subscriber->subscriber_id,
  1440.             ));
  1441.  
  1442.             if (!empty($count)) {
  1443.                 Yii::app()->end();
  1444.             }
  1445.  
  1446.             $trackUnsubscribe = new CampaignTrackUnsubscribe();
  1447.             $trackUnsubscribe->campaign_id   = $campaign->campaign_id;
  1448.             $trackUnsubscribe->subscriber_id = $subscriber->subscriber_id;
  1449.             $trackUnsubscribe->note          = 'Unsubscribed via Web Hook!';
  1450.             $trackUnsubscribe->ip_address    = Yii::app()->request->userHostAddress;
  1451.             $trackUnsubscribe->user_agent    = StringHelper::truncateLength(Yii::app()->request->userAgent, 255);
  1452.             $trackUnsubscribe->save(false);
  1453.  
  1454.             Yii::app()->end();
  1455.         }
  1456.        
  1457.         if ($status == 'Error') {
  1458.  
  1459.             $categoryID           = strtolower($category);
  1460.             $hardBounceCategories = array('NoMailbox', 'AccountProblem');
  1461.             $hardBounceCategories = array_map('strtolower', $hardBounceCategories);
  1462.            
  1463.             $bounceType = null;
  1464.  
  1465.             if (in_array($categoryID, $hardBounceCategories)) {
  1466.                 $bounceType = CampaignBounceLog::BOUNCE_HARD;
  1467.             } else {
  1468.                 $bounceType = CampaignBounceLog::BOUNCE_SOFT;
  1469.             }
  1470.  
  1471.             $count = CampaignBounceLog::model()->countByAttributes(array(
  1472.                 'campaign_id'   => $campaign->campaign_id,
  1473.                 'subscriber_id' => $subscriber->subscriber_id,
  1474.             ));
  1475.  
  1476.             if (!empty($count)) {
  1477.                 Yii::app()->end();
  1478.             }
  1479.  
  1480.             $bounceLog = new CampaignBounceLog();
  1481.             $bounceLog->campaign_id     = $campaign->campaign_id;
  1482.             $bounceLog->subscriber_id   = $subscriber->subscriber_id;
  1483.             $bounceLog->message         = $category;
  1484.             $bounceLog->bounce_type     = $bounceType;
  1485.             $bounceLog->save();
  1486.  
  1487.             if ($bounceLog->bounce_type == CampaignBounceLog::BOUNCE_HARD) {
  1488.                 $subscriber->addToBlacklist($bounceLog->message);
  1489.             }
  1490.  
  1491.             Yii::app()->end();
  1492.         }
  1493.  
  1494.         Yii::app()->end();
  1495.     }
  1496.  
  1497.     /**
  1498.      * Process DynEmail
  1499.      */
  1500.     public function processDyn($server)
  1501.     {
  1502.         $request    = Yii::app()->request;
  1503.         $event      = $request->getQuery('event');
  1504.         $bounceRule = $request->getQuery('rule', $request->getQuery('bouncerule')); // bounce rule
  1505.         $bounceType = $request->getQuery('type', $request->getQuery('bouncetype')); // bounce type
  1506.         $campaign   = $request->getQuery('campaign'); // campaign uid
  1507.         $subscriber = $request->getQuery('subscriber'); // subscriber uid
  1508.  
  1509.         $allowedEvents = array('bounce', 'complaint', 'unsubscribe');
  1510.         if (!in_array($event, $allowedEvents)) {
  1511.             Yii::app()->end();
  1512.         }
  1513.  
  1514.         $campaign = Campaign::model()->findByUid($campaign);
  1515.         if (empty($campaign)) {
  1516.             Yii::app()->end();
  1517.         }
  1518.  
  1519.         $subscriber = ListSubscriber::model()->findByAttributes(array(
  1520.             'list_id'          => $campaign->list_id,
  1521.             'subscriber_uid'   => $subscriber,
  1522.             'status'           => ListSubscriber::STATUS_CONFIRMED,
  1523.         ));
  1524.  
  1525.         if (empty($subscriber)) {
  1526.             Yii::app()->end();
  1527.         }
  1528.        
  1529.         if ($event == 'bounce') {
  1530.  
  1531.             $count = CampaignBounceLog::model()->countByAttributes(array(
  1532.                 'campaign_id'   => $campaign->campaign_id,
  1533.                 'subscriber_id' => $subscriber->subscriber_id,
  1534.             ));
  1535.  
  1536.             if (!empty($count)) {
  1537.                 Yii::app()->end();
  1538.             }
  1539.            
  1540.             $bounceLog = new CampaignBounceLog();
  1541.             $bounceLog->campaign_id     = $campaign->campaign_id;
  1542.             $bounceLog->subscriber_id   = $subscriber->subscriber_id;
  1543.             $bounceLog->message         = $bounceRule;
  1544.             $bounceLog->bounce_type     = $bounceType == 'soft' ? CampaignBounceLog::BOUNCE_SOFT : CampaignBounceLog::BOUNCE_HARD;
  1545.             $bounceLog->save();
  1546.  
  1547.             if ($bounceLog->bounce_type == CampaignBounceLog::BOUNCE_HARD) {
  1548.                 $subscriber->addToBlacklist($bounceLog->message);
  1549.             }
  1550.             Yii::app()->end();
  1551.         }
  1552.        
  1553.         /* remove from suppression list. */
  1554.         if ($event == 'complaint') {
  1555.             $url = sprintf('https://api.email.dynect.net/rest/json/suppressions/activate?apikey=%s&emailaddress=%s', $server->password, urlencode($subscriber->email));
  1556.             AppInitHelper::simpleCurlPost($url, array(), 5);
  1557.         }
  1558.  
  1559.         if (in_array($event, array('complaint', 'unsubscribe'))) {
  1560.            
  1561.             if (Yii::app()->options->get('system.cron.process_feedback_loop_servers.subscriber_action', 'unsubscribe') == 'delete') {
  1562.                 $subscriber->delete();
  1563.                 Yii::app()->end();
  1564.             }
  1565.  
  1566.             $subscriber->saveStatus(ListSubscriber::STATUS_UNSUBSCRIBED);
  1567.  
  1568.             $count = CampaignTrackUnsubscribe::model()->countByAttributes(array(
  1569.                 'campaign_id'   => $campaign->campaign_id,
  1570.                 'subscriber_id' => $subscriber->subscriber_id,
  1571.             ));
  1572.  
  1573.             if (empty($count)) {
  1574.                 $trackUnsubscribe = new CampaignTrackUnsubscribe();
  1575.                 $trackUnsubscribe->campaign_id   = $campaign->campaign_id;
  1576.                 $trackUnsubscribe->subscriber_id = $subscriber->subscriber_id;
  1577.                 $trackUnsubscribe->note          = 'Unsubscribed via Web Hook!';
  1578.                 $trackUnsubscribe->ip_address    = Yii::app()->request->userHostAddress;
  1579.                 $trackUnsubscribe->user_agent    = StringHelper::truncateLength(Yii::app()->request->userAgent, 255);
  1580.                 $trackUnsubscribe->save(false);
  1581.             }
  1582.            
  1583.             // since 1.4.4 - complaints go into their own tables
  1584.             if ($event == 'complaint') {
  1585.                 $count = CampaignComplainLog::model()->countByAttributes(array(
  1586.                     'campaign_id' => $campaign->campaign_id,
  1587.                     'subscriber_id' => $subscriber->subscriber_id,
  1588.                 ));
  1589.  
  1590.                 if (empty($count)) {
  1591.                     $complaintLog = new CampaignComplainLog();
  1592.                     $complaintLog->campaign_id = $campaign->campaign_id;
  1593.                     $complaintLog->subscriber_id = $subscriber->subscriber_id;
  1594.                     $complaintLog->message = 'Abuse complaint via DynEmail!';
  1595.                     $complaintLog->save(false);
  1596.                 }
  1597.             }
  1598.             //
  1599.  
  1600.             Yii::app()->end();
  1601.         }
  1602.  
  1603.         Yii::app()->end();
  1604.     }
  1605.  
  1606.     /**
  1607.      * Process Sparkpost
  1608.      */
  1609.     public function processSparkpost()
  1610.     {
  1611.         $events = file_get_contents("php://input");
  1612.         if (empty($events)) {
  1613.             Yii::app()->end();
  1614.         }
  1615.         $events = CJSON::decode($events);
  1616.  
  1617.         if (empty($events) || !is_array($events)) {
  1618.             $events = array();
  1619.         }
  1620.  
  1621.         foreach ($events as $evt) {
  1622.            
  1623.             if (empty($evt['msys']['message_event'])) {
  1624.                 continue;
  1625.             }
  1626.             $evt = $evt['msys']['message_event'];
  1627.             if (empty($evt['type']) || !in_array($evt['type'], array('bounce', 'spam_complaint', 'list_unsubscribe', 'link_unsubscribe'))) {
  1628.                 continue;
  1629.             }
  1630.  
  1631.             if (empty($evt['rcpt_meta']) || empty($evt['rcpt_meta']['campaign_uid']) || empty($evt['rcpt_meta']['subscriber_uid'])) {
  1632.                 continue;
  1633.             }
  1634.  
  1635.             $campaign = Campaign::model()->findByUid($evt['rcpt_meta']['campaign_uid']);
  1636.             if (empty($campaign)) {
  1637.                 continue;
  1638.             }
  1639.  
  1640.             $subscriber = ListSubscriber::model()->findByAttributes(array(
  1641.                 'list_id'          => $campaign->list_id,
  1642.                 'subscriber_uid'   => $evt['rcpt_meta']['subscriber_uid'],
  1643.                 'status'           => ListSubscriber::STATUS_CONFIRMED,
  1644.             ));
  1645.  
  1646.             if (empty($subscriber)) {
  1647.                 continue;
  1648.             }
  1649.  
  1650.             if (in_array($evt['type'], array('bounce'))) {
  1651.  
  1652.                 $count = CampaignBounceLog::model()->countByAttributes(array(
  1653.                     'campaign_id'   => $campaign->campaign_id,
  1654.                     'subscriber_id' => $subscriber->subscriber_id,
  1655.                 ));
  1656.  
  1657.                 if (!empty($count)) {
  1658.                     continue;
  1659.                 }
  1660.                
  1661.                 // https://support.sparkpost.com/customer/portal/articles/1929896-bounce-classification-codes
  1662.                 $bounceType = CampaignBounceLog::BOUNCE_INTERNAL;
  1663.                 if (in_array($evt['bounce_class'], array(10, 30, 90))) {
  1664.                     $bounceType = CampaignBounceLog::BOUNCE_HARD;
  1665.                 } elseif (in_array($evt['bounce_class'], array(20, 40, 60))) {
  1666.                     $bounceType = CampaignBounceLog::BOUNCE_SOFT;
  1667.                 }
  1668.                
  1669.                 $defaultBounceMessage = 'BOUNCED BACK';
  1670.                 if ($bounceType == CampaignBounceLog::BOUNCE_INTERNAL) {
  1671.                     $defaultBounceMessage = 'Internal Bounce';
  1672.                 }
  1673.                
  1674.                 $bounceLog = new CampaignBounceLog();
  1675.                 $bounceLog->campaign_id     = $campaign->campaign_id;
  1676.                 $bounceLog->subscriber_id   = $subscriber->subscriber_id;
  1677.                 $bounceLog->message         = !empty($evt['reason']) ? $evt['reason'] : $defaultBounceMessage;
  1678.                 $bounceLog->bounce_type     = $bounceType;
  1679.                 $bounceLog->save();
  1680.  
  1681.                 if ($bounceLog->bounce_type == CampaignBounceLog::BOUNCE_HARD) {
  1682.                     $subscriber->addToBlacklist($bounceLog->message);
  1683.                 }
  1684.  
  1685.                 continue;
  1686.             }
  1687.  
  1688.             if (in_array($evt['type'], array('spam_complaint', 'list_unsubscribe', 'link_unsubscribe'))) {
  1689.                
  1690.                 if ($evt['type'] == 'spam_complaint' && Yii::app()->options->get('system.cron.process_feedback_loop_servers.subscriber_action', 'unsubscribe') == 'delete') {
  1691.                     $subscriber->delete();
  1692.                     continue;
  1693.                 }
  1694.  
  1695.                 $subscriber->saveStatus(ListSubscriber::STATUS_UNSUBSCRIBED);
  1696.  
  1697.                 $count = CampaignTrackUnsubscribe::model()->countByAttributes(array(
  1698.                     'campaign_id'   => $campaign->campaign_id,
  1699.                     'subscriber_id' => $subscriber->subscriber_id,
  1700.                 ));
  1701.  
  1702.                 if (empty($count)) {
  1703.                     $trackUnsubscribe = new CampaignTrackUnsubscribe();
  1704.                     $trackUnsubscribe->campaign_id   = $campaign->campaign_id;
  1705.                     $trackUnsubscribe->subscriber_id = $subscriber->subscriber_id;
  1706.                     $trackUnsubscribe->note          = 'Unsubscribed via Web Hook!';
  1707.                     $trackUnsubscribe->ip_address    = Yii::app()->request->userHostAddress;
  1708.                     $trackUnsubscribe->user_agent    = StringHelper::truncateLength(Yii::app()->request->userAgent, 255);
  1709.                     $trackUnsubscribe->save(false);
  1710.                 }
  1711.  
  1712.                 // since 1.4.4 - complaints go into their own tables
  1713.                 if ($evt['type'] == 'spam_complaint') {
  1714.                     $count = CampaignComplainLog::model()->countByAttributes(array(
  1715.                         'campaign_id'   => $campaign->campaign_id,
  1716.                         'subscriber_id' => $subscriber->subscriber_id,
  1717.                     ));
  1718.  
  1719.                     if (empty($count)) {
  1720.                         $complaintLog = new CampaignComplainLog();
  1721.                         $complaintLog->campaign_id = $campaign->campaign_id;
  1722.                         $complaintLog->subscriber_id = $subscriber->subscriber_id;
  1723.                         $complaintLog->message = 'Abuse complaint via Sparkpost!';
  1724.                         $complaintLog->save(false);
  1725.                     }
  1726.                 }
  1727.                 //
  1728.  
  1729.                 continue;
  1730.             }
  1731.         }
  1732.  
  1733.         Yii::app()->end();
  1734.     }
  1735.  
  1736.     /**
  1737.      * Process Pepipost
  1738.      * @throws CDbException
  1739.      */
  1740.     public function processPepipost()
  1741.     {
  1742.         $events = file_get_contents("php://input");
  1743.         if (empty($events)) {
  1744.             Yii::app()->end();
  1745.         }
  1746.         $events = CJSON::decode($events);
  1747.  
  1748.         if (empty($events) || !is_array($events)) {
  1749.             $events = array();
  1750.         }
  1751.  
  1752.         foreach ($events as $evt) {
  1753.  
  1754.             if (empty($evt['TRANSID']) || empty($evt['X-APIHEADER']) || empty($evt['EVENT'])) {
  1755.                 continue;
  1756.             }
  1757.            
  1758.             if (!in_array($evt['EVENT'], array('bounced', 'unsubscribed', 'spam'))) {
  1759.                 continue;
  1760.             }
  1761.            
  1762.             $metaData = CJSON::decode(trim(str_replace('\"', '"', $evt['X-APIHEADER']), '"'));
  1763.             if (empty($metaData['campaign_uid']) || empty($metaData['subscriber_uid'])) {
  1764.                 continue;
  1765.             }
  1766.  
  1767.             $campaign = Campaign::model()->findByUid($metaData['campaign_uid']);
  1768.             if (empty($campaign)) {
  1769.                 continue;
  1770.             }
  1771.  
  1772.             $subscriber = ListSubscriber::model()->findByAttributes(array(
  1773.                 'list_id'          => $campaign->list_id,
  1774.                 'subscriber_uid'   => $metaData['subscriber_uid'],
  1775.                 'status'           => ListSubscriber::STATUS_CONFIRMED,
  1776.             ));
  1777.  
  1778.             if (empty($subscriber)) {
  1779.                 continue;
  1780.             }
  1781.  
  1782.             if (in_array($evt['EVENT'], array('bounced'))) {
  1783.  
  1784.                 $count = CampaignBounceLog::model()->countByAttributes(array(
  1785.                     'campaign_id'   => $campaign->campaign_id,
  1786.                     'subscriber_id' => $subscriber->subscriber_id,
  1787.                 ));
  1788.  
  1789.                 if (!empty($count)) {
  1790.                     continue;
  1791.                 }
  1792.  
  1793.                 $bounceType = CampaignBounceLog::BOUNCE_INTERNAL;
  1794.                 if ($evt['BOUNCE_TYPE'] == 'HARDBOUNCE') {
  1795.                     $bounceType = CampaignBounceLog::BOUNCE_HARD;
  1796.                 } elseif ($evt['BOUNCE_TYPE'] == 'SOFTBOUNCE') {
  1797.                     $bounceType = CampaignBounceLog::BOUNCE_SOFT;
  1798.                 }
  1799.  
  1800.                 $defaultBounceMessage = 'BOUNCED BACK';
  1801.                 if ($bounceType == CampaignBounceLog::BOUNCE_INTERNAL) {
  1802.                     $defaultBounceMessage = 'Internal Bounce';
  1803.                 }
  1804.  
  1805.                 $bounceLog = new CampaignBounceLog();
  1806.                 $bounceLog->campaign_id     = $campaign->campaign_id;
  1807.                 $bounceLog->subscriber_id   = $subscriber->subscriber_id;
  1808.                 $bounceLog->message         = !empty($evt['BOUNCE_REASON']) ? $evt['BOUNCE_REASON'] : $defaultBounceMessage;
  1809.                 $bounceLog->bounce_type     = $bounceType;
  1810.                 $bounceLog->save();
  1811.  
  1812.                 if ($bounceLog->bounce_type == CampaignBounceLog::BOUNCE_HARD) {
  1813.                     $subscriber->addToBlacklist($bounceLog->message);
  1814.                 }
  1815.  
  1816.                 continue;
  1817.             }
  1818.  
  1819.             if (in_array($evt['EVENT'], array('spam', 'unsubscribe'))) {
  1820.  
  1821.                 if ($evt['EVENT'] == 'spam' && Yii::app()->options->get('system.cron.process_feedback_loop_servers.subscriber_action', 'unsubscribe') == 'delete') {
  1822.                     $subscriber->delete();
  1823.                     continue;
  1824.                 }
  1825.  
  1826.                 $subscriber->saveStatus(ListSubscriber::STATUS_UNSUBSCRIBED);
  1827.  
  1828.                 $count = CampaignTrackUnsubscribe::model()->countByAttributes(array(
  1829.                     'campaign_id'   => $campaign->campaign_id,
  1830.                     'subscriber_id' => $subscriber->subscriber_id,
  1831.                 ));
  1832.  
  1833.                 if (empty($count)) {
  1834.                     $trackUnsubscribe = new CampaignTrackUnsubscribe();
  1835.                     $trackUnsubscribe->campaign_id   = $campaign->campaign_id;
  1836.                     $trackUnsubscribe->subscriber_id = $subscriber->subscriber_id;
  1837.                     $trackUnsubscribe->note          = 'Unsubscribed via Web Hook!';
  1838.                     $trackUnsubscribe->ip_address    = Yii::app()->request->userHostAddress;
  1839.                     $trackUnsubscribe->user_agent    = StringHelper::truncateLength(Yii::app()->request->userAgent, 255);
  1840.                     $trackUnsubscribe->save(false);
  1841.                 }
  1842.  
  1843.                 // since 1.4.4 - complaints go into their own tables
  1844.                 if ($evt['EVENT'] == 'spam') {
  1845.                     $count = CampaignComplainLog::model()->countByAttributes(array(
  1846.                         'campaign_id'   => $campaign->campaign_id,
  1847.                         'subscriber_id' => $subscriber->subscriber_id,
  1848.                     ));
  1849.  
  1850.                     if (empty($count)) {
  1851.                         $complaintLog = new CampaignComplainLog();
  1852.                         $complaintLog->campaign_id   = $campaign->campaign_id;
  1853.                         $complaintLog->subscriber_id = $subscriber->subscriber_id;
  1854.                         $complaintLog->message       = 'Abuse complaint via PepiPost!';
  1855.                         $complaintLog->save(false);
  1856.                     }
  1857.                 }
  1858.                 //
  1859.  
  1860.                 continue;
  1861.             }
  1862.         }
  1863.  
  1864.         Yii::app()->end();
  1865.     }
  1866.    
  1867.     /**
  1868.      * Process MailJet
  1869.      */
  1870.     public function processMailjet()
  1871.     {
  1872.         $events = file_get_contents("php://input");
  1873.         if (empty($events)) {
  1874.             Yii::app()->end();
  1875.         }
  1876.        
  1877.         $events = CJSON::decode($events);
  1878.        
  1879.         if (empty($events) || !is_array($events)) {
  1880.             $events = array();
  1881.         }
  1882.        
  1883.         if (isset($events['event'])) {
  1884.             $events = array($events);
  1885.         }
  1886.  
  1887.         foreach ($events as $event) {
  1888.             if (!isset($event['MessageID'], $event['event'])) {
  1889.                 continue;
  1890.             }
  1891.  
  1892.             $messageId = $event['MessageID'];
  1893.  
  1894.             $criteria = new CDbCriteria();
  1895.             $criteria->addCondition('`email_message_id` = :email_message_id AND `status` = :status');
  1896.             $criteria->params = array(
  1897.                 'email_message_id' => (string)$messageId,
  1898.                 'status'           => CampaignDeliveryLog::STATUS_SUCCESS,
  1899.             );
  1900.  
  1901.             $deliveryLog = CampaignDeliveryLog::model()->find($criteria);
  1902.             if (empty($deliveryLog)) {
  1903.                 $deliveryLog = CampaignDeliveryLogArchive::model()->find($criteria);
  1904.             }
  1905.  
  1906.             if (empty($deliveryLog)) {
  1907.                 continue;
  1908.             }
  1909.  
  1910.             $campaign = Campaign::model()->findByPk($deliveryLog->campaign_id);
  1911.             if (empty($campaign)) {
  1912.                 continue;
  1913.             }
  1914.  
  1915.             $subscriber = ListSubscriber::model()->findByAttributes(array(
  1916.                 'list_id'          => $campaign->list_id,
  1917.                 'subscriber_id'    => $deliveryLog->subscriber_id,
  1918.                 'status'           => ListSubscriber::STATUS_CONFIRMED,
  1919.             ));
  1920.  
  1921.             if (empty($subscriber)) {
  1922.                 continue;
  1923.             }
  1924.            
  1925.             if (in_array($event['event'], array('bounce', 'blocked'))) {
  1926.  
  1927.                 $count = CampaignBounceLog::model()->countByAttributes(array(
  1928.                     'campaign_id'   => $campaign->campaign_id,
  1929.                     'subscriber_id' => $subscriber->subscriber_id,
  1930.                 ));
  1931.  
  1932.                 if (!empty($count)) {
  1933.                     continue;
  1934.                 }
  1935.                
  1936.                 $bounceLog = new CampaignBounceLog();
  1937.                 $bounceLog->campaign_id     = $campaign->campaign_id;
  1938.                 $bounceLog->subscriber_id   = $subscriber->subscriber_id;
  1939.                 $bounceLog->message         = !empty($event['error'])  ? $event['error'] : 'BOUNCED BACK';
  1940.                 $bounceLog->bounce_type     = empty($event['hard_bounce']) ? CampaignBounceLog::BOUNCE_SOFT : CampaignBounceLog::BOUNCE_HARD;
  1941.                 $bounceLog->save();
  1942.  
  1943.                 if (!empty($event['hard_bounce'])) {
  1944.                     $subscriber->addToBlacklist($bounceLog->message);
  1945.                 }
  1946.                
  1947.                 continue;
  1948.             }
  1949.            
  1950.             if (in_array($event['event'], array('spam', 'unsub'))) {
  1951.  
  1952.                 if ($event['event'] == 'spam' && Yii::app()->options->get('system.cron.process_feedback_loop_servers.subscriber_action', 'unsubscribe') == 'delete') {
  1953.                     $subscriber->delete();
  1954.                     continue;
  1955.                 }
  1956.  
  1957.                 $subscriber->saveStatus(ListSubscriber::STATUS_UNSUBSCRIBED);
  1958.                
  1959.                 $count = CampaignTrackUnsubscribe::model()->countByAttributes(array(
  1960.                     'campaign_id'   => $campaign->campaign_id,
  1961.                     'subscriber_id' => $subscriber->subscriber_id,
  1962.                 ));
  1963.                
  1964.                 if (empty($count)) {
  1965.                     $trackUnsubscribe = new CampaignTrackUnsubscribe();
  1966.                     $trackUnsubscribe->campaign_id   = $campaign->campaign_id;
  1967.                     $trackUnsubscribe->subscriber_id = $subscriber->subscriber_id;
  1968.                     $trackUnsubscribe->note          = $event['event'] == 'spam' ? 'Abuse complaint!' : 'Unsubscribed via Web Hook!';
  1969.                     $trackUnsubscribe->ip_address    = Yii::app()->request->userHostAddress;
  1970.                     $trackUnsubscribe->user_agent    = StringHelper::truncateLength(Yii::app()->request->userAgent, 255);
  1971.                     $trackUnsubscribe->save(false);
  1972.                 }
  1973.                
  1974.                 // since 1.4.4 - complaints go into their own tables
  1975.                 if ($event['event'] == 'spam') {
  1976.                     $count = CampaignComplainLog::model()->countByAttributes(array(
  1977.                         'campaign_id'   => $campaign->campaign_id,
  1978.                         'subscriber_id' => $subscriber->subscriber_id,
  1979.                     ));
  1980.  
  1981.                     if (empty($count)) {
  1982.                         $complaintLog = new CampaignComplainLog();
  1983.                         $complaintLog->campaign_id   = $campaign->campaign_id;
  1984.                         $complaintLog->subscriber_id = $subscriber->subscriber_id;
  1985.                         $complaintLog->message       = 'Abuse complaint via Mailjet!';
  1986.                         $complaintLog->save(false);
  1987.                     }
  1988.                 }
  1989.                 //
  1990.  
  1991.                 continue;
  1992.             }
  1993.         }
  1994.  
  1995.         Yii::app()->end();
  1996.     }
  1997.  
  1998.     /**
  1999.      * Process SendinBlue
  2000.      */
  2001.     public function processSendinblue()
  2002.     {
  2003.         $event = file_get_contents("php://input");
  2004.         if (empty($event)) {
  2005.             Yii::app()->end();
  2006.         }
  2007.  
  2008.         $event = CJSON::decode($event);
  2009.  
  2010.         if (empty($event) || !is_array($event) || empty($event['event']) || empty($event['message-id'])) {
  2011.             Yii::app()->end();
  2012.         }
  2013.        
  2014.         $messageId = $event['message-id'];
  2015.  
  2016.         $criteria = new CDbCriteria();
  2017.         $criteria->addCondition('`email_message_id` = :email_message_id AND `status` = :status');
  2018.         $criteria->params = array(
  2019.             'email_message_id' => (string)$messageId,
  2020.             'status'           => CampaignDeliveryLog::STATUS_SUCCESS,
  2021.         );
  2022.  
  2023.         $deliveryLog = CampaignDeliveryLog::model()->find($criteria);
  2024.         if (empty($deliveryLog)) {
  2025.             $deliveryLog = CampaignDeliveryLogArchive::model()->find($criteria);
  2026.         }
  2027.  
  2028.         if (empty($deliveryLog)) {
  2029.             Yii::app()->end();
  2030.         }
  2031.  
  2032.         $campaign = Campaign::model()->findByPk($deliveryLog->campaign_id);
  2033.         if (empty($campaign)) {
  2034.             Yii::app()->end();
  2035.         }
  2036.  
  2037.         $subscriber = ListSubscriber::model()->findByAttributes(array(
  2038.             'list_id'          => $campaign->list_id,
  2039.             'subscriber_id'    => $deliveryLog->subscriber_id,
  2040.             'status'           => ListSubscriber::STATUS_CONFIRMED,
  2041.         ));
  2042.  
  2043.         if (empty($subscriber)) {
  2044.             Yii::app()->end();
  2045.         }
  2046.  
  2047.         if (in_array($event['event'], array('hard_bounce', 'soft_bounce', 'blocked', 'invalid_email'))) {
  2048.  
  2049.             $count = CampaignBounceLog::model()->countByAttributes(array(
  2050.                 'campaign_id'   => $campaign->campaign_id,
  2051.                 'subscriber_id' => $subscriber->subscriber_id,
  2052.             ));
  2053.  
  2054.             if (!empty($count)) {
  2055.                 Yii::app()->end();
  2056.             }
  2057.            
  2058.             $bounceLog = new CampaignBounceLog();
  2059.             $bounceLog->campaign_id     = $campaign->campaign_id;
  2060.             $bounceLog->subscriber_id   = $subscriber->subscriber_id;
  2061.             $bounceLog->message         = !empty($event['reason'])  ? $event['reason'] : 'BOUNCED BACK';
  2062.             $bounceLog->bounce_type     = $event['event'] == 'soft_bounce' ? CampaignBounceLog::BOUNCE_SOFT : CampaignBounceLog::BOUNCE_HARD;
  2063.             $bounceLog->save();
  2064.  
  2065.             if ($bounceLog->bounce_type == CampaignBounceLog::BOUNCE_HARD) {
  2066.                 $subscriber->addToBlacklist($bounceLog->message);
  2067.             }
  2068.  
  2069.             Yii::app()->end();
  2070.         }
  2071.  
  2072.         if (in_array($event['event'], array('spam', 'unsubscribe'))) {
  2073.  
  2074.             if ($event['event'] == 'spam' && Yii::app()->options->get('system.cron.process_feedback_loop_servers.subscriber_action', 'unsubscribe') == 'delete') {
  2075.                 $subscriber->delete();
  2076.                 Yii::app()->end();
  2077.             }
  2078.  
  2079.             $subscriber->saveStatus(ListSubscriber::STATUS_UNSUBSCRIBED);
  2080.            
  2081.             $count = CampaignTrackUnsubscribe::model()->countByAttributes(array(
  2082.                 'campaign_id'   => $campaign->campaign_id,
  2083.                 'subscriber_id' => $subscriber->subscriber_id,
  2084.             ));
  2085.  
  2086.             if (empty($count)) {
  2087.                 $trackUnsubscribe = new CampaignTrackUnsubscribe();
  2088.                 $trackUnsubscribe->campaign_id   = $campaign->campaign_id;
  2089.                 $trackUnsubscribe->subscriber_id = $subscriber->subscriber_id;
  2090.                 $trackUnsubscribe->note          = $event['event'] == 'spam' ? 'Abuse complaint!' : 'Unsubscribed via Web Hook!';
  2091.                 $trackUnsubscribe->ip_address    = Yii::app()->request->userHostAddress;
  2092.                 $trackUnsubscribe->user_agent    = StringHelper::truncateLength(Yii::app()->request->userAgent, 255);
  2093.                 $trackUnsubscribe->save(false);
  2094.             }
  2095.            
  2096.             // since 1.4.4 - complaints go into their own tables
  2097.             if ($event['event'] == 'spam') {
  2098.                
  2099.                 $count = CampaignComplainLog::model()->countByAttributes(array(
  2100.                     'campaign_id'   => $campaign->campaign_id,
  2101.                     'subscriber_id' => $subscriber->subscriber_id,
  2102.                 ));
  2103.  
  2104.                 if (empty($count)) {
  2105.                     $complaintLog = new CampaignComplainLog();
  2106.                     $complaintLog->campaign_id = $campaign->campaign_id;
  2107.                     $complaintLog->subscriber_id = $subscriber->subscriber_id;
  2108.                     $complaintLog->message = 'Abuse complaint via SendInBlue!';
  2109.                     $complaintLog->save(false);
  2110.                 }
  2111.             }
  2112.             //
  2113.            
  2114.             Yii::app()->end();
  2115.         }
  2116.  
  2117.         Yii::app()->end();
  2118.     }
  2119.  
  2120.     /**
  2121.      * Process Tipimail
  2122.      */
  2123.     public function processTipimail()
  2124.     {
  2125.         $event = file_get_contents("php://input");
  2126.         if (empty($event)) {
  2127.             Yii::app()->end();
  2128.         }
  2129.  
  2130.         $event = CJSON::decode($event);
  2131.  
  2132.         if (empty($event) || !is_array($event) || empty($event['status'])) {
  2133.             Yii::app()->end();
  2134.         }
  2135.        
  2136.         if (empty($event['meta']) || empty($event['meta']['campaign_uid']) || empty($event['meta']['subscriber_uid'])) {
  2137.             Yii::app()->end();
  2138.         }
  2139.        
  2140.         $campaign = Campaign::model()->findByAttributes(array(
  2141.             'campaign_uid' => $event['meta']['campaign_uid'],
  2142.         ));
  2143.        
  2144.         if (empty($campaign)) {
  2145.             Yii::app()->end();
  2146.         }
  2147.  
  2148.         $subscriber = ListSubscriber::model()->findByAttributes(array(
  2149.             'list_id'          => $campaign->list_id,
  2150.             'subscriber_uid'   => $event['meta']['subscriber_uid'],
  2151.             'status'           => ListSubscriber::STATUS_CONFIRMED,
  2152.         ));
  2153.  
  2154.         if (empty($subscriber)) {
  2155.             Yii::app()->end();
  2156.         }
  2157.        
  2158.         if (in_array($event['status'], array('error', 'rejected', 'hardbounced'))) {
  2159.  
  2160.             $count = CampaignBounceLog::model()->countByAttributes(array(
  2161.                 'campaign_id'   => $campaign->campaign_id,
  2162.                 'subscriber_id' => $subscriber->subscriber_id,
  2163.             ));
  2164.  
  2165.             if (!empty($count)) {
  2166.                 Yii::app()->end();
  2167.             }
  2168.            
  2169.             $bounceLog = new CampaignBounceLog();
  2170.             $bounceLog->campaign_id    = $campaign->campaign_id;
  2171.             $bounceLog->subscriber_id  = $subscriber->subscriber_id;
  2172.             $bounceLog->message        = !empty($event['description']) ? $event['description'] : 'BOUNCED BACK';
  2173.             $bounceLog->bounce_type    = CampaignBounceLog::BOUNCE_HARD;
  2174.             $bounceLog->save();
  2175.  
  2176.             $subscriber->addToBlacklist($bounceLog->message);
  2177.  
  2178.             Yii::app()->end();
  2179.         }
  2180.  
  2181.         if (in_array($event['status'], array('complaint', 'unsubscribed'))) {
  2182.  
  2183.             if ($event['status'] == 'complaint' && Yii::app()->options->get('system.cron.process_feedback_loop_servers.subscriber_action', 'unsubscribe') == 'delete') {
  2184.                 $subscriber->delete();
  2185.                 Yii::app()->end();
  2186.             }
  2187.  
  2188.             $subscriber->saveStatus(ListSubscriber::STATUS_UNSUBSCRIBED);
  2189.            
  2190.             $count = CampaignTrackUnsubscribe::model()->countByAttributes(array(
  2191.                 'campaign_id'   => $campaign->campaign_id,
  2192.                 'subscriber_id' => $subscriber->subscriber_id,
  2193.             ));
  2194.  
  2195.             if (empty($count)) {
  2196.                 $trackUnsubscribe = new CampaignTrackUnsubscribe();
  2197.                 $trackUnsubscribe->campaign_id   = $campaign->campaign_id;
  2198.                 $trackUnsubscribe->subscriber_id = $subscriber->subscriber_id;
  2199.                 $trackUnsubscribe->note          = $event['status'] == 'complaint' ? 'Abuse complaint!' : 'Unsubscribed via Web Hook!';
  2200.                 $trackUnsubscribe->ip_address    = Yii::app()->request->userHostAddress;
  2201.                 $trackUnsubscribe->user_agent    = StringHelper::truncateLength(Yii::app()->request->userAgent, 255);
  2202.                 $trackUnsubscribe->save(false);
  2203.             }
  2204.  
  2205.             // since 1.4.4 - complaints go into their own tables
  2206.             if ($event['status'] == 'complaint') {
  2207.                 $count = CampaignComplainLog::model()->countByAttributes(array(
  2208.                     'campaign_id'   => $campaign->campaign_id,
  2209.                     'subscriber_id' => $subscriber->subscriber_id,
  2210.                 ));
  2211.  
  2212.                 if (empty($count)) {
  2213.                     $complaintLog = new CampaignComplainLog();
  2214.                     $complaintLog->campaign_id = $campaign->campaign_id;
  2215.                     $complaintLog->subscriber_id = $subscriber->subscriber_id;
  2216.                     $complaintLog->message = 'Abuse complaint via TipiMail!';
  2217.                     $complaintLog->save(false);
  2218.                 }
  2219.             }
  2220.             //
  2221.            
  2222.             Yii::app()->end();
  2223.         }
  2224.  
  2225.         Yii::app()->end();
  2226.     }
  2227.  
  2228.     /**
  2229.      * Process Postmark
  2230.      */
  2231.     public function processPostmark()
  2232.     {
  2233.         $event = file_get_contents("php://input");
  2234.  
  2235.         if (empty($event)) {
  2236.             Yii::app()->end();
  2237.         }
  2238.  
  2239.         $event = json_decode($event, true);
  2240.  
  2241.         if (empty($event) || !is_array($event) || empty($event['MessageID'])) {
  2242.             Yii::app()->end();
  2243.         }
  2244.  
  2245.         $messageId = $event['MessageID'];
  2246.  
  2247.         $criteria = new CDbCriteria();
  2248.         $criteria->addCondition('`email_message_id` = :email_message_id AND `status` = :status');
  2249.         $criteria->params = [
  2250.             'email_message_id' => (string)$messageId,
  2251.             'status'           => CampaignDeliveryLog::STATUS_SUCCESS,
  2252.         ];
  2253.  
  2254.         $deliveryLog = CampaignDeliveryLog::model()->find($criteria);
  2255.         if (empty($deliveryLog)) {
  2256.             $deliveryLog = CampaignDeliveryLogArchive::model()->find($criteria);
  2257.         }
  2258.  
  2259.         if (empty($deliveryLog)) {
  2260.             Yii::app()->end();
  2261.         }
  2262.  
  2263.         /** @var Campaign $campaign */
  2264.         $campaign = Campaign::model()->findByPk($deliveryLog->campaign_id);
  2265.         if (empty($campaign)) {
  2266.             Yii::app()->end();
  2267.         }
  2268.  
  2269.         $subscriber = ListSubscriber::model()->findByAttributes([
  2270.             'list_id'          => $campaign->list_id,
  2271.             'subscriber_id'    => $deliveryLog->subscriber_id,
  2272.             'status'           => ListSubscriber::STATUS_CONFIRMED,
  2273.         ]);
  2274.  
  2275.         if (empty($subscriber)) {
  2276.             Yii::app()->end();
  2277.         }
  2278.  
  2279.         /* Please see the bounce types here: https://postmarkapp.com/developer/api/bounce-api#bounce-types */
  2280.         $bounceTypes = array(
  2281.             'HardBounce', 'SoftBounce', 'Blocked', 'BadEmailAddress', 'AutoResponder', 'DnsError', 'AddressChange',
  2282.             'ManuallyDeactivated', 'SMTPApiError', 'InboundError', 'DMARCPolicy'
  2283.         );
  2284.  
  2285.         if (in_array($event['Type'], $bounceTypes)) {
  2286.             $count = CampaignBounceLog::model()->countByAttributes([
  2287.                 'campaign_id'   => $campaign->campaign_id,
  2288.                 'subscriber_id' => $subscriber->subscriber_id,
  2289.             ]);
  2290.  
  2291.             if (!empty($count)) {
  2292.                 Yii::app()->end();
  2293.             }
  2294.  
  2295.             $message = 'BOUNCED BACK';
  2296.             if (!empty($event['Description'])) {
  2297.                 $message = $event['Description'];
  2298.             } elseif (!empty($event['Details'])) {
  2299.                 $message = $event['Details'];
  2300.             }
  2301.  
  2302.             $mapping = array(
  2303.                 CampaignBounceLog::BOUNCE_INTERNAL => array('Blocked', 'SMTPApiError', 'InboundError', 'DMARCPolicy'),
  2304.                 CampaignBounceLog::BOUNCE_HARD     => array('HardBounce', 'BadEmailAddress'),
  2305.                 CampaignBounceLog::BOUNCE_SOFT     => array('SoftBounce', 'AutoResponder', 'AddressChange', 'ManuallyDeactivated'),
  2306.             );
  2307.  
  2308.             $bounceType = CampaignBounceLog::BOUNCE_INTERNAL;
  2309.             foreach ($mapping as $bType => $bounces) {
  2310.                 if (in_array($event['Type'], $bounces)) {
  2311.                     $bounceType = $bType;
  2312.                     break;
  2313.                 }
  2314.             }
  2315.  
  2316.             $bounceLog = new CampaignBounceLog();
  2317.             $bounceLog->campaign_id     = $campaign->campaign_id;
  2318.             $bounceLog->subscriber_id   = $subscriber->subscriber_id;
  2319.             $bounceLog->message         = $message;
  2320.             $bounceLog->bounce_type     = $bounceType;
  2321.             $bounceLog->save();
  2322.  
  2323.             if ($bounceLog->bounce_type == CampaignBounceLog::BOUNCE_HARD) {
  2324.                 $subscriber->addToBlacklist($bounceLog->message);
  2325.             }
  2326.  
  2327.             Yii::app()->end();
  2328.         }
  2329.  
  2330.         if (in_array($event['Type'], array('SpamNotification', 'Unsubscribe'))) {
  2331.  
  2332.             if ($event['Type'] == 'SpamNotification' && Yii::app()->options->get('system.cron.process_feedback_loop_servers.subscriber_action', 'unsubscribe') == 'delete') {
  2333.                 $subscriber->delete();
  2334.                 Yii::app()->end();
  2335.             }
  2336.  
  2337.             $subscriber->saveStatus(ListSubscriber::STATUS_UNSUBSCRIBED);
  2338.  
  2339.             $count = CampaignTrackUnsubscribe::model()->countByAttributes(array(
  2340.                 'campaign_id'   => $campaign->campaign_id,
  2341.                 'subscriber_id' => $subscriber->subscriber_id,
  2342.             ));
  2343.  
  2344.             if (empty($count)) {
  2345.                 $trackUnsubscribe = new CampaignTrackUnsubscribe();
  2346.                 $trackUnsubscribe->campaign_id   = $campaign->campaign_id;
  2347.                 $trackUnsubscribe->subscriber_id = $subscriber->subscriber_id;
  2348.                 $trackUnsubscribe->note          = 'Unsubscribed via Web Hook!';
  2349.                 $trackUnsubscribe->ip_address    = Yii::app()->request->userHostAddress;
  2350.                 $trackUnsubscribe->user_agent    = StringHelper::truncateLength(Yii::app()->request->userAgent, 255);
  2351.                 $trackUnsubscribe->save(false);
  2352.             }
  2353.  
  2354.             // since 1.4.4 - complaints go into their own tables
  2355.             if ($event['Type'] == 'SpamNotification') {
  2356.  
  2357.                 $count = CampaignComplainLog::model()->countByAttributes(array(
  2358.                     'campaign_id'   => $campaign->campaign_id,
  2359.                     'subscriber_id' => $subscriber->subscriber_id,
  2360.                 ));
  2361.  
  2362.                 if (empty($count)) {
  2363.                     $complaintLog = new CampaignComplainLog();
  2364.                     $complaintLog->campaign_id   = $campaign->campaign_id;
  2365.                     $complaintLog->subscriber_id = $subscriber->subscriber_id;
  2366.                     $complaintLog->message       = 'Abuse complaint via PostMark!';
  2367.                     $complaintLog->save(false);
  2368.                 }
  2369.             }
  2370.  
  2371.             Yii::app()->end();
  2372.         }
  2373.  
  2374.         Yii::app()->end();
  2375.     }
  2376.  
  2377.     /**
  2378.      * @param string $message
  2379.      */
  2380.     public function end($message = "OK")
  2381.     {
  2382.         if ($message) {
  2383.             echo $message;
  2384.         }
  2385.         Yii::app()->end();
  2386.     }
  2387. }
Add Comment
Please, Sign In to add comment