Source for file rfc822address.php

Documentation is available at rfc822address.php

  1. <?php
  2.  
  3. /**
  4.  * rfc822address.php
  5.  *
  6.  * Contains rfc822 email address function parsing functions.
  7.  *
  8.  * @copyright &copy; 2004-2006 The SquirrelMail Project Team
  9.  * @license http://opensource.org/licenses/gpl-license.php GNU Public License
  10.  * @version $Id: rfc822address.php,v 1.11 2006/07/15 12:00:45 tokul Exp $
  11.  * @package squirrelmail
  12.  */
  13.  
  14.  
  15. /**
  16.  * parseRFC822Address: function for parsing RFC822 email address strings and store
  17.  *               them in an address array
  18.  *
  19.  * @param string  $address The email address string to parse
  20.  * @param integer $iLimit stop on $iLimit parsed addresses
  21.  * @public
  22.  * @author Marc Groot Koerkamp
  23.  *
  24.  ***/
  25. function parseRFC822Address($sAddress,$iLimit 0{
  26.  
  27.     $aTokens _getAddressTokens($sAddress);
  28.     $sPersonal $sEmail $sComment $sGroup '';
  29.     $aStack $aComment $aAddress array();
  30.     foreach ($aTokens as $sToken{
  31.         if ($iLimit && $iLimit == count($aAddress)) {
  32.             return $aAddress;
  33.         }
  34.         $cChar $sToken{0};
  35.         switch ($cChar)
  36.         {
  37.         case '=':
  38.         case '"':
  39.         case ' ':
  40.             $aStack[$sToken;
  41.             break;
  42.         case '(':
  43.             $aComment[substr($sToken,1,-1);
  44.             break;
  45.         case ';':
  46.             if ($sGroup{
  47.                 $aAddress[_createAddressElement($aStack,$aComment,$sEmail);
  48.                 $aAddr end($aAddress);
  49.                 if(!$aAddr || ((isset($aAddr)) && !$aAddr[SQM_ADDR_MAILBOX&& !$aAddr[SQM_ADDR_PERSONAL])) {
  50.                     $sEmail $sGroup ':;';
  51.                 }
  52.                 $aAddress[_createAddressElement($aStack,$aComment,$sEmail);
  53.                 $sGroup '';
  54.                 $aStack $aComment array();
  55.                 break;
  56.             }
  57.         case ',':
  58.             $aAddress[_createAddressElement($aStack,$aComment,$sEmail);
  59.             break;
  60.         case ':':
  61.             $sGroup trim(implode(' ',$aStack));
  62.             $sGroup preg_replace('/\s+/',' ',$sGroup);
  63.             $aStack array();
  64.             break;
  65.         case '<':
  66.             $sEmail trim(substr($sToken,1,-1));
  67.             break;
  68.         case '>':
  69.             /* skip */
  70.             break;
  71.         default$aStack[$sTokenbreak;
  72.         }
  73.     }
  74.     /* now do the action again for the last address */
  75.     $aAddress[_createAddressElement($aStack,$aComment,$sEmail);
  76.     return $aAddress;
  77. }
  78.  
  79.  
  80. /**
  81.  * Do the address array to string translation
  82.  *
  83.  * @param array $aAddressList list with email address arrays
  84.  * @param array  $aProps  associative array with properties
  85.  * @return string 
  86.  * @public
  87.  * @see parseRFC822Address
  88.  * @author Marc Groot Koerkamp
  89.  *
  90.  ***/
  91. function getAddressString($aAddressList,$aProps{
  92.     $aPropsDefault array (
  93.                             'separator' => ',',     // address separator
  94.                             'limit'  => 0,          // limits returned addresses
  95.                             'personal' => true,     // show persnal part
  96.                             'email'    => true,     // show email part
  97.                             'best'     => false,    // show personal if available
  98.                             'encode'   => false,    // encode the personal part
  99.                             'unique'   => false,    // make email addresses unique.
  100.                             'exclude'  => array()   // array with exclude addresses
  101.                                                     // format of address: mailbox@host
  102.                             );
  103.  
  104.     $aProps is_array($aPropsarray_merge($aPropsDefault,$aProps$aPropsDefault;
  105.  
  106.     $aNewAddressList array();
  107.     $aEmailUnique array();
  108.     foreach ($aAddressList as $aAddr{
  109.         if ($aProps['limit'&& count($aNewAddressList== $aProps['limit']{
  110.             break;
  111.         }
  112.         $sPersonal (isset($aAddr[SQM_ADDR_PERSONAL])) $aAddr[SQM_ADDR_PERSONAL'';
  113.         $sMailbox  (isset($aAddr[SQM_ADDR_MAILBOX]))  $aAddr[SQM_ADDR_MAILBOX]  '';
  114.         $sHost     (isset($aAddr[SQM_ADDR_HOST]))     $aAddr[SQM_ADDR_HOST]     '';
  115.  
  116.         $sEmail    ($sHost"$sMailbox@$sHost"$sMailbox;
  117.  
  118.         if (in_array($sEmail,$aProps['exclude'],true)) {
  119.             continue;
  120.         }
  121.  
  122.         if ($aProps['unique']{
  123.             if  (in_array($sEmail,$aEmailUnique,true)) {
  124.                 continue;
  125.             else {
  126.                 $aEmailUnique[$sEmail;
  127.             }
  128.         }
  129.  
  130.         $s '';
  131.         if ($aProps['best']{
  132.             $s .= ($sPersonal$sPersonal $sEmail;
  133.         else {
  134.             if ($aProps['personal'&& $sPersonal{
  135.                 if ($aProps['encode']{
  136.                     $sPersonal encodeHeader($sPersonal);
  137.                 }
  138.                 $s .= $sPersonal;
  139.             }
  140.             if ($aProps['email'&& $sEmail{
  141.                $s.= ($s' <'.$sEmail.'>''<'.$sEmail.'>';
  142.             }
  143.         }
  144.         if ($s{
  145.             $aNewAddressList[$s;
  146.         }
  147.     }
  148.     return implode($aProps['separator'],$aNewAddressList);
  149. }
  150.  
  151.  
  152. /**
  153.  * Do after address parsing handling. This is used by compose.php and should
  154.  * be moved to compose.php.
  155.  * The AddressStructure objetc is now obsolete and dependent parts of that will
  156.  * be adapted so that it can make use of this function
  157.  * After that we can remove the parseAddress method from the Rfc822Header class completely
  158.  * so we achieved 1 single instance of parseAddress instead of two like we have now.
  159.  *
  160.  * @param array $aAddressList list with email address arrays
  161.  * @param array  $aProps  associative array with properties
  162.  * @return string 
  163.  * @public
  164.  * @see parseRFC822Address
  165.  * @see Rfc822Header
  166.  * @author Marc Groot Koerkamp
  167.  *
  168.  ***/
  169. function processAddressArray($aAddresses,$aProps{
  170.     $aPropsDefault array (
  171.                             'domain' => '',
  172.                             'limit'  => 0,
  173.                             'abooklookup' => false);
  174.  
  175.     $aProps is_array($aPropsarray_merge($aPropsDefault,$aProps$aPropsDefault;
  176.     $aProcessedAddress array();
  177.  
  178.     foreach ($aAddresses as $aEntry{
  179.         /*
  180.          * if the emailaddress does not contain the domainpart it can concern
  181.          * an alias or local (in the same domain as the user is) email
  182.          * address. In that case we try to look it up in the addressbook or add
  183.          * the local domain part
  184.          */
  185.         if (!$aEntry[SQM_ADDR_HOST]{
  186.             if ($cbLookup{
  187.                 $aAddr call_user_func_array($cbLookup,array($aEntry[SQM_ADDR_MAILBOX]));
  188.                 if (isset($aAddr['email'])) {
  189.                     /*
  190.                      * if the returned email address concerns multiple email
  191.                      * addresses we have to process those as well
  192.                      */
  193.                     if (strpos($aAddr['email'],',')) /* multiple addresses */
  194.                         /* add the parsed addresses to the processed address array */
  195.                         $aProcessedAddress array_merge($aProcessedAddress,parseAddress($aAddr['email']));
  196.                         /* skip to next address, all processing is done */
  197.                         continue;
  198.                     else /* single address */
  199.                         $iPosAt strpos($aAddr['email']'@');
  200.                         $aEntry[SQM_ADDR_MAILBOXsubstr($aAddr['email']0$iPosAt);
  201.                         $aEntry[SQM_ADDR_HOSTsubstr($aAddr['email']$iPosAt+1);
  202.                         if (isset($aAddr['name'])) {
  203.                             $aEntry[SQM_ADDR_PERSONAL$aAddr['name'];
  204.                         else {
  205.                             $aEntry[SQM_ADDR_PERSONALencodeHeader($sPersonal);
  206.                         }
  207.                     }
  208.                 }
  209.             }
  210.             /*
  211.              * append the domain
  212.              *
  213.              */
  214.             if (!$aEntry[SQM_ADDR_MAILBOX]{
  215.                 $aEntry[SQM_ADDR_MAILBOXtrim($sEmail);
  216.             }
  217.             if ($sDomain && !$aEntry[SQM_ADDR_HOST]{
  218.                 $aEntry[SQM_ADDR_HOST$sDomain;
  219.             }
  220.         }
  221.         if ($aEntry[SQM_ADDR_MAILBOX]{
  222.             $aProcessedAddress[$aEntry;
  223.         }
  224.     }
  225.     return $aProcessedAddress;
  226. }
  227.  
  228. /**
  229.  * Internal function for creating an address array
  230.  *
  231.  * @param array $aStack 
  232.  * @param array $aComment 
  233.  * @param string $sEmail 
  234.  * @return array $aAddr array with personal (0), adl(1), mailbox(2) and host(3) info
  235.  * @private
  236.  * @author Marc Groot Koerkamp
  237.  *
  238.  ***/
  239.  
  240. function _createAddressElement(&$aStack,&$aComment,&$sEmail{
  241.     if (!$sEmail{
  242.         while (count($aStack&& !$sEmail{
  243.             $sEmail trim(array_pop($aStack));
  244.         }
  245.     }
  246.     if (count($aStack)) {
  247.         $sPersonal trim(implode('',$aStack));
  248.     else {
  249.         $sPersonal '';
  250.     }
  251.     if (!$sPersonal && count($aComment)) {
  252.         $sComment trim(implode(' ',$aComment));
  253.         $sPersonal .= $sComment;
  254.     }
  255.     $aAddr array();
  256. //        if ($sPersonal && substr($sPersonal,0,2) == '=?') {
  257. //            $aAddr[SQM_ADDR_PERSONAL] = encodeHeader($sPersonal);
  258. //        } else {
  259.         $aAddr[SQM_ADDR_PERSONAL$sPersonal;
  260. //        }
  261.  
  262.     $iPosAt strpos($sEmail,'@');
  263.     if ($iPosAt{
  264.         $aAddr[SQM_ADDR_MAILBOXsubstr($sEmail0$iPosAt);
  265.         $aAddr[SQM_ADDR_HOSTsubstr($sEmail$iPosAt+1);
  266.     else {
  267.         $aAddr[SQM_ADDR_MAILBOX$sEmail;
  268.         $aAddr[SQM_ADDR_HOSTfalse;
  269.     }
  270.     $sEmail '';
  271.     $aStack $aComment array();
  272.     return $aAddr;
  273. }
  274.  
  275. /**
  276.  * Tokenizer function for parsing the RFC822 email address string
  277.  *
  278.  * @param string $address The email address string to parse
  279.  * @return array $aTokens
  280.  * @private
  281.  * @author Marc Groot Koerkamp
  282.  *
  283.  ***/
  284.  
  285. function _getAddressTokens($address{
  286.     $aTokens array();
  287.     $aSpecials array('(' ,'<' ,',' ,';' ,':');
  288.     $aReplace =  array(' (',' <',' ,',' ;',' :');
  289.     $address str_replace($aSpecials,$aReplace,$address);
  290.     $iCnt strlen($address);
  291.     $i 0;
  292.     while ($i $iCnt{
  293.         $cChar $address{$i};
  294.         switch($cChar)
  295.         {
  296.         case '<':
  297.             $iEnd strpos($address,'>',$i+1);
  298.             if (!$iEnd{
  299.                 $sToken substr($address,$i);
  300.                 $i $iCnt;
  301.             else {
  302.                 $sToken substr($address,$i,$iEnd $i +1);
  303.                 $i $iEnd;
  304.             }
  305.             $sToken str_replace($aReplace$aSpecials,$sToken);
  306.             if ($sToken$aTokens[$sToken;
  307.             break;
  308.         case '"':
  309.             $iEnd strpos($address,$cChar,$i+1);
  310.             if ($iEnd{
  311.                 // skip escaped quotes
  312.                 $prev_char $address{$iEnd-1};
  313.                 while ($prev_char === '\\' && substr($address,$iEnd-2,2!== '\\\\'{
  314.                     $iEnd strpos($address,$cChar,$iEnd+1);
  315.                     if ($iEnd{
  316.                         $prev_char $address{$iEnd-1};
  317.                     else {
  318.                         $prev_char false;
  319.                     }
  320.                 }
  321.             }
  322.             if (!$iEnd{
  323.                 $sToken substr($address,$i);
  324.                 $i $iCnt;
  325.             else {
  326.                 // also remove the surrounding quotes
  327.                 $sToken substr($address,$i+1,$iEnd $i -1);
  328.                 $i $iEnd;
  329.             }
  330.             $sToken str_replace($aReplace$aSpecials,$sToken);
  331.             if ($sToken$aTokens[$sToken;
  332.             break;
  333.         case '(':
  334.             array_pop($aTokens)//remove inserted space
  335.             $iEnd strpos($address,')',$i);
  336.             if (!$iEnd{
  337.                 $sToken substr($address,$i);
  338.                 $i $iCnt;
  339.             else {
  340.                 $iDepth 1;
  341.                 $iComment $i;
  342.                 while (($iDepth 0&& (++$iComment $iCnt)) {
  343.                     $cCharComment $address{$iComment};
  344.                     switch($cCharComment{
  345.                         case '\\':
  346.                             ++$iComment;
  347.                             break;
  348.                         case '(':
  349.                             ++$iDepth;
  350.                             break;
  351.                         case ')':
  352.                             --$iDepth;
  353.                             break;
  354.                         default:
  355.                             break;
  356.                     }
  357.                 }
  358.                 if ($iDepth == 0{
  359.                     $sToken substr($address,$i,$iComment $i +1);
  360.                     $i $iComment;
  361.                 else {
  362.                     $sToken substr($address,$i,$iEnd $i 1);
  363.                     $i $iEnd;
  364.                 }
  365.             }
  366.             // check the next token in case comments appear in the middle of email addresses
  367.             $prevToken end($aTokens);
  368.             if (!in_array($prevToken,$aSpecials,true)) {
  369.                 if ($i+1<strlen($address&& !in_array($address{$i+1},$aSpecials,true)) {
  370.                     $iEnd strpos($address,' ',$i+1);
  371.                     if ($iEnd{
  372.                         $sNextToken trim(substr($address,$i+1,$iEnd $i -1));
  373.                         $i $iEnd-1;
  374.                     else {
  375.                         $sNextToken trim(substr($address,$i+1));
  376.                         $i $iCnt;
  377.                     }
  378.                     // remove the token
  379.                     array_pop($aTokens);
  380.                     // create token and add it again
  381.                     $sNewToken $prevToken $sNextToken;
  382.                     if($sNewToken$aTokens[$sNewToken;
  383.                 }
  384.             }
  385.             $sToken str_replace($aReplace$aSpecials,$sToken);
  386.             if ($sToken$aTokens[$sToken;
  387.             break;
  388.         case ',':
  389.         case ':':
  390.         case ';':
  391.         case ' ':
  392.             $aTokens[$cChar;
  393.             break;
  394.         default:
  395.             $iEnd strpos($address,' ',$i+1);
  396.             if ($iEnd{
  397.                 $sToken trim(substr($address,$i,$iEnd $i));
  398.                 $i $iEnd-1;
  399.             else {
  400.                 $sToken trim(substr($address,$i));
  401.                 $i $iCnt;
  402.             }
  403.             if ($sToken$aTokens[$sToken;
  404.         }
  405.         ++$i;
  406.     }
  407.     return $aTokens;
  408. }

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