Changeset 8762
- Timestamp:
- 08/28/2008 08:26:36 PM (16 years ago)
- Location:
- trunk/wp-includes
- Files:
-
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/wp-includes/class-phpmailer.php
r8082 r8762 1 1 <?php 2 /** 3 * PHPMailer - PHP email class 4 * 5 * Class for sending email using either sendmail, PHP mail(), or SMTP. Methods 6 * are based upon the standard AspEmail(tm) classes. 7 * 8 * @copyright 2001 - 2003 Brent R. Matzelle 9 * @license LGPL 10 * @package PHPMailer 11 */ 2 /*~ class.phpmailer.php 3 .---------------------------------------------------------------------------. 4 | Software: PHPMailer - PHP email class | 5 | Version: 2.0.2 | 6 | Contact: via sourceforge.net support pages (also www.codeworxtech.com) | 7 | Info: http://phpmailer.sourceforge.net | 8 | Support: http://sourceforge.net/projects/phpmailer/ | 9 | ------------------------------------------------------------------------- | 10 | Author: Andy Prevost (project admininistrator) | 11 | Author: Brent R. Matzelle (original founder) | 12 | Copyright (c) 2004-2007, Andy Prevost. All Rights Reserved. | 13 | Copyright (c) 2001-2003, Brent R. Matzelle | 14 | ------------------------------------------------------------------------- | 15 | License: Distributed under the Lesser General Public License (LGPL) | 16 | http://www.gnu.org/copyleft/lesser.html | 17 | This program is distributed in the hope that it will be useful - WITHOUT | 18 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | 19 | FITNESS FOR A PARTICULAR PURPOSE. | 20 | ------------------------------------------------------------------------- | 21 | We offer a number of paid services (www.codeworxtech.com): | 22 | - Web Hosting on highly optimized fast and secure servers | 23 | - Technology Consulting | 24 | - Oursourcing (highly qualified programmers and graphic designers) | 25 '---------------------------------------------------------------------------' 12 26 13 27 /** 14 28 * PHPMailer - PHP email transport class 15 29 * @package PHPMailer 16 * @author Brent R. Matzelle17 * @copyright 200 1 - 2003 Brent R. Matzelle30 * @author Andy Prevost 31 * @copyright 2004 - 2008 Andy Prevost 18 32 */ 19 class PHPMailer 20 { 21 ///////////////////////////////////////////////// 22 // PUBLIC VARIABLES 23 ///////////////////////////////////////////////// 24 25 /** 26 * Email priority (1 = High, 3 = Normal, 5 = low). 27 * @var int 28 */ 29 var $Priority = 3; 30 31 /** 32 * Sets the CharSet of the message. 33 * @var string 34 */ 35 var $CharSet = "UTF-8"; 36 37 /** 38 * Sets the Content-type of the message. 39 * @var string 40 */ 41 var $ContentType = "text/plain"; 42 43 /** 44 * Sets the Encoding of the message. Options for this are "8bit", 45 * "7bit", "binary", "base64", and "quoted-printable". 46 * @var string 47 */ 48 var $Encoding = "8bit"; 49 50 /** 51 * Holds the most recent mailer error message. 52 * @var string 53 */ 54 var $ErrorInfo = ""; 55 56 /** 57 * Sets the From email address for the message. 58 * @var string 59 */ 60 var $From = "localhost.localdomain"; 61 62 /** 63 * Sets the From name of the message. 64 * @var string 65 */ 66 var $FromName = "Support"; 67 68 /** 69 * Sets the Sender email (Return-Path) of the message. If not empty, 70 * will be sent via -f to sendmail or as 'MAIL FROM' in smtp mode. 71 * @var string 72 */ 73 var $Sender = ""; 74 75 /** 76 * Sets the Subject of the message. 77 * @var string 78 */ 79 var $Subject = ""; 80 81 /** 82 * Sets the Body of the message. This can be either an HTML or text body. 83 * If HTML then run IsHTML(true). 84 * @var string 85 */ 86 var $Body = ""; 87 88 /** 89 * Sets the text-only body of the message. This automatically sets the 90 * email to multipart/alternative. This body can be read by mail 91 * clients that do not have HTML email capability such as mutt. Clients 92 * that can read HTML will view the normal Body. 93 * @var string 94 */ 95 var $AltBody = ""; 96 97 /** 98 * Sets word wrapping on the body of the message to a given number of 99 * characters. 100 * @var int 101 */ 102 var $WordWrap = 0; 103 104 /** 105 * Method to send mail: ("mail", "sendmail", or "smtp"). 106 * @var string 107 */ 108 var $Mailer = "mail"; 109 110 /** 111 * Sets the path of the sendmail program. 112 * @var string 113 */ 114 var $Sendmail = "/usr/sbin/sendmail"; 115 116 /** 117 * Path to PHPMailer plugins. This is now only useful if the SMTP class 118 * is in a different directory than the PHP include path. 119 * @var string 120 */ 121 var $PluginDir = ""; 122 123 /** 124 * Holds PHPMailer version. 125 * @var string 126 */ 127 var $Version = "1.73"; 128 129 /** 130 * Sets the email address that a reading confirmation will be sent. 131 * @var string 132 */ 133 var $ConfirmReadingTo = ""; 134 135 /** 136 * Sets the hostname to use in Message-Id and Received headers 137 * and as default HELO string. If empty, the value returned 138 * by SERVER_NAME is used or 'localhost.localdomain'. 139 * @var string 140 */ 141 var $Hostname = ""; 142 143 ///////////////////////////////////////////////// 144 // SMTP VARIABLES 145 ///////////////////////////////////////////////// 146 147 /** 148 * Sets the SMTP hosts. All hosts must be separated by a 149 * semicolon. You can also specify a different port 150 * for each host by using this format: [hostname:port] 151 * (e.g. "smtp1.example.com:25;smtp2.example.com"). 152 * Hosts will be tried in order. 153 * @var string 154 */ 155 var $Host = "localhost"; 156 157 /** 158 * Sets the default SMTP server port. 159 * @var int 160 */ 161 var $Port = 25; 162 163 /** 164 * Sets the SMTP HELO of the message (Default is $Hostname). 165 * @var string 166 */ 167 var $Helo = ""; 168 169 /** 170 * Sets SMTP authentication. Utilizes the Username and Password variables. 171 * @var bool 172 */ 173 var $SMTPAuth = false; 174 175 /** 176 * Sets SMTP username. 177 * @var string 178 */ 179 var $Username = ""; 180 181 /** 182 * Sets SMTP password. 183 * @var string 184 */ 185 var $Password = ""; 186 187 /** 188 * Sets the SMTP server timeout in seconds. This function will not 189 * work with the win32 version. 190 * @var int 191 */ 192 var $Timeout = 10; 193 194 /** 195 * Sets SMTP class debugging on or off. 196 * @var bool 197 */ 198 var $SMTPDebug = false; 199 200 /** 201 * Prevents the SMTP connection from being closed after each mail 202 * sending. If this is set to true then to close the connection 203 * requires an explicit call to SmtpClose(). 204 * @var bool 205 */ 206 var $SMTPKeepAlive = false; 207 208 /**#@+ 209 * @access private 210 */ 211 var $smtp = NULL; 212 var $to = array(); 213 var $cc = array(); 214 var $bcc = array(); 215 var $ReplyTo = array(); 216 var $attachment = array(); 217 var $CustomHeader = array(); 218 var $message_type = ""; 219 var $boundary = array(); 220 var $language = array(); 221 var $error_count = 0; 222 var $LE = "\n"; 223 /**#@-*/ 224 225 ///////////////////////////////////////////////// 226 // VARIABLE METHODS 227 ///////////////////////////////////////////////// 228 229 /** 230 * Sets message type to HTML. 231 * @param bool $bool 232 * @return void 233 */ 234 function IsHTML($bool) { 235 if($bool == true) 236 $this->ContentType = "text/html"; 237 else 238 $this->ContentType = "text/plain"; 239 } 240 241 /** 242 * Sets Mailer to send message using SMTP. 243 * @return void 244 */ 245 function IsSMTP() { 246 $this->Mailer = "smtp"; 247 } 248 249 /** 250 * Sets Mailer to send message using PHP mail() function. 251 * @return void 252 */ 253 function IsMail() { 254 $this->Mailer = "mail"; 255 } 256 257 /** 258 * Sets Mailer to send message using the $Sendmail program. 259 * @return void 260 */ 261 function IsSendmail() { 262 $this->Mailer = "sendmail"; 263 } 264 265 /** 266 * Sets Mailer to send message using the qmail MTA. 267 * @return void 268 */ 269 function IsQmail() { 270 $this->Sendmail = "/var/qmail/bin/sendmail"; 271 $this->Mailer = "sendmail"; 272 } 273 274 275 ///////////////////////////////////////////////// 276 // RECIPIENT METHODS 277 ///////////////////////////////////////////////// 278 279 /** 280 * Adds a "To" address. 281 * @param string $address 282 * @param string $name 283 * @return void 284 */ 285 function AddAddress($address, $name = "") { 286 $cur = count($this->to); 287 $this->to[$cur][0] = trim($address); 288 $this->to[$cur][1] = $name; 289 } 290 291 /** 292 * Adds a "Cc" address. Note: this function works 293 * with the SMTP mailer on win32, not with the "mail" 294 * mailer. 295 * @param string $address 296 * @param string $name 297 * @return void 298 */ 299 function AddCC($address, $name = "") { 300 $cur = count($this->cc); 301 $this->cc[$cur][0] = trim($address); 302 $this->cc[$cur][1] = $name; 303 } 304 305 /** 306 * Adds a "Bcc" address. Note: this function works 307 * with the SMTP mailer on win32, not with the "mail" 308 * mailer. 309 * @param string $address 310 * @param string $name 311 * @return void 312 */ 313 function AddBCC($address, $name = "") { 314 $cur = count($this->bcc); 315 $this->bcc[$cur][0] = trim($address); 316 $this->bcc[$cur][1] = $name; 317 } 318 319 /** 320 * Adds a "Reply-to" address. 321 * @param string $address 322 * @param string $name 323 * @return void 324 */ 325 function AddReplyTo($address, $name = "") { 326 $cur = count($this->ReplyTo); 327 $this->ReplyTo[$cur][0] = trim($address); 328 $this->ReplyTo[$cur][1] = $name; 329 } 330 331 332 ///////////////////////////////////////////////// 333 // MAIL SENDING METHODS 334 ///////////////////////////////////////////////// 335 336 /** 337 * Creates message and assigns Mailer. If the message is 338 * not sent successfully then it returns false. Use the ErrorInfo 339 * variable to view description of the error. 340 * @return bool 341 */ 342 function Send() { 343 $header = ""; 344 $body = ""; 345 $result = true; 346 347 if((count($this->to) + count($this->cc) + count($this->bcc)) < 1) 348 { 349 $this->SetError($this->Lang("provide_address")); 350 return false; 33 34 class PHPMailer { 35 36 ///////////////////////////////////////////////// 37 // PROPERTIES, PUBLIC 38 ///////////////////////////////////////////////// 39 40 /** 41 * Email priority (1 = High, 3 = Normal, 5 = low). 42 * @var int 43 */ 44 var $Priority = 3; 45 46 /** 47 * Sets the CharSet of the message. 48 * @var string 49 */ 50 var $CharSet = 'iso-8859-1'; 51 52 /** 53 * Sets the Content-type of the message. 54 * @var string 55 */ 56 var $ContentType = 'text/plain'; 57 58 /** 59 * Sets the Encoding of the message. Options for this are "8bit", 60 * "7bit", "binary", "base64", and "quoted-printable". 61 * @var string 62 */ 63 var $Encoding = '8bit'; 64 65 /** 66 * Holds the most recent mailer error message. 67 * @var string 68 */ 69 var $ErrorInfo = ''; 70 71 /** 72 * Sets the From email address for the message. 73 * @var string 74 */ 75 var $From = 'root@localhost'; 76 77 /** 78 * Sets the From name of the message. 79 * @var string 80 */ 81 var $FromName = 'Root User'; 82 83 /** 84 * Sets the Sender email (Return-Path) of the message. If not empty, 85 * will be sent via -f to sendmail or as 'MAIL FROM' in smtp mode. 86 * @var string 87 */ 88 var $Sender = ''; 89 90 /** 91 * Sets the Subject of the message. 92 * @var string 93 */ 94 var $Subject = ''; 95 96 /** 97 * Sets the Body of the message. This can be either an HTML or text body. 98 * If HTML then run IsHTML(true). 99 * @var string 100 */ 101 var $Body = ''; 102 103 /** 104 * Sets the text-only body of the message. This automatically sets the 105 * email to multipart/alternative. This body can be read by mail 106 * clients that do not have HTML email capability such as mutt. Clients 107 * that can read HTML will view the normal Body. 108 * @var string 109 */ 110 var $AltBody = ''; 111 112 /** 113 * Sets word wrapping on the body of the message to a given number of 114 * characters. 115 * @var int 116 */ 117 var $WordWrap = 0; 118 119 /** 120 * Method to send mail: ("mail", "sendmail", or "smtp"). 121 * @var string 122 */ 123 var $Mailer = 'mail'; 124 125 /** 126 * Sets the path of the sendmail program. 127 * @var string 128 */ 129 var $Sendmail = '/usr/sbin/sendmail'; 130 131 /** 132 * Path to PHPMailer plugins. This is now only useful if the SMTP class 133 * is in a different directory than the PHP include path. 134 * @var string 135 */ 136 var $PluginDir = ''; 137 138 /** 139 * Holds PHPMailer version. 140 * @var string 141 */ 142 var $Version = "2.0.2"; 143 144 /** 145 * Sets the email address that a reading confirmation will be sent. 146 * @var string 147 */ 148 var $ConfirmReadingTo = ''; 149 150 /** 151 * Sets the hostname to use in Message-Id and Received headers 152 * and as default HELO string. If empty, the value returned 153 * by SERVER_NAME is used or 'localhost.localdomain'. 154 * @var string 155 */ 156 var $Hostname = ''; 157 158 /** 159 * Sets the message ID to be used in the Message-Id header. 160 * If empty, a unique id will be generated. 161 * @var string 162 */ 163 var $MessageID = ''; 164 165 ///////////////////////////////////////////////// 166 // PROPERTIES FOR SMTP 167 ///////////////////////////////////////////////// 168 169 /** 170 * Sets the SMTP hosts. All hosts must be separated by a 171 * semicolon. You can also specify a different port 172 * for each host by using this format: [hostname:port] 173 * (e.g. "smtp1.example.com:25;smtp2.example.com"). 174 * Hosts will be tried in order. 175 * @var string 176 */ 177 var $Host = 'localhost'; 178 179 /** 180 * Sets the default SMTP server port. 181 * @var int 182 */ 183 var $Port = 25; 184 185 /** 186 * Sets the SMTP HELO of the message (Default is $Hostname). 187 * @var string 188 */ 189 var $Helo = ''; 190 191 /** 192 * Sets connection prefix. 193 * Options are "", "ssl" or "tls" 194 * @var string 195 */ 196 var $SMTPSecure = ""; 197 198 /** 199 * Sets SMTP authentication. Utilizes the Username and Password variables. 200 * @var bool 201 */ 202 var $SMTPAuth = false; 203 204 /** 205 * Sets SMTP username. 206 * @var string 207 */ 208 var $Username = ''; 209 210 /** 211 * Sets SMTP password. 212 * @var string 213 */ 214 var $Password = ''; 215 216 /** 217 * Sets the SMTP server timeout in seconds. This function will not 218 * work with the win32 version. 219 * @var int 220 */ 221 var $Timeout = 10; 222 223 /** 224 * Sets SMTP class debugging on or off. 225 * @var bool 226 */ 227 var $SMTPDebug = false; 228 229 /** 230 * Prevents the SMTP connection from being closed after each mail 231 * sending. If this is set to true then to close the connection 232 * requires an explicit call to SmtpClose(). 233 * @var bool 234 */ 235 var $SMTPKeepAlive = false; 236 237 /** 238 * Provides the ability to have the TO field process individual 239 * emails, instead of sending to entire TO addresses 240 * @var bool 241 */ 242 var $SingleTo = false; 243 244 ///////////////////////////////////////////////// 245 // PROPERTIES, PRIVATE 246 ///////////////////////////////////////////////// 247 248 var $smtp = NULL; 249 var $to = array(); 250 var $cc = array(); 251 var $bcc = array(); 252 var $ReplyTo = array(); 253 var $attachment = array(); 254 var $CustomHeader = array(); 255 var $message_type = ''; 256 var $boundary = array(); 257 var $language = array(); 258 var $error_count = 0; 259 var $LE = "\n"; 260 var $sign_key_file = ""; 261 var $sign_key_pass = ""; 262 263 ///////////////////////////////////////////////// 264 // METHODS, VARIABLES 265 ///////////////////////////////////////////////// 266 267 /** 268 * Sets message type to HTML. 269 * @param bool $bool 270 * @return void 271 */ 272 function IsHTML($bool) { 273 if($bool == true) { 274 $this->ContentType = 'text/html'; 275 } else { 276 $this->ContentType = 'text/plain'; 277 } 278 } 279 280 /** 281 * Sets Mailer to send message using SMTP. 282 * @return void 283 */ 284 function IsSMTP() { 285 $this->Mailer = 'smtp'; 286 } 287 288 /** 289 * Sets Mailer to send message using PHP mail() function. 290 * @return void 291 */ 292 function IsMail() { 293 $this->Mailer = 'mail'; 294 } 295 296 /** 297 * Sets Mailer to send message using the $Sendmail program. 298 * @return void 299 */ 300 function IsSendmail() { 301 $this->Mailer = 'sendmail'; 302 } 303 304 /** 305 * Sets Mailer to send message using the qmail MTA. 306 * @return void 307 */ 308 function IsQmail() { 309 $this->Sendmail = '/var/qmail/bin/sendmail'; 310 $this->Mailer = 'sendmail'; 311 } 312 313 ///////////////////////////////////////////////// 314 // METHODS, RECIPIENTS 315 ///////////////////////////////////////////////// 316 317 /** 318 * Adds a "To" address. 319 * @param string $address 320 * @param string $name 321 * @return void 322 */ 323 function AddAddress($address, $name = '') { 324 $cur = count($this->to); 325 $this->to[$cur][0] = trim($address); 326 $this->to[$cur][1] = $name; 327 } 328 329 /** 330 * Adds a "Cc" address. Note: this function works 331 * with the SMTP mailer on win32, not with the "mail" 332 * mailer. 333 * @param string $address 334 * @param string $name 335 * @return void 336 */ 337 function AddCC($address, $name = '') { 338 $cur = count($this->cc); 339 $this->cc[$cur][0] = trim($address); 340 $this->cc[$cur][1] = $name; 341 } 342 343 /** 344 * Adds a "Bcc" address. Note: this function works 345 * with the SMTP mailer on win32, not with the "mail" 346 * mailer. 347 * @param string $address 348 * @param string $name 349 * @return void 350 */ 351 function AddBCC($address, $name = '') { 352 $cur = count($this->bcc); 353 $this->bcc[$cur][0] = trim($address); 354 $this->bcc[$cur][1] = $name; 355 } 356 357 /** 358 * Adds a "Reply-To" address. 359 * @param string $address 360 * @param string $name 361 * @return void 362 */ 363 function AddReplyTo($address, $name = '') { 364 $cur = count($this->ReplyTo); 365 $this->ReplyTo[$cur][0] = trim($address); 366 $this->ReplyTo[$cur][1] = $name; 367 } 368 369 ///////////////////////////////////////////////// 370 // METHODS, MAIL SENDING 371 ///////////////////////////////////////////////// 372 373 /** 374 * Creates message and assigns Mailer. If the message is 375 * not sent successfully then it returns false. Use the ErrorInfo 376 * variable to view description of the error. 377 * @return bool 378 */ 379 function Send() { 380 $header = ''; 381 $body = ''; 382 $result = true; 383 384 if((count($this->to) + count($this->cc) + count($this->bcc)) < 1) { 385 $this->SetError($this->Lang('provide_address')); 386 return false; 387 } 388 389 /* Set whether the message is multipart/alternative */ 390 if(!empty($this->AltBody)) { 391 $this->ContentType = 'multipart/alternative'; 392 } 393 394 $this->error_count = 0; // reset errors 395 $this->SetMessageType(); 396 $header .= $this->CreateHeader(); 397 $body = $this->CreateBody(); 398 399 if($body == '') { 400 return false; 401 } 402 403 /* Choose the mailer */ 404 switch($this->Mailer) { 405 case 'sendmail': 406 $result = $this->SendmailSend($header, $body); 407 break; 408 case 'smtp': 409 $result = $this->SmtpSend($header, $body); 410 break; 411 case 'mail': 412 $result = $this->MailSend($header, $body); 413 break; 414 default: 415 $result = $this->MailSend($header, $body); 416 break; 417 //$this->SetError($this->Mailer . $this->Lang('mailer_not_supported')); 418 //$result = false; 419 //break; 420 } 421 422 return $result; 423 } 424 425 /** 426 * Sends mail using the $Sendmail program. 427 * @access private 428 * @return bool 429 */ 430 function SendmailSend($header, $body) { 431 if ($this->Sender != '') { 432 $sendmail = sprintf("%s -oi -f %s -t", escapeshellcmd($this->Sendmail), escapeshellarg($this->Sender)); 433 } else { 434 $sendmail = sprintf("%s -oi -t", escapeshellcmd($this->Sendmail)); 435 } 436 437 if(!@$mail = popen($sendmail, 'w')) { 438 $this->SetError($this->Lang('execute') . $this->Sendmail); 439 return false; 440 } 441 442 fputs($mail, $header); 443 fputs($mail, $body); 444 445 $result = pclose($mail); 446 if (version_compare(phpversion(), '4.2.3') == -1) { 447 $result = $result >> 8 & 0xFF; 448 } 449 if($result != 0) { 450 $this->SetError($this->Lang('execute') . $this->Sendmail); 451 return false; 452 } 453 return true; 454 } 455 456 /** 457 * Sends mail using the PHP mail() function. 458 * @access private 459 * @return bool 460 */ 461 function MailSend($header, $body) { 462 463 $to = ''; 464 for($i = 0; $i < count($this->to); $i++) { 465 if($i != 0) { $to .= ', '; } 466 $to .= $this->AddrFormat($this->to[$i]); 467 } 468 469 $toArr = split(',', $to); 470 471 $params = sprintf("-oi -f %s", $this->Sender); 472 if ($this->Sender != '' && strlen(ini_get('safe_mode')) < 1) { 473 $old_from = ini_get('sendmail_from'); 474 ini_set('sendmail_from', $this->Sender); 475 if ($this->SingleTo === true && count($toArr) > 1) { 476 foreach ($toArr as $key => $val) { 477 $rt = @mail($val, $this->EncodeHeader($this->SecureHeader($this->Subject)), $body, $header, $params); 351 478 } 352 353 // Set whether the message is multipart/alternative 354 if(!empty($this->AltBody)) 355 $this->ContentType = "multipart/alternative"; 356 357 $this->error_count = 0; // reset errors 358 $this->SetMessageType(); 359 $header .= $this->CreateHeader(); 360 $body = $this->CreateBody(); 361 362 if($body == "") { return false; } 363 364 // Choose the mailer 365 switch($this->Mailer) 366 { 367 case "sendmail": 368 $result = $this->SendmailSend($header, $body); 369 break; 370 case "mail": 371 $result = $this->MailSend($header, $body); 372 break; 373 case "smtp": 374 $result = $this->SmtpSend($header, $body); 375 break; 376 default: 377 $this->SetError($this->Mailer . $this->Lang("mailer_not_supported")); 378 $result = false; 379 break; 479 } else { 480 $rt = @mail($to, $this->EncodeHeader($this->SecureHeader($this->Subject)), $body, $header, $params); 481 } 482 } else { 483 if ($this->SingleTo === true && count($toArr) > 1) { 484 foreach ($toArr as $key => $val) { 485 $rt = @mail($val, $this->EncodeHeader($this->SecureHeader($this->Subject)), $body, $header, $params); 380 486 } 381 382 return $result; 383 } 384 385 /** 386 * Sends mail using the $Sendmail program. 387 * @access private 388 * @return bool 389 */ 390 function SendmailSend($header, $body) { 391 if ($this->Sender != "") 392 $sendmail = sprintf("%s -oi -f %s -t", $this->Sendmail, escapeshellarg($this->Sender)); 393 else 394 $sendmail = sprintf("%s -oi -t", $this->Sendmail); 395 396 if(!@$mail = popen($sendmail, "w")) 397 { 398 $this->SetError($this->Lang("execute") . $this->Sendmail); 399 return false; 487 } else { 488 $rt = @mail($to, $this->EncodeHeader($this->SecureHeader($this->Subject)), $body, $header); 489 } 490 } 491 492 if (isset($old_from)) { 493 ini_set('sendmail_from', $old_from); 494 } 495 496 if(!$rt) { 497 $this->SetError($this->Lang('instantiate')); 498 return false; 499 } 500 501 return true; 502 } 503 504 /** 505 * Sends mail via SMTP using PhpSMTP (Author: 506 * Chris Ryan). Returns bool. Returns false if there is a 507 * bad MAIL FROM, RCPT, or DATA input. 508 * @access private 509 * @return bool 510 */ 511 function SmtpSend($header, $body) { 512 include_once($this->PluginDir . 'class-smtp.php'); 513 $error = ''; 514 $bad_rcpt = array(); 515 516 if(!$this->SmtpConnect()) { 517 return false; 518 } 519 520 $smtp_from = ($this->Sender == '') ? $this->From : $this->Sender; 521 if(!$this->smtp->Mail($smtp_from)) { 522 $error = $this->Lang('from_failed') . $smtp_from; 523 $this->SetError($error); 524 $this->smtp->Reset(); 525 return false; 526 } 527 528 /* Attempt to send attach all recipients */ 529 for($i = 0; $i < count($this->to); $i++) { 530 if(!$this->smtp->Recipient($this->to[$i][0])) { 531 $bad_rcpt[] = $this->to[$i][0]; 532 } 533 } 534 for($i = 0; $i < count($this->cc); $i++) { 535 if(!$this->smtp->Recipient($this->cc[$i][0])) { 536 $bad_rcpt[] = $this->cc[$i][0]; 537 } 538 } 539 for($i = 0; $i < count($this->bcc); $i++) { 540 if(!$this->smtp->Recipient($this->bcc[$i][0])) { 541 $bad_rcpt[] = $this->bcc[$i][0]; 542 } 543 } 544 545 if(count($bad_rcpt) > 0) { // Create error message 546 for($i = 0; $i < count($bad_rcpt); $i++) { 547 if($i != 0) { 548 $error .= ', '; 400 549 } 401 402 fputs($mail, $header); 403 fputs($mail, $body); 404 405 $result = pclose($mail) >> 8 & 0xFF; 406 if($result != 0) 407 { 408 $this->SetError($this->Lang("execute") . $this->Sendmail); 409 return false; 550 $error .= $bad_rcpt[$i]; 551 } 552 $error = $this->Lang('recipients_failed') . $error; 553 $this->SetError($error); 554 $this->smtp->Reset(); 555 return false; 556 } 557 558 if(!$this->smtp->Data($header . $body)) { 559 $this->SetError($this->Lang('data_not_accepted')); 560 $this->smtp->Reset(); 561 return false; 562 } 563 if($this->SMTPKeepAlive == true) { 564 $this->smtp->Reset(); 565 } else { 566 $this->SmtpClose(); 567 } 568 569 return true; 570 } 571 572 /** 573 * Initiates a connection to an SMTP server. Returns false if the 574 * operation failed. 575 * @access private 576 * @return bool 577 */ 578 function SmtpConnect() { 579 if($this->smtp == NULL) { 580 $this->smtp = new SMTP(); 581 } 582 583 $this->smtp->do_debug = $this->SMTPDebug; 584 $hosts = explode(';', $this->Host); 585 $index = 0; 586 $connection = ($this->smtp->Connected()); 587 588 /* Retry while there is no connection */ 589 while($index < count($hosts) && $connection == false) { 590 $hostinfo = array(); 591 if(eregi('^(.+):([0-9]+)$', $hosts[$index], $hostinfo)) { 592 $host = $hostinfo[1]; 593 $port = $hostinfo[2]; 594 } else { 595 $host = $hosts[$index]; 596 $port = $this->Port; 597 } 598 599 if($this->smtp->Connect(((!empty($this->SMTPSecure))?$this->SMTPSecure.'://':'').$host, $port, $this->Timeout)) { 600 if ($this->Helo != '') { 601 $this->smtp->Hello($this->Helo); 602 } else { 603 $this->smtp->Hello($this->ServerHostname()); 410 604 } 411 605 412 return true; 413 } 414 415 /** 416 * Sends mail using the PHP mail() function. 417 * @access private 418 * @return bool 419 */ 420 function MailSend($header, $body) { 421 $to = ""; 422 for($i = 0; $i < count($this->to); $i++) 423 { 424 if($i != 0) { $to .= ", "; } 425 $to .= $this->to[$i][0]; 606 $connection = true; 607 if($this->SMTPAuth) { 608 if(!$this->smtp->Authenticate($this->Username, $this->Password)) { 609 $this->SetError($this->Lang('authenticate')); 610 $this->smtp->Reset(); 611 $connection = false; 612 } 426 613 } 427 428 if ($this->Sender != "" && strlen(ini_get("safe_mode"))< 1) 429 { 430 $old_from = ini_get("sendmail_from"); 431 ini_set("sendmail_from", $this->Sender); 432 $params = sprintf("-oi -f %s", $this->Sender); 433 $rt = @mail($to, $this->EncodeHeader($this->Subject), $body, 434 $header, $params); 614 } 615 $index++; 616 } 617 if(!$connection) { 618 $this->SetError($this->Lang('connect_host')); 619 } 620 621 return $connection; 622 } 623 624 /** 625 * Closes the active SMTP session if one exists. 626 * @return void 627 */ 628 function SmtpClose() { 629 if($this->smtp != NULL) { 630 if($this->smtp->Connected()) { 631 $this->smtp->Quit(); 632 $this->smtp->Close(); 633 } 634 } 635 } 636 637 /** 638 * Sets the language for all class error messages. Returns false 639 * if it cannot load the language file. The default language type 640 * is English. 641 * @param string $lang_type Type of language (e.g. Portuguese: "br") 642 * @param string $lang_path Path to the language file directory 643 * @access public 644 * @return bool 645 */ 646 function SetLanguage($lang_type, $lang_path = 'language/') { 647 if(file_exists($lang_path.'phpmailer.lang-'.$lang_type.'.php')) { 648 include($lang_path.'phpmailer.lang-'.$lang_type.'.php'); 649 } elseif (file_exists($lang_path.'phpmailer.lang-en.php')) { 650 include($lang_path.'phpmailer.lang-en.php'); 651 } else { 652 $this->SetError('Could not load language file'); 653 return false; 654 } 655 $this->language = $PHPMAILER_LANG; 656 657 return true; 658 } 659 660 ///////////////////////////////////////////////// 661 // METHODS, MESSAGE CREATION 662 ///////////////////////////////////////////////// 663 664 /** 665 * Creates recipient headers. 666 * @access private 667 * @return string 668 */ 669 function AddrAppend($type, $addr) { 670 $addr_str = $type . ': '; 671 $addr_str .= $this->AddrFormat($addr[0]); 672 if(count($addr) > 1) { 673 for($i = 1; $i < count($addr); $i++) { 674 $addr_str .= ', ' . $this->AddrFormat($addr[$i]); 675 } 676 } 677 $addr_str .= $this->LE; 678 679 return $addr_str; 680 } 681 682 /** 683 * Formats an address correctly. 684 * @access private 685 * @return string 686 */ 687 function AddrFormat($addr) { 688 if(empty($addr[1])) { 689 $formatted = $this->SecureHeader($addr[0]); 690 } else { 691 $formatted = $this->EncodeHeader($this->SecureHeader($addr[1]), 'phrase') . " <" . $this->SecureHeader($addr[0]) . ">"; 692 } 693 694 return $formatted; 695 } 696 697 /** 698 * Wraps message for use with mailers that do not 699 * automatically perform wrapping and for quoted-printable. 700 * Original written by philippe. 701 * @access private 702 * @return string 703 */ 704 function WrapText($message, $length, $qp_mode = false) { 705 $soft_break = ($qp_mode) ? sprintf(" =%s", $this->LE) : $this->LE; 706 // If utf-8 encoding is used, we will need to make sure we don't 707 // split multibyte characters when we wrap 708 $is_utf8 = (strtolower($this->CharSet) == "utf-8"); 709 710 $message = $this->FixEOL($message); 711 if (substr($message, -1) == $this->LE) { 712 $message = substr($message, 0, -1); 713 } 714 715 $line = explode($this->LE, $message); 716 $message = ''; 717 for ($i=0 ;$i < count($line); $i++) { 718 $line_part = explode(' ', $line[$i]); 719 $buf = ''; 720 for ($e = 0; $e<count($line_part); $e++) { 721 $word = $line_part[$e]; 722 if ($qp_mode and (strlen($word) > $length)) { 723 $space_left = $length - strlen($buf) - 1; 724 if ($e != 0) { 725 if ($space_left > 20) { 726 $len = $space_left; 727 if ($is_utf8) { 728 $len = $this->UTF8CharBoundary($word, $len); 729 } elseif (substr($word, $len - 1, 1) == "=") { 730 $len--; 731 } elseif (substr($word, $len - 2, 1) == "=") { 732 $len -= 2; 733 } 734 $part = substr($word, 0, $len); 735 $word = substr($word, $len); 736 $buf .= ' ' . $part; 737 $message .= $buf . sprintf("=%s", $this->LE); 738 } else { 739 $message .= $buf . $soft_break; 740 } 741 $buf = ''; 742 } 743 while (strlen($word) > 0) { 744 $len = $length; 745 if ($is_utf8) { 746 $len = $this->UTF8CharBoundary($word, $len); 747 } elseif (substr($word, $len - 1, 1) == "=") { 748 $len--; 749 } elseif (substr($word, $len - 2, 1) == "=") { 750 $len -= 2; 751 } 752 $part = substr($word, 0, $len); 753 $word = substr($word, $len); 754 755 if (strlen($word) > 0) { 756 $message .= $part . sprintf("=%s", $this->LE); 757 } else { 758 $buf = $part; 759 } 760 } 761 } else { 762 $buf_o = $buf; 763 $buf .= ($e == 0) ? $word : (' ' . $word); 764 765 if (strlen($buf) > $length and $buf_o != '') { 766 $message .= $buf_o . $soft_break; 767 $buf = $word; 768 } 435 769 } 436 else 437 $rt = @mail($to, $this->EncodeHeader($this->Subject), $body, $header); 438 439 if (isset($old_from)) 440 ini_set("sendmail_from", $old_from); 441 442 if(!$rt) 443 { 444 $this->SetError($this->Lang("instantiate")); 445 return false; 770 } 771 $message .= $buf . $this->LE; 772 } 773 774 return $message; 775 } 776 777 /** 778 * Finds last character boundary prior to maxLength in a utf-8 779 * quoted (printable) encoded string. 780 * Original written by Colin Brown. 781 * @access private 782 * @param string $encodedText utf-8 QP text 783 * @param int $maxLength find last character boundary prior to this length 784 * @return int 785 */ 786 function UTF8CharBoundary($encodedText, $maxLength) { 787 $foundSplitPos = false; 788 $lookBack = 3; 789 while (!$foundSplitPos) { 790 $lastChunk = substr($encodedText, $maxLength - $lookBack, $lookBack); 791 $encodedCharPos = strpos($lastChunk, "="); 792 if ($encodedCharPos !== false) { 793 // Found start of encoded character byte within $lookBack block. 794 // Check the encoded byte value (the 2 chars after the '=') 795 $hex = substr($encodedText, $maxLength - $lookBack + $encodedCharPos + 1, 2); 796 $dec = hexdec($hex); 797 if ($dec < 128) { // Single byte character. 798 // If the encoded char was found at pos 0, it will fit 799 // otherwise reduce maxLength to start of the encoded char 800 $maxLength = ($encodedCharPos == 0) ? $maxLength : 801 $maxLength - ($lookBack - $encodedCharPos); 802 $foundSplitPos = true; 803 } elseif ($dec >= 192) { // First byte of a multi byte character 804 // Reduce maxLength to split at start of character 805 $maxLength = $maxLength - ($lookBack - $encodedCharPos); 806 $foundSplitPos = true; 807 } elseif ($dec < 192) { // Middle byte of a multi byte character, look further back 808 $lookBack += 3; 446 809 } 447 448 return true; 449 } 450 451 /** 452 * Sends mail via SMTP using PhpSMTP (Author: 453 * Chris Ryan). Returns bool. Returns false if there is a 454 * bad MAIL FROM, RCPT, or DATA input. 455 * @access private 456 * @return bool 457 */ 458 function SmtpSend($header, $body) { 459 include_once($this->PluginDir . "class-smtp.php"); 460 $error = ""; 461 $bad_rcpt = array(); 462 463 if(!$this->SmtpConnect()) 464 return false; 465 466 $smtp_from = ($this->Sender == "") ? $this->From : $this->Sender; 467 if(!$this->smtp->Mail($smtp_from)) 468 { 469 $error = $this->Lang("from_failed") . $smtp_from; 470 $this->SetError($error); 471 $this->smtp->Reset(); 472 return false; 810 } else { 811 // No encoded character found 812 $foundSplitPos = true; 813 } 814 } 815 return $maxLength; 816 } 817 818 /** 819 * Set the body wrapping. 820 * @access private 821 * @return void 822 */ 823 function SetWordWrap() { 824 if($this->WordWrap < 1) { 825 return; 826 } 827 828 switch($this->message_type) { 829 case 'alt': 830 /* fall through */ 831 case 'alt_attachments': 832 $this->AltBody = $this->WrapText($this->AltBody, $this->WordWrap); 833 break; 834 default: 835 $this->Body = $this->WrapText($this->Body, $this->WordWrap); 836 break; 837 } 838 } 839 840 /** 841 * Assembles message header. 842 * @access private 843 * @return string 844 */ 845 function CreateHeader() { 846 $result = ''; 847 848 /* Set the boundaries */ 849 $uniq_id = md5(uniqid(time())); 850 $this->boundary[1] = 'b1_' . $uniq_id; 851 $this->boundary[2] = 'b2_' . $uniq_id; 852 853 $result .= $this->HeaderLine('Date', $this->RFCDate()); 854 if($this->Sender == '') { 855 $result .= $this->HeaderLine('Return-Path', trim($this->From)); 856 } else { 857 $result .= $this->HeaderLine('Return-Path', trim($this->Sender)); 858 } 859 860 /* To be created automatically by mail() */ 861 if($this->Mailer != 'mail') { 862 if(count($this->to) > 0) { 863 $result .= $this->AddrAppend('To', $this->to); 864 } elseif (count($this->cc) == 0) { 865 $result .= $this->HeaderLine('To', 'undisclosed-recipients:;'); 866 } 867 if(count($this->cc) > 0) { 868 $result .= $this->AddrAppend('Cc', $this->cc); 869 } 870 } 871 872 $from = array(); 873 $from[0][0] = trim($this->From); 874 $from[0][1] = $this->FromName; 875 $result .= $this->AddrAppend('From', $from); 876 877 /* sendmail and mail() extract Cc from the header before sending */ 878 if((($this->Mailer == 'sendmail') || ($this->Mailer == 'mail')) && (count($this->cc) > 0)) { 879 $result .= $this->AddrAppend('Cc', $this->cc); 880 } 881 882 /* sendmail and mail() extract Bcc from the header before sending */ 883 if((($this->Mailer == 'sendmail') || ($this->Mailer == 'mail')) && (count($this->bcc) > 0)) { 884 $result .= $this->AddrAppend('Bcc', $this->bcc); 885 } 886 887 if(count($this->ReplyTo) > 0) { 888 $result .= $this->AddrAppend('Reply-To', $this->ReplyTo); 889 } 890 891 /* mail() sets the subject itself */ 892 if($this->Mailer != 'mail') { 893 $result .= $this->HeaderLine('Subject', $this->EncodeHeader($this->SecureHeader($this->Subject))); 894 } 895 896 if($this->MessageID != '') { 897 $result .= $this->HeaderLine('Message-ID',$this->MessageID); 898 } else { 899 $result .= sprintf("Message-ID: <%s@%s>%s", $uniq_id, $this->ServerHostname(), $this->LE); 900 } 901 $result .= $this->HeaderLine('X-Priority', $this->Priority); 902 $result .= $this->HeaderLine('X-Mailer', 'PHPMailer (phpmailer.sourceforge.net) [version ' . $this->Version . ']'); 903 904 if($this->ConfirmReadingTo != '') { 905 $result .= $this->HeaderLine('Disposition-Notification-To', '<' . trim($this->ConfirmReadingTo) . '>'); 906 } 907 908 // Add custom headers 909 for($index = 0; $index < count($this->CustomHeader); $index++) { 910 $result .= $this->HeaderLine(trim($this->CustomHeader[$index][0]), $this->EncodeHeader(trim($this->CustomHeader[$index][1]))); 911 } 912 if (!$this->sign_key_file) { 913 $result .= $this->HeaderLine('MIME-Version', '1.0'); 914 $result .= $this->GetMailMIME(); 915 } 916 917 return $result; 918 } 919 920 /** 921 * Returns the message MIME. 922 * @access private 923 * @return string 924 */ 925 function GetMailMIME() { 926 $result = ''; 927 switch($this->message_type) { 928 case 'plain': 929 $result .= $this->HeaderLine('Content-Transfer-Encoding', $this->Encoding); 930 $result .= sprintf("Content-Type: %s; charset=\"%s\"", $this->ContentType, $this->CharSet); 931 break; 932 case 'attachments': 933 /* fall through */ 934 case 'alt_attachments': 935 if($this->InlineImageExists()){ 936 $result .= sprintf("Content-Type: %s;%s\ttype=\"text/html\";%s\tboundary=\"%s\"%s", 'multipart/related', $this->LE, $this->LE, $this->boundary[1], $this->LE); 937 } else { 938 $result .= $this->HeaderLine('Content-Type', 'multipart/mixed;'); 939 $result .= $this->TextLine("\tboundary=\"" . $this->boundary[1] . '"'); 473 940 } 474 475 // Attempt to send attach all recipients 476 for($i = 0; $i < count($this->to); $i++) 477 { 478 if(!$this->smtp->Recipient($this->to[$i][0])) 479 $bad_rcpt[] = $this->to[$i][0]; 941 break; 942 case 'alt': 943 $result .= $this->HeaderLine('Content-Type', 'multipart/alternative;'); 944 $result .= $this->TextLine("\tboundary=\"" . $this->boundary[1] . '"'); 945 break; 946 } 947 948 if($this->Mailer != 'mail') { 949 $result .= $this->LE.$this->LE; 950 } 951 952 return $result; 953 } 954 955 /** 956 * Assembles the message body. Returns an empty string on failure. 957 * @access private 958 * @return string 959 */ 960 function CreateBody() { 961 $result = ''; 962 if ($this->sign_key_file) { 963 $result .= $this->GetMailMIME(); 964 } 965 966 $this->SetWordWrap(); 967 968 switch($this->message_type) { 969 case 'alt': 970 $result .= $this->GetBoundary($this->boundary[1], '', 'text/plain', ''); 971 $result .= $this->EncodeString($this->AltBody, $this->Encoding); 972 $result .= $this->LE.$this->LE; 973 $result .= $this->GetBoundary($this->boundary[1], '', 'text/html', ''); 974 $result .= $this->EncodeString($this->Body, $this->Encoding); 975 $result .= $this->LE.$this->LE; 976 $result .= $this->EndBoundary($this->boundary[1]); 977 break; 978 case 'plain': 979 $result .= $this->EncodeString($this->Body, $this->Encoding); 980 break; 981 case 'attachments': 982 $result .= $this->GetBoundary($this->boundary[1], '', '', ''); 983 $result .= $this->EncodeString($this->Body, $this->Encoding); 984 $result .= $this->LE; 985 $result .= $this->AttachAll(); 986 break; 987 case 'alt_attachments': 988 $result .= sprintf("--%s%s", $this->boundary[1], $this->LE); 989 $result .= sprintf("Content-Type: %s;%s" . "\tboundary=\"%s\"%s", 'multipart/alternative', $this->LE, $this->boundary[2], $this->LE.$this->LE); 990 $result .= $this->GetBoundary($this->boundary[2], '', 'text/plain', '') . $this->LE; // Create text body 991 $result .= $this->EncodeString($this->AltBody, $this->Encoding); 992 $result .= $this->LE.$this->LE; 993 $result .= $this->GetBoundary($this->boundary[2], '', 'text/html', '') . $this->LE; // Create the HTML body 994 $result .= $this->EncodeString($this->Body, $this->Encoding); 995 $result .= $this->LE.$this->LE; 996 $result .= $this->EndBoundary($this->boundary[2]); 997 $result .= $this->AttachAll(); 998 break; 999 } 1000 1001 if($this->IsError()) { 1002 $result = ''; 1003 } else if ($this->sign_key_file) { 1004 $file = tempnam("", "mail"); 1005 $fp = fopen($file, "w"); 1006 fwrite($fp, $result); 1007 fclose($fp); 1008 $signed = tempnam("", "signed"); 1009 1010 if (@openssl_pkcs7_sign($file, $signed, "file://".$this->sign_key_file, array("file://".$this->sign_key_file, $this->sign_key_pass), null)) { 1011 $fp = fopen($signed, "r"); 1012 $result = fread($fp, filesize($this->sign_key_file)); 1013 fclose($fp); 1014 } else { 1015 $this->SetError($this->Lang("signing").openssl_error_string()); 1016 $result = ''; 1017 } 1018 1019 unlink($file); 1020 unlink($signed); 1021 } 1022 1023 return $result; 1024 } 1025 1026 /** 1027 * Returns the start of a message boundary. 1028 * @access private 1029 */ 1030 function GetBoundary($boundary, $charSet, $contentType, $encoding) { 1031 $result = ''; 1032 if($charSet == '') { 1033 $charSet = $this->CharSet; 1034 } 1035 if($contentType == '') { 1036 $contentType = $this->ContentType; 1037 } 1038 if($encoding == '') { 1039 $encoding = $this->Encoding; 1040 } 1041 $result .= $this->TextLine('--' . $boundary); 1042 $result .= sprintf("Content-Type: %s; charset = \"%s\"", $contentType, $charSet); 1043 $result .= $this->LE; 1044 $result .= $this->HeaderLine('Content-Transfer-Encoding', $encoding); 1045 $result .= $this->LE; 1046 1047 return $result; 1048 } 1049 1050 /** 1051 * Returns the end of a message boundary. 1052 * @access private 1053 */ 1054 function EndBoundary($boundary) { 1055 return $this->LE . '--' . $boundary . '--' . $this->LE; 1056 } 1057 1058 /** 1059 * Sets the message type. 1060 * @access private 1061 * @return void 1062 */ 1063 function SetMessageType() { 1064 if(count($this->attachment) < 1 && strlen($this->AltBody) < 1) { 1065 $this->message_type = 'plain'; 1066 } else { 1067 if(count($this->attachment) > 0) { 1068 $this->message_type = 'attachments'; 1069 } 1070 if(strlen($this->AltBody) > 0 && count($this->attachment) < 1) { 1071 $this->message_type = 'alt'; 1072 } 1073 if(strlen($this->AltBody) > 0 && count($this->attachment) > 0) { 1074 $this->message_type = 'alt_attachments'; 1075 } 1076 } 1077 } 1078 1079 /* Returns a formatted header line. 1080 * @access private 1081 * @return string 1082 */ 1083 function HeaderLine($name, $value) { 1084 return $name . ': ' . $value . $this->LE; 1085 } 1086 1087 /** 1088 * Returns a formatted mail line. 1089 * @access private 1090 * @return string 1091 */ 1092 function TextLine($value) { 1093 return $value . $this->LE; 1094 } 1095 1096 ///////////////////////////////////////////////// 1097 // CLASS METHODS, ATTACHMENTS 1098 ///////////////////////////////////////////////// 1099 1100 /** 1101 * Adds an attachment from a path on the filesystem. 1102 * Returns false if the file could not be found 1103 * or accessed. 1104 * @param string $path Path to the attachment. 1105 * @param string $name Overrides the attachment name. 1106 * @param string $encoding File encoding (see $Encoding). 1107 * @param string $type File extension (MIME) type. 1108 * @return bool 1109 */ 1110 function AddAttachment($path, $name = '', $encoding = 'base64', $type = 'application/octet-stream') { 1111 if(!@is_file($path)) { 1112 $this->SetError($this->Lang('file_access') . $path); 1113 return false; 1114 } 1115 1116 $filename = basename($path); 1117 if($name == '') { 1118 $name = $filename; 1119 } 1120 1121 $cur = count($this->attachment); 1122 $this->attachment[$cur][0] = $path; 1123 $this->attachment[$cur][1] = $filename; 1124 $this->attachment[$cur][2] = $name; 1125 $this->attachment[$cur][3] = $encoding; 1126 $this->attachment[$cur][4] = $type; 1127 $this->attachment[$cur][5] = false; // isStringAttachment 1128 $this->attachment[$cur][6] = 'attachment'; 1129 $this->attachment[$cur][7] = 0; 1130 1131 return true; 1132 } 1133 1134 /** 1135 * Attaches all fs, string, and binary attachments to the message. 1136 * Returns an empty string on failure. 1137 * @access private 1138 * @return string 1139 */ 1140 function AttachAll() { 1141 /* Return text of body */ 1142 $mime = array(); 1143 1144 /* Add all attachments */ 1145 for($i = 0; $i < count($this->attachment); $i++) { 1146 /* Check for string attachment */ 1147 $bString = $this->attachment[$i][5]; 1148 if ($bString) { 1149 $string = $this->attachment[$i][0]; 1150 } else { 1151 $path = $this->attachment[$i][0]; 1152 } 1153 1154 $filename = $this->attachment[$i][1]; 1155 $name = $this->attachment[$i][2]; 1156 $encoding = $this->attachment[$i][3]; 1157 $type = $this->attachment[$i][4]; 1158 $disposition = $this->attachment[$i][6]; 1159 $cid = $this->attachment[$i][7]; 1160 1161 $mime[] = sprintf("--%s%s", $this->boundary[1], $this->LE); 1162 $mime[] = sprintf("Content-Type: %s; name=\"%s\"%s", $type, $name, $this->LE); 1163 $mime[] = sprintf("Content-Transfer-Encoding: %s%s", $encoding, $this->LE); 1164 1165 if($disposition == 'inline') { 1166 $mime[] = sprintf("Content-ID: <%s>%s", $cid, $this->LE); 1167 } 1168 1169 $mime[] = sprintf("Content-Disposition: %s; filename=\"%s\"%s", $disposition, $name, $this->LE.$this->LE); 1170 1171 /* Encode as string attachment */ 1172 if($bString) { 1173 $mime[] = $this->EncodeString($string, $encoding); 1174 if($this->IsError()) { 1175 return ''; 480 1176 } 481 for($i = 0; $i < count($this->cc); $i++) 482 { 483 if(!$this->smtp->Recipient($this->cc[$i][0])) 484 $bad_rcpt[] = $this->cc[$i][0]; 1177 $mime[] = $this->LE.$this->LE; 1178 } else { 1179 $mime[] = $this->EncodeFile($path, $encoding); 1180 if($this->IsError()) { 1181 return ''; 485 1182 } 486 for($i = 0; $i < count($this->bcc); $i++) 487 { 488 if(!$this->smtp->Recipient($this->bcc[$i][0])) 489 $bad_rcpt[] = $this->bcc[$i][0]; 1183 $mime[] = $this->LE.$this->LE; 1184 } 1185 } 1186 1187 $mime[] = sprintf("--%s--%s", $this->boundary[1], $this->LE); 1188 1189 return join('', $mime); 1190 } 1191 1192 /** 1193 * Encodes attachment in requested format. Returns an 1194 * empty string on failure. 1195 * @access private 1196 * @return string 1197 */ 1198 function EncodeFile ($path, $encoding = 'base64') { 1199 if(!@$fd = fopen($path, 'rb')) { 1200 $this->SetError($this->Lang('file_open') . $path); 1201 return ''; 1202 } 1203 $magic_quotes = get_magic_quotes_runtime(); 1204 set_magic_quotes_runtime(0); 1205 $file_buffer = fread($fd, filesize($path)); 1206 $file_buffer = $this->EncodeString($file_buffer, $encoding); 1207 fclose($fd); 1208 set_magic_quotes_runtime($magic_quotes); 1209 1210 return $file_buffer; 1211 } 1212 1213 /** 1214 * Encodes string to requested format. Returns an 1215 * empty string on failure. 1216 * @access private 1217 * @return string 1218 */ 1219 function EncodeString ($str, $encoding = 'base64') { 1220 $encoded = ''; 1221 switch(strtolower($encoding)) { 1222 case 'base64': 1223 /* chunk_split is found in PHP >= 3.0.6 */ 1224 $encoded = chunk_split(base64_encode($str), 76, $this->LE); 1225 break; 1226 case '7bit': 1227 case '8bit': 1228 $encoded = $this->FixEOL($str); 1229 if (substr($encoded, -(strlen($this->LE))) != $this->LE) 1230 $encoded .= $this->LE; 1231 break; 1232 case 'binary': 1233 $encoded = $str; 1234 break; 1235 case 'quoted-printable': 1236 $encoded = $this->EncodeQP($str); 1237 break; 1238 default: 1239 $this->SetError($this->Lang('encoding') . $encoding); 1240 break; 1241 } 1242 return $encoded; 1243 } 1244 1245 /** 1246 * Encode a header string to best of Q, B, quoted or none. 1247 * @access private 1248 * @return string 1249 */ 1250 function EncodeHeader ($str, $position = 'text') { 1251 $x = 0; 1252 1253 switch (strtolower($position)) { 1254 case 'phrase': 1255 if (!preg_match('/[\200-\377]/', $str)) { 1256 /* Can't use addslashes as we don't know what value has magic_quotes_sybase. */ 1257 $encoded = addcslashes($str, "\0..\37\177\\\""); 1258 if (($str == $encoded) && !preg_match('/[^A-Za-z0-9!#$%&\'*+\/=?^_`{|}~ -]/', $str)) { 1259 return ($encoded); 1260 } else { 1261 return ("\"$encoded\""); 1262 } 490 1263 } 491 492 if(count($bad_rcpt) > 0) // Create error message 493 { 494 for($i = 0; $i < count($bad_rcpt); $i++) 495 { 496 if($i != 0) { $error .= ", "; } 497 $error .= $bad_rcpt[$i]; 498 } 499 $error = $this->Lang("recipients_failed") . $error; 500 $this->SetError($error); 501 $this->smtp->Reset(); 502 return false; 503 } 504 505 if(!$this->smtp->Data($header . $body)) 506 { 507 $this->SetError($this->Lang("data_not_accepted")); 508 $this->smtp->Reset(); 509 return false; 510 } 511 if($this->SMTPKeepAlive == true) 512 $this->smtp->Reset(); 513 else 514 $this->SmtpClose(); 515 516 return true; 517 } 518 519 /** 520 * Initiates a connection to an SMTP server. Returns false if the 521 * operation failed. 522 * @access private 523 * @return bool 524 */ 525 function SmtpConnect() { 526 if($this->smtp == NULL) { $this->smtp = new SMTP(); } 527 528 $this->smtp->do_debug = $this->SMTPDebug; 529 $hosts = explode(";", $this->Host); 530 $index = 0; 531 $connection = ($this->smtp->Connected()); 532 533 // Retry while there is no connection 534 while($index < count($hosts) && $connection == false) 535 { 536 if(strstr($hosts[$index], ":")) 537 list($host, $port) = explode(":", $hosts[$index]); 538 else 539 { 540 $host = $hosts[$index]; 541 $port = $this->Port; 542 } 543 544 if($this->smtp->Connect($host, $port, $this->Timeout)) 545 { 546 if ($this->Helo != '') 547 $this->smtp->Hello($this->Helo); 548 else 549 $this->smtp->Hello($this->ServerHostname()); 550 551 if($this->SMTPAuth) 552 { 553 if(!$this->smtp->Authenticate($this->Username, 554 $this->Password)) 555 { 556 $this->SetError($this->Lang("authenticate")); 557 $this->smtp->Reset(); 558 $connection = false; 559 } 560 } 561 $connection = true; 562 } 563 $index++; 564 } 565 if(!$connection) 566 $this->SetError($this->Lang("connect_host")); 567 568 return $connection; 569 } 570 571 /** 572 * Closes the active SMTP session if one exists. 573 * @return void 574 */ 575 function SmtpClose() { 576 if($this->smtp != NULL) 577 { 578 if($this->smtp->Connected()) 579 { 580 $this->smtp->Quit(); 581 $this->smtp->Close(); 582 } 583 } 584 } 585 586 /** 587 * Sets the language for all class error messages. Returns false 588 * if it cannot load the language file. The default language type 589 * is English. 590 * @param string $lang_type Type of language (e.g. Portuguese: "br") 591 * @param string $lang_path Path to the language file directory 592 * @access public 593 * @return bool 594 */ 595 function SetLanguage($lang_type, $lang_path = "language/") { 596 if(file_exists($lang_path.'phpmailer.lang-'.$lang_type.'.php')) 597 include($lang_path.'phpmailer.lang-'.$lang_type.'.php'); 598 else if(file_exists($lang_path.'phpmailer.lang-en.php')) 599 include($lang_path.'phpmailer.lang-en.php'); 600 else 601 { 602 $this->SetError("Could not load language file"); 603 return false; 604 } 605 $this->language = $PHPMAILER_LANG; 606 607 return true; 608 } 609 610 ///////////////////////////////////////////////// 611 // MESSAGE CREATION METHODS 612 ///////////////////////////////////////////////// 613 614 /** 615 * Creates recipient headers. 616 * @access private 617 * @return string 618 */ 619 function AddrAppend($type, $addr) { 620 $addr_str = $type . ": "; 621 $addr_str .= $this->AddrFormat($addr[0]); 622 if(count($addr) > 1) 623 { 624 for($i = 1; $i < count($addr); $i++) 625 $addr_str .= ", " . $this->AddrFormat($addr[$i]); 626 } 627 $addr_str .= $this->LE; 628 629 return $addr_str; 630 } 631 632 /** 633 * Formats an address correctly. 634 * @access private 635 * @return string 636 */ 637 function AddrFormat($addr) { 638 if(empty($addr[1])) 639 $formatted = $addr[0]; 640 else 641 { 642 $formatted = $this->EncodeHeader($addr[1], 'phrase') . " <" . 643 $addr[0] . ">"; 644 } 645 646 return $formatted; 647 } 648 649 /** 650 * Wraps message for use with mailers that do not 651 * automatically perform wrapping and for quoted-printable. 652 * Original written by philippe. 653 * @access private 654 * @return string 655 */ 656 function WrapText($message, $length, $qp_mode = false) { 657 $soft_break = ($qp_mode) ? sprintf(" =%s", $this->LE) : $this->LE; 658 659 $message = $this->FixEOL($message); 660 if (substr($message, -1) == $this->LE) 661 $message = substr($message, 0, -1); 662 663 $line = explode($this->LE, $message); 664 $message = ""; 665 for ($i=0 ;$i < count($line); $i++) 666 { 667 $line_part = explode(" ", $line[$i]); 668 $buf = ""; 669 for ($e = 0; $e<count($line_part); $e++) 670 { 671 $word = $line_part[$e]; 672 if ($qp_mode and (strlen($word) > $length)) 673 { 674 $space_left = $length - strlen($buf) - 1; 675 if ($e != 0) 676 { 677 if ($space_left > 20) 678 { 679 $len = $space_left; 680 if (substr($word, $len - 1, 1) == "=") 681 $len--; 682 elseif (substr($word, $len - 2, 1) == "=") 683 $len -= 2; 684 $part = substr($word, 0, $len); 685 $word = substr($word, $len); 686 $buf .= " " . $part; 687 $message .= $buf . sprintf("=%s", $this->LE); 688 } 689 else 690 { 691 $message .= $buf . $soft_break; 692 } 693 $buf = ""; 694 } 695 while (strlen($word) > 0) 696 { 697 $len = $length; 698 if (substr($word, $len - 1, 1) == "=") 699 $len--; 700 elseif (substr($word, $len - 2, 1) == "=") 701 $len -= 2; 702 $part = substr($word, 0, $len); 703 $word = substr($word, $len); 704 705 if (strlen($word) > 0) 706 $message .= $part . sprintf("=%s", $this->LE); 707 else 708 $buf = $part; 709 } 710 } 711 else 712 { 713 $buf_o = $buf; 714 $buf .= ($e == 0) ? $word : (" " . $word); 715 716 if (strlen($buf) > $length and $buf_o != "") 717 { 718 $message .= $buf_o . $soft_break; 719 $buf = $word; 720 } 721 } 722 } 723 $message .= $buf . $this->LE; 724 } 725 726 return $message; 727 } 728 729 /** 730 * Set the body wrapping. 731 * @access private 732 * @return void 733 */ 734 function SetWordWrap() { 735 if($this->WordWrap < 1) 736 return; 737 738 switch($this->message_type) 739 { 740 case "alt": 741 // fall through 742 case "alt_attachments": 743 $this->AltBody = $this->WrapText($this->AltBody, $this->WordWrap); 744 break; 745 default: 746 $this->Body = $this->WrapText($this->Body, $this->WordWrap); 747 break; 748 } 749 } 750 751 /** 752 * Assembles message header. 753 * @access private 754 * @return string 755 */ 756 function CreateHeader() { 757 $result = ""; 758 759 // Set the boundaries 760 $uniq_id = md5(uniqid(time())); 761 $this->boundary[1] = "b1_" . $uniq_id; 762 $this->boundary[2] = "b2_" . $uniq_id; 763 764 $result .= $this->HeaderLine("Date", $this->RFCDate()); 765 if($this->Sender == "") 766 $result .= $this->HeaderLine("Return-Path", trim($this->From)); 767 else 768 $result .= $this->HeaderLine("Return-Path", trim($this->Sender)); 769 770 // To be created automatically by mail() 771 if($this->Mailer != "mail") 772 { 773 if(count($this->to) > 0) 774 $result .= $this->AddrAppend("To", $this->to); 775 else if (count($this->cc) == 0) 776 $result .= $this->HeaderLine("To", "undisclosed-recipients:;"); 777 if(count($this->cc) > 0) 778 $result .= $this->AddrAppend("Cc", $this->cc); 779 } 780 781 $from = array(); 782 $from[0][0] = trim($this->From); 783 $from[0][1] = $this->FromName; 784 $result .= $this->AddrAppend("From", $from); 785 786 // sendmail and mail() extract Bcc from the header before sending 787 if((($this->Mailer == "sendmail") || ($this->Mailer == "mail")) && (count($this->bcc) > 0)) 788 $result .= $this->AddrAppend("Bcc", $this->bcc); 789 790 if(count($this->ReplyTo) > 0) 791 $result .= $this->AddrAppend("Reply-to", $this->ReplyTo); 792 793 // mail() sets the subject itself 794 if($this->Mailer != "mail") 795 $result .= $this->HeaderLine("Subject", $this->EncodeHeader(trim($this->Subject))); 796 797 $result .= sprintf("Message-ID: <%s@%s>%s", $uniq_id, $this->ServerHostname(), $this->LE); 798 $result .= $this->HeaderLine("X-Priority", $this->Priority); 799 800 if($this->ConfirmReadingTo != "") 801 { 802 $result .= $this->HeaderLine("Disposition-Notification-To", 803 "<" . trim($this->ConfirmReadingTo) . ">"); 804 } 805 806 // Add custom headers 807 for($index = 0; $index < count($this->CustomHeader); $index++) 808 { 809 $result .= $this->HeaderLine(trim($this->CustomHeader[$index][0]), 810 $this->EncodeHeader(trim($this->CustomHeader[$index][1]))); 811 } 812 $result .= $this->HeaderLine("MIME-Version", "1.0"); 813 814 switch($this->message_type) 815 { 816 case "plain": 817 $result .= $this->HeaderLine("Content-Transfer-Encoding", $this->Encoding); 818 $result .= sprintf("Content-Type: %s; charset=\"%s\"", 819 $this->ContentType, $this->CharSet); 820 break; 821 case "attachments": 822 // fall through 823 case "alt_attachments": 824 if($this->InlineImageExists()) 825 { 826 $result .= sprintf("Content-Type: %s;%s\ttype=\"text/html\";%s\tboundary=\"%s\"%s", 827 "multipart/related", $this->LE, $this->LE, 828 $this->boundary[1], $this->LE); 829 } 830 else 831 { 832 $result .= $this->HeaderLine("Content-Type", "multipart/mixed;"); 833 $result .= $this->TextLine("\tboundary=\"" . $this->boundary[1] . '"'); 834 } 835 break; 836 case "alt": 837 $result .= $this->HeaderLine("Content-Type", "multipart/alternative;"); 838 $result .= $this->TextLine("\tboundary=\"" . $this->boundary[1] . '"'); 839 break; 840 } 841 842 if($this->Mailer != "mail") 843 $result .= $this->LE.$this->LE; 844 845 return $result; 846 } 847 848 /** 849 * Assembles the message body. Returns an empty string on failure. 850 * @access private 851 * @return string 852 */ 853 function CreateBody() { 854 $result = ""; 855 856 $this->SetWordWrap(); 857 858 switch($this->message_type) 859 { 860 case "alt": 861 $result .= $this->GetBoundary($this->boundary[1], "", 862 "text/plain", ""); 863 $result .= $this->EncodeString($this->AltBody, $this->Encoding); 864 $result .= $this->LE.$this->LE; 865 $result .= $this->GetBoundary($this->boundary[1], "", 866 "text/html", ""); 867 868 $result .= $this->EncodeString($this->Body, $this->Encoding); 869 $result .= $this->LE.$this->LE; 870 871 $result .= $this->EndBoundary($this->boundary[1]); 872 break; 873 case "plain": 874 $result .= $this->EncodeString($this->Body, $this->Encoding); 875 break; 876 case "attachments": 877 $result .= $this->GetBoundary($this->boundary[1], "", "", ""); 878 $result .= $this->EncodeString($this->Body, $this->Encoding); 879 $result .= $this->LE; 880 881 $result .= $this->AttachAll(); 882 break; 883 case "alt_attachments": 884 $result .= sprintf("--%s%s", $this->boundary[1], $this->LE); 885 $result .= sprintf("Content-Type: %s;%s" . 886 "\tboundary=\"%s\"%s", 887 "multipart/alternative", $this->LE, 888 $this->boundary[2], $this->LE.$this->LE); 889 890 // Create text body 891 $result .= $this->GetBoundary($this->boundary[2], "", 892 "text/plain", "") . $this->LE; 893 894 $result .= $this->EncodeString($this->AltBody, $this->Encoding); 895 $result .= $this->LE.$this->LE; 896 897 // Create the HTML body 898 $result .= $this->GetBoundary($this->boundary[2], "", 899 "text/html", "") . $this->LE; 900 901 $result .= $this->EncodeString($this->Body, $this->Encoding); 902 $result .= $this->LE.$this->LE; 903 904 $result .= $this->EndBoundary($this->boundary[2]); 905 906 $result .= $this->AttachAll(); 907 break; 908 } 909 if($this->IsError()) 910 $result = ""; 911 912 return $result; 913 } 914 915 /** 916 * Returns the start of a message boundary. 917 * @access private 918 */ 919 function GetBoundary($boundary, $charSet, $contentType, $encoding) { 920 $result = ""; 921 if($charSet == "") { $charSet = $this->CharSet; } 922 if($contentType == "") { $contentType = $this->ContentType; } 923 if($encoding == "") { $encoding = $this->Encoding; } 924 925 $result .= $this->TextLine("--" . $boundary); 926 $result .= sprintf("Content-Type: %s; charset = \"%s\"", 927 $contentType, $charSet); 928 $result .= $this->LE; 929 $result .= $this->HeaderLine("Content-Transfer-Encoding", $encoding); 930 $result .= $this->LE; 931 932 return $result; 933 } 934 935 /** 936 * Returns the end of a message boundary. 937 * @access private 938 */ 939 function EndBoundary($boundary) { 940 return $this->LE . "--" . $boundary . "--" . $this->LE; 941 } 942 943 /** 944 * Sets the message type. 945 * @access private 946 * @return void 947 */ 948 function SetMessageType() { 949 if(count($this->attachment) < 1 && strlen($this->AltBody) < 1) 950 $this->message_type = "plain"; 951 else 952 { 953 if(count($this->attachment) > 0) 954 $this->message_type = "attachments"; 955 if(strlen($this->AltBody) > 0 && count($this->attachment) < 1) 956 $this->message_type = "alt"; 957 if(strlen($this->AltBody) > 0 && count($this->attachment) > 0) 958 $this->message_type = "alt_attachments"; 959 } 960 } 961 962 /** 963 * Returns a formatted header line. 964 * @access private 965 * @return string 966 */ 967 function HeaderLine($name, $value) { 968 return $name . ": " . $value . $this->LE; 969 } 970 971 /** 972 * Returns a formatted mail line. 973 * @access private 974 * @return string 975 */ 976 function TextLine($value) { 977 return $value . $this->LE; 978 } 979 980 ///////////////////////////////////////////////// 981 // ATTACHMENT METHODS 982 ///////////////////////////////////////////////// 983 984 /** 985 * Adds an attachment from a path on the filesystem. 986 * Returns false if the file could not be found 987 * or accessed. 988 * @param string $path Path to the attachment. 989 * @param string $name Overrides the attachment name. 990 * @param string $encoding File encoding (see $Encoding). 991 * @param string $type File extension (MIME) type. 992 * @return bool 993 */ 994 function AddAttachment($path, $name = "", $encoding = "base64", 995 $type = "application/octet-stream") { 996 if(!@is_file($path)) 997 { 998 $this->SetError($this->Lang("file_access") . $path); 999 return false; 1000 } 1001 1002 $filename = basename($path); 1003 if($name == "") 1004 $name = $filename; 1005 1006 $cur = count($this->attachment); 1007 $this->attachment[$cur][0] = $path; 1008 $this->attachment[$cur][1] = $filename; 1009 $this->attachment[$cur][2] = $name; 1010 $this->attachment[$cur][3] = $encoding; 1011 $this->attachment[$cur][4] = $type; 1012 $this->attachment[$cur][5] = false; // isStringAttachment 1013 $this->attachment[$cur][6] = "attachment"; 1014 $this->attachment[$cur][7] = 0; 1015 1016 return true; 1017 } 1018 1019 /** 1020 * Attaches all fs, string, and binary attachments to the message. 1021 * Returns an empty string on failure. 1022 * @access private 1023 * @return string 1024 */ 1025 function AttachAll() { 1026 // Return text of body 1027 $mime = array(); 1028 1029 // Add all attachments 1030 for($i = 0; $i < count($this->attachment); $i++) 1031 { 1032 // Check for string attachment 1033 $bString = $this->attachment[$i][5]; 1034 if ($bString) 1035 $string = $this->attachment[$i][0]; 1036 else 1037 $path = $this->attachment[$i][0]; 1038 1039 $filename = $this->attachment[$i][1]; 1040 $name = $this->attachment[$i][2]; 1041 $encoding = $this->attachment[$i][3]; 1042 $type = $this->attachment[$i][4]; 1043 $disposition = $this->attachment[$i][6]; 1044 $cid = $this->attachment[$i][7]; 1045 1046 $mime[] = sprintf("--%s%s", $this->boundary[1], $this->LE); 1047 $mime[] = sprintf("Content-Type: %s; name=\"%s\"%s", $type, $name, $this->LE); 1048 $mime[] = sprintf("Content-Transfer-Encoding: %s%s", $encoding, $this->LE); 1049 1050 if($disposition == "inline") 1051 $mime[] = sprintf("Content-ID: <%s>%s", $cid, $this->LE); 1052 1053 $mime[] = sprintf("Content-Disposition: %s; filename=\"%s\"%s", 1054 $disposition, $name, $this->LE.$this->LE); 1055 1056 // Encode as string attachment 1057 if($bString) 1058 { 1059 $mime[] = $this->EncodeString($string, $encoding); 1060 if($this->IsError()) { return ""; } 1061 $mime[] = $this->LE.$this->LE; 1062 } 1063 else 1064 { 1065 $mime[] = $this->EncodeFile($path, $encoding); 1066 if($this->IsError()) { return ""; } 1067 $mime[] = $this->LE.$this->LE; 1068 } 1069 } 1070 1071 $mime[] = sprintf("--%s--%s", $this->boundary[1], $this->LE); 1072 1073 return join("", $mime); 1074 } 1075 1076 /** 1077 * Encodes attachment in requested format. Returns an 1078 * empty string on failure. 1079 * @access private 1080 * @return string 1081 */ 1082 function EncodeFile ($path, $encoding = "base64") { 1083 if(!@$fd = fopen($path, "rb")) 1084 { 1085 $this->SetError($this->Lang("file_open") . $path); 1086 return ""; 1087 } 1088 $magic_quotes = get_magic_quotes_runtime(); 1089 set_magic_quotes_runtime(0); 1090 $file_buffer = fread($fd, filesize($path)); 1091 $file_buffer = $this->EncodeString($file_buffer, $encoding); 1092 fclose($fd); 1093 set_magic_quotes_runtime($magic_quotes); 1094 1095 return $file_buffer; 1096 } 1097 1098 /** 1099 * Encodes string to requested format. Returns an 1100 * empty string on failure. 1101 * @access private 1102 * @return string 1103 */ 1104 function EncodeString ($str, $encoding = "base64") { 1105 $encoded = ""; 1106 switch(strtolower($encoding)) { 1107 case "base64": 1108 // chunk_split is found in PHP >= 3.0.6 1109 $encoded = chunk_split(base64_encode($str), 76, $this->LE); 1110 break; 1111 case "7bit": 1112 case "8bit": 1113 $encoded = $this->FixEOL($str); 1114 if (substr($encoded, -(strlen($this->LE))) != $this->LE) 1115 $encoded .= $this->LE; 1116 break; 1117 case "binary": 1118 $encoded = $str; 1119 break; 1120 case "quoted-printable": 1121 $encoded = $this->EncodeQP($str); 1122 break; 1123 default: 1124 $this->SetError($this->Lang("encoding") . $encoding); 1125 break; 1126 } 1127 return $encoded; 1128 } 1129 1130 /** 1131 * Encode a header string to best of Q, B, quoted or none. 1132 * @access private 1133 * @return string 1134 */ 1135 function EncodeHeader ($str, $position = 'text') { 1136 $x = 0; 1137 1138 switch (strtolower($position)) { 1139 case 'phrase': 1140 if (!preg_match('/[\200-\377]/', $str)) { 1141 // Can't use addslashes as we don't know what value has magic_quotes_sybase. 1142 $encoded = addcslashes($str, "\0..\37\177\\\""); 1143 1144 if (($str == $encoded) && !preg_match('/[^A-Za-z0-9!#$%&\'*+\/=?^_`{|}~ -]/', $str)) 1145 return ($encoded); 1146 else 1147 return ("\"$encoded\""); 1148 } 1149 $x = preg_match_all('/[^\040\041\043-\133\135-\176]/', $str, $matches); 1150 break; 1151 case 'comment': 1152 $x = preg_match_all('/[()"]/', $str, $matches); 1153 // Fall-through 1154 case 'text': 1155 default: 1156 $x += preg_match_all('/[\000-\010\013\014\016-\037\177-\377]/', $str, $matches); 1157 break; 1158 } 1159 1160 if ($x == 0) 1161 return ($str); 1162 1163 $maxlen = 75 - 7 - strlen($this->CharSet); 1164 // Try to select the encoding which should produce the shortest output 1165 if (strlen($str)/3 < $x) { 1166 $encoding = 'B'; 1264 $x = preg_match_all('/[^\040\041\043-\133\135-\176]/', $str, $matches); 1265 break; 1266 case 'comment': 1267 $x = preg_match_all('/[()"]/', $str, $matches); 1268 /* Fall-through */ 1269 case 'text': 1270 default: 1271 $x += preg_match_all('/[\000-\010\013\014\016-\037\177-\377]/', $str, $matches); 1272 break; 1273 } 1274 1275 if ($x == 0) { 1276 return ($str); 1277 } 1278 1279 $maxlen = 75 - 7 - strlen($this->CharSet); 1280 /* Try to select the encoding which should produce the shortest output */ 1281 if (strlen($str)/3 < $x) { 1282 $encoding = 'B'; 1283 if (function_exists('mb_strlen') && $this->HasMultiBytes($str)) { 1284 // Use a custom function which correctly encodes and wraps long 1285 // multibyte strings without breaking lines within a character 1286 $encoded = $this->Base64EncodeWrapMB($str); 1287 } else { 1167 1288 $encoded = base64_encode($str); 1168 1289 $maxlen -= $maxlen % 4; 1169 1290 $encoded = trim(chunk_split($encoded, $maxlen, "\n")); 1170 } else { 1171 $encoding = 'Q'; 1172 $encoded = $this->EncodeQ($str, $position); 1173 $encoded = $this->WrapText($encoded, $maxlen, true); 1174 $encoded = str_replace("=".$this->LE, "\n", trim($encoded)); 1175 } 1176 1177 $encoded = preg_replace('/^(.*)$/m', " =?".$this->CharSet."?$encoding?\\1?=", $encoded); 1178 $encoded = trim(str_replace("\n", $this->LE, $encoded)); 1179 1180 return $encoded; 1181 } 1182 1183 /** 1184 * Encode string to quoted-printable. 1185 * @access private 1186 * @return string 1187 */ 1188 function EncodeQP ($str) { 1189 $encoded = $this->FixEOL($str); 1190 if (substr($encoded, -(strlen($this->LE))) != $this->LE) 1191 $encoded .= $this->LE; 1192 1193 // Replace every high ascii, control and = characters 1194 $encoded = preg_replace('/([\000-\010\013\014\016-\037\075\177-\377])/e', 1195 "'='.sprintf('%02X', ord('\\1'))", $encoded); 1196 // Replace every spaces and tabs when it's the last character on a line 1197 $encoded = preg_replace("/([\011\040])".$this->LE."/e", 1198 "'='.sprintf('%02X', ord('\\1')).'".$this->LE."'", $encoded); 1199 1200 // Maximum line length of 76 characters before CRLF (74 + space + '=') 1201 $encoded = $this->WrapText($encoded, 74, true); 1202 1203 return $encoded; 1204 } 1205 1206 /** 1207 * Encode string to q encoding. 1208 * @access private 1209 * @return string 1210 */ 1211 function EncodeQ ($str, $position = "text") { 1212 // There should not be any EOL in the string 1213 $encoded = preg_replace("[\r\n]", "", $str); 1214 1215 switch (strtolower($position)) { 1216 case "phrase": 1217 $encoded = preg_replace("/([^A-Za-z0-9!*+\/ -])/e", "'='.sprintf('%02X', ord('\\1'))", $encoded); 1218 break; 1219 case "comment": 1220 $encoded = preg_replace("/([\(\)\"])/e", "'='.sprintf('%02X', ord('\\1'))", $encoded); 1221 case "text": 1222 default: 1223 // Replace every high ascii, control =, ? and _ characters 1224 $encoded = preg_replace('/([\000-\011\013\014\016-\037\075\077\137\177-\377])/e', 1225 "'='.sprintf('%02X', ord('\\1'))", $encoded); 1226 break; 1291 } 1292 } else { 1293 $encoding = 'Q'; 1294 $encoded = $this->EncodeQ($str, $position); 1295 $encoded = $this->WrapText($encoded, $maxlen, true); 1296 $encoded = str_replace('='.$this->LE, "\n", trim($encoded)); 1297 } 1298 1299 $encoded = preg_replace('/^(.*)$/m', " =?".$this->CharSet."?$encoding?\\1?=", $encoded); 1300 $encoded = trim(str_replace("\n", $this->LE, $encoded)); 1301 1302 return $encoded; 1303 } 1304 1305 /** 1306 * Checks if a string contains multibyte characters. 1307 * @access private 1308 * @param string $str multi-byte text to wrap encode 1309 * @return bool 1310 */ 1311 function HasMultiBytes($str) { 1312 if (function_exists('mb_strlen')) { 1313 return (strlen($str) > mb_strlen($str, $this->CharSet)); 1314 } else { // Assume no multibytes (we can't handle without mbstring functions anyway) 1315 return False; 1316 } 1317 } 1318 1319 /** 1320 * Correctly encodes and wraps long multibyte strings for mail headers 1321 * without breaking lines within a character. 1322 * Adapted from a function by paravoid at http://uk.php.net/manual/en/function.mb-encode-mimeheader.php 1323 * @access private 1324 * @param string $str multi-byte text to wrap encode 1325 * @return string 1326 */ 1327 function Base64EncodeWrapMB($str) { 1328 $start = "=?".$this->CharSet."?B?"; 1329 $end = "?="; 1330 $encoded = ""; 1331 1332 $mb_length = mb_strlen($str, $this->CharSet); 1333 // Each line must have length <= 75, including $start and $end 1334 $length = 75 - strlen($start) - strlen($end); 1335 // Average multi-byte ratio 1336 $ratio = $mb_length / strlen($str); 1337 // Base64 has a 4:3 ratio 1338 $offset = $avgLength = floor($length * $ratio * .75); 1339 1340 for ($i = 0; $i < $mb_length; $i += $offset) { 1341 $lookBack = 0; 1342 1343 do { 1344 $offset = $avgLength - $lookBack; 1345 $chunk = mb_substr($str, $i, $offset, $this->CharSet); 1346 $chunk = base64_encode($chunk); 1347 $lookBack++; 1348 } 1349 while (strlen($chunk) > $length); 1350 1351 $encoded .= $chunk . $this->LE; 1352 } 1353 1354 // Chomp the last linefeed 1355 $encoded = substr($encoded, 0, -strlen($this->LE)); 1356 return $encoded; 1357 } 1358 1359 /** 1360 * Encode string to quoted-printable. 1361 * @access private 1362 * @return string 1363 */ 1364 function EncodeQP( $input = '', $line_max = 76, $space_conv = false ) { 1365 $hex = array('0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'); 1366 $lines = preg_split('/(?:\r\n|\r|\n)/', $input); 1367 $eol = "\r\n"; 1368 $escape = '='; 1369 $output = ''; 1370 while( list(, $line) = each($lines) ) { 1371 $linlen = strlen($line); 1372 $newline = ''; 1373 for($i = 0; $i < $linlen; $i++) { 1374 $c = substr( $line, $i, 1 ); 1375 $dec = ord( $c ); 1376 if ( ( $i == 0 ) && ( $dec == 46 ) ) { // convert first point in the line into =2E 1377 $c = '=2E'; 1227 1378 } 1228 1229 // Replace every spaces to _ (more readable than =20) 1230 $encoded = str_replace(" ", "_", $encoded); 1231 1232 return $encoded; 1233 } 1234 1235 /** 1236 * Adds a string or binary attachment (non-filesystem) to the list. 1237 * This method can be used to attach ascii or binary data, 1238 * such as a BLOB record from a database. 1239 * @param string $string String attachment data. 1240 * @param string $filename Name of the attachment. 1241 * @param string $encoding File encoding (see $Encoding). 1242 * @param string $type File extension (MIME) type. 1243 * @return void 1244 */ 1245 function AddStringAttachment($string, $filename, $encoding = "base64", 1246 $type = "application/octet-stream") { 1247 // Append to $attachment array 1248 $cur = count($this->attachment); 1249 $this->attachment[$cur][0] = $string; 1250 $this->attachment[$cur][1] = $filename; 1251 $this->attachment[$cur][2] = $filename; 1252 $this->attachment[$cur][3] = $encoding; 1253 $this->attachment[$cur][4] = $type; 1254 $this->attachment[$cur][5] = true; // isString 1255 $this->attachment[$cur][6] = "attachment"; 1256 $this->attachment[$cur][7] = 0; 1257 } 1258 1259 /** 1260 * Adds an embedded attachment. This can include images, sounds, and 1261 * just about any other document. Make sure to set the $type to an 1262 * image type. For JPEG images use "image/jpeg" and for GIF images 1263 * use "image/gif". 1264 * @param string $path Path to the attachment. 1265 * @param string $cid Content ID of the attachment. Use this to identify 1266 * the Id for accessing the image in an HTML form. 1267 * @param string $name Overrides the attachment name. 1268 * @param string $encoding File encoding (see $Encoding). 1269 * @param string $type File extension (MIME) type. 1270 * @return bool 1271 */ 1272 function AddEmbeddedImage($path, $cid, $name = "", $encoding = "base64", 1273 $type = "application/octet-stream") { 1274 1275 if(!@is_file($path)) 1276 { 1277 $this->SetError($this->Lang("file_access") . $path); 1278 return false; 1379 if ( $dec == 32 ) { 1380 if ( $i == ( $linlen - 1 ) ) { // convert space at eol only 1381 $c = '=20'; 1382 } else if ( $space_conv ) { 1383 $c = '=20'; 1384 } 1385 } elseif ( ($dec == 61) || ($dec < 32 ) || ($dec > 126) ) { // always encode "\t", which is *not* required 1386 $h2 = floor($dec/16); 1387 $h1 = floor($dec%16); 1388 $c = $escape.$hex[$h2].$hex[$h1]; 1279 1389 } 1280 1281 $filename = basename($path); 1282 if($name == "") 1283 $name = $filename; 1284 1285 // Append to $attachment array 1286 $cur = count($this->attachment); 1287 $this->attachment[$cur][0] = $path; 1288 $this->attachment[$cur][1] = $filename; 1289 $this->attachment[$cur][2] = $name; 1290 $this->attachment[$cur][3] = $encoding; 1291 $this->attachment[$cur][4] = $type; 1292 $this->attachment[$cur][5] = false; // isStringAttachment 1293 $this->attachment[$cur][6] = "inline"; 1294 $this->attachment[$cur][7] = $cid; 1295 1296 return true; 1297 } 1298 1299 /** 1300 * Returns true if an inline attachment is present. 1301 * @access private 1302 * @return bool 1303 */ 1304 function InlineImageExists() { 1305 $result = false; 1306 for($i = 0; $i < count($this->attachment); $i++) 1307 { 1308 if($this->attachment[$i][6] == "inline") 1309 { 1310 $result = true; 1311 break; 1312 } 1390 if ( (strlen($newline) + strlen($c)) >= $line_max ) { // CRLF is not counted 1391 $output .= $newline.$escape.$eol; // soft line break; " =\r\n" is okay 1392 $newline = ''; 1393 // check if newline first character will be point or not 1394 if ( $dec == 46 ) { 1395 $c = '=2E'; 1396 } 1313 1397 } 1314 1315 return $result; 1316 } 1317 1318 ///////////////////////////////////////////////// 1319 // MESSAGE RESET METHODS 1320 ///////////////////////////////////////////////// 1321 1322 /** 1323 * Clears all recipients assigned in the TO array. Returns void. 1324 * @return void 1325 */ 1326 function ClearAddresses() { 1327 $this->to = array(); 1328 } 1329 1330 /** 1331 * Clears all recipients assigned in the CC array. Returns void. 1332 * @return void 1333 */ 1334 function ClearCCs() { 1335 $this->cc = array(); 1336 } 1337 1338 /** 1339 * Clears all recipients assigned in the BCC array. Returns void. 1340 * @return void 1341 */ 1342 function ClearBCCs() { 1343 $this->bcc = array(); 1344 } 1345 1346 /** 1347 * Clears all recipients assigned in the ReplyTo array. Returns void. 1348 * @return void 1349 */ 1350 function ClearReplyTos() { 1351 $this->ReplyTo = array(); 1352 } 1353 1354 /** 1355 * Clears all recipients assigned in the TO, CC and BCC 1356 * array. Returns void. 1357 * @return void 1358 */ 1359 function ClearAllRecipients() { 1360 $this->to = array(); 1361 $this->cc = array(); 1362 $this->bcc = array(); 1363 } 1364 1365 /** 1366 * Clears all previously set filesystem, string, and binary 1367 * attachments. Returns void. 1368 * @return void 1369 */ 1370 function ClearAttachments() { 1371 $this->attachment = array(); 1372 } 1373 1374 /** 1375 * Clears all custom headers. Returns void. 1376 * @return void 1377 */ 1378 function ClearCustomHeaders() { 1379 $this->CustomHeader = array(); 1380 } 1381 1382 1383 ///////////////////////////////////////////////// 1384 // MISCELLANEOUS METHODS 1385 ///////////////////////////////////////////////// 1386 1387 /** 1388 * Adds the error message to the error container. 1389 * Returns void. 1390 * @access private 1391 * @return void 1392 */ 1393 function SetError($msg) { 1394 $this->error_count++; 1395 $this->ErrorInfo = $msg; 1396 } 1397 1398 /** 1399 * Returns the proper RFC 822 formatted date. 1400 * @access private 1401 * @return string 1402 */ 1403 function RFCDate() { 1404 $tz = date("Z"); 1405 $tzs = ($tz < 0) ? "-" : "+"; 1406 $tz = abs($tz); 1407 $tz = ($tz/3600)*100 + ($tz%3600)/60; 1408 $result = sprintf("%s %s%04d", date("D, j M Y H:i:s"), $tzs, $tz); 1409 1410 return $result; 1411 } 1412 1413 /** 1414 * Returns the appropriate server variable. Should work with both 1415 * PHP 4.1.0+ as well as older versions. Returns an empty string 1416 * if nothing is found. 1417 * @access private 1418 * @return mixed 1419 */ 1420 function ServerVar($varName) { 1421 global $HTTP_SERVER_VARS; 1422 global $HTTP_ENV_VARS; 1423 1424 if(!isset($_SERVER)) 1425 { 1426 $_SERVER = $HTTP_SERVER_VARS; 1427 if(!isset($_SERVER["REMOTE_ADDR"])) 1428 $_SERVER = $HTTP_ENV_VARS; // must be Apache 1398 $newline .= $c; 1399 } // end of for 1400 $output .= $newline.$eol; 1401 } // end of while 1402 return trim($output); 1403 } 1404 1405 /** 1406 * Encode string to q encoding. 1407 * @access private 1408 * @return string 1409 */ 1410 function EncodeQ ($str, $position = 'text') { 1411 /* There should not be any EOL in the string */ 1412 $encoded = preg_replace("[\r\n]", '', $str); 1413 1414 switch (strtolower($position)) { 1415 case 'phrase': 1416 $encoded = preg_replace("/([^A-Za-z0-9!*+\/ -])/e", "'='.sprintf('%02X', ord('\\1'))", $encoded); 1417 break; 1418 case 'comment': 1419 $encoded = preg_replace("/([\(\)\"])/e", "'='.sprintf('%02X', ord('\\1'))", $encoded); 1420 case 'text': 1421 default: 1422 /* Replace every high ascii, control =, ? and _ characters */ 1423 $encoded = preg_replace('/([\000-\011\013\014\016-\037\075\077\137\177-\377])/e', 1424 "'='.sprintf('%02X', ord('\\1'))", $encoded); 1425 break; 1426 } 1427 1428 /* Replace every spaces to _ (more readable than =20) */ 1429 $encoded = str_replace(' ', '_', $encoded); 1430 1431 return $encoded; 1432 } 1433 1434 /** 1435 * Adds a string or binary attachment (non-filesystem) to the list. 1436 * This method can be used to attach ascii or binary data, 1437 * such as a BLOB record from a database. 1438 * @param string $string String attachment data. 1439 * @param string $filename Name of the attachment. 1440 * @param string $encoding File encoding (see $Encoding). 1441 * @param string $type File extension (MIME) type. 1442 * @return void 1443 */ 1444 function AddStringAttachment($string, $filename, $encoding = 'base64', $type = 'application/octet-stream') { 1445 /* Append to $attachment array */ 1446 $cur = count($this->attachment); 1447 $this->attachment[$cur][0] = $string; 1448 $this->attachment[$cur][1] = $filename; 1449 $this->attachment[$cur][2] = $filename; 1450 $this->attachment[$cur][3] = $encoding; 1451 $this->attachment[$cur][4] = $type; 1452 $this->attachment[$cur][5] = true; // isString 1453 $this->attachment[$cur][6] = 'attachment'; 1454 $this->attachment[$cur][7] = 0; 1455 } 1456 1457 /** 1458 * Adds an embedded attachment. This can include images, sounds, and 1459 * just about any other document. Make sure to set the $type to an 1460 * image type. For JPEG images use "image/jpeg" and for GIF images 1461 * use "image/gif". 1462 * @param string $path Path to the attachment. 1463 * @param string $cid Content ID of the attachment. Use this to identify 1464 * the Id for accessing the image in an HTML form. 1465 * @param string $name Overrides the attachment name. 1466 * @param string $encoding File encoding (see $Encoding). 1467 * @param string $type File extension (MIME) type. 1468 * @return bool 1469 */ 1470 function AddEmbeddedImage($path, $cid, $name = '', $encoding = 'base64', $type = 'application/octet-stream') { 1471 1472 if(!@is_file($path)) { 1473 $this->SetError($this->Lang('file_access') . $path); 1474 return false; 1475 } 1476 1477 $filename = basename($path); 1478 if($name == '') { 1479 $name = $filename; 1480 } 1481 1482 /* Append to $attachment array */ 1483 $cur = count($this->attachment); 1484 $this->attachment[$cur][0] = $path; 1485 $this->attachment[$cur][1] = $filename; 1486 $this->attachment[$cur][2] = $name; 1487 $this->attachment[$cur][3] = $encoding; 1488 $this->attachment[$cur][4] = $type; 1489 $this->attachment[$cur][5] = false; 1490 $this->attachment[$cur][6] = 'inline'; 1491 $this->attachment[$cur][7] = $cid; 1492 1493 return true; 1494 } 1495 1496 /** 1497 * Returns true if an inline attachment is present. 1498 * @access private 1499 * @return bool 1500 */ 1501 function InlineImageExists() { 1502 $result = false; 1503 for($i = 0; $i < count($this->attachment); $i++) { 1504 if($this->attachment[$i][6] == 'inline') { 1505 $result = true; 1506 break; 1507 } 1508 } 1509 1510 return $result; 1511 } 1512 1513 ///////////////////////////////////////////////// 1514 // CLASS METHODS, MESSAGE RESET 1515 ///////////////////////////////////////////////// 1516 1517 /** 1518 * Clears all recipients assigned in the TO array. Returns void. 1519 * @return void 1520 */ 1521 function ClearAddresses() { 1522 $this->to = array(); 1523 } 1524 1525 /** 1526 * Clears all recipients assigned in the CC array. Returns void. 1527 * @return void 1528 */ 1529 function ClearCCs() { 1530 $this->cc = array(); 1531 } 1532 1533 /** 1534 * Clears all recipients assigned in the BCC array. Returns void. 1535 * @return void 1536 */ 1537 function ClearBCCs() { 1538 $this->bcc = array(); 1539 } 1540 1541 /** 1542 * Clears all recipients assigned in the ReplyTo array. Returns void. 1543 * @return void 1544 */ 1545 function ClearReplyTos() { 1546 $this->ReplyTo = array(); 1547 } 1548 1549 /** 1550 * Clears all recipients assigned in the TO, CC and BCC 1551 * array. Returns void. 1552 * @return void 1553 */ 1554 function ClearAllRecipients() { 1555 $this->to = array(); 1556 $this->cc = array(); 1557 $this->bcc = array(); 1558 } 1559 1560 /** 1561 * Clears all previously set filesystem, string, and binary 1562 * attachments. Returns void. 1563 * @return void 1564 */ 1565 function ClearAttachments() { 1566 $this->attachment = array(); 1567 } 1568 1569 /** 1570 * Clears all custom headers. Returns void. 1571 * @return void 1572 */ 1573 function ClearCustomHeaders() { 1574 $this->CustomHeader = array(); 1575 } 1576 1577 ///////////////////////////////////////////////// 1578 // CLASS METHODS, MISCELLANEOUS 1579 ///////////////////////////////////////////////// 1580 1581 /** 1582 * Adds the error message to the error container. 1583 * Returns void. 1584 * @access private 1585 * @return void 1586 */ 1587 function SetError($msg) { 1588 $this->error_count++; 1589 $this->ErrorInfo = $msg; 1590 } 1591 1592 /** 1593 * Returns the proper RFC 822 formatted date. 1594 * @access private 1595 * @return string 1596 */ 1597 function RFCDate() { 1598 $tz = date('Z'); 1599 $tzs = ($tz < 0) ? '-' : '+'; 1600 $tz = abs($tz); 1601 $tz = (int)($tz/3600)*100 + ($tz%3600)/60; 1602 $result = sprintf("%s %s%04d", date('D, j M Y H:i:s'), $tzs, $tz); 1603 1604 return $result; 1605 } 1606 1607 /** 1608 * Returns the appropriate server variable. Should work with both 1609 * PHP 4.1.0+ as well as older versions. Returns an empty string 1610 * if nothing is found. 1611 * @access private 1612 * @return mixed 1613 */ 1614 function ServerVar($varName) { 1615 global $HTTP_SERVER_VARS; 1616 global $HTTP_ENV_VARS; 1617 1618 if(!isset($_SERVER)) { 1619 $_SERVER = $HTTP_SERVER_VARS; 1620 if(!isset($_SERVER['REMOTE_ADDR'])) { 1621 $_SERVER = $HTTP_ENV_VARS; // must be Apache 1622 } 1623 } 1624 1625 if(isset($_SERVER[$varName])) { 1626 return $_SERVER[$varName]; 1627 } else { 1628 return ''; 1629 } 1630 } 1631 1632 /** 1633 * Returns the server hostname or 'localhost.localdomain' if unknown. 1634 * @access private 1635 * @return string 1636 */ 1637 function ServerHostname() { 1638 if ($this->Hostname != '') { 1639 $result = $this->Hostname; 1640 } elseif ($this->ServerVar('SERVER_NAME') != '') { 1641 $result = $this->ServerVar('SERVER_NAME'); 1642 } else { 1643 $result = 'localhost.localdomain'; 1644 } 1645 1646 return $result; 1647 } 1648 1649 /** 1650 * Returns a message in the appropriate language. 1651 * @access private 1652 * @return string 1653 */ 1654 function Lang($key) { 1655 if(count($this->language) < 1) { 1656 $this->SetLanguage('en'); // set the default language 1657 } 1658 1659 if(isset($this->language[$key])) { 1660 return $this->language[$key]; 1661 } else { 1662 return 'Language string failed to load: ' . $key; 1663 } 1664 } 1665 1666 /** 1667 * Returns true if an error occurred. 1668 * @return bool 1669 */ 1670 function IsError() { 1671 return ($this->error_count > 0); 1672 } 1673 1674 /** 1675 * Changes every end of line from CR or LF to CRLF. 1676 * @access private 1677 * @return string 1678 */ 1679 function FixEOL($str) { 1680 $str = str_replace("\r\n", "\n", $str); 1681 $str = str_replace("\r", "\n", $str); 1682 $str = str_replace("\n", $this->LE, $str); 1683 return $str; 1684 } 1685 1686 /** 1687 * Adds a custom header. 1688 * @return void 1689 */ 1690 function AddCustomHeader($custom_header) { 1691 $this->CustomHeader[] = explode(':', $custom_header, 2); 1692 } 1693 1694 /** 1695 * Evaluates the message and returns modifications for inline images and backgrounds 1696 * @access public 1697 * @return $message 1698 */ 1699 function MsgHTML($message,$basedir='') { 1700 preg_match_all("/(src|background)=\"(.*)\"/Ui", $message, $images); 1701 if(isset($images[2])) { 1702 foreach($images[2] as $i => $url) { 1703 // do not change urls for absolute images (thanks to corvuscorax) 1704 if (!preg_match('/^[A-z][A-z]*:\/\//',$url)) { 1705 $filename = basename($url); 1706 $directory = dirname($url); 1707 ($directory == '.')?$directory='':''; 1708 $cid = 'cid:' . md5($filename); 1709 $fileParts = split("\.", $filename); 1710 $ext = $fileParts[1]; 1711 $mimeType = $this->_mime_types($ext); 1712 if ( strlen($basedir) > 1 && substr($basedir,-1) != '/') { $basedir .= '/'; } 1713 if ( strlen($directory) > 1 && substr($basedir,-1) != '/') { $directory .= '/'; } 1714 $this->AddEmbeddedImage($basedir.$directory.$filename, md5($filename), $filename, 'base64', $mimeType); 1715 if ( $this->AddEmbeddedImage($basedir.$directory.$filename, md5($filename), $filename, 'base64',$mimeType) ) { 1716 $message = preg_replace("/".$images[1][$i]."=\"".preg_quote($url, '/')."\"/Ui", $images[1][$i]."=\"".$cid."\"", $message); 1717 } 1429 1718 } 1430 1431 if(isset($_SERVER[$varName])) 1432 return $_SERVER[$varName]; 1433 else 1434 return ""; 1435 } 1436 1437 /** 1438 * Returns the server hostname or 'localhost.localdomain' if unknown. 1439 * @access private 1440 * @return string 1441 */ 1442 function ServerHostname() { 1443 if ($this->Hostname != "") 1444 $result = $this->Hostname; 1445 elseif ($this->ServerVar('SERVER_NAME') != "") 1446 $result = $this->ServerVar('SERVER_NAME'); 1447 else 1448 $result = "localhost.localdomain"; 1449 1450 return $result; 1451 } 1452 1453 /** 1454 * Returns a message in the appropriate language. 1455 * @access private 1456 * @return string 1457 */ 1458 function Lang($key) { 1459 if(count($this->language) < 1) 1460 $this->SetLanguage("en"); // set the default language 1461 1462 if(isset($this->language[$key])) 1463 return $this->language[$key]; 1464 else 1465 return "Language string failed to load: " . $key; 1466 } 1467 1468 /** 1469 * Returns true if an error occurred. 1470 * @return bool 1471 */ 1472 function IsError() { 1473 return ($this->error_count > 0); 1474 } 1475 1476 /** 1477 * Changes every end of line from CR or LF to CRLF. 1478 * @access private 1479 * @return string 1480 */ 1481 function FixEOL($str) { 1482 $str = str_replace("\r\n", "\n", $str); 1483 $str = str_replace("\r", "\n", $str); 1484 $str = str_replace("\n", $this->LE, $str); 1485 return $str; 1486 } 1487 1488 /** 1489 * Adds a custom header. 1490 * @return void 1491 */ 1492 function AddCustomHeader($custom_header) { 1493 $this->CustomHeader[] = explode(":", $custom_header, 2); 1494 } 1719 } 1720 } 1721 $this->IsHTML(true); 1722 $this->Body = $message; 1723 $textMsg = trim(strip_tags(preg_replace('/<(head|title|style|script)[^>]*>.*?<\/\\1>/s','',$message))); 1724 if ( !empty($textMsg) && empty($this->AltBody) ) { 1725 $this->AltBody = $textMsg; 1726 } 1727 if ( empty($this->AltBody) ) { 1728 $this->AltBody = 'To view this email message, open the email in with HTML compatibility!' . "\n\n"; 1729 } 1730 } 1731 1732 /** 1733 * Gets the mime type of the embedded or inline image 1734 * @access private 1735 * @return mime type of ext 1736 */ 1737 function _mime_types($ext = '') { 1738 $mimes = array( 1739 'hqx' => 'application/mac-binhex40', 1740 'cpt' => 'application/mac-compactpro', 1741 'doc' => 'application/msword', 1742 'bin' => 'application/macbinary', 1743 'dms' => 'application/octet-stream', 1744 'lha' => 'application/octet-stream', 1745 'lzh' => 'application/octet-stream', 1746 'exe' => 'application/octet-stream', 1747 'class' => 'application/octet-stream', 1748 'psd' => 'application/octet-stream', 1749 'so' => 'application/octet-stream', 1750 'sea' => 'application/octet-stream', 1751 'dll' => 'application/octet-stream', 1752 'oda' => 'application/oda', 1753 'pdf' => 'application/pdf', 1754 'ai' => 'application/postscript', 1755 'eps' => 'application/postscript', 1756 'ps' => 'application/postscript', 1757 'smi' => 'application/smil', 1758 'smil' => 'application/smil', 1759 'mif' => 'application/vnd.mif', 1760 'xls' => 'application/vnd.ms-excel', 1761 'ppt' => 'application/vnd.ms-powerpoint', 1762 'wbxml' => 'application/vnd.wap.wbxml', 1763 'wmlc' => 'application/vnd.wap.wmlc', 1764 'dcr' => 'application/x-director', 1765 'dir' => 'application/x-director', 1766 'dxr' => 'application/x-director', 1767 'dvi' => 'application/x-dvi', 1768 'gtar' => 'application/x-gtar', 1769 'php' => 'application/x-httpd-php', 1770 'php4' => 'application/x-httpd-php', 1771 'php3' => 'application/x-httpd-php', 1772 'phtml' => 'application/x-httpd-php', 1773 'phps' => 'application/x-httpd-php-source', 1774 'js' => 'application/x-javascript', 1775 'swf' => 'application/x-shockwave-flash', 1776 'sit' => 'application/x-stuffit', 1777 'tar' => 'application/x-tar', 1778 'tgz' => 'application/x-tar', 1779 'xhtml' => 'application/xhtml+xml', 1780 'xht' => 'application/xhtml+xml', 1781 'zip' => 'application/zip', 1782 'mid' => 'audio/midi', 1783 'midi' => 'audio/midi', 1784 'mpga' => 'audio/mpeg', 1785 'mp2' => 'audio/mpeg', 1786 'mp3' => 'audio/mpeg', 1787 'aif' => 'audio/x-aiff', 1788 'aiff' => 'audio/x-aiff', 1789 'aifc' => 'audio/x-aiff', 1790 'ram' => 'audio/x-pn-realaudio', 1791 'rm' => 'audio/x-pn-realaudio', 1792 'rpm' => 'audio/x-pn-realaudio-plugin', 1793 'ra' => 'audio/x-realaudio', 1794 'rv' => 'video/vnd.rn-realvideo', 1795 'wav' => 'audio/x-wav', 1796 'bmp' => 'image/bmp', 1797 'gif' => 'image/gif', 1798 'jpeg' => 'image/jpeg', 1799 'jpg' => 'image/jpeg', 1800 'jpe' => 'image/jpeg', 1801 'png' => 'image/png', 1802 'tiff' => 'image/tiff', 1803 'tif' => 'image/tiff', 1804 'css' => 'text/css', 1805 'html' => 'text/html', 1806 'htm' => 'text/html', 1807 'shtml' => 'text/html', 1808 'txt' => 'text/plain', 1809 'text' => 'text/plain', 1810 'log' => 'text/plain', 1811 'rtx' => 'text/richtext', 1812 'rtf' => 'text/rtf', 1813 'xml' => 'text/xml', 1814 'xsl' => 'text/xml', 1815 'mpeg' => 'video/mpeg', 1816 'mpg' => 'video/mpeg', 1817 'mpe' => 'video/mpeg', 1818 'qt' => 'video/quicktime', 1819 'mov' => 'video/quicktime', 1820 'avi' => 'video/x-msvideo', 1821 'movie' => 'video/x-sgi-movie', 1822 'doc' => 'application/msword', 1823 'word' => 'application/msword', 1824 'xl' => 'application/excel', 1825 'eml' => 'message/rfc822' 1826 ); 1827 return ( ! isset($mimes[strtolower($ext)])) ? 'application/octet-stream' : $mimes[strtolower($ext)]; 1828 } 1829 1830 /** 1831 * Set (or reset) Class Objects (variables) 1832 * 1833 * Usage Example: 1834 * $page->set('X-Priority', '3'); 1835 * 1836 * @access public 1837 * @param string $name Parameter Name 1838 * @param mixed $value Parameter Value 1839 * NOTE: will not work with arrays, there are no arrays to set/reset 1840 */ 1841 function set ( $name, $value = '' ) { 1842 if ( isset($this->$name) ) { 1843 $this->$name = $value; 1844 } else { 1845 $this->SetError('Cannot set or reset variable ' . $name); 1846 return false; 1847 } 1848 } 1849 1850 /** 1851 * Read a file from a supplied filename and return it. 1852 * 1853 * @access public 1854 * @param string $filename Parameter File Name 1855 */ 1856 function getFile($filename) { 1857 $return = ''; 1858 if ($fp = fopen($filename, 'rb')) { 1859 while (!feof($fp)) { 1860 $return .= fread($fp, 1024); 1861 } 1862 fclose($fp); 1863 return $return; 1864 } else { 1865 return false; 1866 } 1867 } 1868 1869 /** 1870 * Strips newlines to prevent header injection. 1871 * @access private 1872 * @param string $str String 1873 * @return string 1874 */ 1875 function SecureHeader($str) { 1876 $str = trim($str); 1877 $str = str_replace("\r", "", $str); 1878 $str = str_replace("\n", "", $str); 1879 return $str; 1880 } 1881 1882 /** 1883 * Set the private key file and password to sign the message. 1884 * 1885 * @access public 1886 * @param string $key_filename Parameter File Name 1887 * @param string $key_pass Password for private key 1888 */ 1889 function Sign($key_filename, $key_pass) { 1890 $this->sign_key_file = $key_filename; 1891 $this->sign_key_pass = $key_pass; 1892 } 1893 1495 1894 } 1496 1895 -
trunk/wp-includes/class-pop3.php
r8082 r8762 1 1 <?php 2 /*~ class.pop3.php 3 .---------------------------------------------------------------------------. 4 | Software: PHPMailer - PHP email class | 5 | Version: 2.0.2 | 6 | Contact: via sourceforge.net support pages (also www.codeworxtech.com) | 7 | Info: http://phpmailer.sourceforge.net | 8 | Support: http://sourceforge.net/projects/phpmailer/ | 9 | ------------------------------------------------------------------------- | 10 | Author: Andy Prevost (project admininistrator) | 11 | Author: Brent R. Matzelle (original founder) | 12 | Copyright (c) 2004-2007, Andy Prevost. All Rights Reserved. | 13 | Copyright (c) 2001-2003, Brent R. Matzelle | 14 | ------------------------------------------------------------------------- | 15 | License: Distributed under the Lesser General Public License (LGPL) | 16 | http://www.gnu.org/copyleft/lesser.html | 17 | This program is distributed in the hope that it will be useful - WITHOUT | 18 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | 19 | FITNESS FOR A PARTICULAR PURPOSE. | 20 | ------------------------------------------------------------------------- | 21 | We offer a number of paid services (www.codeworxtech.com): | 22 | - Web Hosting on highly optimized fast and secure servers | 23 | - Technology Consulting | 24 | - Oursourcing (highly qualified programmers and graphic designers) | 25 '---------------------------------------------------------------------------' 26 2 27 /** 3 * mail_fetch/setup.php28 * POP Before SMTP Authentication Class 4 29 * 5 * @package SquirrelMail 30 * Author: Richard Davey (rich@corephp.co.uk) 31 * License: LGPL, see PHPMailer License 6 32 * 7 * @copyright (c) 1999-2006 The SquirrelMail Project Team 33 * Specifically for PHPMailer to allow POP before SMTP authentication. 34 * Does not yet work with APOP - if you have an APOP account, contact me 35 * and we can test changes to this script. 8 36 * 9 * @copyright (c) 1999 CDI (cdi@thewebmasters.net) All Rights Reserved 10 * Modified by Philippe Mingo 2001 mingo@rotedic.com 11 * An RFC 1939 compliant wrapper class for the POP3 protocol. 37 * This class is based on the structure of the SMTP class by Chris Ryan 12 38 * 13 * Licensed under the GNU GPL. For full terms see the file COPYING. 39 * This class is rfc 1939 compliant and implements all the commands 40 * required for POP3 connection, authentication and disconnection. 14 41 * 15 * pop3 class 16 * 17 * $Id$ 42 * @package PHPMailer 43 * @author Richard Davey 18 44 */ 19 45 20 /** 21 * POP3 22 * 23 * @package SquirrelMail 24 */ 25 class POP3 { 26 var $ERROR = ''; // Error string. 27 28 var $TIMEOUT = 60; // Default timeout before giving up on a 29 // network operation. 30 31 var $COUNT = -1; // Mailbox msg count 32 33 var $BUFFER = 512; // Socket buffer for socket fgets() calls. 34 // Per RFC 1939 the returned line a POP3 35 // server can send is 512 bytes. 36 37 var $FP = ''; // The connection to the server's 38 // file descriptor 39 40 var $MAILSERVER = ''; // Set this to hard code the server name 41 42 var $DEBUG = FALSE; // set to true to echo pop3 43 // commands and responses to error_log 44 // this WILL log passwords! 45 46 var $BANNER = ''; // Holds the banner returned by the 47 // pop server - used for apop() 48 49 var $ALLOWAPOP = FALSE; // Allow or disallow apop() 50 // This must be set to true 51 // manually 52 53 function POP3 ( $server = '', $timeout = '' ) { 54 settype($this->BUFFER,"integer"); 55 if( !empty($server) ) { 56 // Do not allow programs to alter MAILSERVER 57 // if it is already specified. They can get around 58 // this if they -really- want to, so don't count on it. 59 if(empty($this->MAILSERVER)) 60 $this->MAILSERVER = $server; 61 } 62 if(!empty($timeout)) { 63 settype($timeout,"integer"); 64 $this->TIMEOUT = $timeout; 65 if (!ini_get('safe_mode')) 66 set_time_limit($timeout); 67 } 46 class POP3 47 { 48 /** 49 * Default POP3 port 50 * @var int 51 */ 52 var $POP3_PORT = 110; 53 54 /** 55 * Default Timeout 56 * @var int 57 */ 58 var $POP3_TIMEOUT = 30; 59 60 /** 61 * POP3 Carriage Return + Line Feed 62 * @var string 63 */ 64 var $CRLF = "\r\n"; 65 66 /** 67 * Displaying Debug warnings? (0 = now, 1+ = yes) 68 * @var int 69 */ 70 var $do_debug = 2; 71 72 /** 73 * POP3 Mail Server 74 * @var string 75 */ 76 var $host; 77 78 /** 79 * POP3 Port 80 * @var int 81 */ 82 var $port; 83 84 /** 85 * POP3 Timeout Value 86 * @var int 87 */ 88 var $tval; 89 90 /** 91 * POP3 Username 92 * @var string 93 */ 94 var $username; 95 96 /** 97 * POP3 Password 98 * @var string 99 */ 100 var $password; 101 102 /**#@+ 103 * @access private 104 */ 105 var $pop_conn; 106 var $connected; 107 var $error; // Error log array 108 /**#@-*/ 109 110 /** 111 * Constructor, sets the initial values 112 * 113 * @return POP3 114 */ 115 function POP3 () 116 { 117 $this->pop_conn = 0; 118 $this->connected = false; 119 $this->error = null; 120 } 121 122 /** 123 * Combination of public events - connect, login, disconnect 124 * 125 * @param string $host 126 * @param integer $port 127 * @param integer $tval 128 * @param string $username 129 * @param string $password 130 */ 131 function Authorise ($host, $port = false, $tval = false, $username, $password, $debug_level = 0) 132 { 133 $this->host = $host; 134 135 // If no port value is passed, retrieve it 136 if ($port == false) 137 { 138 $this->port = $this->POP3_PORT; 139 } 140 else 141 { 142 $this->port = $port; 143 } 144 145 // If no port value is passed, retrieve it 146 if ($tval == false) 147 { 148 $this->tval = $this->POP3_TIMEOUT; 149 } 150 else 151 { 152 $this->tval = $tval; 153 } 154 155 $this->do_debug = $debug_level; 156 $this->username = $username; 157 $this->password = $password; 158 159 // Refresh the error log 160 $this->error = null; 161 162 // Connect 163 $result = $this->Connect($this->host, $this->port, $this->tval); 164 165 if ($result) 166 { 167 $login_result = $this->Login($this->username, $this->password); 168 169 if ($login_result) 170 { 171 $this->Disconnect(); 172 68 173 return true; 69 } 70 71 function update_timer () { 72 if (!ini_get('safe_mode')) 73 set_time_limit($this->TIMEOUT); 174 } 175 176 } 177 178 // We need to disconnect regardless if the login succeeded 179 $this->Disconnect(); 180 181 return false; 182 } 183 184 /** 185 * Connect to the POP3 server 186 * 187 * @param string $host 188 * @param integer $port 189 * @param integer $tval 190 * @return boolean 191 */ 192 function Connect ($host, $port = false, $tval = 30) 193 { 194 // Are we already connected? 195 if ($this->connected) 196 { 197 return true; 198 } 199 200 /* 201 On Windows this will raise a PHP Warning error if the hostname doesn't exist. 202 Rather than supress it with @fsockopen, let's capture it cleanly instead 203 */ 204 205 set_error_handler(array(&$this, 'catchWarning')); 206 207 // Connect to the POP3 server 208 $this->pop_conn = fsockopen($host, // POP3 Host 209 $port, // Port # 210 $errno, // Error Number 211 $errstr, // Error Message 212 $tval); // Timeout (seconds) 213 214 // Restore the error handler 215 restore_error_handler(); 216 217 // Does the Error Log now contain anything? 218 if ($this->error && $this->do_debug >= 1) 219 { 220 $this->displayErrors(); 221 } 222 223 // Did we connect? 224 if ($this->pop_conn == false) 225 { 226 // It would appear not... 227 $this->error = array( 228 'error' => "Failed to connect to server $host on port $port", 229 'errno' => $errno, 230 'errstr' => $errstr 231 ); 232 233 if ($this->do_debug >= 1) 234 { 235 $this->displayErrors(); 236 } 237 238 return false; 239 } 240 241 // Increase the stream time-out 242 243 // Check for PHP 4.3.0 or later 244 if (version_compare(phpversion(), '4.3.0', 'ge')) 245 { 246 stream_set_timeout($this->pop_conn, $tval, 0); 247 } 248 else 249 { 250 // Does not work on Windows 251 if (substr(PHP_OS, 0, 3) !== 'WIN') 252 { 253 socket_set_timeout($this->pop_conn, $tval, 0); 254 } 255 } 256 257 // Get the POP3 server response 258 $pop3_response = $this->getResponse(); 259 260 // Check for the +OK 261 if ($this->checkResponse($pop3_response)) 262 { 263 // The connection is established and the POP3 server is talking 264 $this->connected = true; 74 265 return true; 75 } 76 77 function connect ($server, $port = 110) { 78 // Opens a socket to the specified server. Unless overridden, 79 // port defaults to 110. Returns true on success, false on fail 80 81 // If MAILSERVER is set, override $server with it's value 82 83 if (!isset($port) || !$port) {$port = 110;} 84 if(!empty($this->MAILSERVER)) 85 $server = $this->MAILSERVER; 86 87 if(empty($server)){ 88 $this->ERROR = "POP3 connect: " . _("No server specified"); 89 unset($this->FP); 90 return false; 91 } 92 93 $fp = @fsockopen("$server", $port, $errno, $errstr); 94 95 if(!$fp) { 96 $this->ERROR = "POP3 connect: " . _("Error ") . "[$errno] [$errstr]"; 97 unset($this->FP); 98 return false; 99 } 100 101 socket_set_blocking($fp,-1); 102 $this->update_timer(); 103 $reply = fgets($fp,$this->BUFFER); 104 $reply = $this->strip_clf($reply); 105 if($this->DEBUG) 106 error_log("POP3 SEND [connect: $server] GOT [$reply]",0); 107 if(!$this->is_ok($reply)) { 108 $this->ERROR = "POP3 connect: " . _("Error ") . "[$reply]"; 109 unset($this->FP); 110 return false; 111 } 112 $this->FP = $fp; 113 $this->BANNER = $this->parse_banner($reply); 266 } 267 268 } 269 270 /** 271 * Login to the POP3 server (does not support APOP yet) 272 * 273 * @param string $username 274 * @param string $password 275 * @return boolean 276 */ 277 function Login ($username = '', $password = '') 278 { 279 if ($this->connected == false) 280 { 281 $this->error = 'Not connected to POP3 server'; 282 283 if ($this->do_debug >= 1) 284 { 285 $this->displayErrors(); 286 } 287 } 288 289 if (empty($username)) 290 { 291 $username = $this->username; 292 } 293 294 if (empty($password)) 295 { 296 $password = $this->password; 297 } 298 299 $pop_username = "USER $username" . $this->CRLF; 300 $pop_password = "PASS $password" . $this->CRLF; 301 302 // Send the Username 303 $this->sendString($pop_username); 304 $pop3_response = $this->getResponse(); 305 306 if ($this->checkResponse($pop3_response)) 307 { 308 // Send the Password 309 $this->sendString($pop_password); 310 $pop3_response = $this->getResponse(); 311 312 if ($this->checkResponse($pop3_response)) 313 { 314 return true; 315 } 316 else 317 { 318 return false; 319 } 320 } 321 else 322 { 323 return false; 324 } 325 } 326 327 /** 328 * Disconnect from the POP3 server 329 */ 330 function Disconnect () 331 { 332 $this->sendString('QUIT'); 333 334 fclose($this->pop_conn); 335 } 336 337 /* 338 --------------- 339 Private Methods 340 --------------- 341 */ 342 343 /** 344 * Get the socket response back. 345 * $size is the maximum number of bytes to retrieve 346 * 347 * @param integer $size 348 * @return string 349 */ 350 function getResponse ($size = 128) 351 { 352 $pop3_response = fgets($this->pop_conn, $size); 353 354 return $pop3_response; 355 } 356 357 /** 358 * Send a string down the open socket connection to the POP3 server 359 * 360 * @param string $string 361 * @return integer 362 */ 363 function sendString ($string) 364 { 365 $bytes_sent = fwrite($this->pop_conn, $string, strlen($string)); 366 367 return $bytes_sent; 368 369 } 370 371 /** 372 * Checks the POP3 server response for +OK or -ERR 373 * 374 * @param string $string 375 * @return boolean 376 */ 377 function checkResponse ($string) 378 { 379 if (substr($string, 0, 3) !== '+OK') 380 { 381 $this->error = array( 382 'error' => "Server reported an error: $string", 383 'errno' => 0, 384 'errstr' => '' 385 ); 386 387 if ($this->do_debug >= 1) 388 { 389 $this->displayErrors(); 390 } 391 392 return false; 393 } 394 else 395 { 114 396 return true; 115 } 116 117 function user ($user = "") { 118 // Sends the USER command, returns true or false 119 120 if( empty($user) ) { 121 $this->ERROR = "POP3 user: " . _("no login ID submitted"); 122 return false; 123 } elseif(!isset($this->FP)) { 124 $this->ERROR = "POP3 user: " . _("connection not established"); 125 return false; 126 } else { 127 $reply = $this->send_cmd("USER $user"); 128 if(!$this->is_ok($reply)) { 129 $this->ERROR = "POP3 user: " . _("Error ") . "[$reply]"; 130 return false; 131 } else 132 return true; 133 } 134 } 135 136 function pass ($pass = "") { 137 // Sends the PASS command, returns # of msgs in mailbox, 138 // returns false (undef) on Auth failure 139 140 if(empty($pass)) { 141 $this->ERROR = "POP3 pass: " . _("No password submitted"); 142 return false; 143 } elseif(!isset($this->FP)) { 144 $this->ERROR = "POP3 pass: " . _("connection not established"); 145 return false; 146 } else { 147 $reply = $this->send_cmd("PASS $pass"); 148 if(!$this->is_ok($reply)) { 149 $this->ERROR = "POP3 pass: " . _("Authentication failed") . " [$reply]"; 150 $this->quit(); 151 return false; 152 } else { 153 // Auth successful. 154 $count = $this->last("count"); 155 $this->COUNT = $count; 156 return $count; 157 } 158 } 159 } 160 161 function apop ($login,$pass) { 162 // Attempts an APOP login. If this fails, it'll 163 // try a standard login. YOUR SERVER MUST SUPPORT 164 // THE USE OF THE APOP COMMAND! 165 // (apop is optional per rfc1939) 166 167 if(!isset($this->FP)) { 168 $this->ERROR = "POP3 apop: " . _("No connection to server"); 169 return false; 170 } elseif(!$this->ALLOWAPOP) { 171 $retVal = $this->login($login,$pass); 172 return $retVal; 173 } elseif(empty($login)) { 174 $this->ERROR = "POP3 apop: " . _("No login ID submitted"); 175 return false; 176 } elseif(empty($pass)) { 177 $this->ERROR = "POP3 apop: " . _("No password submitted"); 178 return false; 179 } else { 180 $banner = $this->BANNER; 181 if( (!$banner) or (empty($banner)) ) { 182 $this->ERROR = "POP3 apop: " . _("No server banner") . ' - ' . _("abort"); 183 $retVal = $this->login($login,$pass); 184 return $retVal; 185 } else { 186 $AuthString = $banner; 187 $AuthString .= $pass; 188 $APOPString = md5($AuthString); 189 $cmd = "APOP $login $APOPString"; 190 $reply = $this->send_cmd($cmd); 191 if(!$this->is_ok($reply)) { 192 $this->ERROR = "POP3 apop: " . _("apop authentication failed") . ' - ' . _("abort"); 193 $retVal = $this->login($login,$pass); 194 return $retVal; 195 } else { 196 // Auth successful. 197 $count = $this->last("count"); 198 $this->COUNT = $count; 199 return $count; 200 } 201 } 202 } 203 } 204 205 function login ($login = "", $pass = "") { 206 // Sends both user and pass. Returns # of msgs in mailbox or 207 // false on failure (or -1, if the error occurs while getting 208 // the number of messages.) 209 210 if( !isset($this->FP) ) { 211 $this->ERROR = "POP3 login: " . _("No connection to server"); 212 return false; 213 } else { 214 $fp = $this->FP; 215 if( !$this->user( $login ) ) { 216 // Preserve the error generated by user() 217 return false; 218 } else { 219 $count = $this->pass($pass); 220 if( (!$count) || ($count == -1) ) { 221 // Preserve the error generated by last() and pass() 222 return false; 223 } else 224 return $count; 225 } 226 } 227 } 228 229 function top ($msgNum, $numLines = "0") { 230 // Gets the header and first $numLines of the msg body 231 // returns data in an array with each returned line being 232 // an array element. If $numLines is empty, returns 233 // only the header information, and none of the body. 234 235 if(!isset($this->FP)) { 236 $this->ERROR = "POP3 top: " . _("No connection to server"); 237 return false; 238 } 239 $this->update_timer(); 240 241 $fp = $this->FP; 242 $buffer = $this->BUFFER; 243 $cmd = "TOP $msgNum $numLines"; 244 fwrite($fp, "TOP $msgNum $numLines\r\n"); 245 $reply = fgets($fp, $buffer); 246 $reply = $this->strip_clf($reply); 247 if($this->DEBUG) { 248 @error_log("POP3 SEND [$cmd] GOT [$reply]",0); 249 } 250 if(!$this->is_ok($reply)) 251 { 252 $this->ERROR = "POP3 top: " . _("Error ") . "[$reply]"; 253 return false; 254 } 255 256 $count = 0; 257 $MsgArray = array(); 258 259 $line = fgets($fp,$buffer); 260 while ( !ereg("^\.\r\n",$line)) 261 { 262 $MsgArray[$count] = $line; 263 $count++; 264 $line = fgets($fp,$buffer); 265 if(empty($line)) { break; } 266 } 267 268 return $MsgArray; 269 } 270 271 function pop_list ($msgNum = "") { 272 // If called with an argument, returns that msgs' size in octets 273 // No argument returns an associative array of undeleted 274 // msg numbers and their sizes in octets 275 276 if(!isset($this->FP)) 277 { 278 $this->ERROR = "POP3 pop_list: " . _("No connection to server"); 279 return false; 280 } 281 $fp = $this->FP; 282 $Total = $this->COUNT; 283 if( (!$Total) or ($Total == -1) ) 284 { 285 return false; 286 } 287 if($Total == 0) 288 { 289 return array("0","0"); 290 // return -1; // mailbox empty 291 } 292 293 $this->update_timer(); 294 295 if(!empty($msgNum)) 296 { 297 $cmd = "LIST $msgNum"; 298 fwrite($fp,"$cmd\r\n"); 299 $reply = fgets($fp,$this->BUFFER); 300 $reply = $this->strip_clf($reply); 301 if($this->DEBUG) { 302 @error_log("POP3 SEND [$cmd] GOT [$reply]",0); 303 } 304 if(!$this->is_ok($reply)) 305 { 306 $this->ERROR = "POP3 pop_list: " . _("Error ") . "[$reply]"; 307 return false; 308 } 309 list($junk,$num,$size) = preg_split('/\s+/',$reply); 310 return $size; 311 } 312 $cmd = "LIST"; 313 $reply = $this->send_cmd($cmd); 314 if(!$this->is_ok($reply)) 315 { 316 $reply = $this->strip_clf($reply); 317 $this->ERROR = "POP3 pop_list: " . _("Error ") . "[$reply]"; 318 return false; 319 } 320 $MsgArray = array(); 321 $MsgArray[0] = $Total; 322 for($msgC=1;$msgC <= $Total; $msgC++) 323 { 324 if($msgC > $Total) { break; } 325 $line = fgets($fp,$this->BUFFER); 326 $line = $this->strip_clf($line); 327 if(ereg("^\.",$line)) 328 { 329 $this->ERROR = "POP3 pop_list: " . _("Premature end of list"); 330 return false; 331 } 332 list($thisMsg,$msgSize) = preg_split('/\s+/',$line); 333 settype($thisMsg,"integer"); 334 if($thisMsg != $msgC) 335 { 336 $MsgArray[$msgC] = "deleted"; 337 } 338 else 339 { 340 $MsgArray[$msgC] = $msgSize; 341 } 342 } 343 return $MsgArray; 344 } 345 346 function get ($msgNum) { 347 // Retrieve the specified msg number. Returns an array 348 // where each line of the msg is an array element. 349 350 if(!isset($this->FP)) 351 { 352 $this->ERROR = "POP3 get: " . _("No connection to server"); 353 return false; 354 } 355 356 $this->update_timer(); 357 358 $fp = $this->FP; 359 $buffer = $this->BUFFER; 360 $cmd = "RETR $msgNum"; 361 $reply = $this->send_cmd($cmd); 362 363 if(!$this->is_ok($reply)) 364 { 365 $this->ERROR = "POP3 get: " . _("Error ") . "[$reply]"; 366 return false; 367 } 368 369 $count = 0; 370 $MsgArray = array(); 371 372 $line = fgets($fp,$buffer); 373 while ( !ereg("^\.\r\n",$line)) 374 { 375 if ( $line{0} == '.' ) { $line = substr($line,1); } 376 $MsgArray[$count] = $line; 377 $count++; 378 $line = fgets($fp,$buffer); 379 if(empty($line)) { break; } 380 } 381 return $MsgArray; 382 } 383 384 function last ( $type = "count" ) { 385 // Returns the highest msg number in the mailbox. 386 // returns -1 on error, 0+ on success, if type != count 387 // results in a popstat() call (2 element array returned) 388 389 $last = -1; 390 if(!isset($this->FP)) 391 { 392 $this->ERROR = "POP3 last: " . _("No connection to server"); 393 return $last; 394 } 395 396 $reply = $this->send_cmd("STAT"); 397 if(!$this->is_ok($reply)) 398 { 399 $this->ERROR = "POP3 last: " . _("Error ") . "[$reply]"; 400 return $last; 401 } 402 403 $Vars = preg_split('/\s+/',$reply); 404 $count = $Vars[1]; 405 $size = $Vars[2]; 406 settype($count,"integer"); 407 settype($size,"integer"); 408 if($type != "count") 409 { 410 return array($count,$size); 411 } 412 return $count; 413 } 414 415 function reset () { 416 // Resets the status of the remote server. This includes 417 // resetting the status of ALL msgs to not be deleted. 418 // This method automatically closes the connection to the server. 419 420 if(!isset($this->FP)) 421 { 422 $this->ERROR = "POP3 reset: " . _("No connection to server"); 423 return false; 424 } 425 $reply = $this->send_cmd("RSET"); 426 if(!$this->is_ok($reply)) 427 { 428 // The POP3 RSET command -never- gives a -ERR 429 // response - if it ever does, something truely 430 // wild is going on. 431 432 $this->ERROR = "POP3 reset: " . _("Error ") . "[$reply]"; 433 @error_log("POP3 reset: ERROR [$reply]",0); 434 } 435 $this->quit(); 436 return true; 437 } 438 439 function send_cmd ( $cmd = "" ) 440 { 441 // Sends a user defined command string to the 442 // POP server and returns the results. Useful for 443 // non-compliant or custom POP servers. 444 // Do NOT includ the \r\n as part of your command 445 // string - it will be appended automatically. 446 447 // The return value is a standard fgets() call, which 448 // will read up to $this->BUFFER bytes of data, until it 449 // encounters a new line, or EOF, whichever happens first. 450 451 // This method works best if $cmd responds with only 452 // one line of data. 453 454 if(!isset($this->FP)) 455 { 456 $this->ERROR = "POP3 send_cmd: " . _("No connection to server"); 457 return false; 458 } 459 460 if(empty($cmd)) 461 { 462 $this->ERROR = "POP3 send_cmd: " . _("Empty command string"); 463 return ""; 464 } 465 466 $fp = $this->FP; 467 $buffer = $this->BUFFER; 468 $this->update_timer(); 469 fwrite($fp,"$cmd\r\n"); 470 $reply = fgets($fp,$buffer); 471 $reply = $this->strip_clf($reply); 472 if($this->DEBUG) { @error_log("POP3 SEND [$cmd] GOT [$reply]",0); } 473 return $reply; 474 } 475 476 function quit() { 477 // Closes the connection to the POP3 server, deleting 478 // any msgs marked as deleted. 479 480 if(!isset($this->FP)) 481 { 482 $this->ERROR = "POP3 quit: " . _("connection does not exist"); 483 return false; 484 } 485 $fp = $this->FP; 486 $cmd = "QUIT"; 487 fwrite($fp,"$cmd\r\n"); 488 $reply = fgets($fp,$this->BUFFER); 489 $reply = $this->strip_clf($reply); 490 if($this->DEBUG) { @error_log("POP3 SEND [$cmd] GOT [$reply]",0); } 491 fclose($fp); 492 unset($this->FP); 493 return true; 494 } 495 496 function popstat () { 497 // Returns an array of 2 elements. The number of undeleted 498 // msgs in the mailbox, and the size of the mbox in octets. 499 500 $PopArray = $this->last("array"); 501 502 if($PopArray == -1) { return false; } 503 504 if( (!$PopArray) or (empty($PopArray)) ) 505 { 506 return false; 507 } 508 return $PopArray; 509 } 510 511 function uidl ($msgNum = "") 512 { 513 // Returns the UIDL of the msg specified. If called with 514 // no arguments, returns an associative array where each 515 // undeleted msg num is a key, and the msg's uidl is the element 516 // Array element 0 will contain the total number of msgs 517 518 if(!isset($this->FP)) { 519 $this->ERROR = "POP3 uidl: " . _("No connection to server"); 520 return false; 521 } 522 523 $fp = $this->FP; 524 $buffer = $this->BUFFER; 525 526 if(!empty($msgNum)) { 527 $cmd = "UIDL $msgNum"; 528 $reply = $this->send_cmd($cmd); 529 if(!$this->is_ok($reply)) 530 { 531 $this->ERROR = "POP3 uidl: " . _("Error ") . "[$reply]"; 532 return false; 533 } 534 list ($ok,$num,$myUidl) = preg_split('/\s+/',$reply); 535 return $myUidl; 536 } else { 537 $this->update_timer(); 538 539 $UIDLArray = array(); 540 $Total = $this->COUNT; 541 $UIDLArray[0] = $Total; 542 543 if ($Total < 1) 544 { 545 return $UIDLArray; 546 } 547 $cmd = "UIDL"; 548 fwrite($fp, "UIDL\r\n"); 549 $reply = fgets($fp, $buffer); 550 $reply = $this->strip_clf($reply); 551 if($this->DEBUG) { @error_log("POP3 SEND [$cmd] GOT [$reply]",0); } 552 if(!$this->is_ok($reply)) 553 { 554 $this->ERROR = "POP3 uidl: " . _("Error ") . "[$reply]"; 555 return false; 556 } 557 558 $line = ""; 559 $count = 1; 560 $line = fgets($fp,$buffer); 561 while ( !ereg("^\.\r\n",$line)) { 562 if(ereg("^\.\r\n",$line)) { 563 break; 564 } 565 list ($msg,$msgUidl) = preg_split('/\s+/',$line); 566 $msgUidl = $this->strip_clf($msgUidl); 567 if($count == $msg) { 568 $UIDLArray[$msg] = $msgUidl; 569 } 570 else 571 { 572 $UIDLArray[$count] = 'deleted'; 573 } 574 $count++; 575 $line = fgets($fp,$buffer); 576 } 577 } 578 return $UIDLArray; 579 } 580 581 function delete ($msgNum = "") { 582 // Flags a specified msg as deleted. The msg will not 583 // be deleted until a quit() method is called. 584 585 if(!isset($this->FP)) 586 { 587 $this->ERROR = "POP3 delete: " . _("No connection to server"); 588 return false; 589 } 590 if(empty($msgNum)) 591 { 592 $this->ERROR = "POP3 delete: " . _("No msg number submitted"); 593 return false; 594 } 595 $reply = $this->send_cmd("DELE $msgNum"); 596 if(!$this->is_ok($reply)) 597 { 598 $this->ERROR = "POP3 delete: " . _("Command failed ") . "[$reply]"; 599 return false; 600 } 601 return true; 602 } 603 604 // ********************************************************* 605 606 // The following methods are internal to the class. 607 608 function is_ok ($cmd = "") { 609 // Return true or false on +OK or -ERR 610 611 if( empty($cmd) ) 612 return false; 613 else 614 return( ereg ("^\+OK", $cmd ) ); 615 } 616 617 function strip_clf ($text = "") { 618 // Strips \r\n from server responses 619 620 if(empty($text)) 621 return $text; 622 else { 623 $stripped = str_replace("\r",'',$text); 624 $stripped = str_replace("\n",'',$stripped); 625 return $stripped; 626 } 627 } 628 629 function parse_banner ( $server_text ) { 630 $outside = true; 631 $banner = ""; 632 $length = strlen($server_text); 633 for($count =0; $count < $length; $count++) 634 { 635 $digit = substr($server_text,$count,1); 636 if(!empty($digit)) { 637 if( (!$outside) && ($digit != '<') && ($digit != '>') ) 638 { 639 $banner .= $digit; 640 } 641 if ($digit == '<') 642 { 643 $outside = false; 644 } 645 if($digit == '>') 646 { 647 $outside = true; 648 } 649 } 650 } 651 $banner = $this->strip_clf($banner); // Just in case 652 return "<$banner>"; 653 } 654 655 } // End class 397 } 398 399 } 400 401 /** 402 * If debug is enabled, display the error message array 403 * 404 */ 405 function displayErrors () 406 { 407 echo '<pre>'; 408 409 foreach ($this->error as $single_error) 410 { 411 print_r($single_error); 412 } 413 414 echo '</pre>'; 415 } 416 417 /** 418 * Takes over from PHP for the socket warning handler 419 * 420 * @param integer $errno 421 * @param string $errstr 422 * @param string $errfile 423 * @param integer $errline 424 */ 425 function catchWarning ($errno, $errstr, $errfile, $errline) 426 { 427 $this->error[] = array( 428 'error' => "Connecting to the POP3 server raised a PHP warning: ", 429 'errno' => $errno, 430 'errstr' => $errstr 431 ); 432 } 433 434 // End of class 435 } 656 436 ?> -
trunk/wp-includes/class-smtp.php
r8187 r8762 1 1 <?php 2 /** 3 * SMTP - PHP SMTP class 4 * 5 * Define an SMTP class that can be used to connect and communicate with any 6 * SMTP server. It implements all the SMTP functions defined in RFC821 except 7 * TURN. 8 * 9 * @version 1.02 10 * @author Chris Ryan 11 * @license LGPL 12 * @package PHPMailer 13 */ 2 /*~ class.smtp.php 3 .---------------------------------------------------------------------------. 4 | Software: PHPMailer - PHP email class | 5 | Version: 2.0.2 | 6 | Contact: via sourceforge.net support pages (also www.codeworxtech.com) | 7 | Info: http://phpmailer.sourceforge.net | 8 | Support: http://sourceforge.net/projects/phpmailer/ | 9 | ------------------------------------------------------------------------- | 10 | Author: Andy Prevost (project admininistrator) | 11 | Author: Brent R. Matzelle (original founder) | 12 | Copyright (c) 2004-2007, Andy Prevost. All Rights Reserved. | 13 | Copyright (c) 2001-2003, Brent R. Matzelle | 14 | ------------------------------------------------------------------------- | 15 | License: Distributed under the Lesser General Public License (LGPL) | 16 | http://www.gnu.org/copyleft/lesser.html | 17 | This program is distributed in the hope that it will be useful - WITHOUT | 18 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | 19 | FITNESS FOR A PARTICULAR PURPOSE. | 20 | ------------------------------------------------------------------------- | 21 | We offer a number of paid services (www.codeworxtech.com): | 22 | - Web Hosting on highly optimized fast and secure servers | 23 | - Technology Consulting | 24 | - Oursourcing (highly qualified programmers and graphic designers) | 25 '---------------------------------------------------------------------------' 14 26 15 27 /** … … 18 30 * error. SMTP also provides some utility methods for sending mail 19 31 * to an SMTP server. 20 *21 32 * @package PHPMailer 22 33 * @author Chris Ryan 23 34 */ 35 24 36 class SMTP 25 37 { 26 /** 27 * SMTP server port 28 * @var int 29 */ 30 var $SMTP_PORT = 25; 31 32 /** 33 * SMTP reply line ending 34 * @var string 35 */ 36 var $CRLF = "\r\n"; 37 38 /** 39 * Sets whether debugging is turned on 40 * @var bool 41 */ 42 var $do_debug; # the level of debug to perform 43 44 /**#@+ 45 * @access private 46 */ 47 var $smtp_conn; # the socket to the server 48 var $error; # error if any on the last call 49 var $helo_rply; # the reply the server sent to us for HELO 50 /**#@-*/ 51 52 /** 53 * Initialize the class so that the data is in a known state. 54 * @access public 55 * @return void 56 */ 57 function SMTP() { 58 $this->smtp_conn = 0; 59 $this->error = null; 60 $this->helo_rply = null; 61 62 $this->do_debug = 0; 63 } 64 65 /************************************************************* 66 * CONNECTION FUNCTIONS * 67 ***********************************************************/ 68 69 /** 70 * Connect to the server specified on the port specified. 71 * If the port is not specified use the default SMTP_PORT. 72 * If tval is specified then a connection will try and be 73 * established with the server for that number of seconds. 74 * If tval is not specified the default is 30 seconds to 75 * try on the connection. 76 * 77 * SMTP CODE SUCCESS: 220 78 * SMTP CODE FAILURE: 421 79 * @access public 80 * @return bool 81 */ 82 function Connect($host,$port=0,$tval=30) { 83 # set the error val to null so there is no confusion 84 $this->error = null; 85 86 # make sure we are __not__ connected 87 if($this->connected()) { 88 # ok we are connected! what should we do? 89 # for now we will just give an error saying we 90 # are already connected 91 $this->error = 92 array("error" => "Already connected to a server"); 93 return false; 38 /** 39 * SMTP server port 40 * @var int 41 */ 42 var $SMTP_PORT = 25; 43 44 /** 45 * SMTP reply line ending 46 * @var string 47 */ 48 var $CRLF = "\r\n"; 49 50 /** 51 * Sets whether debugging is turned on 52 * @var bool 53 */ 54 var $do_debug; # the level of debug to perform 55 56 /** 57 * Sets VERP use on/off (default is off) 58 * @var bool 59 */ 60 var $do_verp = false; 61 62 /**#@+ 63 * @access private 64 */ 65 var $smtp_conn; # the socket to the server 66 var $error; # error if any on the last call 67 var $helo_rply; # the reply the server sent to us for HELO 68 /**#@-*/ 69 70 /** 71 * Initialize the class so that the data is in a known state. 72 * @access public 73 * @return void 74 */ 75 function SMTP() { 76 $this->smtp_conn = 0; 77 $this->error = null; 78 $this->helo_rply = null; 79 80 $this->do_debug = 0; 81 } 82 83 /************************************************************* 84 * CONNECTION FUNCTIONS * 85 ***********************************************************/ 86 87 /** 88 * Connect to the server specified on the port specified. 89 * If the port is not specified use the default SMTP_PORT. 90 * If tval is specified then a connection will try and be 91 * established with the server for that number of seconds. 92 * If tval is not specified the default is 30 seconds to 93 * try on the connection. 94 * 95 * SMTP CODE SUCCESS: 220 96 * SMTP CODE FAILURE: 421 97 * @access public 98 * @return bool 99 */ 100 function Connect($host,$port=0,$tval=30) { 101 # set the error val to null so there is no confusion 102 $this->error = null; 103 104 # make sure we are __not__ connected 105 if($this->connected()) { 106 # ok we are connected! what should we do? 107 # for now we will just give an error saying we 108 # are already connected 109 $this->error = array("error" => "Already connected to a server"); 110 return false; 111 } 112 113 if(empty($port)) { 114 $port = $this->SMTP_PORT; 115 } 116 117 #connect to the smtp server 118 $this->smtp_conn = fsockopen($host, # the host of the server 119 $port, # the port to use 120 $errno, # error number if any 121 $errstr, # error message if any 122 $tval); # give up after ? secs 123 # verify we connected properly 124 if(empty($this->smtp_conn)) { 125 $this->error = array("error" => "Failed to connect to server", 126 "errno" => $errno, 127 "errstr" => $errstr); 128 if($this->do_debug >= 1) { 129 echo "SMTP -> ERROR: " . $this->error["error"] . 130 ": $errstr ($errno)" . $this->CRLF; 131 } 132 return false; 133 } 134 135 # sometimes the SMTP server takes a little longer to respond 136 # so we will give it a longer timeout for the first read 137 // Windows still does not have support for this timeout function 138 if(substr(PHP_OS, 0, 3) != "WIN") 139 socket_set_timeout($this->smtp_conn, $tval, 0); 140 141 # get any announcement stuff 142 $announce = $this->get_lines(); 143 144 # set the timeout of any socket functions at 1/10 of a second 145 //if(function_exists("socket_set_timeout")) 146 // socket_set_timeout($this->smtp_conn, 0, 100000); 147 148 if($this->do_debug >= 2) { 149 echo "SMTP -> FROM SERVER:" . $this->CRLF . $announce; 150 } 151 152 return true; 153 } 154 155 /** 156 * Performs SMTP authentication. Must be run after running the 157 * Hello() method. Returns true if successfully authenticated. 158 * @access public 159 * @return bool 160 */ 161 function Authenticate($username, $password) { 162 // Start authentication 163 fputs($this->smtp_conn,"AUTH LOGIN" . $this->CRLF); 164 165 $rply = $this->get_lines(); 166 $code = substr($rply,0,3); 167 168 if($code != 334) { 169 $this->error = 170 array("error" => "AUTH not accepted from server", 171 "smtp_code" => $code, 172 "smtp_msg" => substr($rply,4)); 173 if($this->do_debug >= 1) { 174 echo "SMTP -> ERROR: " . $this->error["error"] . 175 ": " . $rply . $this->CRLF; 176 } 177 return false; 178 } 179 180 // Send encoded username 181 fputs($this->smtp_conn, base64_encode($username) . $this->CRLF); 182 183 $rply = $this->get_lines(); 184 $code = substr($rply,0,3); 185 186 if($code != 334) { 187 $this->error = 188 array("error" => "Username not accepted from server", 189 "smtp_code" => $code, 190 "smtp_msg" => substr($rply,4)); 191 if($this->do_debug >= 1) { 192 echo "SMTP -> ERROR: " . $this->error["error"] . 193 ": " . $rply . $this->CRLF; 194 } 195 return false; 196 } 197 198 // Send encoded password 199 fputs($this->smtp_conn, base64_encode($password) . $this->CRLF); 200 201 $rply = $this->get_lines(); 202 $code = substr($rply,0,3); 203 204 if($code != 235) { 205 $this->error = 206 array("error" => "Password not accepted from server", 207 "smtp_code" => $code, 208 "smtp_msg" => substr($rply,4)); 209 if($this->do_debug >= 1) { 210 echo "SMTP -> ERROR: " . $this->error["error"] . 211 ": " . $rply . $this->CRLF; 212 } 213 return false; 214 } 215 216 return true; 217 } 218 219 /** 220 * Returns true if connected to a server otherwise false 221 * @access private 222 * @return bool 223 */ 224 function Connected() { 225 if(!empty($this->smtp_conn)) { 226 $sock_status = socket_get_status($this->smtp_conn); 227 if($sock_status["eof"]) { 228 # hmm this is an odd situation... the socket is 229 # valid but we are not connected anymore 230 if($this->do_debug >= 1) { 231 echo "SMTP -> NOTICE:" . $this->CRLF . 232 "EOF caught while checking if connected"; 94 233 } 95 96 if(empty($port)) { 97 $port = $this->SMTP_PORT; 234 $this->Close(); 235 return false; 236 } 237 return true; # everything looks good 238 } 239 return false; 240 } 241 242 /** 243 * Closes the socket and cleans up the state of the class. 244 * It is not considered good to use this function without 245 * first trying to use QUIT. 246 * @access public 247 * @return void 248 */ 249 function Close() { 250 $this->error = null; # so there is no confusion 251 $this->helo_rply = null; 252 if(!empty($this->smtp_conn)) { 253 # close the connection and cleanup 254 fclose($this->smtp_conn); 255 $this->smtp_conn = 0; 256 } 257 } 258 259 /*************************************************************** 260 * SMTP COMMANDS * 261 *************************************************************/ 262 263 /** 264 * Issues a data command and sends the msg_data to the server 265 * finializing the mail transaction. $msg_data is the message 266 * that is to be send with the headers. Each header needs to be 267 * on a single line followed by a <CRLF> with the message headers 268 * and the message body being seperated by and additional <CRLF>. 269 * 270 * Implements rfc 821: DATA <CRLF> 271 * 272 * SMTP CODE INTERMEDIATE: 354 273 * [data] 274 * <CRLF>.<CRLF> 275 * SMTP CODE SUCCESS: 250 276 * SMTP CODE FAILURE: 552,554,451,452 277 * SMTP CODE FAILURE: 451,554 278 * SMTP CODE ERROR : 500,501,503,421 279 * @access public 280 * @return bool 281 */ 282 function Data($msg_data) { 283 $this->error = null; # so no confusion is caused 284 285 if(!$this->connected()) { 286 $this->error = array( 287 "error" => "Called Data() without being connected"); 288 return false; 289 } 290 291 fputs($this->smtp_conn,"DATA" . $this->CRLF); 292 293 $rply = $this->get_lines(); 294 $code = substr($rply,0,3); 295 296 if($this->do_debug >= 2) { 297 echo "SMTP -> FROM SERVER:" . $this->CRLF . $rply; 298 } 299 300 if($code != 354) { 301 $this->error = 302 array("error" => "DATA command not accepted from server", 303 "smtp_code" => $code, 304 "smtp_msg" => substr($rply,4)); 305 if($this->do_debug >= 1) { 306 echo "SMTP -> ERROR: " . $this->error["error"] . 307 ": " . $rply . $this->CRLF; 308 } 309 return false; 310 } 311 312 # the server is ready to accept data! 313 # according to rfc 821 we should not send more than 1000 314 # including the CRLF 315 # characters on a single line so we will break the data up 316 # into lines by \r and/or \n then if needed we will break 317 # each of those into smaller lines to fit within the limit. 318 # in addition we will be looking for lines that start with 319 # a period '.' and append and additional period '.' to that 320 # line. NOTE: this does not count towards are limit. 321 322 # normalize the line breaks so we know the explode works 323 $msg_data = str_replace("\r\n","\n",$msg_data); 324 $msg_data = str_replace("\r","\n",$msg_data); 325 $lines = explode("\n",$msg_data); 326 327 # we need to find a good way to determine is headers are 328 # in the msg_data or if it is a straight msg body 329 # currently I am assuming rfc 822 definitions of msg headers 330 # and if the first field of the first line (':' sperated) 331 # does not contain a space then it _should_ be a header 332 # and we can process all lines before a blank "" line as 333 # headers. 334 $field = substr($lines[0],0,strpos($lines[0],":")); 335 $in_headers = false; 336 if(!empty($field) && !strstr($field," ")) { 337 $in_headers = true; 338 } 339 340 $max_line_length = 998; # used below; set here for ease in change 341 342 while(list(,$line) = @each($lines)) { 343 $lines_out = null; 344 if($line == "" && $in_headers) { 345 $in_headers = false; 346 } 347 # ok we need to break this line up into several 348 # smaller lines 349 while(strlen($line) > $max_line_length) { 350 $pos = strrpos(substr($line,0,$max_line_length)," "); 351 352 # Patch to fix DOS attack 353 if(!$pos) { 354 $pos = $max_line_length - 1; 98 355 } 99 356 100 #connect to the smtp server 101 $this->smtp_conn = fsockopen($host, # the host of the server 102 $port, # the port to use 103 $errno, # error number if any 104 $errstr, # error message if any 105 $tval); # give up after ? secs 106 # verify we connected properly 107 if(empty($this->smtp_conn)) { 108 $this->error = array("error" => "Failed to connect to server", 109 "errno" => $errno, 110 "errstr" => $errstr); 111 if($this->do_debug >= 1) { 112 echo "SMTP -> ERROR: " . $this->error["error"] . 113 ": $errstr ($errno)" . $this->CRLF; 114 } 115 return false; 357 $lines_out[] = substr($line,0,$pos); 358 $line = substr($line,$pos + 1); 359 # if we are processing headers we need to 360 # add a LWSP-char to the front of the new line 361 # rfc 822 on long msg headers 362 if($in_headers) { 363 $line = "\t" . $line; 116 364 } 117 118 # sometimes the SMTP server takes a little longer to respond 119 # so we will give it a longer timeout for the first read 120 // Windows still does not have support for this timeout function 121 if(substr(PHP_OS, 0, 3) != "WIN") 122 socket_set_timeout($this->smtp_conn, $tval, 0); 123 124 # get any announcement stuff 125 $announce = $this->get_lines(); 126 127 # set the timeout of any socket functions at 1/10 of a second 128 //if(function_exists("socket_set_timeout")) 129 // socket_set_timeout($this->smtp_conn, 0, 100000); 130 131 if($this->do_debug >= 2) { 132 echo "SMTP -> FROM SERVER:" . $this->CRLF . $announce; 365 } 366 $lines_out[] = $line; 367 368 # now send the lines to the server 369 while(list(,$line_out) = @each($lines_out)) { 370 if(strlen($line_out) > 0) 371 { 372 if(substr($line_out, 0, 1) == ".") { 373 $line_out = "." . $line_out; 374 } 133 375 } 134 135 return true; 136 } 137 138 /** 139 * Performs SMTP authentication. Must be run after running the 140 * Hello() method. Returns true if successfully authenticated. 141 * @access public 142 * @return bool 143 */ 144 function Authenticate($username, $password) { 145 // Start authentication 146 fputs($this->smtp_conn,"AUTH LOGIN" . $this->CRLF); 147 148 $rply = $this->get_lines(); 149 $code = substr($rply,0,3); 150 151 if($code != 334) { 152 $this->error = 153 array("error" => "AUTH not accepted from server", 154 "smtp_code" => $code, 155 "smtp_msg" => substr($rply,4)); 156 if($this->do_debug >= 1) { 157 echo "SMTP -> ERROR: " . $this->error["error"] . 158 ": " . $rply . $this->CRLF; 159 } 160 return false; 161 } 162 163 // Send encoded username 164 fputs($this->smtp_conn, base64_encode($username) . $this->CRLF); 165 166 $rply = $this->get_lines(); 167 $code = substr($rply,0,3); 168 169 if($code != 334) { 170 $this->error = 171 array("error" => "Username not accepted from server", 172 "smtp_code" => $code, 173 "smtp_msg" => substr($rply,4)); 174 if($this->do_debug >= 1) { 175 echo "SMTP -> ERROR: " . $this->error["error"] . 176 ": " . $rply . $this->CRLF; 177 } 178 return false; 179 } 180 181 // Send encoded password 182 fputs($this->smtp_conn, base64_encode($password) . $this->CRLF); 183 184 $rply = $this->get_lines(); 185 $code = substr($rply,0,3); 186 187 if($code != 235) { 188 $this->error = 189 array("error" => "Password not accepted from server", 190 "smtp_code" => $code, 191 "smtp_msg" => substr($rply,4)); 192 if($this->do_debug >= 1) { 193 echo "SMTP -> ERROR: " . $this->error["error"] . 194 ": " . $rply . $this->CRLF; 195 } 196 return false; 197 } 198 199 return true; 200 } 201 202 /** 203 * Returns true if connected to a server otherwise false 204 * @access private 205 * @return bool 206 */ 207 function Connected() { 208 if(!empty($this->smtp_conn)) { 209 $sock_status = socket_get_status($this->smtp_conn); 210 if($sock_status["eof"]) { 211 # hmm this is an odd situation... the socket is 212 # valid but we aren't connected anymore 213 if($this->do_debug >= 1) { 214 echo "SMTP -> NOTICE:" . $this->CRLF . 215 "EOF caught while checking if connected"; 216 } 217 $this->Close(); 218 return false; 219 } 220 return true; # everything looks good 221 } 222 return false; 223 } 224 225 /** 226 * Closes the socket and cleans up the state of the class. 227 * It is not considered good to use this function without 228 * first trying to use QUIT. 229 * @access public 230 * @return void 231 */ 232 function Close() { 233 $this->error = null; # so there is no confusion 234 $this->helo_rply = null; 235 if(!empty($this->smtp_conn)) { 236 # close the connection and cleanup 237 fclose($this->smtp_conn); 238 $this->smtp_conn = 0; 239 } 240 } 241 242 243 /*************************************************************** 244 * SMTP COMMANDS * 245 *************************************************************/ 246 247 /** 248 * Issues a data command and sends the msg_data to the server 249 * finializing the mail transaction. $msg_data is the message 250 * that is to be send with the headers. Each header needs to be 251 * on a single line followed by a <CRLF> with the message headers 252 * and the message body being separated by and additional <CRLF>. 253 * 254 * Implements rfc 821: DATA <CRLF> 255 * 256 * SMTP CODE INTERMEDIATE: 354 257 * [data] 258 * <CRLF>.<CRLF> 259 * SMTP CODE SUCCESS: 250 260 * SMTP CODE FAILURE: 552,554,451,452 261 * SMTP CODE FAILURE: 451,554 262 * SMTP CODE ERROR : 500,501,503,421 263 * @access public 264 * @return bool 265 */ 266 function Data($msg_data) { 267 $this->error = null; # so no confusion is caused 268 269 if(!$this->connected()) { 270 $this->error = array( 271 "error" => "Called Data() without being connected"); 272 return false; 273 } 274 275 fputs($this->smtp_conn,"DATA" . $this->CRLF); 276 277 $rply = $this->get_lines(); 278 $code = substr($rply,0,3); 279 280 if($this->do_debug >= 2) { 281 echo "SMTP -> FROM SERVER:" . $this->CRLF . $rply; 282 } 283 284 if($code != 354) { 285 $this->error = 286 array("error" => "DATA command not accepted from server", 287 "smtp_code" => $code, 288 "smtp_msg" => substr($rply,4)); 289 if($this->do_debug >= 1) { 290 echo "SMTP -> ERROR: " . $this->error["error"] . 291 ": " . $rply . $this->CRLF; 292 } 293 return false; 294 } 295 296 # the server is ready to accept data! 297 # according to rfc 821 we should not send more than 1000 298 # including the CRLF 299 # characters on a single line so we will break the data up 300 # into lines by \r and/or \n then if needed we will break 301 # each of those into smaller lines to fit within the limit. 302 # in addition we will be looking for lines that start with 303 # a period '.' and append and additional period '.' to that 304 # line. NOTE: this does not count towards are limit. 305 306 # normalize the line breaks so we know the explode works 307 $msg_data = str_replace("\r\n","\n",$msg_data); 308 $msg_data = str_replace("\r","\n",$msg_data); 309 $lines = explode("\n",$msg_data); 310 311 # we need to find a good way to determine is headers are 312 # in the msg_data or if it is a straight msg body 313 # currently I'm assuming rfc 822 definitions of msg headers 314 # and if the first field of the first line (':' sperated) 315 # does not contain a space then it _should_ be a header 316 # and we can process all lines before a blank "" line as 317 # headers. 318 $field = substr($lines[0],0,strpos($lines[0],":")); 319 $in_headers = false; 320 if(!empty($field) && !strstr($field," ")) { 321 $in_headers = true; 322 } 323 324 $max_line_length = 998; # used below; set here for ease in change 325 326 while(list(,$line) = @each($lines)) { 327 $lines_out = null; 328 if($line == "" && $in_headers) { 329 $in_headers = false; 330 } 331 # ok we need to break this line up into several 332 # smaller lines 333 while(strlen($line) > $max_line_length) { 334 $pos = strrpos(substr($line,0,$max_line_length)," "); 335 336 # Patch to fix DOS attack 337 if(!$pos) { 338 $pos = $max_line_length - 1; 339 } 340 341 $lines_out[] = substr($line,0,$pos); 342 $line = substr($line,$pos + 1); 343 # if we are processing headers we need to 344 # add a LWSP-char to the front of the new line 345 # rfc 822 on long msg headers 346 if($in_headers) { 347 $line = "\t" . $line; 348 } 349 } 350 $lines_out[] = $line; 351 352 # now send the lines to the server 353 while(list(,$line_out) = @each($lines_out)) { 354 if(strlen($line_out) > 0) 355 { 356 if(substr($line_out, 0, 1) == ".") { 357 $line_out = "." . $line_out; 358 } 359 } 360 fputs($this->smtp_conn,$line_out . $this->CRLF); 361 } 362 } 363 364 # ok all the message data has been sent so lets get this 365 # over with aleady 366 fputs($this->smtp_conn, $this->CRLF . "." . $this->CRLF); 367 368 $rply = $this->get_lines(); 369 $code = substr($rply,0,3); 370 371 if($this->do_debug >= 2) { 372 echo "SMTP -> FROM SERVER:" . $this->CRLF . $rply; 373 } 374 375 if($code != 250) { 376 $this->error = 377 array("error" => "DATA not accepted from server", 378 "smtp_code" => $code, 379 "smtp_msg" => substr($rply,4)); 380 if($this->do_debug >= 1) { 381 echo "SMTP -> ERROR: " . $this->error["error"] . 382 ": " . $rply . $this->CRLF; 383 } 384 return false; 385 } 386 return true; 387 } 388 389 /** 390 * Expand takes the name and asks the server to list all the 391 * people who are members of the _list_. Expand will return 392 * back and array of the result or false if an error occurs. 393 * Each value in the array returned has the format of: 394 * [ <full-name> <sp> ] <path> 395 * The definition of <path> is defined in rfc 821 396 * 397 * Implements rfc 821: EXPN <SP> <string> <CRLF> 398 * 399 * SMTP CODE SUCCESS: 250 400 * SMTP CODE FAILURE: 550 401 * SMTP CODE ERROR : 500,501,502,504,421 402 * @access public 403 * @return string array 404 */ 405 function Expand($name) { 406 $this->error = null; # so no confusion is caused 407 408 if(!$this->connected()) { 409 $this->error = array( 410 "error" => "Called Expand() without being connected"); 411 return false; 412 } 413 414 fputs($this->smtp_conn,"EXPN " . $name . $this->CRLF); 415 416 $rply = $this->get_lines(); 417 $code = substr($rply,0,3); 418 419 if($this->do_debug >= 2) { 420 echo "SMTP -> FROM SERVER:" . $this->CRLF . $rply; 421 } 422 423 if($code != 250) { 424 $this->error = 425 array("error" => "EXPN not accepted from server", 426 "smtp_code" => $code, 427 "smtp_msg" => substr($rply,4)); 428 if($this->do_debug >= 1) { 429 echo "SMTP -> ERROR: " . $this->error["error"] . 430 ": " . $rply . $this->CRLF; 431 } 432 return false; 433 } 434 435 # parse the reply and place in our array to return to user 436 $entries = explode($this->CRLF,$rply); 437 while(list(,$l) = @each($entries)) { 438 $list[] = substr($l,4); 439 } 440 441 return $list; 442 } 443 444 /** 445 * Sends the HELO command to the smtp server. 446 * This makes sure that we and the server are in 447 * the same known state. 448 * 449 * Implements from rfc 821: HELO <SP> <domain> <CRLF> 450 * 451 * SMTP CODE SUCCESS: 250 452 * SMTP CODE ERROR : 500, 501, 504, 421 453 * @access public 454 * @return bool 455 */ 456 function Hello($host="") { 457 $this->error = null; # so no confusion is caused 458 459 if(!$this->connected()) { 460 $this->error = array( 461 "error" => "Called Hello() without being connected"); 462 return false; 463 } 464 465 # if a hostname for the HELO wasn't specified determine 466 # a suitable one to send 467 if(empty($host)) { 468 # we need to determine some sort of appopiate default 469 # to send to the server 470 $host = "localhost"; 471 } 472 473 // Send extended hello first (RFC 2821) 474 if(!$this->SendHello("EHLO", $host)) 475 { 476 if(!$this->SendHello("HELO", $host)) 477 return false; 478 } 479 480 return true; 481 } 482 483 /** 484 * Sends a HELO/EHLO command. 485 * @access private 486 * @return bool 487 */ 488 function SendHello($hello, $host) { 489 fputs($this->smtp_conn, $hello . " " . $host . $this->CRLF); 490 491 $rply = $this->get_lines(); 492 $code = substr($rply,0,3); 493 494 if($this->do_debug >= 2) { 495 echo "SMTP -> FROM SERVER: " . $this->CRLF . $rply; 496 } 497 498 if($code != 250) { 499 $this->error = 500 array("error" => $hello . " not accepted from server", 501 "smtp_code" => $code, 502 "smtp_msg" => substr($rply,4)); 503 if($this->do_debug >= 1) { 504 echo "SMTP -> ERROR: " . $this->error["error"] . 505 ": " . $rply . $this->CRLF; 506 } 507 return false; 508 } 509 510 $this->helo_rply = $rply; 511 512 return true; 513 } 514 515 /** 516 * Gets help information on the keyword specified. If the keyword 517 * is not specified then returns generic help, ussually contianing 518 * A list of keywords that help is available on. This function 519 * returns the results back to the user. It is up to the user to 520 * handle the returned data. If an error occurs then false is 521 * returned with $this->error set appropiately. 522 * 523 * Implements rfc 821: HELP [ <SP> <string> ] <CRLF> 524 * 525 * SMTP CODE SUCCESS: 211,214 526 * SMTP CODE ERROR : 500,501,502,504,421 527 * @access public 528 * @return string 529 */ 530 function Help($keyword="") { 531 $this->error = null; # to avoid confusion 532 533 if(!$this->connected()) { 534 $this->error = array( 535 "error" => "Called Help() without being connected"); 536 return false; 537 } 538 539 $extra = ""; 540 if(!empty($keyword)) { 541 $extra = " " . $keyword; 542 } 543 544 fputs($this->smtp_conn,"HELP" . $extra . $this->CRLF); 545 546 $rply = $this->get_lines(); 547 $code = substr($rply,0,3); 548 549 if($this->do_debug >= 2) { 550 echo "SMTP -> FROM SERVER:" . $this->CRLF . $rply; 551 } 552 553 if($code != 211 && $code != 214) { 554 $this->error = 555 array("error" => "HELP not accepted from server", 556 "smtp_code" => $code, 557 "smtp_msg" => substr($rply,4)); 558 if($this->do_debug >= 1) { 559 echo "SMTP -> ERROR: " . $this->error["error"] . 560 ": " . $rply . $this->CRLF; 561 } 562 return false; 563 } 564 565 return $rply; 566 } 567 568 /** 569 * Starts a mail transaction from the email address specified in 570 * $from. Returns true if successful or false otherwise. If True 571 * the mail transaction is started and then one or more Recipient 572 * commands may be called followed by a Data command. 573 * 574 * Implements rfc 821: MAIL <SP> FROM:<reverse-path> <CRLF> 575 * 576 * SMTP CODE SUCCESS: 250 577 * SMTP CODE SUCCESS: 552,451,452 578 * SMTP CODE SUCCESS: 500,501,421 579 * @access public 580 * @return bool 581 */ 582 function Mail($from) { 583 $this->error = null; # so no confusion is caused 584 585 if(!$this->connected()) { 586 $this->error = array( 587 "error" => "Called Mail() without being connected"); 588 return false; 589 } 590 591 fputs($this->smtp_conn,"MAIL FROM:<" . $from . ">" . $this->CRLF); 592 593 $rply = $this->get_lines(); 594 $code = substr($rply,0,3); 595 596 if($this->do_debug >= 2) { 597 echo "SMTP -> FROM SERVER:" . $this->CRLF . $rply; 598 } 599 600 if($code != 250) { 601 $this->error = 602 array("error" => "MAIL not accepted from server", 603 "smtp_code" => $code, 604 "smtp_msg" => substr($rply,4)); 605 if($this->do_debug >= 1) { 606 echo "SMTP -> ERROR: " . $this->error["error"] . 607 ": " . $rply . $this->CRLF; 608 } 609 return false; 610 } 611 return true; 612 } 613 614 /** 615 * Sends the command NOOP to the SMTP server. 616 * 617 * Implements from rfc 821: NOOP <CRLF> 618 * 619 * SMTP CODE SUCCESS: 250 620 * SMTP CODE ERROR : 500, 421 621 * @access public 622 * @return bool 623 */ 624 function Noop() { 625 $this->error = null; # so no confusion is caused 626 627 if(!$this->connected()) { 628 $this->error = array( 629 "error" => "Called Noop() without being connected"); 630 return false; 631 } 632 633 fputs($this->smtp_conn,"NOOP" . $this->CRLF); 634 635 $rply = $this->get_lines(); 636 $code = substr($rply,0,3); 637 638 if($this->do_debug >= 2) { 639 echo "SMTP -> FROM SERVER:" . $this->CRLF . $rply; 640 } 641 642 if($code != 250) { 643 $this->error = 644 array("error" => "NOOP not accepted from server", 645 "smtp_code" => $code, 646 "smtp_msg" => substr($rply,4)); 647 if($this->do_debug >= 1) { 648 echo "SMTP -> ERROR: " . $this->error["error"] . 649 ": " . $rply . $this->CRLF; 650 } 651 return false; 652 } 653 return true; 654 } 655 656 /** 657 * Sends the quit command to the server and then closes the socket 658 * if there is no error or the $close_on_error argument is true. 659 * 660 * Implements from rfc 821: QUIT <CRLF> 661 * 662 * SMTP CODE SUCCESS: 221 663 * SMTP CODE ERROR : 500 664 * @access public 665 * @return bool 666 */ 667 function Quit($close_on_error=true) { 668 $this->error = null; # so there is no confusion 669 670 if(!$this->connected()) { 671 $this->error = array( 672 "error" => "Called Quit() without being connected"); 673 return false; 674 } 675 676 # send the quit command to the server 677 fputs($this->smtp_conn,"quit" . $this->CRLF); 678 679 # get any good-bye messages 680 $byemsg = $this->get_lines(); 681 682 if($this->do_debug >= 2) { 683 echo "SMTP -> FROM SERVER:" . $this->CRLF . $byemsg; 684 } 685 686 $rval = true; 687 $e = null; 688 689 $code = substr($byemsg,0,3); 690 if($code != 221) { 691 # use e as a tmp var cause Close will overwrite $this->error 692 $e = array("error" => "SMTP server rejected quit command", 693 "smtp_code" => $code, 694 "smtp_rply" => substr($byemsg,4)); 695 $rval = false; 696 if($this->do_debug >= 1) { 697 echo "SMTP -> ERROR: " . $e["error"] . ": " . 698 $byemsg . $this->CRLF; 699 } 700 } 701 702 if(empty($e) || $close_on_error) { 703 $this->Close(); 704 } 705 706 return $rval; 707 } 708 709 /** 710 * Sends the command RCPT to the SMTP server with the TO: argument of $to. 711 * Returns true if the recipient was accepted false if it was rejected. 712 * 713 * Implements from rfc 821: RCPT <SP> TO:<forward-path> <CRLF> 714 * 715 * SMTP CODE SUCCESS: 250,251 716 * SMTP CODE FAILURE: 550,551,552,553,450,451,452 717 * SMTP CODE ERROR : 500,501,503,421 718 * @access public 719 * @return bool 720 */ 721 function Recipient($to) { 722 $this->error = null; # so no confusion is caused 723 724 if(!$this->connected()) { 725 $this->error = array( 726 "error" => "Called Recipient() without being connected"); 727 return false; 728 } 729 730 fputs($this->smtp_conn,"RCPT TO:<" . $to . ">" . $this->CRLF); 731 732 $rply = $this->get_lines(); 733 $code = substr($rply,0,3); 734 735 if($this->do_debug >= 2) { 736 echo "SMTP -> FROM SERVER:" . $this->CRLF . $rply; 737 } 738 739 if($code != 250 && $code != 251) { 740 $this->error = 741 array("error" => "RCPT not accepted from server", 742 "smtp_code" => $code, 743 "smtp_msg" => substr($rply,4)); 744 if($this->do_debug >= 1) { 745 echo "SMTP -> ERROR: " . $this->error["error"] . 746 ": " . $rply . $this->CRLF; 747 } 748 return false; 749 } 750 return true; 751 } 752 753 /** 754 * Sends the RSET command to abort and transaction that is 755 * currently in progress. Returns true if successful false 756 * otherwise. 757 * 758 * Implements rfc 821: RSET <CRLF> 759 * 760 * SMTP CODE SUCCESS: 250 761 * SMTP CODE ERROR : 500,501,504,421 762 * @access public 763 * @return bool 764 */ 765 function Reset() { 766 $this->error = null; # so no confusion is caused 767 768 if(!$this->connected()) { 769 $this->error = array( 770 "error" => "Called Reset() without being connected"); 771 return false; 772 } 773 774 fputs($this->smtp_conn,"RSET" . $this->CRLF); 775 776 $rply = $this->get_lines(); 777 $code = substr($rply,0,3); 778 779 if($this->do_debug >= 2) { 780 echo "SMTP -> FROM SERVER:" . $this->CRLF . $rply; 781 } 782 783 if($code != 250) { 784 $this->error = 785 array("error" => "RSET failed", 786 "smtp_code" => $code, 787 "smtp_msg" => substr($rply,4)); 788 if($this->do_debug >= 1) { 789 echo "SMTP -> ERROR: " . $this->error["error"] . 790 ": " . $rply . $this->CRLF; 791 } 792 return false; 793 } 794 795 return true; 796 } 797 798 /** 799 * Starts a mail transaction from the email address specified in 800 * $from. Returns true if successful or false otherwise. If True 801 * the mail transaction is started and then one or more Recipient 802 * commands may be called followed by a Data command. This command 803 * will send the message to the users terminal if they are logged 804 * in. 805 * 806 * Implements rfc 821: SEND <SP> FROM:<reverse-path> <CRLF> 807 * 808 * SMTP CODE SUCCESS: 250 809 * SMTP CODE SUCCESS: 552,451,452 810 * SMTP CODE SUCCESS: 500,501,502,421 811 * @access public 812 * @return bool 813 */ 814 function Send($from) { 815 $this->error = null; # so no confusion is caused 816 817 if(!$this->connected()) { 818 $this->error = array( 819 "error" => "Called Send() without being connected"); 820 return false; 821 } 822 823 fputs($this->smtp_conn,"SEND FROM:" . $from . $this->CRLF); 824 825 $rply = $this->get_lines(); 826 $code = substr($rply,0,3); 827 828 if($this->do_debug >= 2) { 829 echo "SMTP -> FROM SERVER:" . $this->CRLF . $rply; 830 } 831 832 if($code != 250) { 833 $this->error = 834 array("error" => "SEND not accepted from server", 835 "smtp_code" => $code, 836 "smtp_msg" => substr($rply,4)); 837 if($this->do_debug >= 1) { 838 echo "SMTP -> ERROR: " . $this->error["error"] . 839 ": " . $rply . $this->CRLF; 840 } 841 return false; 842 } 843 return true; 844 } 845 846 /** 847 * Starts a mail transaction from the email address specified in 848 * $from. Returns true if successful or false otherwise. If True 849 * the mail transaction is started and then one or more Recipient 850 * commands may be called followed by a Data command. This command 851 * will send the message to the users terminal if they are logged 852 * in and send them an email. 853 * 854 * Implements rfc 821: SAML <SP> FROM:<reverse-path> <CRLF> 855 * 856 * SMTP CODE SUCCESS: 250 857 * SMTP CODE SUCCESS: 552,451,452 858 * SMTP CODE SUCCESS: 500,501,502,421 859 * @access public 860 * @return bool 861 */ 862 function SendAndMail($from) { 863 $this->error = null; # so no confusion is caused 864 865 if(!$this->connected()) { 866 $this->error = array( 867 "error" => "Called SendAndMail() without being connected"); 868 return false; 869 } 870 871 fputs($this->smtp_conn,"SAML FROM:" . $from . $this->CRLF); 872 873 $rply = $this->get_lines(); 874 $code = substr($rply,0,3); 875 876 if($this->do_debug >= 2) { 877 echo "SMTP -> FROM SERVER:" . $this->CRLF . $rply; 878 } 879 880 if($code != 250) { 881 $this->error = 882 array("error" => "SAML not accepted from server", 883 "smtp_code" => $code, 884 "smtp_msg" => substr($rply,4)); 885 if($this->do_debug >= 1) { 886 echo "SMTP -> ERROR: " . $this->error["error"] . 887 ": " . $rply . $this->CRLF; 888 } 889 return false; 890 } 891 return true; 892 } 893 894 /** 895 * Starts a mail transaction from the email address specified in 896 * $from. Returns true if successful or false otherwise. If True 897 * the mail transaction is started and then one or more Recipient 898 * commands may be called followed by a Data command. This command 899 * will send the message to the users terminal if they are logged 900 * in or mail it to them if they are not. 901 * 902 * Implements rfc 821: SOML <SP> FROM:<reverse-path> <CRLF> 903 * 904 * SMTP CODE SUCCESS: 250 905 * SMTP CODE SUCCESS: 552,451,452 906 * SMTP CODE SUCCESS: 500,501,502,421 907 * @access public 908 * @return bool 909 */ 910 function SendOrMail($from) { 911 $this->error = null; # so no confusion is caused 912 913 if(!$this->connected()) { 914 $this->error = array( 915 "error" => "Called SendOrMail() without being connected"); 916 return false; 917 } 918 919 fputs($this->smtp_conn,"SOML FROM:" . $from . $this->CRLF); 920 921 $rply = $this->get_lines(); 922 $code = substr($rply,0,3); 923 924 if($this->do_debug >= 2) { 925 echo "SMTP -> FROM SERVER:" . $this->CRLF . $rply; 926 } 927 928 if($code != 250) { 929 $this->error = 930 array("error" => "SOML not accepted from server", 931 "smtp_code" => $code, 932 "smtp_msg" => substr($rply,4)); 933 if($this->do_debug >= 1) { 934 echo "SMTP -> ERROR: " . $this->error["error"] . 935 ": " . $rply . $this->CRLF; 936 } 937 return false; 938 } 939 return true; 940 } 941 942 /** 943 * This is an optional command for SMTP that this class does not 944 * support. This method is here to make the RFC821 Definition 945 * complete for this class and __may__ be implimented in the future 946 * 947 * Implements from rfc 821: TURN <CRLF> 948 * 949 * SMTP CODE SUCCESS: 250 950 * SMTP CODE FAILURE: 502 951 * SMTP CODE ERROR : 500, 503 952 * @access public 953 * @return bool 954 */ 955 function Turn() { 956 $this->error = array("error" => "This method, TURN, of the SMTP ". 957 "is not implemented"); 958 if($this->do_debug >= 1) { 959 echo "SMTP -> NOTICE: " . $this->error["error"] . $this->CRLF; 960 } 961 return false; 962 } 963 964 /** 965 * Verifies that the name is recognized by the server. 966 * Returns false if the name could not be verified otherwise 967 * the response from the server is returned. 968 * 969 * Implements rfc 821: VRFY <SP> <string> <CRLF> 970 * 971 * SMTP CODE SUCCESS: 250,251 972 * SMTP CODE FAILURE: 550,551,553 973 * SMTP CODE ERROR : 500,501,502,421 974 * @access public 975 * @return int 976 */ 977 function Verify($name) { 978 $this->error = null; # so no confusion is caused 979 980 if(!$this->connected()) { 981 $this->error = array( 982 "error" => "Called Verify() without being connected"); 983 return false; 984 } 985 986 fputs($this->smtp_conn,"VRFY " . $name . $this->CRLF); 987 988 $rply = $this->get_lines(); 989 $code = substr($rply,0,3); 990 991 if($this->do_debug >= 2) { 992 echo "SMTP -> FROM SERVER:" . $this->CRLF . $rply; 993 } 994 995 if($code != 250 && $code != 251) { 996 $this->error = 997 array("error" => "VRFY failed on name '$name'", 998 "smtp_code" => $code, 999 "smtp_msg" => substr($rply,4)); 1000 if($this->do_debug >= 1) { 1001 echo "SMTP -> ERROR: " . $this->error["error"] . 1002 ": " . $rply . $this->CRLF; 1003 } 1004 return false; 1005 } 1006 return $rply; 1007 } 1008 1009 /******************************************************************* 1010 * INTERNAL FUNCTIONS * 1011 ******************************************************************/ 1012 1013 /** 1014 * Read in as many lines as possible 1015 * either before eof or socket timeout occurs on the operation. 1016 * With SMTP we can tell if we have more lines to read if the 1017 * 4th character is '-' symbol. If it is a space then we don't 1018 * need to read anything else. 1019 * @access private 1020 * @return string 1021 */ 1022 function get_lines() { 1023 $data = ""; 1024 while($str = fgets($this->smtp_conn,515)) { 1025 if($this->do_debug >= 4) { 1026 echo "SMTP -> get_lines(): \$data was \"$data\"" . 1027 $this->CRLF; 1028 echo "SMTP -> get_lines(): \$str is \"$str\"" . 1029 $this->CRLF; 1030 } 1031 $data .= $str; 1032 if($this->do_debug >= 4) { 1033 echo "SMTP -> get_lines(): \$data is \"$data\"" . $this->CRLF; 1034 } 1035 # if the 4th character is a space then we are done reading 1036 # so just break the loop 1037 if(substr($str,3,1) == " ") { break; } 1038 } 1039 return $data; 1040 } 376 fputs($this->smtp_conn,$line_out . $this->CRLF); 377 } 378 } 379 380 # ok all the message data has been sent so lets get this 381 # over with aleady 382 fputs($this->smtp_conn, $this->CRLF . "." . $this->CRLF); 383 384 $rply = $this->get_lines(); 385 $code = substr($rply,0,3); 386 387 if($this->do_debug >= 2) { 388 echo "SMTP -> FROM SERVER:" . $this->CRLF . $rply; 389 } 390 391 if($code != 250) { 392 $this->error = 393 array("error" => "DATA not accepted from server", 394 "smtp_code" => $code, 395 "smtp_msg" => substr($rply,4)); 396 if($this->do_debug >= 1) { 397 echo "SMTP -> ERROR: " . $this->error["error"] . 398 ": " . $rply . $this->CRLF; 399 } 400 return false; 401 } 402 return true; 403 } 404 405 /** 406 * Expand takes the name and asks the server to list all the 407 * people who are members of the _list_. Expand will return 408 * back and array of the result or