Add fake pop server and POP-before-SMTP tests.

Update POP before SMTP example to use new static method.
This commit is contained in:
Synchro 2013-08-02 16:19:01 +02:00
parent 3374536cac
commit 73093a32a3
6 changed files with 227 additions and 22 deletions

View File

@ -35,6 +35,10 @@
* Introduce autoloader
* Allow overriding of SMTP class
* Overhaul of PHPDocs
* Fix broken Q-encoding
* Czech language update (Thanks to @nemelu)
* Removal of excess blank lines in messages
* Added fake POP server and unit tests for POP-before-SMTP
## Version 5.2.6 (April 11th 2013)
* Reflect move to PHPMailer GitHub organisation at https://github.com/PHPMailer/PHPMailer

View File

@ -56,6 +56,7 @@ class POP3
* POP3 Carriage Return + Line Feed.
* @type string
* @access public
* @deprecated Use the constant instead
*/
public $CRLF = "\r\n";
@ -123,10 +124,14 @@ class POP3
*/
private $error;
/**
* Line break constant
*/
const CRLF = "\r\n";
/**
* Constructor.
* @access public
* @access private
*/
public function __construct()
{
@ -135,6 +140,21 @@ class POP3
$this->error = null;
}
/**
* Simple static wrapper for all-in-one POP before SMTP
* @param $host
* @param bool $port
* @param bool $tval
* @param string $username
* @param string $password
* @return bool
*/
public static function popBeforeSmtp($host, $port = false, $tval = false, $username = '', $password = '')
{
$pop = new POP3;
return $pop->authorise($host, $port, $tval, $username, $password);
}
/**
* Authenticate with a POP3 server.
* A connect, login, disconnect sequence
@ -151,14 +171,14 @@ class POP3
public function authorise($host, $port = false, $tval = false, $username = '', $password = '', $debug_level = 0)
{
$this->host = $host;
// If no port value is passed, retrieve it
if ($port == false) {
// If no port value provided, use default
if ($port === false) {
$this->port = $this->POP3_PORT;
} else {
$this->port = $port;
}
// If no port value is passed, retrieve it
if ($tval == false) {
// If no timeout value provided, use default
if ($tval === false) {
$this->tval = $this->POP3_TIMEOUT;
} else {
$this->tval = $tval;
@ -177,7 +197,7 @@ class POP3
return true;
}
}
// We need to disconnect regardless if the login succeeded
// We need to disconnect regardless of whether the login succeeded
$this->disconnect();
return false;
}
@ -274,14 +294,13 @@ class POP3
if (empty($password)) {
$password = $this->password;
}
$pop_username = "USER $username" . $this->CRLF;
$pop_password = "PASS $password" . $this->CRLF;
// send the Username
$this->sendString($pop_username);
// Send the Username
$this->sendString("USER $username" . self::CRLF);
$pop3_response = $this->getResponse();
if ($this->checkResponse($pop3_response)) {
// send the Password
$this->sendString($pop_password);
// Send the Password
$this->sendString("PASS $password" . self::CRLF);
$pop3_response = $this->getResponse();
if ($this->checkResponse($pop3_response)) {
return true;
@ -297,7 +316,9 @@ class POP3
public function disconnect()
{
$this->sendString('QUIT');
fclose($this->pop_conn);
//The QUIT command may cause the daemon to exit, which will kill our connection
//So ignore errors here
@fclose($this->pop_conn);
}
/**
@ -309,8 +330,7 @@ class POP3
*/
private function getResponse($size = 128)
{
$pop3_response = fgets($this->pop_conn, $size);
return $pop3_response;
return fgets($this->pop_conn, $size);
}
/**
@ -321,8 +341,10 @@ class POP3
*/
private function sendString($string)
{
$bytes_sent = fwrite($this->pop_conn, $string, strlen($string));
return $bytes_sent;
if ($this->pop_conn) {
return fwrite($this->pop_conn, $string, strlen($string));
}
return 0;
}
/**

View File

@ -8,12 +8,10 @@
<?php
require '../PHPMailerAutoload.php';
//Create a new POP client instance
$pop = new POP3();
//authenticate via POP
$pop->authorise('pop3.yourdomain.com', 110, 30, 'username', 'password', 1);
//Authenticate via POP3
//Now you should be clear to submit messages over SMTP for a while
//Only applies if your host supports POP-before-SMTP
$pop = POP3::popBeforeSmtp('pop3.example.com', 110, 30, 'username', 'password', 1);
//Create a new PHPMailer instance
//Passing true to the constructor enables the use of exceptions for error handling

125
test/fakepopserver.sh Executable file
View File

@ -0,0 +1,125 @@
#!/usr/bin/env bash
# Fake POP3 server
# By Marcus Bointon <phpmailer@synchromedia.co.uk>
# Based on code by 'Frater' found at http://www.linuxquestions.org/questions/programming-9/fake-pop3-server-to-capture-pop3-passwords-933733
# Does not actually serve any mail, but supports commands sufficient to test POP-before SMTP
# Can be run directly from a shell like this:
# mkfifo fifo; nc -l 1100 <fifo |./fakepopserver.sh >fifo; rm fifo
# It will accept any user name and will return a positive response for the password 'test'
# Licensed under the GNU Lesser General Public License: http://www.gnu.org/copyleft/lesser.html
# Enable debug output
#set -xv
export PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin
LOGFOLDER=/tmp
LOGFILE=${LOGFOLDER}/fakepop.log
LOGGING=1
DEBUG=1
TIMEOUT=10
POP_USER=
POP_PASSWRD=test
LINES=1
BREAK=0
write_log () {
if [ ${LINES} -eq 1 ] ; then
echo '---' >>${LOGFILE}
fi
let LINES+=1
[ ${LOGGING} = 0 ] || echo -e "`date '+%b %d %H:%M'` pop3 $*" >>${LOGFILE}
}
ANSWER="+OK Fake POP3 Service Ready"
while [ ${BREAK} -eq 0 ] ; do
echo -en "${ANSWER}\r\n"
REPLY=""
#Input appears in $REPLY
read -t ${TIMEOUT}
ANSWER="+OK "
COMMAND=""
ARGS=""
TIMEOUT=30
if [ "$REPLY" ] ; then
write_log "RAW input: '`echo "${REPLY}" | tr -cd '[ -~]'`'"
COMMAND="`echo "${REPLY}" | awk '{print $1}' | tr -cd '\40-\176' | tr 'a-z' 'A-Z'`"
ARGS="`echo "${REPLY}" | tr -cd '\40-\176' | awk '{for(i=2;i<=NF;i++){printf "%s ", $i};printf "\n"}' | sed 's/ $//'`"
write_log "Command: \"${COMMAND}\""
write_log "Arguments: \"${ARGS}\""
case "$COMMAND" in
QUIT)
break
;;
USER)
if [ -n "${ARGS}" ] ; then
POP_USER="${ARGS}"
ANSWER="+OK Please send PASS command"
fi
;;
AUTH)
ANSWER="+OK \r\n."
;;
CAPA)
ANSWER="+OK Capabilities include\r\nUSER\r\nCAPA\r\n."
;;
PASS)
if [ "${POP_PASSWRD}" == "${ARGS}" ] ; then
ANSWER="+OK Logged in.\r\n"
AUTH=1
else
ANSWER="-ERR Login failed\r\n"
fi
;;
LIST)
if [ "${AUTH}" = 0 ] ; then
ANSWER="-ERR Not authenticated"
else
if [ -z "${ARGS}" ] ; then
ANSWER="+OK No messages, really\r\n."
else
ANSWER="-ERR No messages, no list, no status"
fi
fi
;;
RSET)
ANSWER="+OK Resetting or whatever\r\n."
;;
LAST)
if [ "${AUTH}" = 0 ] ; then
ANSWER="-ERR Not authenticated"
else
ANSWER="+OK 0"
fi
;;
STAT)
if [ "${AUTH}" = 0 ] ; then
ANSWER="-ERR Not authenticated"
else
ANSWER="+OK 0 0"
fi
;;
NOOP)
ANSWER="+OK Hang on, doing nothing"
;;
esac
else
echo "+OK Connection timed out\r\n"
break
fi
done
echo "+OK Bye!\r\n"

View File

@ -58,6 +58,13 @@ class PHPMailerTest extends PHPUnit_Framework_TestCase
*/
public $INCLUDE_DIR = '../';
/**
* PIDs of any processes we need to kill
* @type array
* @access private
*/
private $pids = array();
/**
* Run before each test is started.
*/
@ -121,6 +128,11 @@ class PHPMailerTest extends PHPUnit_Framework_TestCase
$this->Mail = null;
$this->ChangeLog = array();
$this->NoteLog = array();
foreach ($this->pids as $pid) {
$p = escapeshellarg($pid);
shell_exec("ps $p && kill -TERM $p");
}
}
@ -1136,7 +1148,7 @@ EOT;
}
/**
* Encoding tests
* Encoding and charset tests
*/
public function testEncodings()
{
@ -1170,6 +1182,13 @@ EOT;
);
}
public function testBase64()
{
$this->Mail->Subject .= ': Base-64 encoding';
$this->Mail->Encoding = 'base64';
$this->buildBody();
$this->assertTrue($this->Mail->send(), 'Base64 encoding failed');
}
/**
* S/MIME Signing tests
*/
@ -1259,6 +1278,34 @@ EOT;
$this->assertEquals($target, PHPMailer::normalizeBreaks($mixedsrc), 'Mixed break reformatting failed');
}
/**
* Use a fake POP3 server to test POP-before-SMTP auth
*/
public function testPopBeforeSmtp()
{
//Start a fake POP server
$pid = shell_exec('nohup ./runfakepopserver.sh >/dev/null 2>/dev/null & printf "%u" $!');
$this->pids[] = $pid;
//Test a known-good login
$this->assertTrue(
POP3::popBeforeSmtp('localhost', 1100, 10, 'user', 'test'),
'POP before SMTP failed'
);
//Kill the fake server
shell_exec('kill -TERM '.escapeshellarg($pid));
$pid = shell_exec('nohup ./runfakepopserver.sh >/dev/null 2>/dev/null & printf "%u" $!');
$this->pids[] = $pid;
//Test a known-bad login
$this->assertFalse(
POP3::popBeforeSmtp('localhost', 1100, 10, 'user', 'xxx'),
'POP before SMTP should have failed'
);
shell_exec('kill -TERM '.escapeshellarg($pid));
}
/**
* Miscellaneous calls to improve test coverage and some small tests
*/

9
test/runfakepopserver.sh Executable file
View File

@ -0,0 +1,9 @@
#!/usr/bin/env bash
# Run the fake pop server from bash
# Idea from http://blog.ale-re.net/2007/09/ipersimple-remote-shell-with-netcat.html
# Defaults to port 1100 so it can be run by unpriv users and not clash with a real server
mkfifo fifo
nc -l 1100 <fifo |bash ./fakepopserver.sh >fifo
rm fifo