<?php
class Bounced {
	var $requiredClasses=array(
		'DB',
		'pop3',
		'stat'
	);

	var $log='';
	var $debug=false;

        function Bounced() {
		$this->checkRequiredClasses();
        }

        function addLog($text, $is_date=true, $is_enter=true) {
                $text=($is_date ? date("d.m.y [H:i:s]> ") : "").$text.($is_enter ? "\n" : "");
                $this->log.=$text;
                if ($this->debug) print nl2br($text);
                return $text;
        }

	function checkRequiredClasses() {
		$error='';
		foreach ($this->requiredClasses as $key => $class) {
			if (!class_exists($class)) $error.="ERROR: Can't find class \"{$class}\"\n";
		}
		if ($error) die(nl2br($error));
	}

	function getMessageInfo($st) {
		$res=array();
		$res["X-Failed-Recipients"]=trim(ereg("\r\nX-Failed-Recipients:", $st));
		$res["Auto-Submitted"]=trim((ereg("\r\nAuto-Submitted:([^\r]*)\r\n", $st, $array) ? $array[1] : ""));
		$res["Delivery-date"]=trim((ereg("\r\nDelivery-date:([^\r]*)\r\n", $st, $array) ? $array[1] : ""));
		preg_match("/The following address\(es\) failed:\r\n\r\n([^\r]*)\r\n([^\r]*)\r\n/m", $st, $array);
		$res["mail"]=trim((isset($array[1]) ? trim($array[1]) : ""));
		$res["error"]=trim((isset($array[2]) ? trim($array[2]) : ""));
		$res["message_id"]='';
		preg_match_all('/Received: from/', $st, $array, PREG_OFFSET_CAPTURE);
		if (count($array[0])) {
			$pos=$array[0][count($array[0])-1][1];
			$s=substr($st, $pos);
			preg_match("/id ([^\r]*)/", $s, $array);
			if (isset($array[1])) $res["message_id"]=trim($array[1]);
		}
		return $res;
	}

        function check($POP3, $from=1, $count=0) {
		global $config, $db;
		$table_b='stat_bounced'.$config['table_prefix'];
		$table_s='subscribers'.$config['table_prefix'];
		$res=0;
		$type_list=array(
			'autoresponder',
			'campaign_schedule',
			'newsletters',
		);
		$bounced_status_list=array(	
			0	=> 'IGNORED',
			1	=> 'DEACTIVATED',
			2	=> 'DELETED',
			3	=> 'BLACKLISTED',
		);
		$stat=new stat("stat");
                $pop=new POP3();
		if ($pop->connect($POP3["login"], $POP3["password"], $POP3["host"], $POP3["port"])) {
			$i=$pop->getMessageCount();
			if ($from<1) $from=1;
			elseif ($from>$i) $from=$i;
			if (!$count) $count=($i-$from+1);
			if ($from+$count>$i+1) $count=$i-$from+1;
			for ($i=$from; $i<$from+$count; $i++) {
				$this->addLog("Checking message #{$i}", true, true);
				$message=$pop->getMessage($i);
				$messageInfo=$this->getMessageInfo($message);
				if ($messageInfo["X-Failed-Recipients"] or in_array($messageInfo["Auto-Submitted"], array('auto-generated', 'auto-replied'))) {
					$this->addLog("Mail delivery report found (Message ID={$messageInfo[message_id]})", true, true);
					$is_bounced=false;
					foreach ($type_list as $key => $type) {
						$table="msg_".$type.$config["table_prefix"];
						$t=($messageInfo["Delivery-date"] ? strtotime($messageInfo["Delivery-date"]) : time());
						if ($type=='newsletters') {
							$sql="select m.*
							from
								{$table} m
							where
								m.status=1 and
								m.message_id='{$messageInfo[message_id]}'";
						} else {
							$sql="select m.*, t.newsletter_id, t.owner_id".($type=="autoresponder" ? ", t.is_newsletter" : "")."
							from
								{$table} m,
								".substr($table, 4)." t
							where
								m.status=1 and
								m.task_id=t.id and
								m.message_id='{$messageInfo[message_id]}'";
						}
						list($data)=$db->select($sql);
						if (isset($data[0])) {
							$is_bounced=true;
							$this->addLog("[{$type}] id={$data[id]}", false, true);
							$data["log"].=$this->addLog("Mail delivery failed: ".$messageInfo["error"], true, true);
							$data["status"]=-1;
							$fields="log, status";
							$sql=get_sql_update($table, $fields, $data, "where id='{$data[id]}'");
							$db->execute($sql);

							$subcode=($type!='newsletters' ? ($type=="campaign_schedule" ? ".CAMPAIGN" : ".AUTORESPONDER") : '');
							$stat->update('NEWSLETTER['.$data['newsletter_id']."]{$subcode}.UNDELIVERED.ALL", 0);
							$stat->update('NEWSLETTER['.$data['newsletter_id']."]{$subcode}.UNDELIVERED", $data['date_created']);
							$sql="select * from {$table_s} where id='{$data[subscriber_id]}'";
							list($r)=$db->select($sql);
							if (isset($r['id'])) {
								$is_delete=false;
								$r['bounce_count']++;
								if ($r['bounce_count']>=$POP3["bounce_count"]) {
									$this->addLog('BOUNCED-USER-ID='.$r['id'], false, true);
									$code=$bounced_status_list[$POP3['bounce_type']];
									$is_delete=($POP3['bounce_type']==2);
									$r['status']=($POP3['bounce_type']==1 ? 0 : $POP3['bounce_type']);
									$stat->update('NEWSLETTER['.$data['newsletter_id']."].BOUNCED.ALL", 0);
									$stat->update('NEWSLETTER['.$data['newsletter_id']."].BOUNCED");
									// Inserting to LOG
									$fields='date_created, subscriber_id, newsletter_id, type';
									$_r=array(
										'date_created'	=> time(),
										'subscriber_id'	=> $r['id'],
										'newsletter_id'	=> $data['newsletter_id'],
										'type'		=> $POP3['bounce_type'],
									);
									$sql=get_sql_insert($table_b, $fields, $_r);
									$db->execute($sql);
								}
								if ($is_delete) $sql="delete from subscribers{$config[table_prefix]} where id='{$data[subscriber_id]}'";
								else $sql=get_sql_update('subscribers'.$config['table_prefix'], 'bounce_count, status', $r, "where id='{$data[subscriber_id]}'");
								$db->execute($sql);
							}
							$pop->del($i);
						} else {
							// This message not from list, skip this message
							$this->addLog("[{$type}] This message not from list, skip this message", false, true);
						}
	                        	}
					if ($is_bounced) $res++;
                		} else {
						// Not delivery-report, skip this message
						$this->addLog("Not delivery-report, skip this message", true, true);
				}
			}
			$pop->close();
		} else {
			// Error connecion
			$this->addLog("Error connection", true, true);
		}
		return $res;
        }

        function close($filename='') {
		if ($filename) {
			if ($f=fopen($filename, "a")) {
				fwrite($f, $this->log);
				fclose($f);
			} else die("Can't save in file \"$filename\"");
                }
        }
}
?>