Source for file class.POP3.php

Documentation is available at class.POP3.php

  1. <?php 
  2.  
  3.    /**
  4.     * mail_fetch/setup.php
  5.     *
  6.     * Copyright (c) 1999-2006 The SquirrelMail Project Team
  7.     *
  8.     * Copyright (c) 1999 CDI ([email protected]) All Rights Reserved
  9.     * Modified by Philippe Mingo 2001 [email protected]
  10.     * An RFC 1939 compliant wrapper class for the POP3 protocol.
  11.     *
  12.     * Licensed under the GNU GPL. For full terms see the file COPYING.
  13.     *
  14.     * pop3 class
  15.     *
  16.     * $Id: class.POP3.php,v 1.10.2.9 2006/02/03 22:27:52 jervfors Exp $
  17.     */
  18.  
  19. class POP3 {
  20.     var $ERROR      = '';       //  Error string.
  21.  
  22.     
  23.     var $TIMEOUT    = 60;       //  Default timeout before giving up on a
  24.                                 //  network operation.
  25.  
  26.     
  27.     var $COUNT      = -1;       //  Mailbox msg count
  28.  
  29.     
  30.     var $BUFFER     = 512;      //  Socket buffer for socket fgets() calls.
  31.                                 //  Per RFC 1939 the returned line a POP3
  32.                                 //  server can send is 512 bytes.
  33.  
  34.     
  35.     var $FP         = '';       //  The connection to the server's
  36.                                 //  file descriptor
  37.  
  38.     
  39.     var $MAILSERVER = '';       // Set this to hard code the server name
  40.  
  41.     
  42.     var $DEBUG      = FALSE;    // set to true to echo pop3
  43.                                 // commands and responses to error_log
  44.                                 // this WILL log passwords!
  45.  
  46.     
  47.     var $BANNER     = '';       //  Holds the banner returned by the
  48.                                 //  pop server - used for apop()
  49.  
  50.     
  51.     var $ALLOWAPOP  = FALSE;    //  Allow or disallow apop()
  52.                                 //  This must be set to true
  53.                                 //  manually
  54.  
  55.     
  56.     function POP3 $server ''$timeout '' {
  57.         settype($this->BUFFER,"integer");
  58.         if!empty($server) ) {
  59.             // Do not allow programs to alter MAILSERVER
  60.             // if it is already specified. They can get around
  61.             // this if they -really- want to, so don't count on it.
  62.             if(empty($this->MAILSERVER))
  63.                 $this->MAILSERVER = $server;
  64.         }
  65.         if(!empty($timeout)) {
  66.             settype($timeout,"integer");
  67.             $this->TIMEOUT = $timeout;
  68.             if (!ini_get('safe_mode'))
  69.                 set_time_limit($timeout);
  70.         }
  71.         return true;
  72.     }
  73.  
  74.     function update_timer ({
  75.         if (!ini_get('safe_mode'))
  76.             set_time_limit($this->TIMEOUT);
  77.         return true;
  78.     }
  79.  
  80.     function connect ($server$port 110)  {
  81.         //  Opens a socket to the specified server. Unless overridden,
  82.         //  port defaults to 110. Returns true on success, false on fail
  83.  
  84.         // If MAILSERVER is set, override $server with it's value
  85.     
  86.     if (!isset($port|| !$port{$port 110;}
  87.         if(!empty($this->MAILSERVER))
  88.             $server $this->MAILSERVER;
  89.  
  90.         if(empty($server)){
  91.             $this->ERROR = _("POP3 connect:"' ' _("No server specified");
  92.             unset($this->FP);
  93.             return false;
  94.         }
  95.  
  96.         $fp @fsockopen("$server"$port$errno$errstr);
  97.  
  98.         if(!$fp{
  99.             $this->ERROR = _("POP3 connect:"' ' _("Error ""[$errno] [$errstr]";
  100.             unset($this->FP);
  101.             return false;
  102.         }
  103.  
  104.         socket_set_blocking($fp,-1);
  105.         $this->update_timer();
  106.         $reply fgets($fp,$this->BUFFER);
  107.         $reply $this->strip_clf($reply);
  108.         if($this->DEBUG)
  109.             error_log("POP3 SEND [connect$server] GOT [$reply]",0);
  110.         if(!$this->is_ok($reply)) {
  111.             $this->ERROR = _("POP3 connect:"' ' _("Error ""[$reply]";
  112.             unset($this->FP);
  113.             return false;
  114.         }
  115.         $this->FP = $fp;
  116.         $this->BANNER = $this->parse_banner($reply);
  117.         return true;
  118.     }
  119.  
  120.     function user ($user ""{
  121.         // Sends the USER command, returns true or false
  122.  
  123.         ifempty($user) ) {
  124.             $this->ERROR = _("POP3 user:"' ' _("no login ID submitted");
  125.             return false;
  126.         elseif(!isset($this->FP)) {
  127.             $this->ERROR = _("POP3 user:"' ' _("connection not established");
  128.             return false;
  129.         else {
  130.             $reply $this->send_cmd("USER $user");
  131.             if(!$this->is_ok($reply)) {
  132.                 $this->ERROR = _("POP3 user:"' ' _("Error ""[$reply]";
  133.                 return false;
  134.             else
  135.                 return true;
  136.         }
  137.     }
  138.  
  139.     function pass ($pass "")     {
  140.         // Sends the PASS command, returns # of msgs in mailbox,
  141.         // returns false (undef) on Auth failure
  142.  
  143.         if(empty($pass)) {
  144.             $this->ERROR = _("POP3 pass:"' ' _("No password submitted");
  145.             return false;
  146.         elseif(!isset($this->FP)) {
  147.             $this->ERROR = _("POP3 pass:"' ' _("connection not established");
  148.             return false;
  149.         else {
  150.             $reply $this->send_cmd("PASS $pass");
  151.             if(!$this->is_ok($reply)) {
  152.                 $this->ERROR = _("POP3 pass:"' ' _("Authentication failed"" [$reply]";
  153.                 $this->quit();
  154.                 return false;
  155.             else {
  156.                 //  Auth successful.
  157.                 $count $this->last("count");
  158.                 $this->COUNT = $count;
  159.                 return $count;
  160.             }
  161.         }
  162.     }
  163.  
  164.     function apop ($login,$pass{
  165.         //  Attempts an APOP login. If this fails, it'll
  166.         //  try a standard login. YOUR SERVER MUST SUPPORT
  167.         //  THE USE OF THE APOP COMMAND!
  168.         //  (apop is optional per rfc1939)
  169.  
  170.         if(!isset($this->FP)) {
  171.             $this->ERROR = _("POP3 apop:"' ' _("No connection to server");
  172.             return false;
  173.         elseif(!$this->ALLOWAPOP{
  174.             $retVal $this->login($login,$pass);
  175.             return $retVal;
  176.         elseif(empty($login)) {
  177.             $this->ERROR = _("POP3 apop:"' ' _("No login ID submitted");
  178.             return false;
  179.         elseif(empty($pass)) {
  180.             $this->ERROR = _("POP3 apop:"' ' _("No password submitted");
  181.             return false;
  182.         else {
  183.             $banner $this->BANNER;
  184.             if( (!$banneror (empty($banner)) ) {
  185.                 $this->ERROR = _("POP3 apop:"' ' _("No server banner"' - ' _("abort");
  186.                 $retVal $this->login($login,$pass);
  187.                 return $retVal;
  188.             else {
  189.                 $AuthString $banner;
  190.                 $AuthString .= $pass;
  191.                 $APOPString md5($AuthString);
  192.                 $cmd "APOP $login $APOPString";
  193.                 $reply $this->send_cmd($cmd);
  194.                 if(!$this->is_ok($reply)) {
  195.                     $this->ERROR = _("POP3 apop:"' ' _("apop authentication failed"' - ' _("abort");
  196.                     $retVal $this->login($login,$pass);
  197.                     return $retVal;
  198.                 else {
  199.                     //  Auth successful.
  200.                     $count $this->last("count");
  201.                     $this->COUNT = $count;
  202.                     return $count;
  203.                 }
  204.             }
  205.         }
  206.     }
  207.  
  208.     function login ($login ""$pass ""{
  209.         // Sends both user and pass. Returns # of msgs in mailbox or
  210.         // false on failure (or -1, if the error occurs while getting
  211.         // the number of messages.)
  212.  
  213.         if!isset($this->FP) ) {
  214.             $this->ERROR = _("POP3 login:"' ' _("No connection to server");
  215.             return false;
  216.         else {
  217.             $fp $this->FP;
  218.             if!$this->user$login ) ) {
  219.                 //  Preserve the error generated by user()
  220.                 return false;
  221.             else {
  222.                 $count $this->pass($pass);
  223.                 if( (!$count|| ($count == -1) ) {
  224.                     //  Preserve the error generated by last() and pass()
  225.                     return false;
  226.                 else
  227.                     return $count;
  228.             }
  229.         }
  230.     }
  231.  
  232.     function top ($msgNum$numLines "0"{
  233.         //  Gets the header and first $numLines of the msg body
  234.         //  returns data in an array with each returned line being
  235.         //  an array element. If $numLines is empty, returns
  236.         //  only the header information, and none of the body.
  237.  
  238.         if(!isset($this->FP)) {
  239.             $this->ERROR = _("POP3 top:"' ' _("No connection to server");
  240.             return false;
  241.         }
  242.         $this->update_timer();
  243.  
  244.         $fp $this->FP;
  245.         $buffer $this->BUFFER;
  246.         $cmd "TOP $msgNum $numLines";
  247.         fwrite($fp"TOP $msgNum $numLines\r\n");
  248.         $reply fgets($fp$buffer);
  249.         $reply $this->strip_clf($reply);
  250.         if($this->DEBUG{
  251.             @error_log("POP3 SEND [$cmd] GOT [$reply]",0);
  252.         }
  253.         if(!$this->is_ok($reply))
  254.         {
  255.             $this->ERROR = _("POP3 top:"' ' _("Error ""[$reply]";
  256.             return false;
  257.         }
  258.  
  259.         $count 0;
  260.         $MsgArray array();
  261.  
  262.         $line fgets($fp,$buffer);
  263.         while !ereg("^\.\r\n",$line))
  264.         {
  265.             $MsgArray[$count$line;
  266.             $count++;
  267.             $line fgets($fp,$buffer);
  268.             if(empty($line))    break}
  269.         }
  270.  
  271.         return $MsgArray;
  272.     }
  273.  
  274.     function pop_list ($msgNum ""{
  275.         //  If called with an argument, returns that msgs' size in octets
  276.         //  No argument returns an associative array of undeleted
  277.         //  msg numbers and their sizes in octets
  278.  
  279.         if(!isset($this->FP))
  280.         {
  281.             $this->ERROR = _("POP3 pop_list:"' ' _("No connection to server");
  282.             return false;
  283.         }
  284.         $fp $this->FP;
  285.         $Total $this->COUNT;
  286.         if( (!$Totalor ($Total == -1) )
  287.         {
  288.             return false;
  289.         }
  290.         if($Total == 0)
  291.         {
  292.             return array("0","0");
  293.             // return -1;   // mailbox empty
  294.         }
  295.  
  296.         $this->update_timer();
  297.  
  298.         if(!empty($msgNum))
  299.         {
  300.             $cmd "LIST $msgNum";
  301.             fwrite($fp,"$cmd\r\n");
  302.             $reply fgets($fp,$this->BUFFER);
  303.             $reply $this->strip_clf($reply);
  304.             if($this->DEBUG{
  305.                 @error_log("POP3 SEND [$cmd] GOT [$reply]",0);
  306.             }
  307.             if(!$this->is_ok($reply))
  308.             {
  309.                 $this->ERROR = _("POP3 pop_list:"' ' _("Error ""[$reply]";
  310.                 return false;
  311.             }
  312.             list($junk,$num,$sizepreg_split('/\s+/',$reply);
  313.             return $size;
  314.         }
  315.         $cmd "LIST";
  316.         $reply $this->send_cmd($cmd);
  317.         if(!$this->is_ok($reply))
  318.         {
  319.             $reply $this->strip_clf($reply);
  320.             $this->ERROR = _("POP3 pop_list:"' ' _("Error ".  "[$reply]";
  321.             return false;
  322.         }
  323.         $MsgArray array();
  324.         $MsgArray[0$Total;
  325.         for($msgC=1;$msgC <= $Total$msgC++)
  326.         {
  327.             if($msgC $Totalbreak}
  328.             $line fgets($fp,$this->BUFFER);
  329.             $line $this->strip_clf($line);
  330.             if(ereg("^\.",$line))
  331.             {
  332.                 $this->ERROR = _("POP3 pop_list:"' ' _("Premature end of list");
  333.                 return false;
  334.             }
  335.             list($thisMsg,$msgSizepreg_split('/\s+/',$line);
  336.             settype($thisMsg,"integer");
  337.             if($thisMsg != $msgC)
  338.             {
  339.                 $MsgArray[$msgC"deleted";
  340.             }
  341.             else
  342.             {
  343.                 $MsgArray[$msgC$msgSize;
  344.             }
  345.         }
  346.         return $MsgArray;
  347.     }
  348.  
  349.     function get ($msgNum{
  350.         //  Retrieve the specified msg number. Returns an array
  351.         //  where each line of the msg is an array element.
  352.  
  353.         if(!isset($this->FP))
  354.         {
  355.             $this->ERROR = _("POP3 get:"' ' _("No connection to server");
  356.             return false;
  357.         }
  358.  
  359.         $this->update_timer();
  360.  
  361.         $fp $this->FP;
  362.         $buffer $this->BUFFER;
  363.         $cmd "RETR $msgNum";
  364.         $reply $this->send_cmd($cmd);
  365.  
  366.         if(!$this->is_ok($reply))
  367.         {
  368.             $this->ERROR = _("POP3 get:"' ' _("Error ""[$reply]";
  369.             return false;
  370.         }
  371.  
  372.         $count 0;
  373.         $MsgArray array();
  374.  
  375.         $line fgets($fp,$buffer);
  376.         while !ereg("^\.\r\n",$line))
  377.         {
  378.             $MsgArray[$count$line;
  379.             $count++;
  380.             $line fgets($fp,$buffer);
  381.             if(empty($line))    break}
  382.         }
  383.         return $MsgArray;
  384.     }
  385.  
  386.     function last $type "count" {
  387.         //  Returns the highest msg number in the mailbox.
  388.         //  returns -1 on error, 0+ on success, if type != count
  389.         //  results in a popstat() call (2 element array returned)
  390.  
  391.         $last = -1;
  392.         if(!isset($this->FP))
  393.         {
  394.             $this->ERROR = _("POP3 last:"' ' _("No connection to server");
  395.             return $last;
  396.         }
  397.  
  398.         $reply $this->send_cmd("STAT");
  399.         if(!$this->is_ok($reply))
  400.         {
  401.             $this->ERROR = _("POP3 last:"' ' _("Error ""[$reply]";
  402.             return $last;
  403.         }
  404.  
  405.         $Vars preg_split('/\s+/',$reply);
  406.         $count $Vars[1];
  407.         $size $Vars[2];
  408.         settype($count,"integer");
  409.         settype($size,"integer");
  410.         if($type != "count")
  411.         {
  412.             return array($count,$size);
  413.         }
  414.         return $count;
  415.     }
  416.  
  417.     function reset ({
  418.         //  Resets the status of the remote server. This includes
  419.         //  resetting the status of ALL msgs to not be deleted.
  420.         //  This method automatically closes the connection to the server.
  421.  
  422.         if(!isset($this->FP))
  423.         {
  424.             $this->ERROR = _("POP3 reset:"' ' _("No connection to server");
  425.             return false;
  426.         }
  427.         $reply $this->send_cmd("RSET");
  428.         if(!$this->is_ok($reply))
  429.         {
  430.             //  The POP3 RSET command -never- gives a -ERR
  431.             //  response - if it ever does, something truely
  432.             //  wild is going on.
  433.  
  434.             $this->ERROR = _("POP3 reset:"' ' _("Error ""[$reply]";
  435.             @error_log("POP3 resetERROR [$reply]",0);
  436.         }
  437.         $this->quit();
  438.         return true;
  439.     }
  440.  
  441.     function send_cmd $cmd "" )
  442.     {
  443.         //  Sends a user defined command string to the
  444.         //  POP server and returns the results. Useful for
  445.         //  non-compliant or custom POP servers.
  446.         //  Do NOT includ the \r\n as part of your command
  447.         //  string - it will be appended automatically.
  448.  
  449.         //  The return value is a standard fgets() call, which
  450.         //  will read up to $this->BUFFER bytes of data, until it
  451.         //  encounters a new line, or EOF, whichever happens first.
  452.  
  453.         //  This method works best if $cmd responds with only
  454.         //  one line of data.
  455.  
  456.         if(!isset($this->FP))
  457.         {
  458.             $this->ERROR = _("POP3 send_cmd:"' ' _("No connection to server");
  459.             return false;
  460.         }
  461.  
  462.         if(empty($cmd))
  463.         {
  464.             $this->ERROR = _("POP3 send_cmd:"' ' _("Empty command string");
  465.             return "";
  466.         }
  467.  
  468.         $fp $this->FP;
  469.         $buffer $this->BUFFER;
  470.         $this->update_timer();
  471.         fwrite($fp,"$cmd\r\n");
  472.         $reply fgets($fp,$buffer);
  473.         $reply $this->strip_clf($reply);
  474.         if($this->DEBUG@error_log("POP3 SEND [$cmd] GOT [$reply]",0)}
  475.         return $reply;
  476.     }
  477.  
  478.     function quit({
  479.         //  Closes the connection to the POP3 server, deleting
  480.         //  any msgs marked as deleted.
  481.  
  482.         if(!isset($this->FP))
  483.         {
  484.             $this->ERROR = _("POP3 quit:"' ' _("connection does not exist");
  485.             return false;
  486.         }
  487.         $fp $this->FP;
  488.         $cmd "QUIT";
  489.         fwrite($fp,"$cmd\r\n");
  490.         $reply fgets($fp,$this->BUFFER);
  491.         $reply $this->strip_clf($reply);
  492.         if($this->DEBUG@error_log("POP3 SEND [$cmd] GOT [$reply]",0)}
  493.         fclose($fp);
  494.         unset($this->FP);
  495.         return true;
  496.     }
  497.  
  498.     function popstat ({
  499.         //  Returns an array of 2 elements. The number of undeleted
  500.         //  msgs in the mailbox, and the size of the mbox in octets.
  501.  
  502.         $PopArray $this->last("array");
  503.  
  504.         if($PopArray == -1return false}
  505.  
  506.         if( (!$PopArrayor (empty($PopArray)) )
  507.         {
  508.             return false;
  509.         }
  510.         return $PopArray;
  511.     }
  512.  
  513.     function uidl ($msgNum "")
  514.     {
  515.         //  Returns the UIDL of the msg specified. If called with
  516.         //  no arguments, returns an associative array where each
  517.         //  undeleted msg num is a key, and the msg's uidl is the element
  518.         //  Array element 0 will contain the total number of msgs
  519.  
  520.         if(!isset($this->FP)) {
  521.             $this->ERROR = _("POP3 uidl:"' ' _("No connection to server");
  522.             return false;
  523.         }
  524.  
  525.         $fp $this->FP;
  526.         $buffer $this->BUFFER;
  527.  
  528.         if(!empty($msgNum)) {
  529.             $cmd "UIDL $msgNum";
  530.             $reply $this->send_cmd($cmd);
  531.             if(!$this->is_ok($reply))
  532.             {
  533.                 $this->ERROR = _("POP3 uidl:"' ' _("Error ""[$reply]";
  534.                 return false;
  535.             }
  536.             list ($ok,$num,$myUidlpreg_split('/\s+/',$reply);
  537.             return $myUidl;
  538.         else {
  539.             $this->update_timer();
  540.  
  541.             $UIDLArray array();
  542.             $Total $this->COUNT;
  543.             $UIDLArray[0$Total;
  544.  
  545.             if ($Total 1)
  546.             {
  547.                 return $UIDLArray;
  548.             }
  549.             $cmd "UIDL";
  550.             fwrite($fp"UIDL\r\n");
  551.             $reply fgets($fp$buffer);
  552.             $reply $this->strip_clf($reply);
  553.             if($this->DEBUG@error_log("POP3 SEND [$cmd] GOT [$reply]",0)}
  554.             if(!$this->is_ok($reply))
  555.             {
  556.                 $this->ERROR = _("POP3 uidl:"' ' _("Error ""[$reply]";
  557.                 return false;
  558.             }
  559.  
  560.             $line "";
  561.             $count 1;
  562.             $line fgets($fp,$buffer);
  563.             while !ereg("^\.\r\n",$line)) {
  564.                 if(ereg("^\.\r\n",$line)) {
  565.                     break;
  566.                 }
  567.                 list ($msg,$msgUidlpreg_split('/\s+/',$line);
  568.                 $msgUidl $this->strip_clf($msgUidl);
  569.                 if($count == $msg{
  570.                     $UIDLArray[$msg$msgUidl;
  571.                 }
  572.                 else
  573.                 {
  574.                     $UIDLArray[$count'deleted';
  575.                 }
  576.                 $count++;
  577.                 $line fgets($fp,$buffer);
  578.             }
  579.         }
  580.         return $UIDLArray;
  581.     }
  582.  
  583.     function delete ($msgNum ""{
  584.         //  Flags a specified msg as deleted. The msg will not
  585.         //  be deleted until a quit() method is called.
  586.  
  587.         if(!isset($this->FP))
  588.         {
  589.             $this->ERROR = _("POP3 delete:"' ' _("No connection to server");
  590.             return false;
  591.         }
  592.         if(empty($msgNum))
  593.         {
  594.             $this->ERROR = _("POP3 delete:"' ' _("No msg number submitted");
  595.             return false;
  596.         }
  597.         $reply $this->send_cmd("DELE $msgNum");
  598.         if(!$this->is_ok($reply))
  599.         {
  600.             $this->ERROR = _("POP3 delete:"' ' _("Command failed ""[$reply]";
  601.             return false;
  602.         }
  603.         return true;
  604.     }
  605.  
  606.     //  *********************************************************
  607.  
  608.     //  The following methods are internal to the class.
  609.  
  610.     
  611.     function is_ok ($cmd ""{
  612.         //  Return true or false on +OK or -ERR
  613.  
  614.         ifempty($cmd) )
  615.             return false;
  616.         else
  617.             returnereg ("^\+OK"$cmd ) );
  618.     }
  619.  
  620.     function strip_clf ($text ""{
  621.         // Strips \r\n from server responses
  622.  
  623.         if(empty($text))
  624.             return $text;
  625.         else {
  626.             $stripped str_replace("\r",'',$text);
  627.             $stripped str_replace("\n",'',$stripped);
  628.             return $stripped;
  629.         }
  630.     }
  631.  
  632.     function parse_banner $server_text {
  633.         $outside true;
  634.         $banner "";
  635.         $length strlen($server_text);
  636.         for($count =0$count $length$count++)
  637.         {
  638.             $digit substr($server_text,$count,1);
  639.             if(!empty($digit))             {
  640.                 if( (!$outside&& ($digit != '<'&& ($digit != '>') )
  641.                 {
  642.                     $banner .= $digit;
  643.                 }
  644.                 if ($digit == '<')
  645.                 {
  646.                     $outside false;
  647.                 }
  648.                 if($digit == '>')
  649.                 {
  650.                     $outside true;
  651.                 }
  652.             }
  653.         }
  654.         $banner $this->strip_clf($banner);    // Just in case
  655.         return "<$banner>";
  656.     }
  657.  
  658. }   // End class
  659.  
  660. ?>

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