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 ([email protected]) All Rights Reserved
  7.  * Modified by Philippe Mingo 2001 [email protected]
  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"' ' "[$reply]";
  440.             @error_log("POP3 resetERROR [$reply]",0);
  441.         }
  442.         $this->quit();
  443.         return true;
  444.     }
  445.  
  446.     function send_cmd $cmd "" )
  447.     {
  448.         //  Sends a user defined command string to the
  449.         //  POP server and returns the results. Useful for
  450.         //  non-compliant or custom POP servers.
  451.         //  Do NOT includ the \r\n as part of your command
  452.         //  string - it will be appended automatically.
  453.  
  454.         //  The return value is a standard fgets() call, which
  455.         //  will read up to $this->BUFFER bytes of data, until it
  456.         //  encounters a new line, or EOF, whichever happens first.
  457.  
  458.         //  This method works best if $cmd responds with only
  459.         //  one line of data.
  460.  
  461.         if(!isset($this->FP))
  462.         {
  463.             $this->ERROR = _("POP3 send_cmd:"' ' _("No connection to server");
  464.             return false;
  465.         }
  466.  
  467.         if(empty($cmd))
  468.         {
  469.             $this->ERROR = _("POP3 send_cmd:"' ' _("Empty command string");
  470.             return "";
  471.         }
  472.  
  473.         $fp $this->FP;
  474.         $buffer $this->BUFFER;
  475.         $this->update_timer();
  476.         fwrite($fp,"$cmd\r\n");
  477.         $reply fgets($fp,$buffer);
  478.         $reply $this->strip_clf($reply);
  479.         if($this->DEBUG@error_log("POP3 SEND [$cmd] GOT [$reply]",0)}
  480.         return $reply;
  481.     }
  482.  
  483.     function quit({
  484.         //  Closes the connection to the POP3 server, deleting
  485.         //  any msgs marked as deleted.
  486.  
  487.         if(!isset($this->FP))
  488.         {
  489.             $this->ERROR = _("POP3 quit:"' ' _("connection does not exist");
  490.             return false;
  491.         }
  492.         $fp $this->FP;
  493.         $cmd "QUIT";
  494.         fwrite($fp,"$cmd\r\n");
  495.         $reply fgets($fp,$this->BUFFER);
  496.         $reply $this->strip_clf($reply);
  497.         if($this->DEBUG@error_log("POP3 SEND [$cmd] GOT [$reply]",0)}
  498.         fclose($fp);
  499.         unset($this->FP);
  500.         return true;
  501.     }
  502.  
  503.     function popstat ({
  504.         //  Returns an array of 2 elements. The number of undeleted
  505.         //  msgs in the mailbox, and the size of the mbox in octets.
  506.  
  507.         $PopArray $this->last("array");
  508.  
  509.         if($PopArray == -1return false}
  510.  
  511.         if( (!$PopArrayor (empty($PopArray)) )
  512.         {
  513.             return false;
  514.         }
  515.         return $PopArray;
  516.     }
  517.  
  518.     function uidl ($msgNum "")
  519.     {
  520.         //  Returns the UIDL of the msg specified. If called with
  521.         //  no arguments, returns an associative array where each
  522.         //  undeleted msg num is a key, and the msg's uidl is the element
  523.         //  Array element 0 will contain the total number of msgs
  524.  
  525.         if(!isset($this->FP)) {
  526.             $this->ERROR = _("POP3 uidl:"' ' _("No connection to server");
  527.             return false;
  528.         }
  529.  
  530.         $fp $this->FP;
  531.         $buffer $this->BUFFER;
  532.  
  533.         if(!empty($msgNum)) {
  534.             $cmd "UIDL $msgNum";
  535.             $reply $this->send_cmd($cmd);
  536.             if(!$this->is_ok($reply))
  537.             {
  538.                 $this->ERROR = _("POP3 uidl:"' ' _("Error"' ' "[$reply]";
  539.                 return false;
  540.             }
  541.             list ($ok,$num,$myUidlpreg_split('/\s+/',$reply);
  542.             return $myUidl;
  543.         else {
  544.             $this->update_timer();
  545.  
  546.             $UIDLArray array();
  547.             $Total $this->COUNT;
  548.             $UIDLArray[0$Total;
  549.  
  550.             if ($Total 1)
  551.             {
  552.                 return $UIDLArray;
  553.             }
  554.             $cmd "UIDL";
  555.             fwrite($fp"UIDL\r\n");
  556.             $reply fgets($fp$buffer);
  557.             $reply $this->strip_clf($reply);
  558.             if($this->DEBUG@error_log("POP3 SEND [$cmd] GOT [$reply]",0)}
  559.             if(!$this->is_ok($reply))
  560.             {
  561.                 $this->ERROR = _("POP3 uidl:"' ' _("Error"' ' "[$reply]";
  562.                 return false;
  563.             }
  564.  
  565.             $line "";
  566.             $count 1;
  567.             $line fgets($fp,$buffer);
  568.             while !ereg("^\.\r\n",$line)) {
  569.                 if(ereg("^\.\r\n",$line)) {
  570.                     break;
  571.                 }
  572.                 list ($msg,$msgUidlpreg_split('/\s+/',$line);
  573.                 $msgUidl $this->strip_clf($msgUidl);
  574.                 if($count == $msg{
  575.                     $UIDLArray[$msg$msgUidl;
  576.                 }
  577.                 else
  578.                 {
  579.                     $UIDLArray[$count'deleted';
  580.                 }
  581.                 $count++;
  582.                 $line fgets($fp,$buffer);
  583.             }
  584.         }
  585.         return $UIDLArray;
  586.     }
  587.  
  588.     function delete ($msgNum ""{
  589.         //  Flags a specified msg as deleted. The msg will not
  590.         //  be deleted until a quit() method is called.
  591.  
  592.         if(!isset($this->FP))
  593.         {
  594.             $this->ERROR = _("POP3 delete:"' ' _("No connection to server");
  595.             return false;
  596.         }
  597.         if(empty($msgNum))
  598.         {
  599.             $this->ERROR = _("POP3 delete:"' ' _("No msg number submitted");
  600.             return false;
  601.         }
  602.         $reply $this->send_cmd("DELE $msgNum");
  603.         if(!$this->is_ok($reply))
  604.         {
  605.             $this->ERROR = _("POP3 delete:"' ' _("Command failed"' ' "[$reply]";
  606.             return false;
  607.         }
  608.         return true;
  609.     }
  610.  
  611.     //  *********************************************************
  612.  
  613.     //  The following methods are internal to the class.
  614.  
  615.     
  616.     function is_ok ($cmd ""{
  617.         //  Return true or false on +OK or -ERR
  618.  
  619.         ifempty($cmd) )
  620.             return false;
  621.         else
  622.             returnereg ("^\+OK"$cmd ) );
  623.     }
  624.  
  625.     function strip_clf ($text ""{
  626.         // Strips \r\n from server responses
  627.  
  628.         if(empty($text))
  629.             return $text;
  630.         else {
  631.             $stripped str_replace("\r",'',$text);
  632.             $stripped str_replace("\n",'',$stripped);
  633.             return $stripped;
  634.         }
  635.     }
  636.  
  637.     function parse_banner $server_text {
  638.         $outside true;
  639.         $banner "";
  640.         $length strlen($server_text);
  641.         for($count =0$count $length$count++)
  642.         {
  643.             $digit substr($server_text,$count,1);
  644.             if(!empty($digit))             {
  645.                 if( (!$outside&& ($digit != '<'&& ($digit != '>') )
  646.                 {
  647.                     $banner .= $digit;
  648.                 }
  649.                 if ($digit == '<')
  650.                 {
  651.                     $outside false;
  652.                 }
  653.                 if($digit == '>')
  654.                 {
  655.                     $outside true;
  656.                 }
  657.             }
  658.         }
  659.         $banner $this->strip_clf($banner);    // Just in case
  660.         return "<$banner>";
  661.     }
  662.  
  663. }   // End class

Documentation generated on Sat, 07 Oct 2006 16:09:11 +0300 by phpDocumentor 1.3.0RC6