Source for file class.POP3.php

Documentation is available at class.POP3.php

  1. <?php
  2.  
  3. /**
  4.  * mail_fetch/class.POP3.php
  5.  *
  6.  * Copyright (c) 1999 CDI (cdi@thewebmasters.net) All Rights Reserved
  7.  * Modified by Philippe Mingo 2001 mingo@rotedic.com
  8.  * An RFC 1939 compliant wrapper class for the POP3 protocol.
  9.  *
  10.  * POP3 class
  11.  *
  12.  * @copyright &copy; 1999-2006 The SquirrelMail Project Team
  13.  * @license http://opensource.org/licenses/gpl-license.php GNU Public License
  14.  * @version $Id: class.POP3.php,v 1.27 2006/07/15 12:01:18 tokul Exp $
  15.  * @package plugins
  16.  * @subpackage mail_fetch
  17.  */
  18.  
  19. /**
  20.  * This is the POP3 class - DOCUMENT ME
  21.  * @package plugins
  22.  * @subpackage mail_fetch
  23.  */
  24. class POP3 {
  25.     var $ERROR      = '';       //  Error string.
  26.  
  27.     
  28.     var $TIMEOUT    = 60;       //  Default timeout before giving up on a
  29.                                 //  network operation.
  30.  
  31.     
  32.     var $COUNT      = -1;       //  Mailbox msg count
  33.  
  34.     
  35.     var $BUFFER     = 512;      //  Socket buffer for socket fgets() calls.
  36.                                 //  Per RFC 1939 the returned line a POP3
  37.                                 //  server can send is 512 bytes.
  38.  
  39.     
  40.     var $FP         = '';       //  The connection to the server's
  41.                                 //  file descriptor
  42.  
  43.     
  44.     var $MAILSERVER = '';       // Set this to hard code the server name
  45.  
  46.     
  47.     var $DEBUG      = FALSE;    // set to true to echo pop3
  48.                                 // commands and responses to error_log
  49.                                 // this WILL log passwords!
  50.  
  51.     
  52.     var $BANNER     = '';       //  Holds the banner returned by the
  53.                                 //  pop server - used for apop()
  54.  
  55.     
  56.     var $ALLOWAPOP  = FALSE;    //  Allow or disallow apop()
  57.                                 //  This must be set to true
  58.                                 //  manually
  59.  
  60.     
  61.     function POP3 $server ''$timeout '' {
  62.         settype($this->BUFFER,"integer");
  63.         if!empty($server) ) {
  64.             // Do not allow programs to alter MAILSERVER
  65.             // if it is already specified. They can get around
  66.             // this if they -really- want to, so don't count on it.
  67.             if(empty($this->MAILSERVER))
  68.                 $this->MAILSERVER = $server;
  69.         }
  70.         if(!empty($timeout)) {
  71.             settype($timeout,"integer");
  72.             $this->TIMEOUT = $timeout;
  73.             if (!ini_get('safe_mode'))
  74.                 set_time_limit($timeout);
  75.         }
  76.         return true;
  77.     }
  78.  
  79.     function update_timer ({
  80.         if (!ini_get('safe_mode'))
  81.             set_time_limit($this->TIMEOUT);
  82.         return true;
  83.     }
  84.  
  85.     function connect ($server$port 110)  {
  86.         //  Opens a socket to the specified server. Unless overridden,
  87.         //  port defaults to 110. Returns true on success, false on fail
  88.  
  89.         // If MAILSERVER is set, override $server with it's value
  90.  
  91.         if (!isset($port|| !$port{$port 110;}
  92.         if(!empty($this->MAILSERVER))
  93.             $server $this->MAILSERVER;
  94.  
  95.         if(empty($server)){
  96.             $this->ERROR = _("POP3 connect:"' ' _("No server specified");
  97.             unset($this->FP);
  98.             return false;
  99.         }
  100.  
  101.         $fp @fsockopen("$server"$port$errno$errstr);
  102.  
  103.         if(!$fp{
  104.             $this->ERROR = _("POP3 connect:"' ' _("Error"' ' "[$errno] [$errstr]";
  105.             unset($this->FP);
  106.             return false;
  107.         }
  108.  
  109.         socket_set_blocking($fp,-1);
  110.         $this->update_timer();
  111.         $reply fgets($fp,$this->BUFFER);
  112.         $reply $this->strip_clf($reply);
  113.         if($this->DEBUG)
  114.             error_log("POP3 SEND [connect$server] GOT [$reply]",0);
  115.         if(!$this->is_ok($reply)) {
  116.             $this->ERROR = _("POP3 connect:"' ' _("Error"' ' "[$reply]";
  117.             unset($this->FP);
  118.             return false;
  119.         }
  120.         $this->FP = $fp;
  121.         $this->BANNER = $this->parse_banner($reply);
  122.         return true;
  123.     }
  124.  
  125.     function user ($user ""{
  126.         // Sends the USER command, returns true or false
  127.  
  128.         ifempty($user) ) {
  129.             $this->ERROR = _("POP3 user:"' ' _("no login ID submitted");
  130.             return false;
  131.         elseif(!isset($this->FP)) {
  132.             $this->ERROR = _("POP3 user:"' ' _("connection not established");
  133.             return false;
  134.         else {
  135.             $reply $this->send_cmd("USER $user");
  136.             if(!$this->is_ok($reply)) {
  137.                 $this->ERROR = _("POP3 user:"' ' _("Error"' ' "[$reply]";
  138.                 return false;
  139.             else
  140.                 return true;
  141.         }
  142.     }
  143.  
  144.     function pass ($pass "")     {
  145.         // Sends the PASS command, returns # of msgs in mailbox,
  146.         // returns false (undef) on Auth failure
  147.  
  148.         if(empty($pass)) {
  149.             $this->ERROR = _("POP3 pass:"' ' _("No password submitted");
  150.             return false;
  151.         elseif(!isset($this->FP)) {
  152.             $this->ERROR = _("POP3 pass:"' ' _("connection not established");
  153.             return false;
  154.         else {
  155.             $reply $this->send_cmd("PASS $pass");
  156.             if(!$this->is_ok($reply)) {
  157.                 $this->ERROR = _("POP3 pass:"' ' _("Authentication failed"" [$reply]";
  158.                 $this->quit();
  159.                 return false;
  160.             else {
  161.                 //  Auth successful.
  162.                 $count $this->last("count");
  163.                 $this->COUNT = $count;
  164.                 return $count;
  165.             }
  166.         }
  167.     }
  168.  
  169.     function apop ($login,$pass{
  170.         //  Attempts an APOP login. If this fails, it'll
  171.         //  try a standard login. YOUR SERVER MUST SUPPORT
  172.         //  THE USE OF THE APOP COMMAND!
  173.         //  (apop is optional per rfc1939)
  174.  
  175.         if(!isset($this->FP)) {
  176.             $this->ERROR = _("POP3 apop:"' ' _("No connection to server");
  177.             return false;
  178.         elseif(!$this->ALLOWAPOP{
  179.             $retVal $this->login($login,$pass);
  180.             return $retVal;
  181.         elseif(empty($login)) {
  182.             $this->ERROR = _("POP3 apop:"' ' _("No login ID submitted");
  183.             return false;
  184.         elseif(empty($pass)) {
  185.             $this->ERROR = _("POP3 apop:"' ' _("No password submitted");
  186.             return false;
  187.         else {
  188.             $banner $this->BANNER;
  189.             if( (!$banneror (empty($banner)) ) {
  190.                 $this->ERROR = _("POP3 apop:"' ' _("No server banner"' - ' _("abort");
  191.                 $retVal $this->login($login,$pass);
  192.                 return $retVal;
  193.             else {
  194.                 $AuthString $banner;
  195.                 $AuthString .= $pass;
  196.                 $APOPString md5($AuthString);
  197.                 $cmd "APOP $login $APOPString";
  198.                 $reply $this->send_cmd($cmd);
  199.                 if(!$this->is_ok($reply)) {
  200.                     $this->ERROR = _("POP3 apop:"' ' _("apop authentication failed"' - ' _("abort");
  201.                     $retVal $this->login($login,$pass);
  202.                     return $retVal;
  203.                 else {
  204.                     //  Auth successful.
  205.                     $count $this->last("count");
  206.                     $this->COUNT = $count;
  207.                     return $count;
  208.                 }
  209.             }
  210.         }
  211.     }
  212.  
  213.     function login ($login ""$pass ""{
  214.         // Sends both user and pass. Returns # of msgs in mailbox or
  215.         // false on failure (or -1, if the error occurs while getting
  216.         // the number of messages.)
  217.  
  218.         if!isset($this->FP) ) {
  219.             $this->ERROR = _("POP3 login:"' ' _("No connection to server");
  220.             return false;
  221.         else {
  222.             $fp $this->FP;
  223.             if!$this->user$login ) ) {
  224.                 //  Preserve the error generated by user()
  225.                 return false;
  226.             else {
  227.                 $count $this->pass($pass);
  228.                 if( (!$count|| ($count == -1) ) {
  229.                     //  Preserve the error generated by last() and pass()
  230.                     return false;
  231.                 else
  232.                     return $count;
  233.             }
  234.         }
  235.     }
  236.  
  237.     function top ($msgNum$numLines "0"{
  238.         //  Gets the header and first $numLines of the msg body
  239.         //  returns data in an array with each returned line being
  240.         //  an array element. If $numLines is empty, returns
  241.         //  only the header information, and none of the body.
  242.  
  243.         if(!isset($this->FP)) {
  244.             $this->ERROR = _("POP3 top:"' ' _("No connection to server");
  245.             return false;
  246.         }
  247.         $this->update_timer();
  248.  
  249.         $fp $this->FP;
  250.         $buffer $this->BUFFER;
  251.         $cmd "TOP $msgNum $numLines";
  252.         fwrite($fp"TOP $msgNum $numLines\r\n");
  253.         $reply fgets($fp$buffer);
  254.         $reply $this->strip_clf($reply);
  255.         if($this->DEBUG{
  256.             @error_log("POP3 SEND [$cmd] GOT [$reply]",0);
  257.         }
  258.         if(!$this->is_ok($reply))
  259.         {
  260.             $this->ERROR = _("POP3 top:"' ' _("Error"' ' "[$reply]";
  261.             return false;
  262.         }
  263.  
  264.         $count 0;
  265.         $MsgArray array();
  266.  
  267.         $line fgets($fp,$buffer);
  268.         while !ereg("^\.\r\n",$line))
  269.         {
  270.             $MsgArray[$count$line;
  271.             $count++;
  272.             $line fgets($fp,$buffer);
  273.             if(empty($line))    break}
  274.         }
  275.  
  276.         return $MsgArray;
  277.     }
  278.  
  279.     function pop_list ($msgNum ""{
  280.         //  If called with an argument, returns that msgs' size in octets
  281.         //  No argument returns an associative array of undeleted
  282.         //  msg numbers and their sizes in octets
  283.  
  284.         if(!isset($this->FP))
  285.         {
  286.             $this->ERROR = _("POP3 pop_list:"' ' _("No connection to server");
  287.             return false;
  288.         }
  289.         $fp $this->FP;
  290.         $Total $this->COUNT;
  291.         if( (!$Totalor ($Total == -1) )
  292.         {
  293.             return false;
  294.         }
  295.         if($Total == 0)
  296.         {
  297.             return array("0","0");
  298.             // return -1;   // mailbox empty
  299.         }
  300.  
  301.         $this->update_timer();
  302.  
  303.         if(!empty($msgNum))
  304.         {
  305.             $cmd "LIST $msgNum";
  306.             fwrite($fp,"$cmd\r\n");
  307.             $reply fgets($fp,$this->BUFFER);
  308.             $reply $this->strip_clf($reply);
  309.             if($this->DEBUG{
  310.                 @error_log("POP3 SEND [$cmd] GOT [$reply]",0);
  311.             }
  312.             if(!$this->is_ok($reply))
  313.             {
  314.                 $this->ERROR = _("POP3 pop_list:"' ' _("Error"' ' "[$reply]";
  315.                 return false;
  316.             }
  317.             list($junk,$num,$sizepreg_split('/\s+/',$reply);
  318.             return $size;
  319.         }
  320.         $cmd "LIST";
  321.         $reply $this->send_cmd($cmd);
  322.         if(!$this->is_ok($reply))
  323.         {
  324.             $reply $this->strip_clf($reply);
  325.             $this->ERROR = _("POP3 pop_list:"' ' _("Error"' ' .  "[$reply]";
  326.             return false;
  327.         }
  328.         $MsgArray array();
  329.         $MsgArray[0$Total;
  330.         for($msgC=1;$msgC <= $Total$msgC++)
  331.         {
  332.             if($msgC $Totalbreak}
  333.             $line fgets($fp,$this->BUFFER);
  334.             $line $this->strip_clf($line);
  335.             if(ereg("^\.",$line))
  336.             {
  337.                 $this->ERROR = _("POP3 pop_list:"' ' _("Premature end of list");
  338.                 return false;
  339.             }
  340.             list($thisMsg,$msgSizepreg_split('/\s+/',$line);
  341.             settype($thisMsg,"integer");
  342.             if($thisMsg != $msgC)
  343.             {
  344.                 $MsgArray[$msgC"deleted";
  345.             }
  346.             else
  347.             {
  348.                 $MsgArray[$msgC$msgSize;
  349.             }
  350.         }
  351.         return $MsgArray;
  352.     }
  353.  
  354.     function get ($msgNum{
  355.         //  Retrieve the specified msg number. Returns an array
  356.         //  where each line of the msg is an array element.
  357.  
  358.         if(!isset($this->FP))
  359.         {
  360.             $this->ERROR = _("POP3 get:"' ' _("No connection to server");
  361.             return false;
  362.         }
  363.  
  364.         $this->update_timer();
  365.  
  366.         $fp $this->FP;
  367.         $buffer $this->BUFFER;
  368.         $cmd "RETR $msgNum";
  369.         $reply $this->send_cmd($cmd);
  370.  
  371.         if(!$this->is_ok($reply))
  372.         {
  373.             $this->ERROR = _("POP3 get:"' ' _("Error"' ' "[$reply]";
  374.             return false;
  375.         }
  376.  
  377.         $count 0;
  378.         $MsgArray array();
  379.  
  380.         $line fgets($fp,$buffer);
  381.         while !ereg("^\.\r\n",$line))
  382.         {
  383.             $MsgArray[$count$line;
  384.             $count++;
  385.             $line fgets($fp,$buffer);
  386.             if(empty($line))    break}
  387.         }
  388.         return $MsgArray;
  389.     }
  390.  
  391.     function last $type "count" {
  392.         //  Returns the highest msg number in the mailbox.
  393.         //  returns -1 on error, 0+ on success, if type != count
  394.         //  results in a popstat() call (2 element array returned)
  395.  
  396.         $last = -1;
  397.         if(!isset($this->FP))
  398.         {
  399.             $this->ERROR = _("POP3 last:"' ' _("No connection to server");
  400.             return $last;
  401.         }
  402.  
  403.         $reply $this->send_cmd("STAT");
  404.         if(!$this->is_ok($reply))
  405.         {
  406.             $this->ERROR = _("POP3 last:"' ' _("Error"' ' "[$reply]";
  407.             return $last;
  408.         }
  409.  
  410.         $Vars preg_split('/\s+/',$reply);
  411.         $count $Vars[1];
  412.         $size $Vars[2];
  413.         settype($count,"integer");
  414.         settype($size,"integer");
  415.         if($type != "count")
  416.         {
  417.             return array($count,$size);
  418.         }
  419.         return $count;
  420.     }
  421.  
  422.     function reset ({
  423.         //  Resets the status of the remote server. This includes
  424.         //  resetting the status of ALL msgs to not be deleted.
  425.         //  This method automatically closes the connection to the server.
  426.  
  427.         if(!isset($this->FP))
  428.         {
  429.             $this->ERROR = _("POP3 reset:"' ' _("No connection to server");
  430.             return false;
  431.         }
  432.         $reply $this->send_cmd("RSET");
  433.         if(!$this->is_ok($reply))
  434.         {
  435.             //  The POP3 RSET command -never- gives a -ERR
  436.             //  response - if it ever does, something truely
  437.             //  wild is going on.
  438.  
  439.             $this->ERROR = _("POP3 reset:"' ' _("Error"' ' "