XoopsModules25x /
xnewsletter
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
| 1 | <?php |
||
| 2 | /* class.phpmailer-bmh.php |
||
| 3 | .---------------------------------------------------------------------------. |
||
| 4 | | Software: PHPMailer-BMH (Bounce Mail Handler) | |
||
| 5 | | Version: 5.0.0rc1 | |
||
| 6 | | Contact: [email protected] | |
||
| 7 | | Info: http://phpmailer.codeworxtech.com | |
||
| 8 | | ------------------------------------------------------------------------- | |
||
| 9 | | Author: Andy Prevost [email protected] (admin) | |
||
| 10 | | Copyright (c) 2002-2009, Andy Prevost. All Rights Reserved. | |
||
| 11 | | ------------------------------------------------------------------------- | |
||
| 12 | | License: Distributed under the General Public License (GPL) | |
||
| 13 | | (http://www.gnu.org/licenses/gpl.html) | |
||
| 14 | | This program is distributed in the hope that it will be useful - WITHOUT | |
||
| 15 | | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
||
| 16 | | FITNESS FOR A PARTICULAR PURPOSE. | |
||
| 17 | | ------------------------------------------------------------------------- | |
||
| 18 | | This is a update of the original Bounce Mail Handler script | |
||
| 19 | | http://sourceforge.net/projects/bmh/ | |
||
| 20 | | The script has been renamed from Bounce Mail Handler to PHPMailer-BMH | |
||
| 21 | | ------------------------------------------------------------------------- | |
||
| 22 | | We offer a number of paid services: | |
||
| 23 | | - Web Hosting on highly optimized fast and secure servers | |
||
| 24 | | - Technology Consulting | |
||
| 25 | | - Oursourcing (highly qualified programmers and graphic designers) | |
||
| 26 | '---------------------------------------------------------------------------' |
||
| 27 | Last updated: January 21 2009 13:49 EST */ |
||
| 28 | |||
| 29 | /** |
||
| 30 | * PHPMailer-BMH (Bounce Mail Handler) |
||
| 31 | * |
||
| 32 | * PHPMailer-BMH is a PHP program to check your IMAP/POP3 inbox and |
||
| 33 | * delete all 'hard' bounced emails. It features a callback function where |
||
| 34 | * you can create a custom action. This provides you the ability to write |
||
| 35 | * a script to match your database records and either set inactive or |
||
| 36 | * delete records with email addresses that match the 'hard' bounce results. |
||
| 37 | * |
||
| 38 | * @package PHPMailer-BMH |
||
| 39 | * @author Andy Prevost |
||
| 40 | * @copyright 2008-2009, Andy Prevost |
||
| 41 | * @license GPL licensed |
||
| 42 | * @link http://sourceforge.net/projects/bmh |
||
| 43 | */ |
||
| 44 | require_once dirname(dirname(dirname(dirname(__DIR__)))) . '/mainfile.php'; |
||
| 45 | require_once XOOPS_ROOT_PATH . '/modules/xnewsletter/include/phpmailer_bmh/phpmailer-bmh_rules.php'; |
||
| 46 | |||
| 47 | define('VERBOSE_QUIET', 0); // means no output at all |
||
| 48 | define('VERBOSE_SIMPLE', 1); // means only output simple report |
||
| 49 | define('VERBOSE_REPORT', 2); // means output a detail report |
||
| 50 | define('VERBOSE_DEBUG', 3); // means output detail report as well as debug info. |
||
| 51 | |||
| 52 | /** |
||
| 53 | * Class BounceMailHandler |
||
| 54 | */ |
||
| 55 | class BounceMailHandler |
||
| 56 | { |
||
| 57 | ///////////////////////////////////////////////// |
||
| 58 | // PROPERTIES, PUBLIC |
||
| 59 | ///////////////////////////////////////////////// |
||
| 60 | |||
| 61 | /** |
||
| 62 | * Holds Bounce Mail Handler version. |
||
| 63 | * |
||
| 64 | * @var string |
||
| 65 | */ |
||
| 66 | public $Version = '5.0.0rc1 goffy'; |
||
| 67 | |||
| 68 | /** |
||
| 69 | * Holds result of last processing. |
||
| 70 | * |
||
| 71 | * @var array |
||
| 72 | */ |
||
| 73 | public $result_total = 0; |
||
| 74 | public $result_processed = 0; |
||
| 75 | public $result_unprocessed = 0; |
||
| 76 | public $result_deleted = 0; |
||
| 77 | public $result_moved = 0; |
||
| 78 | |||
| 79 | /** |
||
| 80 | * Mail server |
||
| 81 | * |
||
| 82 | * @var string |
||
| 83 | */ |
||
| 84 | public $mailhost = 'localhost'; |
||
| 85 | |||
| 86 | /** |
||
| 87 | * The username of mailbox |
||
| 88 | * |
||
| 89 | * @var string |
||
| 90 | */ |
||
| 91 | |||
| 92 | public $mailbox_username; |
||
| 93 | /** |
||
| 94 | * The password needed to access mailbox |
||
| 95 | * |
||
| 96 | * @var string |
||
| 97 | */ |
||
| 98 | public $mailbox_password; |
||
| 99 | |||
| 100 | /** |
||
| 101 | * The last error msg |
||
| 102 | * |
||
| 103 | * @var string |
||
| 104 | */ |
||
| 105 | public $error_msg; |
||
| 106 | |||
| 107 | /** |
||
| 108 | * Maximum limit messages processed in one batch |
||
| 109 | * |
||
| 110 | * @var int |
||
| 111 | */ |
||
| 112 | public $max_messages = 3000; |
||
| 113 | |||
| 114 | /** |
||
| 115 | * Callback Action function name |
||
| 116 | * the function that handles the bounce mail. Parameters: |
||
| 117 | * int $msgnum the message number returned by Bounce Mail Handler |
||
| 118 | * string $bounce_type the bounce type: 'antispam','autoreply','concurrent','content_reject','command_reject','internal_error','defer','delayed' => array('remove'=>0,'bounce_type'=>'temporary'),'dns_loop','dns_unknown','full','inactive','latin_only','other','oversize','outofoffice','unknown','unrecognized','user_reject','warning' |
||
| 119 | * string $email the target email address |
||
| 120 | * string $subject the subject, ignore now |
||
| 121 | * string $xheader the XBounceHeader from the mail |
||
| 122 | * 1 or 0 $remove delete status, 0 is not deleted, 1 is deleted |
||
| 123 | * string $rule_no bounce mail detect rule no. |
||
| 124 | * string $rule_cat bounce mail detect rule category |
||
| 125 | * int $totalFetched total number of messages in the mailbox |
||
| 126 | * |
||
| 127 | * @var string |
||
| 128 | */ |
||
| 129 | public $action_function = 'callbackAction'; |
||
| 130 | |||
| 131 | /** |
||
| 132 | * Internal variable |
||
| 133 | * The resource handler for the opened mailbox (POP3/IMAP/NNTP/etc.) |
||
| 134 | * |
||
| 135 | * @var object |
||
| 136 | */ |
||
| 137 | public $_mailbox_link = false; |
||
| 138 | |||
| 139 | /** |
||
| 140 | * Test mode, if true will not delete messages |
||
| 141 | * |
||
| 142 | * @var bool |
||
| 143 | */ |
||
| 144 | public $testmode = false; |
||
| 145 | |||
| 146 | /** |
||
| 147 | * Purge the unknown messages (or not) |
||
| 148 | * |
||
| 149 | * @var bool |
||
| 150 | */ |
||
| 151 | public $purge_unprocessed = false; |
||
| 152 | |||
| 153 | /** |
||
| 154 | * Control the debug output, default is VERBOSE_SIMPLE |
||
| 155 | * |
||
| 156 | * @var int |
||
| 157 | */ |
||
| 158 | public $verbose = VERBOSE_SIMPLE; |
||
| 159 | |||
| 160 | /** |
||
| 161 | * control the failed DSN rules output |
||
| 162 | * |
||
| 163 | * @var bool |
||
| 164 | */ |
||
| 165 | public $debug_dsn_rule = false; |
||
| 166 | |||
| 167 | /** |
||
| 168 | * control the failed BODY rules output |
||
| 169 | * |
||
| 170 | * @var bool |
||
| 171 | */ |
||
| 172 | public $debug_body_rule = false; |
||
| 173 | |||
| 174 | /** |
||
| 175 | * Control the method to process the mail header |
||
| 176 | * if set true, uses the imap_fetchstructure function |
||
| 177 | * otherwise, detect message type directly from headers, |
||
| 178 | * a bit faster than imap_fetchstructure function and take less resources. |
||
| 179 | * however - the difference is negligible |
||
| 180 | * |
||
| 181 | * @var bool |
||
| 182 | */ |
||
| 183 | public $use_fetchstructure = true; |
||
| 184 | |||
| 185 | /** |
||
| 186 | * If disable_delete is equal to true, it will disable the delete function |
||
| 187 | * |
||
| 188 | * @var bool |
||
| 189 | */ |
||
| 190 | public $disable_delete = false; |
||
| 191 | |||
| 192 | /* |
||
| 193 | * Defines new line ending |
||
| 194 | */ |
||
| 195 | public $bmh_newline = "<br>\n"; |
||
| 196 | |||
| 197 | /* |
||
| 198 | * Defines port number, default is '143', other common choices are '110' (pop3), '993' (gmail) |
||
| 199 | * @var integer |
||
| 200 | */ |
||
| 201 | public $port = 143; |
||
| 202 | |||
| 203 | /* |
||
| 204 | * Defines service, default is 'imap', choice includes 'pop3' |
||
| 205 | * @var string |
||
| 206 | */ |
||
| 207 | public $service = 'imap'; |
||
| 208 | |||
| 209 | /* |
||
| 210 | * Defines service option, default is 'notls', other choices are 'tls', 'ssl' |
||
| 211 | * @var string |
||
| 212 | */ |
||
| 213 | public $service_option = 'notls'; |
||
| 214 | |||
| 215 | /* |
||
| 216 | * Mailbox type, default is 'INBOX', other choices are (Tasks, Spam, Replies, etc.) |
||
| 217 | * @var string |
||
| 218 | */ |
||
| 219 | public $boxname = 'INBOX'; |
||
| 220 | |||
| 221 | /* |
||
| 222 | * Determines if soft bounces will be moved to another mailbox folder |
||
| 223 | * @var boolean |
||
| 224 | */ |
||
| 225 | public $moveSoft = false; |
||
| 226 | |||
| 227 | /* |
||
| 228 | * Mailbox folder to move soft bounces to, default is 'soft' |
||
| 229 | * @var string |
||
| 230 | */ |
||
| 231 | public $softMailbox = 'INBOX.soft'; |
||
| 232 | |||
| 233 | /* |
||
| 234 | * Determines if this mail should be moved to softMailbox |
||
| 235 | * @var boolean |
||
| 236 | */ |
||
| 237 | public $moveSoftFlag = false; |
||
| 238 | |||
| 239 | /* |
||
| 240 | * Determines if hard bounces will be moved to another mailbox folder |
||
| 241 | * NOTE: If true, this will disable delete and perform a move operation instead |
||
| 242 | * @var boolean |
||
| 243 | */ |
||
| 244 | public $moveHard = false; |
||
| 245 | |||
| 246 | /* |
||
| 247 | * Mailbox folder to move hard bounces to, default is 'hard' |
||
| 248 | * @var string |
||
| 249 | */ |
||
| 250 | public $hardMailbox = 'INBOX.hard'; |
||
| 251 | |||
| 252 | /* |
||
| 253 | * Determines if this mail should be moved to hardMailbox |
||
| 254 | * @var boolean |
||
| 255 | */ |
||
| 256 | public $moveHardFlag = false; |
||
| 257 | |||
| 258 | /* |
||
| 259 | * Deletes messages globally prior to date in variable |
||
| 260 | * NOTE: excludes any message folder that includes 'sent' in mailbox name |
||
| 261 | * format is same as MySQL: 'yyyy-mm-dd' |
||
| 262 | * if variable is blank, will not process global delete |
||
| 263 | * @var string |
||
| 264 | */ |
||
| 265 | public $deleteMsgDate = ''; |
||
| 266 | |||
| 267 | ///////////////////////////////////////////////// |
||
| 268 | // METHODS |
||
| 269 | ///////////////////////////////////////////////// |
||
| 270 | |||
| 271 | /** |
||
| 272 | * Output additional msg for debug |
||
| 273 | * |
||
| 274 | * @param bool|string $msg , if not given, output the last error msg |
||
| 275 | * @param int $verbose_level , the output level of this message |
||
| 276 | */ |
||
| 277 | public function output($msg = false, $verbose_level = VERBOSE_SIMPLE) |
||
| 278 | { |
||
| 279 | if ($this->verbose >= $verbose_level) { |
||
| 280 | if (empty($msg)) { |
||
| 281 | echo $this->error_msg . $this->bmh_newline; |
||
| 282 | } |
||
| 283 | //echo $msg . $this->bmh_newline; |
||
| 284 | } |
||
| 285 | } |
||
| 286 | |||
| 287 | /** |
||
| 288 | * Open a mail box |
||
| 289 | * |
||
| 290 | * @return bool |
||
| 291 | */ |
||
| 292 | public function openMailbox() |
||
| 293 | { |
||
| 294 | // before starting the processing, let's check the delete flag and do global deletes if true |
||
| 295 | if ('' != trim($this->deleteMsgDate)) { |
||
| 296 | //echo "processing global delete based on date of " . $this->deleteMsgDate . "<br>"; |
||
| 297 | //$this->globalDelete($nameRaw); |
||
| 298 | $this->globalDelete(); |
||
| 299 | } |
||
| 300 | // disable move operations if server is Gmail ... Gmail does not support mailbox creation |
||
| 301 | // if ( stristr($this->mailhost,'gmail') ) { |
||
| 302 | // $this->moveSoft = false; |
||
| 303 | // $this->moveHard = false; |
||
| 304 | // } |
||
| 305 | $port = $this->port . '/' . $this->service . '/' . $this->service_option; |
||
| 306 | set_time_limit(6000); |
||
| 307 | //echo "{".$this->mailhost.":".$port."}" . $this->boxname."<br>"; |
||
| 308 | if (!$this->testmode) { |
||
| 309 | $this->_mailbox_link = imap_open('{' . $this->mailhost . ':' . $port . '}' . $this->boxname, $this->mailbox_username, $this->mailbox_password, CL_EXPUNGE); |
||
| 310 | } else { |
||
| 311 | $this->_mailbox_link = imap_open('{' . $this->mailhost . ':' . $port . '}' . $this->boxname, $this->mailbox_username, $this->mailbox_password); |
||
| 312 | } |
||
| 313 | if (!$this->_mailbox_link) { |
||
| 314 | $this->error_msg = 'Cannot create ' . $this->service . ' connection to ' . $this->mailhost . $this->bmh_newline . 'Error MSG: ' . imap_last_error(); |
||
| 315 | $this->output(); |
||
| 316 | |||
| 317 | return false; |
||
| 318 | } |
||
| 319 | $this->output('Connected to: ' . $this->mailhost . ' (' . $this->mailbox_username . ')'); |
||
| 320 | |||
| 321 | return true; |
||
| 322 | } |
||
| 323 | |||
| 324 | /** |
||
| 325 | * Open a mail box in local file system |
||
| 326 | * |
||
| 327 | * @param string $file_path (The local mailbox file path) |
||
| 328 | * |
||
| 329 | * @return bool |
||
| 330 | */ |
||
| 331 | public function openLocal($file_path) |
||
| 332 | { |
||
| 333 | set_time_limit(6000); |
||
| 334 | if (!$this->testmode) { |
||
| 335 | $this->_mailbox_link = imap_open((string)$file_path, '', '', CL_EXPUNGE); |
||
| 336 | } else { |
||
| 337 | $this->_mailbox_link = imap_open((string)$file_path, '', ''); |
||
| 338 | } |
||
| 339 | if (!$this->_mailbox_link) { |
||
| 340 | $this->error_msg = 'Cannot open the mailbox file to ' . $file_path . $this->bmh_newline . 'Error MSG: ' . imap_last_error(); |
||
| 341 | $this->output(); |
||
| 342 | |||
| 343 | return false; |
||
| 344 | } |
||
| 345 | $this->output('Opened ' . $file_path); |
||
| 346 | |||
| 347 | return true; |
||
| 348 | } |
||
| 349 | |||
| 350 | /** |
||
| 351 | * Process the messages in a mailbox |
||
| 352 | * |
||
| 353 | * @param bool|string $max (maximum limit messages processed in one batch, if not given uses the property $max_messages |
||
| 354 | * |
||
| 355 | * @return bool |
||
| 356 | */ |
||
| 357 | public function processMailbox($max = false) |
||
| 358 | { |
||
| 359 | if (empty($this->action_function) || !function_exists($this->action_function)) { |
||
| 360 | $this->error_msg = 'Action function not found!'; |
||
| 361 | $this->output(); |
||
| 362 | |||
| 363 | return false; |
||
| 364 | } |
||
| 365 | |||
| 366 | if ($this->moveHard && (false === $this->disable_delete)) { |
||
| 367 | $this->disable_delete = true; |
||
| 368 | } |
||
| 369 | |||
| 370 | if (!empty($max)) { |
||
| 371 | $this->max_messages = $max; |
||
| 372 | } |
||
| 373 | |||
| 374 | // initialize counters |
||
| 375 | $c_total = imap_num_msg($this->_mailbox_link); |
||
| 376 | $c_fetched = $c_total; |
||
| 377 | $c_processed = 0; |
||
| 378 | $c_unprocessed = 0; |
||
| 379 | $c_deleted = 0; |
||
| 380 | $c_moved = 0; |
||
| 381 | $this->output('Total: ' . $c_total . ' messages '); |
||
| 382 | // proccess maximum number of messages |
||
| 383 | if ($c_fetched > $this->max_messages) { |
||
| 384 | $c_fetched = $this->max_messages; |
||
| 385 | $this->output('Processing first ' . $c_fetched . ' messages '); |
||
| 386 | } |
||
| 387 | |||
| 388 | if ($this->testmode) { |
||
| 389 | $this->output('Running in test mode, not deleting messages from mailbox<br>'); |
||
| 390 | } else { |
||
| 391 | if ($this->disable_delete) { |
||
| 392 | if ($this->moveHard) { |
||
| 393 | $this->output('Running in move mode<br>'); |
||
| 394 | } else { |
||
| 395 | $this->output('Running in disable_delete mode, not deleting messages from mailbox<br>'); |
||
| 396 | } |
||
| 397 | } else { |
||
| 398 | $this->output('Processed messages will be deleted from mailbox<br>'); |
||
| 399 | } |
||
| 400 | } |
||
| 401 | for ($x = 1; $x <= $c_fetched; ++$x) { |
||
| 402 | /* |
||
| 403 | $this->output( $x . ":",VERBOSE_REPORT); |
||
| 404 | if ($x % 10 == 0) { |
||
| 405 | $this->output( '.',VERBOSE_SIMPLE); |
||
| 406 | } |
||
| 407 | */ |
||
| 408 | // fetch the messages one at a time |
||
| 409 | if ($this->use_fetchstructure) { |
||
| 410 | $structure = imap_fetchstructure($this->_mailbox_link, $x); |
||
| 411 | if (1 == $structure->type |
||
| 412 | && $structure->ifsubtype |
||
| 413 | && 'REPORT' === $structure->subtype |
||
| 414 | && $structure->ifparameters |
||
| 415 | && $this->isParameter($structure->parameters, 'REPORT-TYPE', 'delivery-status')) { |
||
| 416 | $processed = $this->processBounce($x, 'DSN', $c_total); |
||
| 417 | View Code Duplication | } else { // not standard DSN msg |
|
| 418 | $this->output('Msg #' . $x . ' is not a standard DSN message', VERBOSE_REPORT); |
||
| 419 | if ($this->debug_body_rule) { |
||
| 420 | $this->output(" Content-Type : {$match[1]}", VERBOSE_DEBUG); |
||
| 421 | } |
||
| 422 | $processed = $this->processBounce($x, 'BODY', $c_total); |
||
| 423 | } |
||
| 424 | } else { |
||
| 425 | $header = imap_fetchheader($this->_mailbox_link, $x); |
||
| 426 | // Could be multi-line, if the new line begins with SPACE or HTAB |
||
| 427 | if (preg_match("/Content-Type:((?:[^\n]|\n[\t ])+)(?:\n[^\t ]|$)/is", $header, $match)) { |
||
| 428 | if (preg_match("/multipart\/report/is", $match[1]) |
||
| 429 | && preg_match("/report-type=[\"']?delivery-status[\"']?/is", $match[1])) { |
||
| 430 | // standard DSN msg |
||
| 431 | $processed = $this->processBounce($x, 'DSN', $c_total); |
||
| 432 | View Code Duplication | } else { // not standard DSN msg |
|
| 433 | $this->output('Msg #' . $x . ' is not a standard DSN message', VERBOSE_REPORT); |
||
| 434 | if ($this->debug_body_rule) { |
||
| 435 | $this->output(" Content-Type : {$match[1]}", VERBOSE_DEBUG); |
||
| 436 | } |
||
| 437 | $processed = $this->processBounce($x, 'BODY', $c_total); |
||
| 438 | } |
||
| 439 | } else { // didn't get content-type header |
||
| 440 | $this->output('Msg #' . $x . ' is not a well-formatted MIME mail, missing Content-Type', VERBOSE_REPORT); |
||
| 441 | if ($this->debug_body_rule) { |
||
| 442 | $this->output(' Headers: ' . $this->bmh_newline . $header . $this->bmh_newline, VERBOSE_DEBUG); |
||
| 443 | } |
||
| 444 | $processed = $this->processBounce($x, 'BODY', $c_total); |
||
| 445 | } |
||
| 446 | } |
||
| 447 | |||
| 448 | $deleteFlag[$x] = false; |
||
| 449 | $moveFlag[$x] = false; |
||
| 450 | if ($processed) { |
||
| 451 | ++$c_processed; |
||
| 452 | if ((false === $this->testmode) && (false === $this->disable_delete)) { |
||
| 453 | // delete the bounce if not in test mode and not in disable_delete mode |
||
| 454 | @imap_delete($this->_mailbox_link, $x); |
||
| 455 | $deleteFlag[$x] = true; |
||
| 456 | ++$c_deleted; |
||
| 457 | } elseif ($this->moveHard && $this->moveHardFlag) { |
||
| 458 | // check if the move directory exists, if not create it |
||
| 459 | $this->mailbox_exist($this->hardMailbox); |
||
| 460 | // move the message |
||
| 461 | @imap_mail_move($this->_mailbox_link, $x, $this->hardMailbox); |
||
| 462 | $moveFlag[$x] = true; |
||
| 463 | ++$c_moved; |
||
| 464 | } elseif ($this->moveSoft && $this->moveSoftFlag) { |
||
| 465 | // check if the move directory exists, if not create it |
||
| 466 | $this->mailbox_exist($this->softMailbox); |
||
| 467 | // move the message |
||
| 468 | @imap_mail_move($this->_mailbox_link, $x, $this->softMailbox); |
||
| 469 | $moveFlag[$x] = true; |
||
| 470 | ++$c_moved; |
||
| 471 | } |
||
| 472 | } else { // not processed |
||
| 473 | ++$c_unprocessed; |
||
| 474 | if (!$this->testmode && !$this->disable_delete && $this->purge_unprocessed) { |
||
| 475 | // delete this bounce if not in test mode, not in disable_delete mode, and the flag BOUNCE_PURGE_UNPROCESSED is set |
||
| 476 | @imap_delete($this->_mailbox_link, $x); |
||
| 477 | $deleteFlag[$x] = true; |
||
| 478 | ++$c_deleted; |
||
| 479 | } |
||
| 480 | } |
||
| 481 | flush(); |
||
| 482 | } |
||
| 483 | $this->output($this->bmh_newline . 'Closing mailbox, and purging messages'); |
||
| 484 | imap_close($this->_mailbox_link); |
||
| 485 | $this->output('Read: ' . $c_fetched . ' messages'); |
||
| 486 | $this->output($c_processed . ' action taken'); |
||
| 487 | $this->output($c_unprocessed . ' no action taken'); |
||
| 488 | $this->output($c_deleted . ' messages deleted'); |
||
| 489 | $this->output($c_moved . ' messages moved'); |
||
| 490 | |||
| 491 | $this->result_total = $c_fetched; |
||
| 492 | $this->result_processed = $c_processed; |
||
| 493 | $this->result_unprocessed = $c_unprocessed; |
||
| 494 | $this->result_deleted = $c_deleted; |
||
| 495 | $this->result_moved = $c_moved; |
||
| 496 | |||
| 497 | return true; |
||
| 498 | } |
||
| 499 | |||
| 500 | /** |
||
| 501 | * Function to determine if a particular value is found in a imap_fetchstructure key |
||
| 502 | * |
||
| 503 | * @param array $currParameters (imap_fetstructure parameters) |
||
| 504 | * @param string $varKey (imap_fetstructure key) |
||
| 505 | * @param string $varValue (value to check for) |
||
| 506 | * |
||
| 507 | * @return bool |
||
| 508 | */ |
||
| 509 | public function isParameter($currParameters, $varKey, $varValue) |
||
| 510 | { |
||
| 511 | foreach ($currParameters as $key => $value) { |
||
| 512 | if ($key == $varKey) { |
||
| 513 | if ($value == $varValue) { |
||
| 514 | return true; |
||
| 515 | } |
||
| 516 | } |
||
| 517 | } |
||
| 518 | |||
| 519 | return false; |
||
| 520 | } |
||
| 521 | |||
| 522 | /** |
||
| 523 | * Function to process each individual message |
||
| 524 | * |
||
| 525 | * @param int $pos (message number) |
||
| 526 | * @param string $type (DNS or BODY type) |
||
| 527 | * @param string $totalFetched (total number of messages in mailbox) |
||
| 528 | * |
||
| 529 | * @return bool |
||
| 530 | */ |
||
| 531 | public function processBounce($pos, $type, $totalFetched) |
||
| 532 | { |
||
| 533 | $header = imap_headerinfo($this->_mailbox_link, $pos); |
||
| 534 | $subject = strip_tags($header->subject); |
||
| 535 | if ('DSN' === $type) { |
||
| 536 | // first part of DSN (Delivery Status Notification), human-readable explanation |
||
| 537 | $dsn_msg = imap_fetchbody($this->_mailbox_link, $pos, '1'); |
||
| 538 | $dsn_msg_structure = imap_bodystruct($this->_mailbox_link, $pos, '1'); |
||
| 539 | |||
| 540 | View Code Duplication | if (4 == $dsn_msg_structure->encoding) { |
|
|
0 ignored issues
–
show
|
|||
| 541 | $dsn_msg = quoted_printable_decode($dsn_msg); |
||
| 542 | } elseif (3 == $dsn_msg_structure->encoding) { |
||
| 543 | $dsn_msg = base64_decode($dsn_msg, true); |
||
| 544 | } |
||
| 545 | |||
| 546 | // second part of DSN (Delivery Status Notification), delivery-status |
||
| 547 | $dsn_report = imap_fetchbody($this->_mailbox_link, $pos, '2'); |
||
| 548 | |||
| 549 | // process bounces by rules |
||
| 550 | $result = bmhDSNRules($dsn_msg, $dsn_report, $this->debug_dsn_rule); |
||
| 551 | } elseif ('BODY' === $type) { |
||
| 552 | $structure = imap_fetchstructure($this->_mailbox_link, $pos); |
||
| 553 | switch ($structure->type) { |
||
| 554 | case 0: // Content-type = text |
||
| 555 | case 1: // Content-type = multipart |
||
| 556 | $body = imap_fetchbody($this->_mailbox_link, $pos, '1'); |
||
| 557 | // Detect encoding and decode - only base64 |
||
| 558 | if (4 == $structure->parts[0]->encoding) { |
||
| 559 | $body = quoted_printable_decode($body); |
||
| 560 | } elseif (3 == $structure->parts[0]->encoding) { |
||
| 561 | $body = base64_decode($body, true); |
||
| 562 | } |
||
| 563 | $result = bmhBodyRules($body, $structure, $this->debug_body_rule); |
||
| 564 | break; |
||
| 565 | case 2: // Content-type = message |
||
| 566 | $body = imap_body($this->_mailbox_link, $pos); |
||
| 567 | View Code Duplication | if (4 == $structure->encoding) { |
|
|
0 ignored issues
–
show
This code seems to be duplicated across your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. Loading history...
|
|||
| 568 | $body = quoted_printable_decode($body); |
||
| 569 | } elseif (3 == $structure->encoding) { |
||
| 570 | $body = base64_decode($body, true); |
||
| 571 | } |
||
| 572 | $body = mb_substr($body, 0, 1000); |
||
| 573 | $result = bmhBodyRules($body, $structure, $this->debug_body_rule); |
||
| 574 | break; |
||
| 575 | default: // unsupport Content-type |
||
| 576 | $this->output('Msg #' . $pos . ' is unsupported Content-Type:' . $structure->type, VERBOSE_REPORT); |
||
| 577 | |||
| 578 | return false; |
||
| 579 | } |
||
| 580 | } else { // internal error |
||
| 581 | $this->error_msg = 'Internal Error: unknown type'; |
||
| 582 | |||
| 583 | return false; |
||
| 584 | } |
||
| 585 | $email = $result['email']; |
||
| 586 | $bounce_type = $result['bounce_type']; |
||
| 587 | $this->moveHardFlag = false; |
||
| 588 | $this->moveSoftFlag = false; |
||
| 589 | if ($this->moveHard && 1 == $result['remove']) { |
||
| 590 | $remove = 'moved (hard)'; |
||
| 591 | $this->moveHardFlag = true; |
||
| 592 | } elseif ($this->moveSoft && 2 == $result['remove']) { |
||
| 593 | $remove = 'moved (soft)'; |
||
| 594 | $this->moveSoftFlag = true; |
||
| 595 | } elseif ($this->disable_delete) { |
||
| 596 | $remove = 0; |
||
| 597 | } else { |
||
| 598 | $remove = $result['remove']; |
||
| 599 | } |
||
| 600 | $rule_no = $result['rule_no']; |
||
| 601 | $rule_cat = $result['rule_cat']; |
||
| 602 | $xheader = false; |
||
| 603 | |||
| 604 | if ('0000' == $rule_no) { // internal error return false; |
||
| 605 | // code below will use the Callback function, but return no value |
||
| 606 | if ('' == trim($email)) { |
||
| 607 | $email = $header->fromaddress; |
||
| 608 | } |
||
| 609 | $params = [ |
||
| 610 | $pos, |
||
| 611 | $bounce_type, |
||
| 612 | $email, |
||
| 613 | $subject, |
||
| 614 | $xheader, |
||
| 615 | $remove, |
||
| 616 | $rule_no, |
||
| 617 | $rule_cat, |
||
| 618 | $totalFetched, |
||
| 619 | ]; |
||
| 620 | call_user_func_array($this->action_function, $params); |
||
| 621 | } else { // match rule, do bounce action |
||
| 622 | if ($this->testmode) { |
||
| 623 | $this->output('Match: ' . $rule_no . ':' . $rule_cat . '; ' . $bounce_type . '; ' . $email); |
||
| 624 | |||
| 625 | return true; |
||
| 626 | } |
||
| 627 | $params = [ |
||
| 628 | $pos, |
||
| 629 | $bounce_type, |
||
| 630 | $email, |
||
| 631 | $subject, |
||
| 632 | $xheader, |
||
| 633 | $remove, |
||
| 634 | $rule_no, |
||
| 635 | $rule_cat, |
||
| 636 | $totalFetched, |
||
| 637 | ]; |
||
| 638 | |||
| 639 | return call_user_func_array($this->action_function, $params); |
||
| 640 | } |
||
| 641 | |||
| 642 | return null; |
||
| 643 | } |
||
| 644 | |||
| 645 | /** |
||
| 646 | * Function to check if a mailbox exists |
||
| 647 | * - if not found, it will create it |
||
| 648 | * |
||
| 649 | * @param string $mailbox (the mailbox name, must be in 'INBOX.checkmailbox' format) |
||
| 650 | * @param bool $create (whether or not to create the checkmailbox if not found, defaults to true) |
||
| 651 | * |
||
| 652 | * @return null|bool |
||
| 653 | */ |
||
| 654 | public function mailbox_exist($mailbox, $create = true) |
||
| 655 | { |
||
| 656 | if ('' == trim($mailbox) || false === mb_strpos($mailbox, 'INBOX.')) { |
||
| 657 | // this is a critical error with either the mailbox name blank or an invalid mailbox name |
||
| 658 | // need to stop processing and exit at this point |
||
| 659 | echo "Invalid mailbox name for move operation. Cannot continue.<br>\n"; |
||
| 660 | echo "TIP: the mailbox you want to move the message to must include 'INBOX.' at the start.<br>\n"; |
||
| 661 | exit(); |
||
| 662 | } |
||
| 663 | $port = $this->port . '/' . $this->service . '/' . $this->service_option; |
||
| 664 | $mbox = imap_open('{' . $this->mailhost . ':' . $port . '}', $this->mailbox_username, $this->mailbox_password, OP_HALFOPEN); |
||
| 665 | $list = imap_getmailboxes($mbox, '{' . $this->mailhost . ':' . $port . '}', '*'); |
||
| 666 | $mailboxFound = false; |
||
| 667 | if (is_array($list)) { |
||
| 668 | foreach ($list as $key => $val) { |
||
| 669 | // get the mailbox name only |
||
| 670 | $nameArr = explode('}', imap_utf7_decode($val->name)); |
||
| 671 | $nameRaw = $nameArr[count($nameArr) - 1]; |
||
| 672 | if ($mailbox == $nameRaw) { |
||
| 673 | $mailboxFound = true; |
||
| 674 | } |
||
| 675 | } |
||
| 676 | if ((false === $mailboxFound) && $create) { |
||
| 677 | @imap_createmailbox($mbox, imap_utf7_encode('{' . $this->mailhost . ':' . $port . '}' . $mailbox)); |
||
| 678 | imap_close($mbox); |
||
| 679 | |||
| 680 | return true; |
||
| 681 | } |
||
| 682 | imap_close($mbox); |
||
| 683 | |||
| 684 | return false; |
||
| 685 | } |
||
| 686 | imap_close($mbox); |
||
| 687 | |||
| 688 | return false; |
||
| 689 | } |
||
| 690 | |||
| 691 | /** |
||
| 692 | * Function to delete messages in a mailbox, based on date |
||
| 693 | * NOTE: this is global ... will affect all mailboxes except any that have 'sent' in the mailbox name |
||
| 694 | * |
||
| 695 | * @internal param string $mailbox (the mailbox name) |
||
| 696 | */ |
||
| 697 | public function globalDelete() |
||
| 698 | { |
||
| 699 | $dateArr = explode('-', $this->deleteMsgDate); // date format is yyyy-mm-dd |
||
| 700 | $delDate = mktime(0, 0, 0, $dateArr[1], $dateArr[2], $dateArr[0]); |
||
| 701 | |||
| 702 | $port = $this->port . '/' . $this->service . '/' . $this->service_option; |
||
| 703 | $mboxt = imap_open('{' . $this->mailhost . ':' . $port . '}', $this->mailbox_username, $this->mailbox_password, OP_HALFOPEN); |
||
| 704 | $list = imap_getmailboxes($mboxt, '{' . $this->mailhost . ':' . $port . '}', '*'); |
||
| 705 | $mailboxFound = false; |
||
| 706 | if (is_array($list)) { |
||
| 707 | foreach ($list as $key => $val) { |
||
| 708 | // get the mailbox name only |
||
| 709 | $nameArr = explode('}', imap_utf7_decode($val->name)); |
||
| 710 | $nameRaw = $nameArr[count($nameArr) - 1]; |
||
| 711 | if (false === mb_stripos($nameRaw, 'sent')) { |
||
| 712 | $mboxd = imap_open('{' . $this->mailhost . ':' . $port . '}' . $nameRaw, $this->mailbox_username, $this->mailbox_password, CL_EXPUNGE); |
||
| 713 | $messages = imap_sort($mboxd, SORTDATE, 0); |
||
| 714 | $i = 0; |
||
| 715 | $check = imap_mailboxmsginfo($mboxd); |
||
| 716 | foreach ($messages as $message) { |
||
| 717 | $header = imap_headerinfo($mboxd, $message); |
||
| 718 | $fdate = date('F j, Y', $header->udate); |
||
| 719 | // purge if prior to global delete date |
||
| 720 | if ($header->udate < $delDate) { |
||
| 721 | imap_delete($mboxd, $message); |
||
| 722 | } |
||
| 723 | ++$i; |
||
| 724 | } |
||
| 725 | imap_expunge($mboxd); |
||
| 726 | imap_close($mboxd); |
||
| 727 | } |
||
| 728 | } |
||
| 729 | } |
||
| 730 | } |
||
| 731 | } |
||
| 732 |
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.