Initial commit

Signed-off-by: Luke Tainton <luke@tainton.uk>
This commit is contained in:
Luke Tainton
2020-02-26 12:23:50 +00:00
commit 39782c53ef
500 changed files with 141257 additions and 0 deletions

File diff suppressed because it is too large Load Diff

203
hesk/inc/mail/hesk_imap.php Normal file
View File

@@ -0,0 +1,203 @@
#!/usr/bin/php -q
<?php
/**
*
* This file is part of HESK - PHP Help Desk Software.
*
* (c) Copyright Klemen Stirn. All rights reserved.
* https://www.hesk.com
*
* For the full copyright and license agreement information visit
* https://www.hesk.com/eula.php
*
*/
define('IN_SCRIPT',1);
define('HESK_PATH', dirname(dirname(dirname(__FILE__))) . '/');
// Do not send out the default UTF-8 HTTP header
define('NO_HTTP_HEADER',1);
// Get required files and functions
require(HESK_PATH . 'hesk_settings.inc.php');
require(HESK_PATH . 'inc/common.inc.php');
//============================================================================//
// OPTIONAL MODIFICATIONS //
//============================================================================//
// Set category ID where new tickets will be submitted to
$set_category = 1;
// Set ticket priority of new tickets with the following options:
// -1 = use default category priority
// 0 = critical
// 1 = high
// 2 = medium
// 3 = low
$set_priority = -1;
// Uncomment lines below to use different IMAP login details than in settings
/*
$hesk_settings['imap'] = 1;
$hesk_settings['imap_job_wait'] = 15;
$hesk_settings['imap_host_name'] = 'imap.gmail.com';
$hesk_settings['imap_host_port'] = 993;
$hesk_settings['imap_enc'] = 'ssl';
$hesk_settings['imap_keep'] = 0;
$hesk_settings['imap_user'] = 'test@example.com';
$hesk_settings['imap_password'] = 'password';
*/
//============================================================================//
// END OPTIONAL MODIFICATIONS //
//============================================================================//
// Is this feature enabled?
if (empty($hesk_settings['imap']))
{
die($hesklang['ifd']);
}
// Is IMAP available?
if ( ! function_exists('imap_open'))
{
die($hesklang['iei']);
}
// Are we in maintenance mode?
if ( hesk_check_maintenance(false) )
{
// If Debug mode is ON show "Maintenance mode" message
$message = $hesk_settings['debug_mode'] ? $hesklang['mm1'] : '';
die($message);
}
// Don't start IMAP fetching if an existing job is in progress
if ($hesk_settings['imap_job_wait'])
{
// A log file used to store start of IMAP fetching
$job_file = HESK_PATH . $hesk_settings['cache_dir'] . '/__imap-' . sha1(__FILE__) . '.txt';
// If the job file already exists, wait for the previous job to complete unless expired
if ( file_exists($job_file ) )
{
// Get time when the active IMAP fetching started
$last = intval( file_get_contents($job_file) );
// Give a running process at least X minutes to finish
if ( $last + $hesk_settings['imap_job_wait'] * 60 > time() )
{
$message = $hesk_settings['debug_mode'] ? $hesklang['ifr'] : '';
die($message);
}
else
{
// Start the process (force)
file_put_contents($job_file, time() );
}
}
else
{
// No job in progress, log when this one started
file_put_contents($job_file, time() );
}
}
// Get other required includes
require(HESK_PATH . 'inc/pipe_functions.inc.php');
// Tell Hesk we are in IMAP mode
define('HESK_IMAP', true);
// IMAP mailbox based on required encryption
switch ($hesk_settings['imap_enc'])
{
case 'ssl':
$hesk_settings['imap_mailbox'] = '{'.$hesk_settings['imap_host_name'].':'.$hesk_settings['imap_host_port'].'/imap/ssl/novalidate-cert}';
break;
case 'tls':
$hesk_settings['imap_mailbox'] = '{'.$hesk_settings['imap_host_name'].':'.$hesk_settings['imap_host_port'].'/imap/tls/novalidate-cert}';
break;
default:
$hesk_settings['imap_mailbox'] = '{'.$hesk_settings['imap_host_name'].':'.$hesk_settings['imap_host_port'].'}';
}
// Connect to IMAP
$imap = @imap_open($hesk_settings['imap_mailbox'], $hesk_settings['imap_user'], $hesk_settings['imap_password']);
// Connection successful?
if ($imap !== false)
{
echo $hesk_settings['debug_mode'] ? "<pre>Connected to the IMAP server &quot;" . $hesk_settings['imap_mailbox'] . "&quot;.</pre>\n" : '';
if($emails = imap_search($imap, 'UNSEEN'))
{
echo $hesk_settings['debug_mode'] ? "<pre>Unread messages found: " . count($emails) . "</pre>\n" : '';
// Connect to the database
hesk_dbConnect();
// Download and parse each email
foreach($emails as $email_number)
{
// Parse email from the stream
$results = parser();
// Convert email into a ticket (or new reply)
if ( $id = hesk_email2ticket($results, 2, $set_category, $set_priority) )
{
echo $hesk_settings['debug_mode'] ? "<pre>Ticket $id created/updated.</pre>\n" : '';
}
else
{
echo $hesk_settings['debug_mode'] ? "<pre>Ticket NOT inserted - may be duplicate, blocked or an error.</pre>\n" : '';
}
// Queue message to be deleted on connection close
if ( ! $hesk_settings['imap_keep'])
{
imap_delete($imap, $email_number);
}
echo $hesk_settings['debug_mode'] ? "<br /><br />\n\n" : '';
}
if ( ! $hesk_settings['imap_keep'])
{
imap_expunge($imap);
}
}
else
{
echo $hesk_settings['debug_mode'] ? "<pre>No unread messages found.</pre>\n" : '';
}
// Close IMAP connection
imap_close($imap);
echo $hesk_settings['debug_mode'] ? "<pre>Disconnected from the IMAP server.</pre>\n" : '';
}
// Any error messages?
if($errors = imap_errors())
{
if ($hesk_settings['debug_mode'])
{
foreach ($errors as $error)
{
echo "<pre>" . hesk_htmlspecialchars($error) . "</pre>\n";
}
}
else
{
echo "<h2>An error occured.</h2><p>For details turn <b>Debug mode</b> ON in settings and run this script again.</p>\n";
}
}
// Remove active IMAP fetching log file
if ($hesk_settings['imap_job_wait'])
{
unlink($job_file);
}
return NULL;

View File

@@ -0,0 +1,60 @@
#!/usr/bin/php -q
<?php
/**
*
* This file is part of HESK - PHP Help Desk Software.
*
* (c) Copyright Klemen Stirn. All rights reserved.
* https://www.hesk.com
*
* For the full copyright and license agreement information visit
* https://www.hesk.com/eula.php
*
*/
define('IN_SCRIPT',1);
define('HESK_PATH', dirname(dirname(dirname(__FILE__))) . '/');
// Do not send out the default UTF-8 HTTP header
define('NO_HTTP_HEADER',1);
// Get required files and functions
require(HESK_PATH . 'hesk_settings.inc.php');
require(HESK_PATH . 'inc/common.inc.php');
//============================================================================//
// OPTIONAL MODIFICATIONS //
//============================================================================//
// Set category ID where new tickets will be submitted to
$set_category = 1;
// Set ticket priority of new tickets with the following options:
// -1 = use default category priority
// 0 = critical
// 1 = high
// 2 = medium
// 3 = low
$set_priority = -1;
//============================================================================//
// END OPTIONAL MODIFICATIONS //
//============================================================================//
// Is this feature enabled?
if (empty($hesk_settings['email_piping']))
{
die($hesklang['epd']);
}
// Email piping is enabled, get other required includes
require(HESK_PATH . 'inc/pipe_functions.inc.php');
// Parse the incoming email
$results = parser();
// Convert email into a ticket (or new reply)
hesk_dbConnect();
hesk_email2ticket($results, 0, $set_category, $set_priority);
return NULL;

197
hesk/inc/mail/hesk_pop3.php Normal file
View File

@@ -0,0 +1,197 @@
#!/usr/bin/php -q
<?php
/**
*
* This file is part of HESK - PHP Help Desk Software.
*
* (c) Copyright Klemen Stirn. All rights reserved.
* https://www.hesk.com
*
* For the full copyright and license agreement information visit
* https://www.hesk.com/eula.php
*
*/
define('IN_SCRIPT',1);
define('HESK_PATH', dirname(dirname(dirname(__FILE__))) . '/');
// Do not send out the default UTF-8 HTTP header
define('NO_HTTP_HEADER',1);
// Get required files and functions
require(HESK_PATH . 'hesk_settings.inc.php');
require(HESK_PATH . 'inc/common.inc.php');
//============================================================================//
// OPTIONAL MODIFICATIONS //
//============================================================================//
// Set category ID where new tickets will be submitted to
$set_category = 1;
// Set ticket priority of new tickets with the following options:
// -1 = use default category priority
// 0 = critical
// 1 = high
// 2 = medium
// 3 = low
$set_priority = -1;
// Uncomment lines below to use different POP3 login details than in settings
/*
$hesk_settings['pop3_host_name'] = 'mail.server.com';
$hesk_settings['pop3_host_port'] = 110;
$hesk_settings['pop3_tls'] = 0;
$hesk_settings['pop3_user'] = 'user@server.com';
$hesk_settings['pop3_password'] = 'password';
*/
//============================================================================//
// END OPTIONAL MODIFICATIONS //
//============================================================================//
// Is this feature enabled?
if (empty($hesk_settings['pop3']))
{
die($hesklang['pfd']);
}
// Are we in maintenance mode?
if ( hesk_check_maintenance(false) )
{
// If Debug mode is ON show "Maintenance mode" message
$message = $hesk_settings['debug_mode'] ? $hesklang['mm1'] : '';
die($message);
}
// Don't start POP3 fetching if an existing job is in progress
if ($hesk_settings['pop3_job_wait'])
{
// A log file used to store start of POP3 fetching
$job_file = HESK_PATH . $hesk_settings['cache_dir'] . '/__pop3-' . sha1(__FILE__) . '.txt';
// If the job file already exists, wait for the previous job to complete unless expired
if ( file_exists($job_file ) )
{
// Get time when the active POP3 fetching started
$last = intval( file_get_contents($job_file) );
// Give a running process at least 31 minutes to finish
if ( $last + $hesk_settings['pop3_job_wait'] * 60 > time() )
{
$message = $hesk_settings['debug_mode'] ? $hesklang['pfr'] : '';
die($message);
}
else
{
// Start the process (force)
file_put_contents($job_file, time() );
}
}
else
{
// No job in progress, log when this one started
file_put_contents($job_file, time() );
}
}
// Get other required includes
require(HESK_PATH . 'inc/pipe_functions.inc.php');
// Get POP3 class
require(HESK_PATH . 'inc/mail/pop3.php');
// Uncomment when using SASL authentication mechanisms
# require(HESK_PATH . 'inc/mail/sasl/sasl.php');
// If a pop3 wrapper is registered un register it, we need our custom wrapper
if ( in_array('pop3', stream_get_wrappers() ) )
{
stream_wrapper_unregister('pop3');
}
// Register the pop3 stream handler class
stream_wrapper_register('pop3', 'pop3_stream');
// Setup required variables
$pop3 = new pop3_class;
$pop3->hostname = $hesk_settings['pop3_host_name'];
$pop3->port = $hesk_settings['pop3_host_port'];
$pop3->tls = $hesk_settings['pop3_tls'];
$pop3->debug = 0;
$pop3->join_continuation_header_lines = 1;
// Connect to POP3
if(($error=$pop3->Open())=="")
{
echo $hesk_settings['debug_mode'] ? "<pre>Connected to the POP3 server &quot;" . $pop3->hostname . "&quot;.</pre>\n" : '';
// Authenticate
if(($error=$pop3->Login($hesk_settings['pop3_user'], hesk_htmlspecialchars_decode($hesk_settings['pop3_password'])))=="")
{
echo $hesk_settings['debug_mode'] ? "<pre>User &quot;" . $hesk_settings['pop3_user'] . "&quot; logged in.</pre>\n" : '';
// Get number of messages and total size
if(($error=$pop3->Statistics($messages,$size))=="")
{
echo $hesk_settings['debug_mode'] ? "<pre>There are $messages messages in the mail box with a total of $size bytes.</pre>\n" : '';
// If we have any messages, process them
if($messages>0)
{
// Connect to the database
hesk_dbConnect();
for ($message = 1; $message <= $messages; $message++)
{
echo $hesk_settings['debug_mode'] ? "<pre>Parsing message $message of $messages.</pre>\n" : '';
$pop3->GetConnectionName($connection_name);
$message_file = 'pop3://'.$connection_name.'/'.$message;
// Parse the incoming email
$results = parser($message_file);
// Convert email into a ticket (or new reply)
if ( $id = hesk_email2ticket($results, 1, $set_category, $set_priority) )
{
echo $hesk_settings['debug_mode'] ? "<pre>Ticket $id created/updated.</pre>\n" : '';
}
else
{
echo $hesk_settings['debug_mode'] ? "<pre>Ticket NOT inserted - may be duplicate, blocked or an error.</pre>\n" : '';
}
// Queue message to be deleted on connection close
if ( ! $hesk_settings['pop3_keep'])
{
$pop3->DeleteMessage($message);
}
echo $hesk_settings['debug_mode'] ? "<br /><br />\n\n" : '';
}
}
// Disconnect from the server - this also deletes queued messages
if($error == "" && ($error=$pop3->Close()) == "")
{
echo $hesk_settings['debug_mode'] ? "<pre>Disconnected from the POP3 server &quot;" . $pop3->hostname . "&quot;.</pre>\n" : '';
}
}
}
}
// Any error messages?
if($error != '')
{
echo "<h2>Error: " . hesk_htmlspecialchars($error) . "</h2>";
}
// Remove active POP3 fetching log file
if ($hesk_settings['pop3_job_wait'])
{
unlink($job_file);
}
return NULL;

8
hesk/inc/mail/index.htm Normal file
View File

@@ -0,0 +1,8 @@
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<HTML><HEAD>
<TITLE>403 Forbidden</TITLE>
</HEAD><BODY>
<H1>Forbidden</H1>
You don't have permission to access this folder.<P>
<hr />
</BODY></HTML>

File diff suppressed because it is too large Load Diff

801
hesk/inc/mail/pop3.php Normal file
View File

@@ -0,0 +1,801 @@
<?php
/*
* pop3.php
*
* @(#) $Header: /opt2/ena/metal/pop3/pop3.php,v 1.24 2014/01/27 10:46:48 mlemos Exp $
*
*/
class pop3_class
{
var $hostname="";
var $port=110;
var $tls=0;
var $quit_handshake=1;
var $error="";
var $authentication_mechanism="USER";
var $realm="";
var $workstation="";
var $join_continuation_header_lines=1;
/* Private variables - DO NOT ACCESS */
var $connection=0;
var $state="DISCONNECTED";
var $greeting="";
var $must_update=0;
var $debug=0;
var $html_debug=0;
var $next_token="";
var $message_buffer="";
var $connection_name = '';
/* Private methods - DO NOT CALL */
Function Tokenize($string,$separator="")
{
if(!strcmp($separator,""))
{
$separator=$string;
$string=$this->next_token;
}
for($character=0;$character<strlen($separator);$character++)
{
if(GetType($position=strpos($string,$separator[$character]))=="integer")
$found=(IsSet($found) ? min($found,$position) : $position);
}
if(IsSet($found))
{
$this->next_token=substr($string,$found+1);
return(substr($string,0,$found));
}
else
{
$this->next_token="";
return($string);
}
}
Function SetError($error)
{
return($this->error=$error);
}
Function OutputDebug($message)
{
$message.="\n";
if($this->html_debug)
$message=str_replace("\n","<br />\n",HtmlSpecialChars($message));
echo $message;
#flush();
}
Function GetLine()
{
for($line="";;)
{
if(feof($this->connection))
return(0);
$line.=@fgets($this->connection,100);
$length=strlen($line);
if($length>=2
&& substr($line,$length-2,2)=="\r\n")
{
$line=substr($line,0,$length-2);
if($this->debug)
$this->OutputDebug("S $line");
return($line);
}
}
}
Function PutLine($line)
{
if($this->debug)
$this->OutputDebug("C $line");
return(fputs($this->connection,"$line\r\n"));
}
Function OpenConnection()
{
if($this->tls)
{
$version=explode(".",function_exists("phpversion") ? phpversion() : "3.0.7");
$php_version=intval($version[0])*1000000+intval($version[1])*1000+intval($version[2]);
if($php_version<4003000)
return("establishing TLS connections requires at least PHP version 4.3.0");
if(!function_exists("extension_loaded")
|| !extension_loaded("openssl"))
return("establishing TLS connections requires the OpenSSL extension enabled");
}
if($this->hostname=="")
return($this->SetError("2 it was not specified a valid hostname"));
if($this->debug)
$this->OutputDebug("Connecting to ".$this->hostname." ...");
if(($this->connection=@fsockopen(($this->tls ? "tls://" : "").$this->hostname, $this->port, $error, $error_message))==0)
{
switch($error)
{
case -3:
return($this->SetError("-3 socket could not be created"));
case -4:
return($this->SetError("-4 dns lookup on hostname \"$hostname\" failed"));
case -5:
return($this->SetError("-5 connection refused or timed out"));
case -6:
return($this->SetError("-6 fdopen() call failed"));
case -7:
return($this->SetError("-7 setvbuf() call failed"));
default:
return($this->SetError($error." could not connect to the host \"".$this->hostname."\": ".$error_message));
}
}
return("");
}
Function CloseConnection()
{
if($this->debug)
$this->OutputDebug("Closing connection.");
if($this->connection!=0)
{
fclose($this->connection);
$this->connection=0;
}
}
/* Public methods */
/* Open method - set the object variable $hostname to the POP3 server address. */
Function Open()
{
if($this->state!="DISCONNECTED")
return($this->SetError("1 a connection is already opened"));
if(($error=$this->OpenConnection())!="")
return($error);
$greeting=$this->GetLine();
if(GetType($greeting)!="string"
|| $this->Tokenize($greeting," ")!="+OK")
{
$this->CloseConnection();
return($this->SetError("3 POP3 server greeting was not found"));
}
$this->Tokenize("<");
$this->greeting = $this->Tokenize(">");
$this->must_update=0;
$this->state="AUTHORIZATION";
return("");
}
/* Close method - this method must be called at least if there are any
messages to be deleted */
Function Close()
{
if($this->state=="DISCONNECTED")
return($this->SetError("no connection was opened"));
while($this->state=='GETMESSAGE')
{
if(strlen($error=$this->GetMessage(8000, $message, $end_of_message)))
return($error);
}
if($this->must_update
|| $this->quit_handshake)
{
if($this->PutLine("QUIT")==0)
return($this->SetError("Could not send the QUIT command"));
$response=$this->GetLine();
if(GetType($response)!="string")
return($this->SetError("Could not get quit command response"));
if($this->Tokenize($response," ")!="+OK")
return($this->SetError("Could not quit the connection: ".$this->Tokenize("\r\n")));
}
$this->CloseConnection();
$this->state="DISCONNECTED";
$pop3_class = new pop3_class();
$pop3_class->SetConnection(-1, $this->connection_name, $this);
return("");
}
/* Login method - pass the user name and password of POP account. Set
$apop to 1 or 0 wether you want to login using APOP method or not. */
Function Login($user,$password,$apop=0)
{
if($this->state!="AUTHORIZATION")
return($this->SetError("connection is not in AUTHORIZATION state"));
if($apop)
{
if(!strcmp($this->greeting,""))
return($this->SetError("Server does not seem to support APOP authentication"));
if($this->PutLine("APOP $user ".md5("<".$this->greeting.">".$password))==0)
return($this->SetError("Could not send the APOP command"));
$response=$this->GetLine();
if(GetType($response)!="string")
return($this->SetError("Could not get APOP login command response"));
if($this->Tokenize($response," ")!="+OK")
return($this->SetError("APOP login failed: ".$this->Tokenize("\r\n")));
}
else
{
$authenticated=0;
if(strcmp($this->authentication_mechanism,"USER")
&& function_exists("class_exists")
&& class_exists("sasl_client_class"))
{
if(strlen($this->authentication_mechanism))
$mechanisms=array($this->authentication_mechanism);
else
{
$mechanisms=array();
if($this->PutLine("CAPA")==0)
return($this->SetError("Could not send the CAPA command"));
$response=$this->GetLine();
if(GetType($response)!="string")
return($this->SetError("Could not get CAPA command response"));
if(!strcmp($this->Tokenize($response," "),"+OK"))
{
for(;;)
{
$response=$this->GetLine();
if(GetType($response)!="string")
return($this->SetError("Could not retrieve the supported authentication methods"));
switch($this->Tokenize($response," "))
{
case ".":
break 2;
case "SASL":
for($method=1;strlen($mechanism=$this->Tokenize(" "));$method++)
$mechanisms[]=$mechanism;
break;
}
}
}
}
$sasl=new sasl_client_class;
$sasl->SetCredential("user",$user);
$sasl->SetCredential("password",$password);
if(strlen($this->realm))
$sasl->SetCredential("realm",$this->realm);
if(strlen($this->workstation))
$sasl->SetCredential("workstation",$this->workstation);
do
{
$status=$sasl->Start($mechanisms,$message,$interactions);
}
while($status==SASL_INTERACT);
switch($status)
{
case SASL_CONTINUE:
break;
case SASL_NOMECH:
if(strlen($this->authentication_mechanism))
return($this->SetError("authenticated mechanism ".$this->authentication_mechanism." may not be used: ".$sasl->error));
break;
default:
return($this->SetError("Could not start the SASL authentication client: ".$sasl->error));
}
if(strlen($sasl->mechanism))
{
if($this->PutLine("AUTH ".$sasl->mechanism.(IsSet($message) ? " ".base64_encode($message) : ""))==0)
return("Could not send the AUTH command");
$response=$this->GetLine();
if(GetType($response)!="string")
return("Could not get AUTH command response");
switch($this->Tokenize($response," "))
{
case "+OK":
$response="";
break;
case "+":
$response=base64_decode($this->Tokenize("\r\n"));
break;
default:
return($this->SetError("Authentication error: ".$this->Tokenize("\r\n")));
}
for(;!$authenticated;)
{
do
{
$status=$sasl->Step($response,$message,$interactions);
}
while($status==SASL_INTERACT);
switch($status)
{
case SASL_CONTINUE:
if($this->PutLine(base64_encode($message))==0)
return("Could not send message authentication step message");
$response=$this->GetLine();
if(GetType($response)!="string")
return("Could not get authentication step message response");
switch($this->Tokenize($response," "))
{
case "+OK":
$authenticated=1;
break;
case "+":
$response=base64_decode($this->Tokenize("\r\n"));
break;
default:
return($this->SetError("Authentication error: ".$this->Tokenize("\r\n")));
}
break;
default:
return($this->SetError("Could not process the SASL authentication step: ".$sasl->error));
}
}
}
}
if(!$authenticated)
{
if($this->PutLine("USER $user")==0)
return($this->SetError("Could not send the USER command"));
$response=$this->GetLine();
if(GetType($response)!="string")
return($this->SetError("Could not get user login entry response"));
if($this->Tokenize($response," ")!="+OK")
return($this->SetError("User error: ".$this->Tokenize("\r\n")));
if($this->PutLine("PASS $password")==0)
return($this->SetError("Could not send the PASS command"));
$response=$this->GetLine();
if(GetType($response)!="string")
return($this->SetError("Could not get login password entry response"));
if($this->Tokenize($response," ")!="+OK")
return($this->SetError("Password error: ".$this->Tokenize("\r\n")));
}
}
$this->state="TRANSACTION";
return("");
}
/* Statistics method - pass references to variables to hold the number of
messages in the mail box and the size that they take in bytes. */
Function Statistics(&$messages,&$size)
{
if($this->state!="TRANSACTION")
return($this->SetError("connection is not in TRANSACTION state"));
if($this->PutLine("STAT")==0)
return($this->SetError("Could not send the STAT command"));
$response=$this->GetLine();
if(GetType($response)!="string")
return($this->SetError("Could not get the statistics command response"));
if($this->Tokenize($response," ")!="+OK")
return($this->SetError("Could not get the statistics: ".$this->Tokenize("\r\n")));
$messages=$this->Tokenize(" ");
$size=$this->Tokenize(" ");
return("");
}
/* ListMessages method - the $message argument indicates the number of a
message to be listed. If you specify an empty string it will list all
messages in the mail box. The $unique_id flag indicates if you want
to list the each message unique identifier, otherwise it will
return the size of each message listed. If you list all messages the
result will be returned in an array. */
Function ListMessages($message,$unique_id)
{
if($this->state!="TRANSACTION")
return($this->SetError("connection is not in TRANSACTION state"));
if($unique_id)
$list_command="UIDL";
else
$list_command="LIST";
if($this->PutLine("$list_command".($message ? " ".$message : ""))==0)
return($this->SetError("Could not send the $list_command command"));
$response=$this->GetLine();
if(GetType($response)!="string")
return($this->SetError("Could not get message list command response"));
if($this->Tokenize($response," ")!="+OK")
return($this->SetError("Could not get the message listing: ".$this->Tokenize("\r\n")));
if($message=="")
{
for($messages=array();;)
{
$response=$this->GetLine();
if(GetType($response)!="string")
return($this->SetError("Could not get message list response"));
if($response==".")
break;
$message=intval($this->Tokenize($response," "));
if($unique_id)
$messages[$message]=$this->Tokenize(" ");
else
$messages[$message]=intval($this->Tokenize(" "));
}
return($messages);
}
else
{
$message=intval($this->Tokenize(" "));
$value=$this->Tokenize(" ");
return($unique_id ? $value : intval($value));
}
}
/* RetrieveMessage method - the $message argument indicates the number of
a message to be listed. Pass a reference variables that will hold the
arrays of the $header and $body lines. The $lines argument tells how
many lines of the message are to be retrieved. Pass a negative number
if you want to retrieve the whole message. */
Function RetrieveMessage($message,&$headers,&$body,$lines)
{
if($this->state!="TRANSACTION")
return($this->SetError("connection is not in TRANSACTION state"));
if($lines<0)
{
$command="RETR";
$arguments="$message";
}
else
{
$command="TOP";
$arguments="$message $lines";
}
if($this->PutLine("$command $arguments")==0)
return($this->SetError("Could not send the $command command"));
$response=$this->GetLine();
if(GetType($response)!="string")
return($this->SetError("Could not get message retrieval command response"));
if($this->Tokenize($response," ")!="+OK")
return($this->SetError("Could not retrieve the message: ".$this->Tokenize("\r\n")));
for($headers=$body=array(),$line=0;;)
{
$response=$this->GetLine();
if(GetType($response)!="string")
return($this->SetError("Could not retrieve the message"));
switch($response)
{
case ".":
return("");
case "":
break 2;
default:
if(substr($response,0,1)==".")
$response=substr($response,1,strlen($response)-1);
break;
}
if($this->join_continuation_header_lines
&& $line>0
&& ($response[0]=="\t"
|| $response[0]==" "))
$headers[$line-1].=$response;
else
{
$headers[$line]=$response;
$line++;
}
}
for($line=0;;$line++)
{
$response=$this->GetLine();
if(GetType($response)!="string")
return($this->SetError("Could not retrieve the message"));
switch($response)
{
case ".":
return("");
default:
if(substr($response,0,1)==".")
$response=substr($response,1,strlen($response)-1);
break;
}
$body[$line]=$response;
}
return("");
}
/* OpenMessage method - the $message argument indicates the number of
a message to be opened. The $lines argument tells how many lines of
the message are to be retrieved. Pass a negative number if you want
to retrieve the whole message. */
Function OpenMessage($message, $lines=-1)
{
if($this->state!="TRANSACTION")
return($this->SetError("connection is not in TRANSACTION state"));
if($lines<0)
{
$command="RETR";
$arguments="$message";
}
else
{
$command="TOP";
$arguments="$message $lines";
}
if($this->PutLine("$command $arguments")==0)
return($this->SetError("Could not send the $command command"));
$response=$this->GetLine();
if(GetType($response)!="string")
return($this->SetError("Could not get message retrieval command response"));
if($this->Tokenize($response," ")!="+OK")
return($this->SetError("Could not retrieve the message: ".$this->Tokenize("\r\n")));
$this->state="GETMESSAGE";
$this->message_buffer="";
return("");
}
/* GetMessage method - the $count argument indicates the number of bytes
to be read from an opened message. The $message returns by reference
the data read from the message. The $end_of_message argument returns
by reference a boolean value indicated whether it was reached the end
of the message. */
Function GetMessage($count, &$message, &$end_of_message)
{
if($this->state!="GETMESSAGE")
return($this->SetError("connection is not in GETMESSAGE state"));
$message="";
$end_of_message=0;
while($count>strlen($this->message_buffer)
&& !$end_of_message)
{
$response=$this->GetLine();
if(GetType($response)!="string")
return($this->SetError("Could not retrieve the message headers"));
if(!strcmp($response,"."))
{
$end_of_message=1;
$this->state="TRANSACTION";
break;
}
else
{
if(substr($response,0,1)==".")
$response=substr($response,1,strlen($response)-1);
$this->message_buffer.=$response."\r\n";
}
}
if($end_of_message
|| $count>=strlen($this->message_buffer))
{
$message=$this->message_buffer;
$this->message_buffer="";
}
else
{
$message=substr($this->message_buffer, 0, $count);
$this->message_buffer=substr($this->message_buffer, $count);
}
return("");
}
/* DeleteMessage method - the $message argument indicates the number of
a message to be marked as deleted. Messages will only be effectively
deleted upon a successful call to the Close method. */
Function DeleteMessage($message)
{
if($this->state!="TRANSACTION")
return($this->SetError("connection is not in TRANSACTION state"));
if($this->PutLine("DELE $message")==0)
return($this->SetError("Could not send the DELE command"));
$response=$this->GetLine();
if(GetType($response)!="string")
return($this->SetError("Could not get message delete command response"));
if($this->Tokenize($response," ")!="+OK")
return($this->SetError("Could not delete the message: ".$this->Tokenize("\r\n")));
$this->must_update=1;
return("");
}
/* ResetDeletedMessages method - Reset the list of marked to be deleted
messages. No messages will be marked to be deleted upon a successful
call to this method. */
Function ResetDeletedMessages()
{
if($this->state!="TRANSACTION")
return($this->SetError("connection is not in TRANSACTION state"));
if($this->PutLine("RSET")==0)
return($this->SetError("Could not send the RSET command"));
$response=$this->GetLine();
if(GetType($response)!="string")
return($this->SetError("Could not get reset deleted messages command response"));
if($this->Tokenize($response," ")!="+OK")
return($this->SetError("Could not reset deleted messages: ".$this->Tokenize("\r\n")));
$this->must_update=0;
return("");
}
/* IssueNOOP method - Just pings the server to prevent it auto-close the
connection after an idle timeout (tipically 10 minutes). Not very
useful for most likely uses of this class. It's just here for
protocol support completeness. */
Function IssueNOOP()
{
if($this->state!="TRANSACTION")
return($this->SetError("connection is not in TRANSACTION state"));
if($this->PutLine("NOOP")==0)
return($this->SetError("Could not send the NOOP command"));
$response=$this->GetLine();
if(GetType($response)!="string")
return($this->SetError("Could not NOOP command response"));
if($this->Tokenize($response," ")!="+OK")
return($this->SetError("Could not issue the NOOP command: ".$this->Tokenize("\r\n")));
return("");
}
Function &SetConnection($set, &$current_name, &$pop3)
{
static $connections = array();
if($set>0)
{
$current_name = strval(count($connections));
$connections[$current_name] = &$pop3;
}
elseif($set<0)
{
$connections[$current_name] = '';
$current_name = '';
}
elseif(IsSet($connections[$current_name])
&& GetType($connections[$current_name])!='string')
{
$connection = &$connections[$current_name];
return($connection);
}
return($pop3);
}
/* GetConnectionName method - Retrieve the name associated to an
established POP3 server connection to use as virtual host name for
use in POP3 stream wrapper URLs. */
Function GetConnectionName(&$connection_name)
{
if($this->state!="TRANSACTION")
return($this->SetError("cannot get the name of a POP3 connection that was not established and the user has logged in"));
if(strlen($this->connection_name) == 0)
{
$pop3_class = new pop3_class();
$pop3_class->SetConnection(1, $this->connection_name, $this);
}
$connection_name = $this->connection_name;
return('');
}
};
class pop3_stream
{
var $opened = 0;
var $report_errors = 1;
var $read = 0;
var $buffer = "";
var $end_of_message=1;
var $previous_connection = 0;
var $pop3;
Function SetError($error)
{
if($this->report_errors)
trigger_error($error);
return(FALSE);
}
Function ParsePath($path, &$url)
{
if(!$this->previous_connection)
{
if(IsSet($url["host"]))
$this->pop3->hostname=$url["host"];
if(IsSet($url["port"]))
$this->pop3->port=intval($url["port"]);
if(IsSet($url["scheme"])
&& !strcmp($url["scheme"],"pop3s"))
$this->pop3->tls=1;
if(!IsSet($url["user"]))
return($this->SetError("it was not specified a valid POP3 user"));
if(!IsSet($url["pass"]))
return($this->SetError("it was not specified a valid POP3 password"));
if(!IsSet($url["path"]))
return($this->SetError("it was not specified a valid mailbox path"));
}
if(IsSet($url["query"]))
{
parse_str($url["query"],$query);
if(IsSet($query["debug"]))
$this->pop3->debug = intval($query["debug"]);
if(IsSet($query["html_debug"]))
$this->pop3->html_debug = intval($query["html_debug"]);
if(!$this->previous_connection)
{
if(IsSet($query["tls"]))
$this->pop3->tls = intval($query["tls"]);
if(IsSet($query["realm"]))
$this->pop3->realm = UrlDecode($query["realm"]);
if(IsSet($query["workstation"]))
$this->pop3->workstation = UrlDecode($query["workstation"]);
if(IsSet($query["authentication_mechanism"]))
$this->pop3->realm = UrlDecode($query["authentication_mechanism"]);
}
if(IsSet($query["quit_handshake"]))
$this->pop3->quit_handshake = intval($query["quit_handshake"]);
}
return(TRUE);
}
Function stream_open($path, $mode, $options, &$opened_path)
{
$this->report_errors = (($options & STREAM_REPORT_ERRORS) !=0);
if(strcmp($mode, "r"))
return($this->SetError("the message can only be opened for reading"));
$url=parse_url($path);
$host = $url['host'];
$pop3_class = new pop3_class();
$pop3 = &$pop3_class->SetConnection(0, $host, $this->pop3);
if(IsSet($pop3))
{
$this->pop3 = &$pop3;
$this->previous_connection = 1;
}
else
$this->pop3=new pop3_class;
if(!$this->ParsePath($path, $url))
return(FALSE);
$message=substr($url["path"],1);
if(strcmp(intval($message), $message)
|| $message<=0)
return($this->SetError("it was not specified a valid message to retrieve"));
if(!$this->previous_connection)
{
if(strlen($error=$this->pop3->Open()))
return($this->SetError($error));
$this->opened = 1;
$apop = (IsSet($url["query"]["apop"]) ? intval($url["query"]["apop"]) : 0);
if(strlen($error=$this->pop3->Login(UrlDecode($url["user"]), UrlDecode($url["pass"]),$apop)))
{
$this->stream_close();
return($this->SetError($error));
}
}
if(strlen($error=$this->pop3->OpenMessage($message,-1)))
{
$this->stream_close();
return($this->SetError($error));
}
$this->end_of_message=FALSE;
if($options & STREAM_USE_PATH)
$opened_path=$path;
$this->read = 0;
$this->buffer = "";
return(TRUE);
}
Function stream_eof()
{
if($this->read==0)
return(FALSE);
return($this->end_of_message);
}
Function stream_read($count)
{
if($count<=0)
return($this->SetError("it was not specified a valid length of the message to read"));
if($this->end_of_message)
return("");
if(strlen($error=$this->pop3->GetMessage($count, $read, $this->end_of_message)))
return($this->SetError($error));
$this->read += strlen($read);
return($read);
}
Function stream_close()
{
while(!$this->end_of_message)
$this->stream_read(8000);
if($this->opened)
{
$this->pop3->Close();
$this->opened = 0;
}
}
};
?>

View File

@@ -0,0 +1,935 @@
<?php
/*
* rfc822_addresses.php
*
* @(#) $Id: rfc822_addresses.php,v 1.16 2016/07/23 01:50:22 mlemos Exp $
*
*/
/*
{metadocument}<?xml version="1.0" encoding="ISO-8859-1" ?>
<class>
<package>net.manuellemos.mimeparser</package>
<version>@(#) $Id: rfc822_addresses.php,v 1.16 2016/07/23 01:50:22 mlemos Exp $</version>
<copyright>Copyright <20> (C) Manuel Lemos 2006 - 2008</copyright>
<title>RFC 822 e-mail addresses parser</title>
<author>Manuel Lemos</author>
<authoraddress>mlemos-at-acm.org</authoraddress>
<documentation>
<idiom>en</idiom>
<purpose>Parse e-mail addresses from headers of <link>
<url>http://www.ietf.org/rfc/rfc822.txt</url>
<data>RFC 822</data>
</link> compliant e-mail messages.</purpose>
<usage>Use the function <functionlink>ParseAddressList</functionlink>
function to retrieve the list of e-mail addresses contained in
e-mail message headers like <tt>From</tt>, <tt>To</tt>, <tt>Cc</tt>
or <tt>Bcc</tt>.</usage>
</documentation>
{/metadocument}
*/
class rfc822_addresses_class
{
/* Private variables */
var $v = '';
/* Public variables */
/*
{metadocument}
<variable>
<name>error</name>
<type>STRING</type>
<value></value>
<documentation>
<purpose>Store the message that is returned when an error
occurs.</purpose>
<usage>Check this variable to understand what happened when a call to
any of the class functions has failed.<paragraphbreak />
This class uses cumulative error handling. This means that if one
class functions that may fail is called and this variable was
already set to an error message due to a failure in a previous call
to the same or other function, the function will also fail and does
not do anything.<paragraphbreak />
This allows programs using this class to safely call several
functions that may fail and only check the failure condition after
the last function call.<paragraphbreak />
Just set this variable to an empty string to clear the error
condition.</usage>
</documentation>
</variable>
{/metadocument}
*/
var $error = '';
/*
{metadocument}
<variable>
<name>error_position</name>
<type>INTEGER</type>
<value>-1</value>
<documentation>
<purpose>Point to the position of the message data or file that
refers to the last error that occurred.</purpose>
<usage>Check this variable to determine the relevant position of the
message when a parsing error occurs.</usage>
</documentation>
</variable>
{/metadocument}
*/
var $error_position = -1;
/*
{metadocument}
<variable>
<name>ignore_syntax_errors</name>
<type>BOOLEAN</type>
<value>1</value>
<documentation>
<purpose>Specify whether the class should ignore syntax errors in
malformed addresses.</purpose>
<usage>Set this variable to <booleanvalue>0</booleanvalue> if it is
necessary to verify whether message data may be corrupted due to
to eventual bugs in the program that generated the
message.<paragraphbreak />
Currently the class only ignores some types of syntax errors.
Other syntax errors may still cause the
<functionlink>ParseAddressList</functionlink> to fail.</usage>
</documentation>
</variable>
{/metadocument}
*/
var $ignore_syntax_errors=1;
/*
{metadocument}
<variable>
<name>warnings</name>
<type>HASH</type>
<value></value>
<documentation>
<purpose>Return a list of positions of the original message that
contain syntax errors.</purpose>
<usage>Check this variable to retrieve eventual message syntax
errors that were ignored when the
<variablelink>ignore_syntax_errors</variablelink> is set to
<booleanvalue>1</booleanvalue>.<paragraphbreak />
The indexes of this array are the positions of the errors. The
array values are the corresponding syntax error messages.</usage>
</documentation>
</variable>
{/metadocument}
*/
var $warnings=array();
/* Private functions */
Function SetError($error)
{
$this->error = $error;
return(0);
}
Function SetPositionedError($error, $position)
{
$this->error_position = $position;
return($this->SetError($error));
}
Function SetWarning($warning, $position)
{
$this->warnings[$position]=$warning;
return(1);
}
Function SetPositionedWarning($error, $position)
{
if(!$this->ignore_syntax_errors)
return($this->SetPositionedError($error, $position));
return($this->SetWarning($error, $position));
}
Function QDecode($p, &$value, &$encoding)
{
$encoding = $charset = null;
$s = 0;
$decoded = '';
$l = strlen($value);
while($s < $l)
{
if(GetType($q = strpos($value, '=?', $s)) != 'integer')
{
if($s == 0)
return(1);
if($s < $l)
$decoded .= substr($value, $s);
break;
}
if($s < $q)
$decoded .= substr($value, $s, $q - $s);
$q += 2;
if(GetType($c = strpos($value, '?', $q)) != 'integer'
|| $q == $c)
return($this->SetPositionedWarning('invalid Q-encoding character set', $p + $q));
if(IsSet($charset))
{
$another_charset = strtolower(substr($value, $q, $c - $q));
if(strcmp($charset, $another_charset)
&& strcmp($another_charset, 'ascii'))
return($this->SetWarning('it is not possible to decode an encoded value using mixed character sets into a single value', $p + $q));
}
else
{
$charset = strtolower(substr($value, $q, $c - $q));
if(!strcmp($charset, 'ascii'))
$charset = null;
}
++$c;
if(GetType($t = strpos($value, '?', $c)) != 'integer'
|| $c==$t)
return($this->SetPositionedWarning('invalid Q-encoding type', $p + $c));
$type = strtolower(substr($value, $c, $t - $c));
++$t;
if(GetType($e = strpos($value, '?=', $t)) != 'integer')
return($this->SetPositionedWarning('invalid Q-encoding encoded data', $p + $e));
switch($type)
{
case 'q':
for($s = $t; $s<$e;)
{
switch($b = $value[$s])
{
case '=':
$h = HexDec($hex = strtolower(substr($value, $s + 1, 2)));
if($s + 3 > $e
|| strcmp(sprintf('%02x', $h), $hex))
return($this->SetPositionedWarning('invalid Q-encoding q encoded data', $p + $s));
$decoded .= chr($h);
$s += 3;
break;
case '_':
$decoded .= ' ';
++$s;
break;
default:
$decoded .= $b;
++$s;
}
}
break;
case 'b':
if($e <= $t
|| strlen($binary = base64_decode($data = substr($value, $t, $e - $t))) == 0
|| GetType($binary) != 'string')
return($this->SetPositionedWarning('invalid Q-encoding b encoded data', $p + $t));
$decoded .= $binary;
$s = $e;
break;
default:
return($this->SetPositionedWarning('Q-encoding '.$type.' is not yet supported', $p + $c));
}
$s += 2;
$s += strspn($value, " \t", $s);
}
$value = $decoded;
$encoding = $charset;
return(1);
}
Function ParseCText(&$p, &$c_text)
{
$c_text = null;
$v = $this->v;
if($p<strlen($v)
&& GetType(strchr("\t\r\n ()\\\0", $c = $v[$p])) != 'string'
&& Ord($c)<128)
{
$c_text = $c;
++$p;
}
return(1);
}
Function ParseQText(&$p, &$q_text)
{
$q_text = null;
$v = $this->v;
if($p>strlen($v)
|| GetType(strchr("\t\r\n \"\\\0", $c = $v[$p])) == 'string')
return(1);
if(Ord($c) >= 128)
{
if(!$this->ignore_syntax_errors)
return(1);
$this->SetPositionedWarning('it was used an unencoded 8 bit character', $p);
}
$q_text = $c;
++$p;
return(1);
}
Function ParseQuotedPair(&$p, &$quoted_pair)
{
$quoted_pair = null;
$v = $this->v;
$l = strlen($v);
if($p+1 < $l
&& !strcmp($v[$p], '\\')
&& GetType(strchr("\r\n\0", $c = $v[$p + 1])) != 'string'
&& Ord($c)<128)
{
$quoted_pair = $c;
$p += 2;
}
return(1);
}
Function ParseCContent(&$p, &$c_content)
{
$c_content = null;
$c = $p;
if(!$this->ParseQuotedPair($c, $content))
return(0);
if(!IsSet($content))
{
if(!$this->ParseCText($c, $content))
return(0);
if(!IsSet($content))
{
if(!$this->ParseComment($c, $content))
return(0);
if(!IsSet($content))
return(1);
}
}
$c_content = $content;
$p = $c;
return(1);
}
Function SkipWhiteSpace(&$p)
{
$v = $this->v;
$l = strlen($v);
for(;$p<$l; ++$p)
{
switch($v[$p])
{
case ' ':
case "\n":
case "\r":
case "\t":
break;
default:
return(1);
}
}
return(1);
}
Function ParseComment(&$p, &$comment)
{
$comment = null;
$v = $this->v;
$l = strlen($v);
$c = $p;
if($c >= $l
|| strcmp($v[$c], '('))
return(1);
++$c;
for(; $c < $l;)
{
if(!$this->SkipWhiteSpace($c))
return(0);
if(!$this->ParseCContent($c, $c_content))
return(0);
if(!IsSet($c_content))
break;
}
if(!$this->SkipWhiteSpace($c))
return(0);
if($c >= $l
|| strcmp($v[$c], ')'))
return(1);
++$c;
$comment = substr($v, $p, $c - $p);
$p = $c;
return(1);
}
Function SkipCommentGetWhiteSpace(&$p, &$space)
{
$v = $this->v;
$l = strlen($v);
for($space = '';$p<$l;)
{
switch($w = $v[$p])
{
case ' ':
case "\n":
case "\r":
case "\t":
++$p;
$space .= $w;
break;
case '(':
if(!$this->ParseComment($p, $comment))
return(0);
default:
return(1);
}
}
return(1);
}
Function SkipCommentWhiteSpace(&$p)
{
$v = $this->v;
$l = strlen($v);
for(;$p<$l;)
{
switch($w = $v[$p])
{
case ' ':
case "\n":
case "\r":
case "\t":
++$p;
break;
case '(':
if(!$this->ParseComment($p, $comment))
return(0);
default:
return(1);
}
}
return(1);
}
Function ParseQContent(&$p, &$q_content)
{
$q_content = null;
$q = $p;
if(!$this->ParseQuotedPair($q, $content))
return(0);
if(!IsSet($content))
{
if(!$this->ParseQText($q, $content))
return(0);
if(!IsSet($content))
return(1);
}
$q_content = $content;
$p = $q;
return(1);
}
Function ParseAtom(&$p, &$atom, $dot)
{
$atom = null;
$v = $this->v;
$l = strlen($v);
$a = $p;
if(!$this->SkipCommentGetWhiteSpace($a, $space))
return(0);
$match = '/^([-'.($dot ? '.' : '').'A-Za-z0-9!#$%&\'*+\\/=?^_`{|}~]+)/';
for($s = $a;$a < $l;)
{
if(preg_match($match, substr($this->v, $a), $m))
$a += strlen($m[1]);
elseif(Ord($v[$a]) < 128)
break;
elseif(!$this->SetPositionedWarning('it was used an unencoded 8 bit character', $a))
return(0);
else
++$a;
}
if($s == $a)
return(1);
$atom = $space.substr($this->v, $s, $a - $s);
if(!$this->SkipCommentGetWhiteSpace($a, $space))
return(0);
$atom .= $space;
$p = $a;
return(1);
}
Function ParseQuotedString(&$p, &$quoted_string)
{
$quoted_string = null;
$v = $this->v;
$l = strlen($v);
$s = $p;
if(!$this->SkipCommentWhiteSpace($s))
return(0);
if($s >= $l
|| strcmp($v[$s], '"'))
return(1);
++$s;
for($string = '';$s < $l;)
{
$w = $s;
if(!$this->SkipWhiteSpace($s))
return(0);
if($w != $s)
$string .= substr($v, $w, $s - $w);
if(!$this->ParseQContent($s, $q_content))
return(0);
if(!IsSet($q_content))
break;
$string .= $q_content;
}
$w = $s;
if(!$this->SkipWhiteSpace($s))
return(0);
if($w != $s)
$string .= substr($v, $w, $s - $w);
if($s >= $l
|| strcmp($v[$s], '"'))
return(1);
++$s;
if(!$this->SkipCommentWhiteSpace($s))
return(0);
$quoted_string = $string;
$p = $s;
return(1);
}
Function ParseWord(&$p, &$word, &$escape)
{
$word = null;
if(!$this->ParseQuotedString($p, $word))
return(0);
if(IsSet($word))
return(1);
for($w = '';;)
{
$last = $w;
if(!$this->ParseAtom($p, $atom, 0))
return(0);
if(IsSet($atom))
$w .= $atom;
if($this->ignore_syntax_errors)
{
$e = $p;
if(!$this->ParseQuotedPair($p, $quoted_pair))
return(0);
if(IsSet($quoted_pair))
{
$w .= $quoted_pair;
if(!IsSet($escape))
$escape = $e;
}
}
if($last === $w)
break;
}
if(strlen($w))
$word = $w;
return(1);
}
Function ParseObsPhrase(&$p, &$obs_phrase, &$escape)
{
$obs_phrase = null;
$v = $this->v;
$l = strlen($v);
$ph = $p;
if(!$this->ParseWord($ph, $word, $escape))
return(0);
$string = $word;
for(;;)
{
if(!$this->ParseWord($ph, $word, $escape))
return(0);
if(IsSet($word))
{
$string .= $word;
continue;
}
$w = $ph;
if(!$this->SkipCommentGetWhiteSpace($ph, $space))
return(0);
if($w != $ph)
{
$string .= $space;
continue;
}
if($ph >= $l
|| strcmp($v[$ph], '.'))
break;
$string .= '.';
++$ph;
}
$obs_phrase = $string;
$p = $ph;
return(1);
}
Function ParsePhrase(&$p, &$phrase, &$escape)
{
$phrase = null;
if(!$this->ParseObsPhrase($p, $phrase, $escape))
return(0);
if(IsSet($phrase))
return(1);
$ph = $p;
if(!$this->ParseWord($ph, $word, $escape))
return(0);
$string = $word;
for(;;)
{
if(!$this->ParseWord($ph, $word, $escape))
return(0);
if(!IsSet($word))
break;
$string .= $word;
}
$phrase = $string;
$p = $ph;
return(1);
}
Function ParseAddrSpec(&$p, &$addr_spec)
{
$addr_spec = null;
$v = $this->v;
$l = strlen($v);
$a = $p;
if(!$this->ParseQuotedString($a, $local_part))
return(0);
if(!IsSet($local_part))
{
if(!$this->ParseAtom($a, $local_part, 1))
return(0);
$local_part = trim($local_part);
}
if($a >= $l
|| strcmp($v[$a], '@'))
return(1);
++$a;
if(!$this->ParseAtom($a, $domain, 1))
return(0);
if(!IsSet($domain))
return(1);
$addr_spec = $local_part.'@'.trim($domain);
$p = $a;
return(1);
}
Function ParseAngleAddr(&$p, &$addr)
{
$addr = null;
$v = $this->v;
$l = strlen($v);
$a = $p;
if(!$this->SkipCommentWhiteSpace($a))
return(0);
if($a >= $l
|| strcmp($v[$a], '<'))
return(1);
++$a;
if(!$this->ParseAddrSpec($a, $addr_spec))
return(0);
if($a >= $l
|| strcmp($v[$a], '>'))
return(1);
++$a;
if(!$this->SkipCommentWhiteSpace($a))
return(0);
$addr = $addr_spec;
$p = $a;
return(1);
}
Function ParseName(&$p, &$address)
{
$address = $escape = null;
$a = $p;
if(!$this->ParsePhrase($a, $display_name, $escape))
return(0);
if(IsSet($display_name))
{
if(IsSet($escape)
&& !$this->SetPositionedWarning('it was used an escape character outside a quoted value', $escape))
return(0);
if(!$this->QDecode($p, $display_name, $encoding))
return(0);
$address['name'] = trim($display_name);
if(IsSet($encoding))
$address['encoding'] = $encoding;
}
$p = $a;
return(1);
}
Function ParseNameAddr(&$p, &$address)
{
$address = $escape = null;
$a = $p;
if(!$this->ParsePhrase($a, $display_name, $escape))
return(0);
if(!$this->ParseAngleAddr($a, $addr))
return(0);
if(!IsSet($addr))
return(1);
$address = array('address'=>$addr);
if(IsSet($display_name))
{
if(IsSet($escape)
&& !$this->SetPositionedWarning('it was used an escape character outside a quoted value', $escape))
return(0);
if(!$this->QDecode($p, $display_name, $encoding))
return(0);
$address['name'] = trim($display_name);
if(IsSet($encoding))
$address['encoding'] = $encoding;
}
$p = $a;
return(1);
}
Function ParseAddrNameAddr(&$p, &$address)
{
$address = null;
$a = $p;
if(!$this->ParseAddrSpec($a, $display_name))
return(0);
if(!IsSet($display_name))
return(1);
if(!$this->ParseAngleAddr($a, $addr))
return(0);
if(!IsSet($addr))
return(1);
if(!$this->QDecode($p, $display_name, $encoding))
return(0);
$address = array(
'address'=>$addr,
'name' => trim($display_name)
);
if(IsSet($encoding))
$address['encoding'] = $encoding;
$p = $a;
return(1);
}
Function ParseMailbox(&$p, &$address)
{
$address = null;
if($this->ignore_syntax_errors)
{
$a = $p;
if(!$this->ParseAddrNameAddr($p, $address))
return(0);
if(IsSet($address))
return($this->SetPositionedWarning('it was specified an unquoted address as name', $a));
}
if(!$this->ParseNameAddr($p, $address))
return(0);
if(IsSet($address))
return(1);
if(!$this->ParseAddrSpec($p, $addr_spec))
return(0);
if(IsSet($addr_spec))
{
$address = array('address'=>$addr_spec);
return(1);
}
$a = $p;
if($this->ignore_syntax_errors
&& $this->ParseName($p, $address)
&& IsSet($address))
return($this->SetPositionedWarning('it was specified a name without an address', $a));
return(1);
}
Function ParseMailboxGroup(&$p, &$mailbox_group)
{
$v = $this->v;
$l = strlen($v);
$g = $p;
if(!$this->ParseMailbox($g, $address))
return(0);
if(!IsSet($address))
return(1);
$addresses = array($address);
for(;$g < $l;)
{
if(strcmp($v[$g], ','))
break;
++$g;
if(!$this->ParseMailbox($g, $address))
return(0);
if(!IsSet($address))
return(1);
$addresses[] = $address;
}
$mailbox_group = $addresses;
$p = $g;
return(1);
}
Function ParseGroup(&$p, &$address)
{
$address = $escape = null;
$v = $this->v;
$l = strlen($v);
$g = $p;
if(!$this->ParsePhrase($g, $display_name, $escape))
return(0);
if(!IsSet($display_name)
|| $g >= $l
|| strcmp($v[$g], ':'))
return(1);
++$g;
if(!$this->ParseMailboxGroup($g, $mailbox_group))
return(0);
if(!IsSet($mailbox_group))
{
if(!$this->SkipCommentWhiteSpace($g))
return(0);
$mailbox_group = array();
}
if($g >= $l
|| strcmp($v[$g], ';'))
return(1);
$c = ++$g;
if($this->SkipCommentWhiteSpace($g)
&& $g > $c
&& !$this->SetPositionedWarning('it were used invalid comments after a group of addresses', $c))
return(0);
if(IsSet($escape)
&& !$this->SetPositionedWarning('it was used an escape character outside a quoted value', $escape))
return(0);
if(!$this->QDecode($p, $display_name, $encoding))
return(0);
$address = array(
'name'=>$display_name,
'group'=>$mailbox_group
);
if(IsSet($encoding))
$address['encoding'] = $encoding;
$p = $g;
return(1);
}
Function ParseAddress(&$p, &$address)
{
$address = null;
if(!$this->ParseGroup($p, $address))
return(0);
if(!IsSet($address))
{
if(!$this->ParseMailbox($p, $address))
return(0);
}
return(1);
}
/* Public functions */
/*
{metadocument}
<function>
<name>ParseAddressList</name>
<type>BOOLEAN</type>
<documentation>
<purpose>Parse and extract e-mail addresses eventually from headers
of an e-mail message.</purpose>
<usage>Pass a string value with a list of e-mail addresses to the
<argumentlink>
<function>ParseAddressList</function>
<argument>value</argument>
</argumentlink>. The <argumentlink>
<function>ParseAddressList</function>
<argument>addresses</argument>
</argumentlink> returns the list of e-mail addresses found.</usage>
<returnvalue>This function returns <booleanvalue>1</booleanvalue> if
the specified value is parsed successfully. Otherwise,
check the variables <variablelink>error</variablelink> and
<variablelink>error_position</variablelink> to determine what
error occurred and the relevant value position.</returnvalue>
</documentation>
<argument>
<name>value</name>
<type>STRING</type>
<documentation>
<purpose>String with a list of e-mail addresses to parse.</purpose>
</documentation>
</argument>
<argument>
<name>addresses</name>
<type>ARRAY</type>
<out />
<documentation>
<purpose>Return the list of parsed e-mail addresses.
Each entry in the list is an associative array.<paragraphbreak />
For normal addresses, this associative array has the entry
<stringvalue>address</stringvalue> set to the e-mail address.
If the address has an associated name, it is stored in the
entry <stringvalue>name</stringvalue>.<paragraphbreak />
For address groups, there is the entry
<stringvalue>name</stringvalue>.
The group addresses list are stored in the entry
<stringvalue>group</stringvalue> as an array. The structure of
the group addresses list array is the same as this addresses
list array argument.</purpose>
</documentation>
</argument>
<do>
{/metadocument}
*/
Function ParseAddressList($value, &$addresses)
{
$this->warnings = array();
$addresses = array();
$this->v = $v = $value;
$l = strlen($v);
$p = 0;
if(!$this->ParseAddress($p, $address))
return(0);
if(!IsSet($address))
return($this->SetPositionedError('it was not specified a valid address', $p));
$addresses[] = $address;
while($p < $l)
{
if(strcmp($v[$p], ',')
&& !$this->SetPositionedWarning('multiple addresses must be separated by commas: ', $p))
return(0);
++$p;
if(!$this->ParseAddress($p, $address))
return(0);
if(!IsSet($address))
return($this->SetPositionedError('it was not specified a valid address after comma', $p));
$addresses[] = $address;
}
return(1);
}
/*
{metadocument}
</do>
</function>
{/metadocument}
*/
};
/*
{metadocument}
</class>
{/metadocument}
*/
?>

View File

@@ -0,0 +1,61 @@
<?php
/*
* basic_sasl_client.php
*
* @(#) $Id: basic_sasl_client.php,v 1.1 2004/11/17 08:01:23 mlemos Exp $
*
*/
define("SASL_BASIC_STATE_START", 0);
define("SASL_BASIC_STATE_DONE", 1);
class basic_sasl_client_class
{
var $credentials=array();
var $state=SASL_BASIC_STATE_START;
Function Initialize(&$client)
{
return(1);
}
Function Start(&$client, &$message, &$interactions)
{
if($this->state!=SASL_BASIC_STATE_START)
{
$client->error="Basic authentication state is not at the start";
return(SASL_FAIL);
}
$this->credentials=array(
"user"=>"",
"password"=>""
);
$defaults=array(
);
$status=$client->GetCredentials($this->credentials,$defaults,$interactions);
if($status==SASL_CONTINUE)
{
$message=$this->credentials["user"].":".$this->credentials["password"];
$this->state=SASL_BASIC_STATE_DONE;
}
else
Unset($message);
return($status);
}
Function Step(&$client, $response, &$message, &$interactions)
{
switch($this->state)
{
case SASL_BASIC_STATE_DONE:
$client->error="Basic authentication was finished without success";
return(SASL_FAIL);
default:
$client->error="invalid Basic authentication step state";
return(SASL_FAIL);
}
return(SASL_CONTINUE);
}
};
?>

View File

@@ -0,0 +1,67 @@
<?php
/*
* cram_md5_sasl_client.php
*
* @(#) $Id: cram_md5_sasl_client.php,v 1.3 2004/11/17 08:00:37 mlemos Exp $
*
*/
define("SASL_CRAM_MD5_STATE_START", 0);
define("SASL_CRAM_MD5_STATE_RESPOND_CHALLENGE", 1);
define("SASL_CRAM_MD5_STATE_DONE", 2);
class cram_md5_sasl_client_class
{
var $credentials=array();
var $state=SASL_CRAM_MD5_STATE_START;
Function Initialize(&$client)
{
return(1);
}
Function HMACMD5($key,$text)
{
$key=(strlen($key)<64 ? str_pad($key,64,"\0") : substr($key,0,64));
return(md5((str_repeat("\x5c", 64)^$key).pack("H32", md5((str_repeat("\x36", 64)^$key).$text))));
}
Function Start(&$client, &$message, &$interactions)
{
if($this->state!=SASL_CRAM_MD5_STATE_START)
{
$client->error="CRAM-MD5 authentication state is not at the start";
return(SASL_FAIL);
}
$this->credentials=array(
"user"=>"",
"password"=>""
);
$defaults=array();
$status=$client->GetCredentials($this->credentials,$defaults,$interactions);
if($status==SASL_CONTINUE)
$this->state=SASL_CRAM_MD5_STATE_RESPOND_CHALLENGE;
Unset($message);
return($status);
}
Function Step(&$client, $response, &$message, &$interactions)
{
switch($this->state)
{
case SASL_CRAM_MD5_STATE_RESPOND_CHALLENGE:
$message=$this->credentials["user"]." ".$this->HMACMD5($this->credentials["password"], $response);
$this->state=SASL_CRAM_MD5_STATE_DONE;
break;
case SASL_CRAM_MD5_STATE_DONE:
$client->error="CRAM-MD5 authentication was finished without success";
return(SASL_FAIL);
default:
$client->error="invalid CRAM-MD5 authentication step state";
return(SASL_FAIL);
}
return(SASL_CONTINUE);
}
};
?>

View File

@@ -0,0 +1,135 @@
<?php
/*
* digest_sasl_client.php
*
* @(#) $Id: digest_sasl_client.php,v 1.1 2005/10/27 05:24:15 mlemos Exp $
*
*/
define('SASL_DIGEST_STATE_START', 0);
define('SASL_DIGEST_STATE_RESPOND_CHALLENGE', 1);
define('SASL_DIGEST_STATE_DONE', 2);
class digest_sasl_client_class
{
var $credentials=array();
var $state=SASL_DIGEST_STATE_START;
Function unq($string)
{
return(($string[0]=='"' && $string[strlen($string)-1]=='"') ? substr($string, 1, strlen($string)-2) : $string);
}
Function H($data)
{
return md5($data);
}
Function KD($secret, $data)
{
return $this->H($secret.':'.$data);
}
Function Initialize(&$client)
{
return(1);
}
Function Start(&$client, &$message, &$interactions)
{
if($this->state!=SASL_DIGEST_STATE_START)
{
$client->error='Digest authentication state is not at the start';
return(SASL_FAIL);
}
$this->credentials=array(
'user'=>'',
'password'=>'',
'uri'=>'',
'method'=>'',
'session'=>''
);
$defaults=array();
$status=$client->GetCredentials($this->credentials,$defaults,$interactions);
if($status==SASL_CONTINUE)
$this->state=SASL_DIGEST_STATE_RESPOND_CHALLENGE;
Unset($message);
return($status);
}
Function Step(&$client, $response, &$message, &$interactions)
{
switch($this->state)
{
case SASL_DIGEST_STATE_RESPOND_CHALLENGE:
$values=explode(',',$response);
$parameters=array();
for($v=0; $v<count($values); $v++)
$parameters[strtok(trim($values[$v]), '=')]=strtok('');
$message='username="'.$this->credentials['user'].'"';
if(!IsSet($parameters[$p='realm'])
&& !IsSet($parameters[$p='nonce']))
{
$client->error='Digest authentication parameter '.$p.' is missing from the server response';
return(SASL_FAIL);
}
$message.=', realm='.$parameters['realm'];
$message.=', nonce='.$parameters['nonce'];
$message.=', uri="'.$this->credentials['uri'].'"';
if(IsSet($parameters['algorithm']))
{
$algorithm=$this->unq($parameters['algorithm']);
$message.=', algorithm='.$parameters['algorithm'];
}
else
$algorithm='';
$realm=$this->unq($parameters['realm']);
$nonce=$this->unq($parameters['nonce']);
if(IsSet($parameters['qop']))
{
switch($qop=$this->unq($parameters['qop']))
{
case "auth":
$cnonce=$this->credentials['session'];
break;
default:
$client->error='Digest authentication quality of protection '.$qop.' is not yet supported';
return(SASL_FAIL);
}
}
$nc_value='00000001';
if(IsSet($parameters['qop'])
&& !strcmp($algorithm, 'MD5-sess'))
$A1=$this->H($this->credentials['user'].':'. $realm.':'. $this->credentials['password']).':'.$nonce.':'.$cnonce;
else
$A1=$this->credentials['user'].':'. $realm.':'. $this->credentials['password'];
$A2=$this->credentials['method'].':'.$this->credentials['uri'];
if(IsSet($parameters['qop']))
$response=$this->KD($this->H($A1), $nonce.':'. $nc_value.':'. $cnonce.':'. $qop.':'. $this->H($A2));
else
$response=$this->KD($this->H($A1), $nonce.':'. $this->H($A2));
$message.=', response="'.$response.'"';
if(IsSet($parameters['opaque']))
$message.=', opaque='.$parameters['opaque'];
if(IsSet($parameters['qop']))
$message.=', qop="'.$qop.'"';
$message.=', nc='.$nc_value;
if(IsSet($parameters['qop']))
$message.=', cnonce="'.$cnonce.'"';
$client->encode_response=0;
$this->state=SASL_DIGEST_STATE_DONE;
break;
case SASL_DIGEST_STATE_DONE:
$client->error='Digest authentication was finished without success';
return(SASL_FAIL);
default:
$client->error='invalid Digest authentication step state';
return(SASL_FAIL);
}
return(SASL_CONTINUE);
}
};
?>

View File

@@ -0,0 +1,8 @@
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<HTML><HEAD>
<TITLE>403 Forbidden</TITLE>
</HEAD><BODY>
<H1>Forbidden</H1>
You don't have permission to access this folder.<P>
<hr />
</BODY></HTML>

View File

@@ -0,0 +1,69 @@
<?php
/*
* login_sasl_client.php
*
* @(#) $Id: login_sasl_client.php,v 1.2 2004/11/17 08:00:37 mlemos Exp $
*
*/
define("SASL_LOGIN_STATE_START", 0);
define("SASL_LOGIN_STATE_IDENTIFY_USER", 1);
define("SASL_LOGIN_STATE_IDENTIFY_PASSWORD", 2);
define("SASL_LOGIN_STATE_DONE", 3);
class login_sasl_client_class
{
var $credentials=array();
var $state=SASL_LOGIN_STATE_START;
Function Initialize(&$client)
{
return(1);
}
Function Start(&$client, &$message, &$interactions)
{
if($this->state!=SASL_LOGIN_STATE_START)
{
$client->error="LOGIN authentication state is not at the start";
return(SASL_FAIL);
}
$this->credentials=array(
"user"=>"",
"password"=>"",
"realm"=>""
);
$defaults=array(
"realm"=>""
);
$status=$client->GetCredentials($this->credentials,$defaults,$interactions);
if($status==SASL_CONTINUE)
$this->state=SASL_LOGIN_STATE_IDENTIFY_USER;
Unset($message);
return($status);
}
Function Step(&$client, $response, &$message, &$interactions)
{
switch($this->state)
{
case SASL_LOGIN_STATE_IDENTIFY_USER:
$message=$this->credentials["user"].(strlen($this->credentials["realm"]) ? "@".$this->credentials["realm"] : "");
$this->state=SASL_LOGIN_STATE_IDENTIFY_PASSWORD;
break;
case SASL_LOGIN_STATE_IDENTIFY_PASSWORD:
$message=$this->credentials["password"];
$this->state=SASL_LOGIN_STATE_DONE;
break;
case SASL_LOGIN_STATE_DONE:
$client->error="LOGIN authentication was finished without success";
break;
default:
$client->error="invalid LOGIN authentication step state";
return(SASL_FAIL);
}
return(SASL_CONTINUE);
}
};
?>

View File

@@ -0,0 +1,180 @@
<?php
/*
* ntlm_sasl_client.php
*
* @(#) $Id: ntlm_sasl_client.php,v 1.3 2004/11/17 08:00:37 mlemos Exp $
*
*/
define("SASL_NTLM_STATE_START", 0);
define("SASL_NTLM_STATE_IDENTIFY_DOMAIN", 1);
define("SASL_NTLM_STATE_RESPOND_CHALLENGE", 2);
define("SASL_NTLM_STATE_DONE", 3);
class ntlm_sasl_client_class
{
var $credentials=array();
var $state=SASL_NTLM_STATE_START;
Function Initialize(&$client)
{
if(!function_exists($function="mcrypt_encrypt")
|| !function_exists($function="mhash"))
{
$extensions=array(
"mcrypt_encrypt"=>"mcrypt",
"mhash"=>"mhash"
);
$client->error="the extension ".$extensions[$function]." required by the NTLM SASL client class is not available in this PHP configuration";
return(0);
}
return(1);
}
Function ASCIIToUnicode($ascii)
{
for($unicode="",$a=0;$a<strlen($ascii);$a++)
$unicode.=substr($ascii,$a,1).chr(0);
return($unicode);
}
Function TypeMsg1($domain,$workstation)
{
$domain_length=strlen($domain);
$workstation_length=strlen($workstation);
$workstation_offset=32;
$domain_offset=$workstation_offset+$workstation_length;
return(
"NTLMSSP\0".
"\x01\x00\x00\x00".
"\x07\x32\x00\x00".
pack("v",$domain_length).
pack("v",$domain_length).
pack("V",$domain_offset).
pack("v",$workstation_length).
pack("v",$workstation_length).
pack("V",$workstation_offset).
$workstation.
$domain
);
}
Function NTLMResponse($challenge,$password)
{
$unicode=$this->ASCIIToUnicode($password);
$md4=mhash(MHASH_MD4,$unicode);
$padded=$md4.str_repeat(chr(0),21-strlen($md4));
$iv_size=mcrypt_get_iv_size(MCRYPT_DES,MCRYPT_MODE_ECB);
$iv=mcrypt_create_iv($iv_size,MCRYPT_RAND);
for($response="",$third=0;$third<21;$third+=7)
{
for($packed="",$p=$third;$p<$third+7;$p++)
$packed.=str_pad(decbin(ord(substr($padded,$p,1))),8,"0",STR_PAD_LEFT);
for($key="",$p=0;$p<strlen($packed);$p+=7)
{
$s=substr($packed,$p,7);
$b=$s.((substr_count($s,"1") % 2) ? "0" : "1");
$key.=chr(bindec($b));
}
$ciphertext=mcrypt_encrypt(MCRYPT_DES,$key,$challenge,MCRYPT_MODE_ECB,$iv);
$response.=$ciphertext;
}
return $response;
}
Function TypeMsg3($ntlm_response,$user,$domain,$workstation)
{
$domain_unicode=$this->ASCIIToUnicode($domain);
$domain_length=strlen($domain_unicode);
$domain_offset=64;
$user_unicode=$this->ASCIIToUnicode($user);
$user_length=strlen($user_unicode);
$user_offset=$domain_offset+$domain_length;
$workstation_unicode=$this->ASCIIToUnicode($workstation);
$workstation_length=strlen($workstation_unicode);
$workstation_offset=$user_offset+$user_length;
$lm="";
$lm_length=strlen($lm);
$lm_offset=$workstation_offset+$workstation_length;
$ntlm=$ntlm_response;
$ntlm_length=strlen($ntlm);
$ntlm_offset=$lm_offset+$lm_length;
$session="";
$session_length=strlen($session);
$session_offset=$ntlm_offset+$ntlm_length;
return(
"NTLMSSP\0".
"\x03\x00\x00\x00".
pack("v",$lm_length).
pack("v",$lm_length).
pack("V",$lm_offset).
pack("v",$ntlm_length).
pack("v",$ntlm_length).
pack("V",$ntlm_offset).
pack("v",$domain_length).
pack("v",$domain_length).
pack("V",$domain_offset).
pack("v",$user_length).
pack("v",$user_length).
pack("V",$user_offset).
pack("v",$workstation_length).
pack("v",$workstation_length).
pack("V",$workstation_offset).
pack("v",$session_length).
pack("v",$session_length).
pack("V",$session_offset).
"\x01\x02\x00\x00".
$domain_unicode.
$user_unicode.
$workstation_unicode.
$lm.
$ntlm
);
}
Function Start(&$client, &$message, &$interactions)
{
if($this->state!=SASL_NTLM_STATE_START)
{
$client->error="NTLM authentication state is not at the start";
return(SASL_FAIL);
}
$this->credentials=array(
"user"=>"",
"password"=>"",
"realm"=>"",
"workstation"=>""
);
$defaults=array();
$status=$client->GetCredentials($this->credentials,$defaults,$interactions);
if($status==SASL_CONTINUE)
$this->state=SASL_NTLM_STATE_IDENTIFY_DOMAIN;
Unset($message);
return($status);
}
Function Step(&$client, $response, &$message, &$interactions)
{
switch($this->state)
{
case SASL_NTLM_STATE_IDENTIFY_DOMAIN:
$message=$this->TypeMsg1($this->credentials["realm"],$this->credentials["workstation"]);
$this->state=SASL_NTLM_STATE_RESPOND_CHALLENGE;
break;
case SASL_NTLM_STATE_RESPOND_CHALLENGE:
$ntlm_response=$this->NTLMResponse(substr($response,24,8),$this->credentials["password"]);
$message=$this->TypeMsg3($ntlm_response,$this->credentials["user"],$this->credentials["realm"],$this->credentials["workstation"]);
$this->state=SASL_NTLM_STATE_DONE;
break;
case SASL_NTLM_STATE_DONE:
$client->error="NTLM authentication was finished without success";
return(SASL_FAIL);
default:
$client->error="invalid NTLM authentication step state";
return(SASL_FAIL);
}
return(SASL_CONTINUE);
}
};
?>

View File

@@ -0,0 +1,99 @@
<?php
/*
* plain_sasl_client.php
*
* @(#) $Id: plain_sasl_client.php,v 1.2 2004/11/17 08:00:37 mlemos Exp $
*
*/
define("SASL_PLAIN_STATE_START", 0);
define("SASL_PLAIN_STATE_IDENTIFY", 1);
define("SASL_PLAIN_STATE_DONE", 2);
define("SASL_PLAIN_DEFAULT_MODE", 0);
define("SASL_PLAIN_EXIM_MODE", 1);
define("SASL_PLAIN_EXIM_DOCUMENTATION_MODE", 2);
class plain_sasl_client_class
{
var $credentials=array();
var $state=SASL_PLAIN_STATE_START;
Function Initialize(&$client)
{
return(1);
}
Function Start(&$client, &$message, &$interactions)
{
if($this->state!=SASL_PLAIN_STATE_START)
{
$client->error="PLAIN authentication state is not at the start";
return(SASL_FAIL);
}
$this->credentials=array(
"user"=>"",
"password"=>"",
"realm"=>"",
"mode"=>""
);
$defaults=array(
"realm"=>"",
"mode"=>""
);
$status=$client->GetCredentials($this->credentials,$defaults,$interactions);
if($status==SASL_CONTINUE)
{
switch($this->credentials["mode"])
{
case SASL_PLAIN_EXIM_MODE:
$message=$this->credentials["user"]."\0".$this->credentials["password"]."\0";
break;
case SASL_PLAIN_EXIM_DOCUMENTATION_MODE:
$message="\0".$this->credentials["user"]."\0".$this->credentials["password"];
break;
default:
$message=$this->credentials["user"]."\0".$this->credentials["user"].(strlen($this->credentials["realm"]) ? "@".$this->credentials["realm"] : "")."\0".$this->credentials["password"];
break;
}
$this->state=SASL_PLAIN_STATE_DONE;
}
else
Unset($message);
return($status);
}
Function Step(&$client, $response, &$message, &$interactions)
{
switch($this->state)
{
/*
case SASL_PLAIN_STATE_IDENTIFY:
switch($this->credentials["mode"])
{
case SASL_PLAIN_EXIM_MODE:
$message=$this->credentials["user"]."\0".$this->credentials["password"]."\0";
break;
case SASL_PLAIN_EXIM_DOCUMENTATION_MODE:
$message="\0".$this->credentials["user"]."\0".$this->credentials["password"];
break;
default:
$message=$this->credentials["user"]."\0".$this->credentials["user"].(strlen($this->credentials["realm"]) ? "@".$this->credentials["realm"] : "")."\0".$this->credentials["password"];
break;
}
var_dump($message);
$this->state=SASL_PLAIN_STATE_DONE;
break;
*/
case SASL_PLAIN_STATE_DONE:
$client->error="PLAIN authentication was finished without success";
return(SASL_FAIL);
default:
$client->error="invalid PLAIN authentication step state";
return(SASL_FAIL);
}
return(SASL_CONTINUE);
}
};
?>

422
hesk/inc/mail/sasl/sasl.php Normal file
View File

@@ -0,0 +1,422 @@
<?php
/*
* sasl.php
*
* @(#) $Id: sasl.php,v 1.11 2005/10/31 18:43:27 mlemos Exp $
*
*/
define("SASL_INTERACT", 2);
define("SASL_CONTINUE", 1);
define("SASL_OK", 0);
define("SASL_FAIL", -1);
define("SASL_NOMECH", -4);
class sasl_interact_class
{
var $id;
var $challenge;
var $prompt;
var $default_result;
var $result;
};
/*
{metadocument}<?xml version="1.0" encoding="ISO-8859-1" ?>
<class>
<package>net.manuellemos.sasl</package>
<version>@(#) $Id: sasl.php,v 1.11 2005/10/31 18:43:27 mlemos Exp $</version>
<copyright>Copyright <20> (C) Manuel Lemos 2004</copyright>
<title>Simple Authentication and Security Layer client</title>
<author>Manuel Lemos</author>
<authoraddress>mlemos-at-acm.org</authoraddress>
<documentation>
<idiom>en</idiom>
<purpose>Provide a common interface to plug-in driver classes that
implement different mechanisms for authentication used by clients of
standard protocols like SMTP, POP3, IMAP, HTTP, etc.. Currently the
supported authentication mechanisms are: <tt>PLAIN</tt>,
<tt>LOGIN</tt>, <tt>CRAM-MD5</tt>, <tt>Digest</tt> and <tt>NTML</tt>
(Windows or Samba).</purpose>
<usage>.</usage>
</documentation>
{/metadocument}
*/
class sasl_client_class
{
/* Public variables */
/*
{metadocument}
<variable>
<name>error</name>
<type>STRING</type>
<value></value>
<documentation>
<purpose>Store the message that is returned when an error
occurs.</purpose>
<usage>Check this variable to understand what happened when a call to
any of the class functions has failed.<paragraphbreak />
This class uses cumulative error handling. This means that if one
class functions that may fail is called and this variable was
already set to an error message due to a failure in a previous call
to the same or other function, the function will also fail and does
not do anything.<paragraphbreak />
This allows programs using this class to safely call several
functions that may fail and only check the failure condition after
the last function call.<paragraphbreak />
Just set this variable to an empty string to clear the error
condition.</usage>
</documentation>
</variable>
{/metadocument}
*/
var $error='';
/*
{metadocument}
<variable>
<name>mechanism</name>
<type>STRING</type>
<value></value>
<documentation>
<purpose>Store the name of the mechanism that was selected during the
call to the <functionlink>Start</functionlink> function.</purpose>
<usage>You can access this variable but do not change it.</usage>
</documentation>
</variable>
{/metadocument}
*/
var $mechanism='';
/*
{metadocument}
<variable>
<name>encode_response</name>
<type>BOOLEAN</type>
<value>1</value>
<documentation>
<purpose>Let the drivers inform the applications whether responses
need to be encoded.</purpose>
<usage>Applications should check this variable before sending
authentication responses to the server to determine if the
responses need to be encoded, eventually with base64 algorithm.</usage>
</documentation>
</variable>
{/metadocument}
*/
var $encode_response=1;
/* Private variables */
var $driver;
var $drivers=array(
"Digest" => array("digest_sasl_client_class", "digest_sasl_client.php" ),
"CRAM-MD5" => array("cram_md5_sasl_client_class", "cram_md5_sasl_client.php" ),
"LOGIN" => array("login_sasl_client_class", "login_sasl_client.php" ),
"NTLM" => array("ntlm_sasl_client_class", "ntlm_sasl_client.php" ),
"PLAIN" => array("plain_sasl_client_class", "plain_sasl_client.php" ),
"Basic" => array("basic_sasl_client_class", "basic_sasl_client.php" )
);
var $credentials=array();
/* Public functions */
/*
{metadocument}
<function>
<name>SetCredential</name>
<type>VOID</type>
<documentation>
<purpose>Store the value of a credential that may be used by any of
the supported mechanisms to process the authentication messages and
responses.</purpose>
<usage>Call this function before starting the authentication dialog
to pass all the credential values that be needed to use the type
of authentication that the applications may need.</usage>
<returnvalue>.</returnvalue>
</documentation>
<argument>
<name>key</name>
<type>STRING</type>
<documentation>
<purpose>Specify the name of the credential key.</purpose>
</documentation>
</argument>
<argument>
<name>value</name>
<type>STRING</type>
<documentation>
<purpose>Specify the value for the credential.</purpose>
</documentation>
</argument>
<do>
{/metadocument}
*/
Function SetCredential($key,$value)
{
$this->credentials[$key]=$value;
}
/*
{metadocument}
</do>
</function>
{/metadocument}
*/
/*
{metadocument}
<function>
<name>GetCredentials</name>
<type>INTEGER</type>
<documentation>
<purpose>Retrieve the values of one or more credentials to be used by
the authentication mechanism classes.</purpose>
<usage>This is meant to be used by authentication mechanism driver
classes to retrieve the credentials that may be neede.</usage>
<returnvalue>The function may return <tt>SASL_CONTINUE</tt> if it
succeeded, or <tt>SASL_NOMECH</tt> if it was not possible to
retrieve one of the requested credentials.</returnvalue>
</documentation>
<argument>
<name>credentials</name>
<type>HASH</type>
<documentation>
<purpose>Reference to an associative array variable with all the
credentials that are being requested. The function initializes
this associative array values.</purpose>
</documentation>
</argument>
<argument>
<name>defaults</name>
<type>HASH</type>
<documentation>
<purpose>Associative arrays with default values for credentials
that may have not been defined.</purpose>
</documentation>
</argument>
<argument>
<name>interactions</name>
<type>ARRAY</type>
<documentation>
<purpose>Not yet in use. It is meant to provide context
information to retrieve credentials that may be obtained
interacting with the user.</purpose>
</documentation>
</argument>
<do>
{/metadocument}
*/
Function GetCredentials(&$credentials,$defaults,&$interactions)
{
Reset($credentials);
$end=(GetType($key=Key($credentials))!="string");
for(;!$end;)
{
if(!IsSet($this->credentials[$key]))
{
if(IsSet($defaults[$key]))
$credentials[$key]=$defaults[$key];
else
{
$this->error="the requested credential ".$key." is not defined";
return(SASL_NOMECH);
}
}
else
$credentials[$key]=$this->credentials[$key];
Next($credentials);
$end=(GetType($key=Key($credentials))!="string");
}
return(SASL_CONTINUE);
}
/*
{metadocument}
</do>
</function>
{/metadocument}
*/
/*
{metadocument}
<function>
<name>Start</name>
<type>INTEGER</type>
<documentation>
<purpose>Process the initial authentication step initializing the
driver class that implements the first of the list of requested
mechanisms that is supported by this SASL client library
implementation.</purpose>
<usage>Call this function specifying a list of mechanisms that the
server supports. If the <argumentlink>
<argument>message</argument>
<function>Start</function>
</argumentlink> argument returns a string, it should be sent to
the server as initial message. Check the
<variablelink>encode_response</variablelink> variable to determine
whether the initial message needs to be encoded, eventually with
base64 algorithm, before it is sent to the server.</usage>
<returnvalue>The function may return <tt>SASL_CONTINUE</tt> if it
could start one of the requested authentication mechanisms. It
may return <tt>SASL_NOMECH</tt> if it was not possible to start
any of the requested mechanisms. It returns <tt>SASL_FAIL</tt> or
other value in case of error.</returnvalue>
</documentation>
<argument>
<name>mechanisms</name>
<type>ARRAY</type>
<inout />
<documentation>
<purpose>Define the list of names of authentication mechanisms
supported by the that should be tried.</purpose>
</documentation>
</argument>
<argument>
<name>message</name>
<type>STRING</type>
<out />
<documentation>
<purpose>Return the initial message that should be sent to the
server to start the authentication dialog. If this value is
undefined, no message should be sent to the server.</purpose>
</documentation>
</argument>
<argument>
<name>interactions</name>
<type>ARRAY</type>
<documentation>
<purpose>Not yet in use. It is meant to provide context
information to interact with the end user.</purpose>
</documentation>
</argument>
<do>
{/metadocument}
*/
Function Start($mechanisms, &$message, &$interactions)
{
if(strlen($this->error))
return(SASL_FAIL);
if(IsSet($this->driver))
return($this->driver->Start($this,$message,$interactions));
$no_mechanism_error="";
for($m=0;$m<count($mechanisms);$m++)
{
$mechanism=$mechanisms[$m];
if(IsSet($this->drivers[$mechanism]))
{
if(!class_exists($this->drivers[$mechanism][0]))
require(dirname(__FILE__)."/".$this->drivers[$mechanism][1]);
$this->driver=new $this->drivers[$mechanism][0];
if($this->driver->Initialize($this))
{
$this->encode_response=1;
$status=$this->driver->Start($this,$message,$interactions);
switch($status)
{
case SASL_NOMECH:
Unset($this->driver);
if(strlen($no_mechanism_error)==0)
$no_mechanism_error=$this->error;
$this->error="";
break;
case SASL_CONTINUE:
$this->mechanism=$mechanism;
return($status);
default:
Unset($this->driver);
$this->error="";
return($status);
}
}
else
{
Unset($this->driver);
if(strlen($no_mechanism_error)==0)
$no_mechanism_error=$this->error;
$this->error="";
}
}
}
$this->error=(strlen($no_mechanism_error) ? $no_mechanism_error : "it was not requested any of the authentication mechanisms that are supported");
return(SASL_NOMECH);
}
/*
{metadocument}
</do>
</function>
{/metadocument}
*/
/*
{metadocument}
<function>
<name>Step</name>
<type>INTEGER</type>
<documentation>
<purpose>Process the authentication steps after the initial step,
until the authetication iteration dialog is complete.</purpose>
<usage>Call this function iteratively after a successful initial
step calling the <functionlink>Start</functionlink> function.</usage>
<returnvalue>The function returns <tt>SASL_CONTINUE</tt> if step was
processed successfully, or returns <tt>SASL_FAIL</tt> in case of
error.</returnvalue>
</documentation>
<argument>
<name>response</name>
<type>STRING</type>
<in />
<documentation>
<purpose>Pass the response returned by the server to the previous
step.</purpose>
</documentation>
</argument>
<argument>
<name>message</name>
<type>STRING</type>
<out />
<documentation>
<purpose>Return the message that should be sent to the server to
continue the authentication dialog. If this value is undefined,
no message should be sent to the server.</purpose>
</documentation>
</argument>
<argument>
<name>interactions</name>
<type>ARRAY</type>
<documentation>
<purpose>Not yet in use. It is meant to provide context
information to interact with the end user.</purpose>
</documentation>
</argument>
<do>
{/metadocument}
*/
Function Step($response, &$message, &$interactions)
{
if(strlen($this->error))
return(SASL_FAIL);
return($this->driver->Step($this,$response,$message,$interactions));
}
/*
{metadocument}
</do>
</function>
{/metadocument}
*/
};
/*
{metadocument}
</class>
{/metadocument}
*/
?>

1912
hesk/inc/mail/smtp.php Normal file

File diff suppressed because it is too large Load Diff