Source for file strings.php

Documentation is available at strings.php

  1. <?php
  2.  
  3. /**
  4.  * strings.php
  5.  *
  6.  * This code provides various string manipulation functions that are
  7.  * used by the rest of the SquirrelMail code.
  8.  *
  9.  * @copyright &copy; 1999-2006 The SquirrelMail Project Team
  10.  * @license http://opensource.org/licenses/gpl-license.php GNU Public License
  11.  * @version $Id: strings.php,v 1.255 2006/09/30 16:24:00 stekkel Exp $
  12.  * @package squirrelmail
  13.  */
  14.  
  15. /**
  16.  * Appends citation markers to the string.
  17.  * Also appends a trailing space.
  18.  *
  19.  * @author Justus Pendleton
  20.  * @param string $str The string to append to
  21.  * @param int $citeLevel the number of markers to append
  22.  * @return null 
  23.  * @since 1.5.1
  24.  */
  25. function sqMakeCite (&$str$citeLevel{
  26.     for ($i 0$i $citeLevel$i++{
  27.         $str .= '>';
  28.     }
  29.     if ($citeLevel != 0{
  30.         $str .= ' ';
  31.     }
  32. }
  33.  
  34. /**
  35.  * Create a newline in the string, adding citation
  36.  * markers to the newline as necessary.
  37.  *
  38.  * @author Justus Pendleton
  39.  * @param string $str the string to make a newline in
  40.  * @param int $citeLevel the citation level the newline is at
  41.  * @param int $column starting column of the newline
  42.  * @return null 
  43.  * @since 1.5.1
  44.  */
  45. function sqMakeNewLine (&$str$citeLevel&$column{
  46.     $str .= "\n";
  47.     $column 0;
  48.     if ($citeLevel 0{
  49.         sqMakeCite ($str$citeLevel);
  50.         $column $citeLevel 1;
  51.     else {
  52.         $column 0;
  53.     }
  54. }
  55.  
  56. /**
  57.  * Checks for spaces in strings - only used if PHP doesn't have native ctype support
  58.  *
  59.  * You might be able to rewrite the function by adding short evaluation form.
  60.  *
  61.  * possible problems:
  62.  *  - iso-2022-xx charsets  - hex 20 might be part of other symbol. I might
  63.  * be wrong. 0x20 is not used in iso-2022-jp. I haven't checked iso-2022-kr
  64.  * and iso-2022-cn mappings.
  65.  *
  66.  *  - no-break space (&nbsp;) - it is 8bit symbol, that depends on charset.
  67.  * there are at least three different charset groups that have nbsp in
  68.  * different places.
  69.  *
  70.  * I don't see any charset/nbsp options in php ctype either.
  71.  *
  72.  * @param string $string tested string
  73.  * @return bool true when only whitespace symbols are present in test string
  74.  * @since 1.5.1
  75.  */
  76. function sm_ctype_space($string{
  77.     if preg_match('/^[\x09-\x0D]|^\x20/'$string|| $string==''{
  78.         return true;
  79.     else {
  80.         return false;
  81.     }
  82. }
  83.  
  84. /**
  85.  * Wraps text at $wrap characters.  While sqWordWrap takes
  86.  * a single line of text and wraps it, this function works
  87.  * on the entire corpus at once, this allows it to be a little
  88.  * bit smarter and when and how to wrap.
  89.  *
  90.  * @author Justus Pendleton
  91.  * @param string $body the entire body of text
  92.  * @param int $wrap the maximum line length
  93.  * @return string the wrapped text
  94.  * @since 1.5.1
  95.  */
  96. function &sqBodyWrap (&$body$wrap{
  97.     //check for ctype support, and fake it if it doesn't exist
  98.     if (!function_exists('ctype_space')) {
  99.         function ctype_space ($string{
  100.             return sm_ctype_space($string);
  101.         }
  102.     }
  103.  
  104.     // the newly wrapped text
  105.     $outString '';
  106.     // current column since the last newline in the outstring
  107.     $outStringCol 0;
  108.     $length sq_strlen($body);
  109.     // where we are in the original string
  110.     $pos 0;
  111.     // the number of >>> citation markers we are currently at
  112.     $citeLevel 0;
  113.  
  114.     // the main loop, whenever we start a newline of input text
  115.     // we start from here
  116.     while ($pos $length{
  117.        // we're at the beginning of a line, get the new cite level
  118.        $newCiteLevel 0;
  119.  
  120.        while (($pos $length&& (sq_substr($body,$pos,1== '>')) {
  121.            $newCiteLevel++;
  122.            $pos++;
  123.  
  124.            // skip over any spaces interleaved among the cite markers
  125.            while (($pos $length&& (sq_substr($body,$pos,1== ' ')) {
  126.  
  127.                $pos++;
  128.  
  129.            }
  130.            if ($pos >= $length{
  131.                break;
  132.            }
  133.        }
  134.  
  135.        // special case: if this is a blank line then maintain it
  136.        // (i.e. try to preserve original paragraph breaks)
  137.        // unless they occur at the very beginning of the text
  138.        if ((sq_substr($body,$pos,1== "\n" && (sq_strlen($outString!= 0)) {
  139.            $outStringLast $outString{sq_strlen($outString1};
  140.            if ($outStringLast != "\n"{
  141.                $outString .= "\n";
  142.            }
  143.            sqMakeCite ($outString$newCiteLevel);
  144.            $outString .= "\n";
  145.            $pos++;
  146.            $outStringCol 0;
  147.            continue;
  148.        }
  149.  
  150.        // if the cite level has changed, then start a new line
  151.        // with the new cite level.
  152.        if (($citeLevel != $newCiteLevel&& ($pos ($newCiteLevel 1)) && ($outStringCol != 0)) {
  153.            sqMakeNewLine ($outString0$outStringCol);
  154.        }
  155.  
  156.        $citeLevel $newCiteLevel;
  157.  
  158.        // prepend the quote level if necessary
  159.        if ($outStringCol == 0{
  160.            sqMakeCite ($outString$citeLevel);
  161.            // if we added a citation then move the column
  162.            // out by citelevel + 1 (the cite markers + the space)
  163.            $outStringCol $citeLevel ($citeLevel 0);
  164.        else if ($outStringCol $citeLevel{
  165.            // not a cite and we're not at the beginning of a line
  166.            // in the output.  add a space to separate the new text
  167.            // from previous text.
  168.            $outString .= ' ';
  169.            $outStringCol++;
  170.        }
  171.  
  172.        // find the next newline -- we don't want to go further than that
  173.        $nextNewline sq_strpos ($body"\n"$pos);
  174.        if ($nextNewline === FALSE{
  175.            $nextNewline $length;
  176.        }
  177.  
  178.        // Don't wrap unquoted lines at all.  For now the textarea
  179.        // will work fine for this.  Maybe revisit this later though
  180.        // (for completeness more than anything else, I think)
  181.        if ($citeLevel == 0{
  182.            $outString .= sq_substr ($body$pos($nextNewline $pos));
  183.            $outStringCol $nextNewline $pos;
  184.            if ($nextNewline != $length{
  185.                sqMakeNewLine ($outString0$outStringCol);
  186.            }
  187.            $pos $nextNewline 1;
  188.            continue;
  189.        }
  190.        /**
  191.         * Set this to false to stop appending short strings to previous lines
  192.         */
  193.        $smartwrap true;
  194.        // inner loop, (obviously) handles wrapping up to
  195.        // the next newline
  196.        while ($pos $nextNewline{
  197.            // skip over initial spaces
  198.            while (($pos $nextNewline&& (ctype_space (sq_substr($body,$pos,1)))) {
  199.                $pos++;
  200.            }
  201.            // if this is a short line then just append it and continue outer loop
  202.            if (($outStringCol $nextNewline $pos<= ($wrap $citeLevel 1) ) {
  203.                // if this is the final line in the input string then include
  204.                // any trailing newlines
  205.                //      echo substr($body,$pos,$wrap). "<br />";
  206.                if (($nextNewline == $length&& (sq_substr($body,$nextNewline,1== "\n")) {
  207.                    $nextNewline++;
  208.                }
  209.  
  210.                // trim trailing spaces
  211.                $lastRealChar $nextNewline;
  212.                while (($lastRealChar $pos && $lastRealChar $length&& (ctype_space (sq_substr($body,$lastRealChar,1)))) {
  213.                    $lastRealChar--;
  214.                }
  215.                // decide if appending the short string is what we want
  216.                if (($nextNewline $length && sq_substr($body,$nextNewline,1== "\n"&&
  217.                      isset($lastRealChar)) {
  218.                    $mypos $pos;
  219.                    //check the first word:
  220.                    while (($mypos $length&& (sq_substr($body,$mypos,1== '>')) {
  221.                        $mypos++;
  222.                        // skip over any spaces interleaved among the cite markers
  223.                        while (($mypos $length&& (sq_substr($body,$mypos,1== ' ')) {
  224.                            $mypos++;
  225.                        }
  226.                    }
  227. /*
  228.                      $ldnspacecnt = 0;
  229.                      if ($mypos == $nextNewline+1) {
  230.                         while (($mypos < $length) && ($body{$mypos} == ' ')) {
  231.                          $ldnspacecnt++;
  232.                         }
  233.                      }
  234. */
  235.  
  236.                    $firstword sq_substr($body,$mypos,sq_strpos($body,' ',$mypos$mypos);
  237.                    //if ($dowrap || $ldnspacecnt > 1 || ($firstword && (
  238.                    if (!$smartwrap || $firstword && (
  239.                                         $firstword{0== '-' ||
  240.                                         $firstword{0== '+' ||
  241.                                         $firstword{0== '*' ||
  242.                                         sq_substr($firstword,0,1== sq_strtoupper(sq_substr($firstword,0,1)) ||
  243.                                         strpos($firstword,':'))) {
  244.                         $outString .= sq_substr($body,$pos,($lastRealChar $pos+1));
  245.                         $outStringCol += ($lastRealChar $pos);
  246.                         sqMakeNewLine($outString,$citeLevel,$outStringCol);
  247.                         $nextNewline++;
  248.                         $pos $nextNewline;
  249.                         $outStringCol--;
  250.                         continue;
  251.                    }
  252.  
  253.                }
  254.  
  255.                $outString .= sq_substr ($body$pos($lastRealChar $pos 1));
  256.                $outStringCol += ($lastRealChar $pos);
  257.                $pos $nextNewline 1;
  258.                continue;
  259.            }
  260.  
  261.            $eol $pos $wrap $citeLevel $outStringCol;
  262.            // eol is the tentative end of line.
  263.            // look backwards for there for a whitespace to break at.
  264.            // if it's already less than our current position then
  265.            // our current line is already too long, break immediately
  266.            // and restart outer loop
  267.            if ($eol <= $pos{
  268.                sqMakeNewLine ($outString$citeLevel$outStringCol);
  269.                continue;
  270.            }
  271.  
  272.            // start looking backwards for whitespace to break at.
  273.            $breakPoint $eol;
  274.            while (($breakPoint $pos&& (ctype_space (sq_substr($body,$breakPoint,1)))) {
  275.                $breakPoint--;
  276.            }
  277.  
  278.            // if we didn't find a breakpoint by looking backward then we
  279.            // need to figure out what to do about that
  280.            if ($breakPoint == $pos{
  281.                // if we are not at the beginning then end this line
  282.                // and start a new loop
  283.                if ($outStringCol ($citeLevel 1)) {
  284.                    sqMakeNewLine ($outString$citeLevel$outStringCol);
  285.                    continue;
  286.                else {
  287.                    // just hard break here.  most likely we are breaking
  288.                    // a really long URL.  could also try searching
  289.                    // forward for a break point, which is what Mozilla
  290.                    // does.  don't bother for now.
  291.                    $breakPoint $eol;
  292.                }
  293.            }
  294.  
  295.            // special case: maybe we should have wrapped last
  296.            // time.  if the first breakpoint here makes the
  297.            // current line too long and there is already text on
  298.            // the current line, break and loop again if at
  299.            // beginning of current line, don't force break
  300.            $SLOP 6;
  301.            if ((($outStringCol ($breakPoint $pos)) ($wrap $SLOP)) && ($outStringCol ($citeLevel 1))) {
  302.                sqMakeNewLine ($outString$citeLevel$outStringCol);
  303.                continue;
  304.            }
  305.  
  306.            // skip newlines or whitespace at the beginning of the string
  307.            $substring sq_substr ($body$pos($breakPoint $pos));
  308.            $substring rtrim ($substring)// do rtrim and ctype_space have the same ideas about whitespace?
  309.            $outString .= $substring;
  310.            $outStringCol += sq_strlen ($substring);
  311.            // advance past the whitespace which caused the wrap
  312.            $pos $breakPoint;
  313.            while (($pos $length&& (ctype_space (sq_substr($body,$pos,1)))) {
  314.                $pos++;
  315.            }
  316.            if ($pos $length{
  317.                sqMakeNewLine ($outString$citeLevel$outStringCol);
  318.            }
  319.        }
  320.     }
  321.  
  322.     return $outString;
  323. }
  324.  
  325. /**
  326.  * Wraps text at $wrap characters
  327.  *
  328.  * Has a problem with special HTML characters, so call this before
  329.  * you do character translation.
  330.  *
  331.  * Specifically, &amp;#039; comes up as 5 characters instead of 1.
  332.  * This should not add newlines to the end of lines.
  333.  *
  334.  * @param string $line the line of text to wrap, by ref
  335.  * @param int $wrap the maximum line lenth
  336.  * @param string $charset name of charset used in $line string. Available since v.1.5.1.
  337.  * @return void 
  338.  * @since 1.0
  339.  */
  340. function sqWordWrap(&$line$wrap$charset=''{
  341.     global $languages$squirrelmail_language;
  342.  
  343.     // Use custom wrapping function, if translation provides it
  344.     if (isset($languages[$squirrelmail_language]['XTRA_CODE']&&
  345.         function_exists($languages[$squirrelmail_language]['XTRA_CODE''_wordwrap')) {
  346.         if (mb_detect_encoding($line!= 'ASCII'{
  347.             $line call_user_func($languages[$squirrelmail_language]['XTRA_CODE''_wordwrap'$line$wrap);
  348.             return;
  349.         }
  350.     }
  351.  
  352.     ereg("^([\t >]*)([^\t >].*)?$"$line$regs);
  353.     $beginning_spaces $regs[1];
  354.     if (isset($regs[2])) {
  355.         $words explode(' '$regs[2]);
  356.     else {
  357.         $words '';
  358.     }
  359.  
  360.     $i 0;
  361.     $line $beginning_spaces;
  362.  
  363.     while ($i count($words)) {
  364.         /* Force one word to be on a line (minimum) */
  365.         $line .= $words[$i];
  366.         $line_len strlen($beginning_spacessq_strlen($words[$i],$charset2;
  367.         if (isset($words[$i 1]))
  368.             $line_len += sq_strlen($words[$i 1],$charset);
  369.         $i ++;
  370.  
  371.         /* Add more words (as long as they fit) */
  372.         while ($line_len $wrap && $i count($words)) {
  373.             $line .= ' ' $words[$i];
  374.             $i++;
  375.             if (isset($words[$i]))
  376.                 $line_len += sq_strlen($words[$i],$charset1;
  377.             else
  378.                 $line_len += 1;
  379.         }
  380.  
  381.         /* Skip spaces if they are the first thing on a continued line */
  382.         while (!isset($words[$i]&& $i count($words)) {
  383.             $i ++;
  384.         }
  385.  
  386.         /* Go to the next line if we have more to process */
  387.         if ($i count($words)) {
  388.             $line .= "\n";
  389.         }
  390.     }
  391. }
  392.  
  393. /**
  394.  * Does the opposite of sqWordWrap()
  395.  * @param string $body the text to un-wordwrap
  396.  * @return void 
  397.  * @since 1.0
  398.  */
  399. function sqUnWordWrap(&$body{
  400.     global $squirrelmail_language;
  401.  
  402.     if ($squirrelmail_language == 'ja_JP'{
  403.         return;
  404.     }
  405.  
  406.     $lines explode("\n"$body);
  407.     $body '';
  408.     $PreviousSpaces '';
  409.     $cnt count($lines);
  410.     for ($i 0$i $cnt$i ++{
  411.         preg_match("/^([\t >]*)([^\t >].*)?$/"$lines[$i]$regs);
  412.         $CurrentSpaces $regs[1];
  413.         if (isset($regs[2])) {
  414.             $CurrentRest $regs[2];
  415.         else {
  416.             $CurrentRest '';
  417.         }
  418.  
  419.         if ($i == 0{
  420.             $PreviousSpaces $CurrentSpaces;
  421.             $body $lines[$i];
  422.         else if (($PreviousSpaces == $CurrentSpaces/* Do the beginnings match */
  423.                    && (strlen($lines[$i 1]65)    /* Over 65 characters long */
  424.                    && strlen($CurrentRest)) {          /* and there's a line to continue with */
  425.             $body .= ' ' $CurrentRest;
  426.         else {
  427.             $body .= "\n" $lines[$i];
  428.             $PreviousSpaces $CurrentSpaces;
  429.         }
  430.     }
  431.     $body .= "\n";
  432. }
  433.  
  434. /**
  435.  * If $haystack is a full mailbox name and $needle is the mailbox
  436.  * separator character, returns the last part of the mailbox name.
  437.  *
  438.  * @param string haystack full mailbox name to search
  439.  * @param string needle the mailbox separator character
  440.  * @return string the last part of the mailbox name
  441.  * @since 1.0
  442.  */
  443. function readShortMailboxName($haystack$needle{
  444.  
  445.     if ($needle == ''{
  446.         $elem $haystack;
  447.     else {
  448.         $parts explode($needle$haystack);
  449.         $elem array_pop($parts);
  450.         while ($elem == '' && count($parts)) {
  451.             $elem array_pop($parts);
  452.         }
  453.     }
  454.     return$elem );
  455. }
  456.  
  457.  
  458. /**
  459.  * get_location
  460.  *
  461.  * Determines the location to forward to, relative to your server.
  462.  * This is used in HTTP Location: redirects.
  463.  *
  464.  * If set, it uses $config_location_base as the first part of the URL,
  465.  * specifically, the protocol, hostname and port parts. The path is
  466.  * always autodetected.
  467.  *
  468.  * @return string the base url for this SquirrelMail installation
  469.  * @since 1.0
  470.  */
  471. function get_location ({
  472.  
  473.  
  474.     /* Get the path, handle virtual directories */
  475.     if(strpos(php_self()'?')) {
  476.         $path substr(php_self()0strpos(php_self()'?'));
  477.     else {
  478.         $path php_self();
  479.     }
  480.     $path substr($path0strrpos($path'/'));
  481.  
  482.     // proto+host+port are already set in config:
  483.     if !empty($config_location_base) ) {
  484.         return $config_location_base $path ;
  485.     }
  486.     // we computed it before, get it from the session:
  487.     if sqgetGlobalVar('sq_base_url'$full_urlSQ_SESSION) ) {
  488.       return $full_url $path;
  489.     }
  490.     // else: autodetect
  491.  
  492.     /* Check if this is a HTTPS or regular HTTP request. */
  493.     $proto 'http://';
  494.  
  495.     /*
  496.      * If you have 'SSLOptions +StdEnvVars' in your apache config
  497.      *     OR if you have HTTPS=on in your HTTP_SERVER_VARS
  498.      *     OR if you are on port 443
  499.      */
  500.     $getEnvVar getenv('HTTPS');
  501.     if ((isset($getEnvVar&& strcasecmp($getEnvVar'on'=== 0||
  502.         (sqgetGlobalVar('HTTPS'$https_onSQ_SERVER&& strcasecmp($https_on'on'=== 0||
  503.         (sqgetGlobalVar('SERVER_PORT'$server_portSQ_SERVER&&  $server_port == 443)) {
  504.         $proto 'https://';
  505.     }
  506.  
  507.     /* Get the hostname from the Host header or server config. */
  508.     if !sqgetGlobalVar('HTTP_X_FORWARDED_HOST'$hostSQ_SERVER|| empty($host) ) {
  509.         if !sqgetGlobalVar('HTTP_HOST'$hostSQ_SERVER|| empty($host) ) {
  510.             if !sqgetGlobalVar('SERVER_NAME'$hostSQ_SERVER|| empty($host) ) {
  511.                 $host '';
  512.             }
  513.         }
  514.     }
  515.  
  516.     $port '';
  517.     if (strstr($host':')) {
  518.         if (sqgetGlobalVar('SERVER_PORT'$server_portSQ_SERVER)) {
  519.             if (($server_port != 80 && $proto == 'http://'||
  520.                 ($server_port != 443 && $proto == 'https://')) {
  521.                 $port sprintf(':%d'$server_port);
  522.             }
  523.         }
  524.     }
  525.  
  526.     /* this is a workaround for the weird macosx caching that
  527.      * causes Apache to return 16080 as the port number, which causes
  528.      * SM to bail */
  529.  
  530.     if ($imap_server_type == 'macosx' && $port == ':16080'{
  531.         $port '';
  532.     }
  533.  
  534.     /* Fallback is to omit the server name and use a relative */
  535.     /* URI, although this is not RFC 2616 compliant.          */
  536.     $full_url ($host $proto $host $port '');
  537.     sqsession_register($full_url'sq_base_url');
  538.     return $full_url $path;
  539. }
  540.  
  541.  
  542. /**
  543.  * Encrypts password
  544.  *
  545.  * These functions are used to encrypt the password before it is
  546.  * stored in a cookie. The encryption key is generated by
  547.  * OneTimePadCreate();
  548.  *
  549.  * @param string $string the (password)string to encrypt
  550.  * @param string $epad the encryption key
  551.  * @return string the base64-encoded encrypted password
  552.  * @since 1.0
  553.  */
  554. function OneTimePadEncrypt ($string$epad{
  555.     $pad base64_decode($epad);
  556.  
  557.     if (strlen($pad)>0{
  558.         // make sure that pad is longer than string
  559.         while (strlen($string)>strlen($pad)) {
  560.             $pad.=$pad;
  561.         }
  562.     else {
  563.         // FIXME: what should we do when $epad is not base64 encoded or empty.
  564.     }
  565.  
  566.     $encrypted '';
  567.     for ($i 0$i strlen ($string)$i++{
  568.         $encrypted .= chr (ord($string[$i]ord($pad[$i]));
  569.     }
  570.  
  571.     return base64_encode($encrypted);
  572. }
  573.  
  574. /**
  575.  * Decrypts a password from the cookie
  576.  *
  577.  * Decrypts a password from the cookie, encrypted by OneTimePadEncrypt.
  578.  * This uses the encryption key that is stored in the session.
  579.  *
  580.  * @param string $string the string to decrypt
  581.  * @param string $epad the encryption key from the session
  582.  * @return string the decrypted password
  583.  * @since 1.0
  584.  */
  585. function OneTimePadDecrypt ($string$epad{
  586.     $pad base64_decode($epad);
  587.  
  588.     if (strlen($pad)>0{
  589.         // make sure that pad is longer than string
  590.         while (strlen($string)>strlen($pad)) {
  591.             $pad.=$pad;
  592.         }
  593.     else {
  594.         // FIXME: what should we do when $epad is not base64 encoded or empty.
  595.     }
  596.  
  597.     $encrypted base64_decode ($string);
  598.     $decrypted '';
  599.     for ($i 0$i strlen ($encrypted)$i++{
  600.         $decrypted .= chr (ord($encrypted[$i]ord($pad[$i]));
  601.     }
  602.  
  603.     return $decrypted;
  604. }
  605.  
  606.  
  607. /**
  608.  * Randomizes the mt_rand() function.
  609.  *
  610.  * Toss this in strings or integers and it will seed the generator
  611.  * appropriately. With strings, it is better to get them long.
  612.  * Use md5() to lengthen smaller strings.
  613.  *
  614.  * @param mixed $val a value to seed the random number generator. mixed = integer or string.
  615.  * @return void 
  616.  * @since 1.0
  617.  */
  618. function sq_mt_seed($Val{
  619.     /* if mt_getrandmax() does not return a 2^n - 1 number,
  620.        this might not work well.  This uses $Max as a bitmask. */
  621.     $Max mt_getrandmax();
  622.  
  623.     if (is_int($Val)) {
  624.             $Val crc32($Val);
  625.     }
  626.  
  627.     if ($Val 0{
  628.         $Val *= -1;
  629.     }
  630.  
  631.     if ($Val == 0{
  632.         return;
  633.     }
  634.  
  635.     mt_srand(($Val mt_rand(0$Max)) $Max);
  636. }
  637.  
  638.  
  639. /**
  640.  * Init random number generator
  641.  *
  642.  * This function initializes the random number generator fairly well.
  643.  * It also only initializes it once, so you don't accidentally get
  644.  * the same 'random' numbers twice in one session.
  645.  *
  646.  * @return void 
  647.  * @since 1.0
  648.  */
  649. function sq_mt_randomize({
  650.     static $randomized;
  651.  
  652.     if ($randomized{
  653.         return;
  654.     }
  655.  
  656.     /* Global. */
  657.     sqgetGlobalVar('REMOTE_PORT'$remote_portSQ_SERVER);
  658.     sqgetGlobalVar('REMOTE_ADDR'$remote_addrSQ_SERVER);
  659.     sq_mt_seed((int)((double) microtime(1000000));
  660.     sq_mt_seed(md5($remote_port $remote_addr getmypid()));
  661.  
  662.     /* getrusage */
  663.     if (function_exists('getrusage')) {
  664.         /* Avoid warnings with Win32 */
  665.         $dat @getrusage();
  666.         if (isset($dat&& is_array($dat)) {
  667.             $Str '';
  668.             foreach ($dat as $k => $v)
  669.                 {
  670.                     $Str .= $k $v;
  671.                 }
  672.             sq_mt_seed(md5($Str));
  673.         }
  674.     }
  675.  
  676.     if(sqgetGlobalVar('UNIQUE_ID'$unique_idSQ_SERVER)) {
  677.         sq_mt_seed(md5($unique_id));
  678.     }
  679.  
  680.     $randomized 1;
  681. }
  682.  
  683. /**
  684.  * Creates encryption key
  685.  *
  686.  * Creates an encryption key for encrypting the password stored in the cookie.
  687.  * The encryption key itself is stored in the session.
  688.  *
  689.  * Pad must be longer or equal to encoded string length in 1.4.4/1.5.0 and older.
  690.  * @param int $length optional, length of the string to generate
  691.  * @return string the encryption key
  692.  * @since 1.0
  693.  */
  694. function OneTimePadCreate ($length=100{
  695.     sq_mt_randomize();
  696.  
  697.     $pad '';
  698.     for ($i 0$i $length$i++{
  699.         $pad .= chr(mt_rand(0,255));
  700.     }
  701.  
  702.     return base64_encode($pad);
  703. }
  704.  
  705. /**
  706.  * Returns a string showing the size of the message/attachment.
  707.  *
  708.  * @param int $bytes the filesize in bytes
  709.  * @return string the filesize in human readable format
  710.  * @since 1.0
  711.  */
  712. function show_readable_size($bytes{
  713.     $bytes /= 1024;
  714.     $type 'KiB';
  715.  
  716.     if ($bytes 1024 1{
  717.         $bytes /= 1024;
  718.         $type 'MiB';
  719.     }
  720.  
  721.     if ($bytes 10{
  722.         $bytes *= 10;
  723.         settype($bytes'integer');
  724.         $bytes /= 10;
  725.     else {
  726.         settype($bytes'integer');
  727.     }
  728.  
  729.     return $bytes '&nbsp;' $type;
  730. }
  731.  
  732. /**
  733.  * Generates a random string from the character set you pass in
  734.  *
  735.  * @param int $size the length of the string to generate
  736.  * @param string $chars a string containing the characters to use
  737.  * @param int $flags a flag to add a specific set to the characters to use:
  738.  *      Flags:
  739.  *        1 = add lowercase a-z to $chars
  740.  *        2 = add uppercase A-Z to $chars
  741.  *        4 = add numbers 0-9 to $chars
  742.  * @return string the random string
  743.  * @since 1.0
  744.  */
  745. function GenerateRandomString($size$chars$flags 0{
  746.     if ($flags 0x1{
  747.         $chars .= 'abcdefghijklmnopqrstuvwxyz';
  748.     }
  749.     if ($flags 0x2{
  750.         $chars .= 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
  751.     }
  752.     if ($flags 0x4{
  753.         $chars .= '0123456789';
  754.     }
  755.  
  756.     if (($size 1|| (strlen($chars1)) {
  757.         return '';
  758.     }
  759.  
  760.     sq_mt_randomize()/* Initialize the random number generator */
  761.  
  762.     $String '';
  763.     $j strlen$chars 1;
  764.     while (strlen($String$size{
  765.         $String .= $chars{mt_rand(0$j)};
  766.     }
  767.  
  768.     return $String;
  769. }
  770.  
  771. /**
  772.  * Escapes special characters for use in IMAP commands.
  773.  *
  774.  * @param string $str the string to escape
  775.  * @return string the escaped string
  776.  * @since 1.0.3
  777.  */
  778. function quoteimap($str{
  779.     return preg_replace("/([\"\\\\])/""\\\\$1"$str);
  780. }
  781.  
  782. /**
  783.  * Create compose link
  784.  *
  785.  * Returns a link to the compose-page, taking in consideration
  786.  * the compose_in_new and javascript settings.
  787.  * @param string $url the URL to the compose page
  788.  * @param string $text the link text, default "Compose"
  789.  * @param string $target (since 1.4.3) url target
  790.  * @return string a link to the compose page
  791.  * @since 1.4.2
  792.  */
  793. function makeComposeLink($url$text null$target=''{
  794.     global $compose_new_win,$javascript_on$compose_width$compose_height;
  795.  
  796.     if(!$text{
  797.         $text _("Compose");
  798.     }
  799.  
  800.     // if not using "compose in new window", make
  801.     // regular link and be done with it
  802.     if($compose_new_win != '1'{
  803.         return makeInternalLink($url$text$target);
  804.     }
  805.  
  806.     // build the compose in new window link...
  807.  
  808.  
  809.     // if javascript is on, use onclick event to handle it
  810.     if($javascript_on{
  811.         sqgetGlobalVar('base_uri'$base_uriSQ_SESSION);
  812.         $compuri SM_BASE_URI.$url;
  813.         return "<a href=\"javascript:void(0)\" onclick=\"comp_in_new('$compuri','$compose_width','$compose_height')\">$text</a>";
  814.     }
  815.  
  816.     // otherwise, just open new window using regular HTML
  817.     return makeInternalLink($url$text'_blank');
  818. }
  819.  
  820. /**
  821.  * version of fwrite which checks for failure
  822.  * @param resource $fp 
  823.  * @param string $string 
  824.  * @return number of written bytes. false on failure
  825.  * @since 1.4.3
  826.  */
  827. function sq_fwrite($fp$string{
  828.         // write to file
  829.         $count @fwrite($fp,$string);
  830.         // the number of bytes written should be the length of the string
  831.         if($count != strlen($string)) {
  832.                 return FALSE;
  833.         }
  834.  
  835.         return $count;
  836. }
  837.  
  838. /**
  839.  * sq_get_html_translation_table
  840.  *
  841.  * Returns the translation table used by sq_htmlentities()
  842.  *
  843.  * @param integer $table html translation table. Possible values (without quotes):
  844.  *              <ul>
  845.  *                 <li>HTML_ENTITIES - full html entities table defined by charset</li>
  846.  *                 <li>HTML_SPECIALCHARS - html special characters table</li>
  847.  *              </ul>
  848.  * @param integer $quote_style quote encoding style. Possible values (without quotes):
  849.  *               <ul>
  850.  *                 <li>ENT_COMPAT - (default) encode double quotes</li>
  851.  *                 <li>ENT_NOQUOTES -  don't encode double or single quotes</li>
  852.  *                 <li>ENT_QUOTES - encode double and single quotes</li>
  853.  *               </ul>
  854.  * @param string $charset charset used for encoding. default to us-ascii, 'auto' uses $default_charset global value.
  855.  * @return array html translation array
  856.  * @since 1.5.1
  857.  */
  858. function sq_get_html_translation_table($table,$quote_style=ENT_COMPAT,$charset='us-ascii'{
  859.   global $default_charset;
  860.  
  861.   if ($table == HTML_SPECIALCHARS$charset='us-ascii';
  862.  
  863.   // Start array with ampersand
  864.   $sq_html_ent_table array"&" => '&amp;' );
  865.  
  866.   // < and >
  867.   $sq_html_ent_table array_merge($sq_html_ent_table,
  868.                         array("<" => '&lt;',
  869.                               ">" => '&gt;')
  870.                         );
  871.   // double quotes
  872.   if ($quote_style == ENT_COMPAT)
  873.      $sq_html_ent_table array_merge($sq_html_ent_table,
  874.                             array("\"" => '&quot;')
  875.                             );
  876.  
  877.   // double and single quotes
  878.   if ($quote_style == ENT_QUOTES)
  879.      $sq_html_ent_table array_merge($sq_html_ent_table,
  880.                             array("\"" => '&quot;',
  881.                               "'" => '&#39;')
  882.                             );
  883.  
  884.   if ($charset=='auto'$charset=$default_charset;
  885.  
  886.   // add entities that depend on charset
  887.   switch($charset){
  888.   case 'iso-8859-1':
  889.     include_once(SM_PATH 'functions/htmlentities/iso-8859-1.php');
  890.     break;
  891.   case 'utf-8':
  892.     include_once(SM_PATH 'functions/htmlentities/utf-8.php');
  893.     break;
  894.   case 'us-ascii':
  895.   default:
  896.     break;
  897.   }
  898.   // return table
  899.   return $sq_html_ent_table;
  900. }
  901.  
  902. /**
  903.  * sq_htmlentities
  904.  *
  905.  * Convert all applicable characters to HTML entities.
  906.  * Minimal php requirement - v.4.0.5.
  907.  *
  908.  * Function is designed for people that want to use full power of htmlentities() in
  909.  * i18n environment.
  910.  *
  911.  * @param string $string string that has to be sanitized
  912.  * @param integer $quote_style quote encoding style. Possible values (without quotes):
  913.  *               <ul>
  914.  *                 <li>ENT_COMPAT - (default) encode double quotes</li>
  915.  *                 <li>ENT_NOQUOTES - don't encode double or single quotes</li>
  916.  *                 <li>ENT_QUOTES - encode double and single quotes</li>
  917.  *               </ul>
  918.  * @param string $charset charset used for encoding. defaults to 'us-ascii', 'auto' uses $default_charset global value.
  919.  * @return string sanitized string
  920.  * @since 1.5.1
  921.  */
  922. function sq_htmlentities($string,$quote_style=ENT_COMPAT,$charset='us-ascii'{
  923.   // get translation table
  924.   $sq_html_ent_table=sq_get_html_translation_table(HTML_ENTITIES,$quote_style,$charset);
  925.   // convert characters
  926.   return str_replace(array_keys($sq_html_ent_table),array_values($sq_html_ent_table),$string);
  927. }
  928.  
  929. /**
  930.  * Tests if string contains 8bit symbols.
  931.  *
  932.  * If charset is not set, function defaults to default_charset.
  933.  * $default_charset global must be set correctly if $charset is
  934.  * not used.
  935.  * @param string $string tested string
  936.  * @param string $charset charset used in a string
  937.  * @return bool true if 8bit symbols are detected
  938.  * @since 1.5.1 and 1.4.4
  939.  */
  940. function sq_is8bit($string,$charset=''{
  941.     global $default_charset;
  942.  
  943.     if ($charset==''$charset=$default_charset;
  944.  
  945.     /**
  946.      * Don't use \240 in ranges. Sometimes RH 7.2 doesn't like it.
  947.      * Don't use \200-\237 for iso-8859-x charsets. This range
  948.      * stores control symbols in those charsets.
  949.      * Use preg_match instead of ereg in order to avoid problems
  950.      * with mbstring overloading
  951.      */
  952.     if (preg_match("/^iso-8859/i",$charset)) {
  953.         $needle='/\240|[\241-\377]/';
  954.     else {
  955.         $needle='/[\200-\237]|\240|[\241-\377]/';
  956.     }
  957.     return preg_match("$needle",$string);
  958. }
  959.  
  960. /**
  961.  * Replacement of mb_list_encodings function
  962.  *
  963.  * This function provides replacement for function that is available only
  964.  * in php 5.x. Function does not test all mbstring encodings. Only the ones
  965.  * that might be used in SM translations.
  966.  *
  967.  * Supported strings are stored in session in order to reduce number of
  968.  * mb_internal_encoding function calls.
  969.  *
  970.  * If you want to test all mbstring encodings - fill $list_of_encodings
  971.  * array.
  972.  * @return array list of encodings supported by php mbstring extension
  973.  * @since 1.5.1 and 1.4.6
  974.  */
  975. function sq_mb_list_encodings({
  976.     if (function_exists('mb_internal_encoding'))
  977.         return array();
  978.  
  979.     // php 5+ function
  980.     if (function_exists('mb_list_encodings')) {
  981.         $ret mb_list_encodings();
  982.         array_walk($ret,'sq_lowercase_array_vals');
  983.         return $ret;
  984.     }
  985.  
  986.     // don't try to test encodings, if they are already stored in session
  987.     if (sqgetGlobalVar('mb_supported_encodings',$mb_supported_encodings,SQ_SESSION))
  988.         return $mb_supported_encodings;
  989.  
  990.     // save original encoding
  991.     $orig_encoding=mb_internal_encoding();
  992.  
  993.     $list_of_encoding=array(
  994.         'pass',
  995.         'auto',
  996.         'ascii',
  997.         'jis',
  998.         'utf-8',
  999.         'sjis',
  1000.         'euc-jp',
  1001.         'iso-8859-1',
  1002.         'iso-8859-2',
  1003.         'iso-8859-7',
  1004.         'iso-8859-9',
  1005.         'iso-8859-15',
  1006.         'koi8-r',
  1007.         'koi8-u',
  1008.         'big5',
  1009.         'gb2312',
  1010.         'gb18030',
  1011.         'windows-1251',
  1012.         'windows-1255',
  1013.         'windows-1256',
  1014.         'tis-620',
  1015.         'iso-2022-jp',
  1016.         'euc-cn',
  1017.         'euc-kr',
  1018.         'euc-tw',
  1019.         'uhc',
  1020.         'utf7-imap');
  1021.  
  1022.     $supported_encodings=array();
  1023.  
  1024.     foreach ($list_of_encoding as $encoding{
  1025.         // try setting encodings. suppress warning messages
  1026.         if (@mb_internal_encoding($encoding))
  1027.             $supported_encodings[]=$encoding;
  1028.     }
  1029.  
  1030.     // restore original encoding
  1031.     mb_internal_encoding($orig_encoding);
  1032.  
  1033.     // register list in session
  1034.     sqsession_register($supported_encodings,'mb_supported_encodings');
  1035.  
  1036.     return $supported_encodings;
  1037. }
  1038.  
  1039. /**
  1040.  * Callback function used to lowercase array values.
  1041.  * @param string $val array value
  1042.  * @param mixed $key array key
  1043.  * @since 1.5.1 and 1.4.6
  1044.  */
  1045. function sq_lowercase_array_vals(&$val,$key{
  1046.     $val strtolower($val);
  1047. }
  1048.  
  1049.  
  1050. /**
  1051.  * Function returns number of characters in string.
  1052.  *
  1053.  * Returned number might be different from number of bytes in string,
  1054.  * if $charset is multibyte charset. Detection depends on mbstring
  1055.  * functions. If mbstring does not support tested multibyte charset,
  1056.  * vanilla string length function is used.
  1057.  * @param string $str string
  1058.  * @param string $charset charset
  1059.  * @since 1.5.1 and 1.4.6
  1060.  * @return integer number of characters in string
  1061.  */
  1062. function sq_strlen($str$charset=null){
  1063.     // default option
  1064.     if (is_null($charset)) return strlen($str);
  1065.  
  1066.     // lowercase charset name
  1067.     $charset=strtolower($charset);
  1068.  
  1069.     // use automatic charset detection, if function call asks for it
  1070.     if ($charset=='auto'{
  1071.         global $default_charset$squirrelmail_language;
  1072.         set_my_charset();
  1073.         $charset=$default_charset;
  1074.         if ($squirrelmail_language=='ja_JP'$charset='euc-jp';
  1075.     }
  1076.  
  1077.     // Use mbstring only with listed charsets
  1078.     $aList_of_mb_charsets=array('utf-8','big5','gb2312','gb18030','euc-jp','euc-cn','euc-tw','euc-kr');
  1079.  
  1080.     // calculate string length according to charset
  1081.     if (in_array($charset,$aList_of_mb_charsets&& in_array($charset,sq_mb_list_encodings())) {
  1082.         $real_length mb_strlen($str,$charset);
  1083.     else {
  1084.         // own strlen detection code is removed because missing strpos,
  1085.         // strtoupper and substr implementations break string wrapping.
  1086.         $real_length=strlen($str);
  1087.     }
  1088.     return $real_length;
  1089. }
  1090.  
  1091. /**
  1092.  * string padding with multibyte support
  1093.  *
  1094.  * @link http://www.php.net/str_pad
  1095.  * @param string $string original string
  1096.  * @param integer $width padded string width
  1097.  * @param string $pad padding symbols
  1098.  * @param integer $padtype padding type
  1099.  *   (internal php defines, see str_pad() description)
  1100.  * @param string $charset charset used in original string
  1101.  * @return string padded string
  1102.  */
  1103. function sq_str_pad($string$width$pad$padtype$charset=''{
  1104.  
  1105.     $charset strtolower($charset);
  1106.     $padded_string '';
  1107.  
  1108.     switch ($charset{
  1109.     case 'utf-8':
  1110.     case 'big5':
  1111.     case 'gb2312':
  1112.     case 'euc-kr':
  1113.         /*
  1114.          * all multibyte charsets try to increase width value by
  1115.          * adding difference between number of bytes and real length
  1116.          */
  1117.         $width $width sq_strlen($string,$charsetstrlen($string);
  1118.     default:
  1119.         $padded_string=str_pad($string,$width,$pad,$padtype);
  1120.     }
  1121.     return $padded_string;
  1122. }
  1123.  
  1124. /**
  1125.  * Wrapper that is used to switch between vanilla and multibyte substr
  1126.  * functions.
  1127.  * @param string $string 
  1128.  * @param integer $start 
  1129.  * @param integer $length 
  1130.  * @param string $charset 
  1131.  * @return string 
  1132.  * @since 1.5.1
  1133.  * @link http://www.php.net/substr
  1134.  * @link http://www.php.net/mb_substr
  1135.  */
  1136. function sq_substr($string,$start,$length,$charset='auto'{
  1137.     // use automatic charset detection, if function call asks for it
  1138.     static $charset_auto$bUse_mb;
  1139.  
  1140.     if ($charset=='auto'{
  1141.         if (!isset($charset_auto)) {
  1142.             global $default_charset$squirrelmail_language;
  1143.             set_my_charset();
  1144.             $charset=$default_charset;
  1145.             if ($squirrelmail_language=='ja_JP'$charset='euc-jp';
  1146.             $charset_auto $charset;
  1147.         else {
  1148.             $charset $charset_auto;
  1149.         }
  1150.     }
  1151.     $charset strtolower($charset);
  1152.  
  1153.     // in_array call is expensive => do it once and use a static var for
  1154.     // storing the results
  1155.     if (!isset($bUse_mb)) {
  1156.         if (in_array($charset,sq_mb_list_encodings())) {
  1157.             $bUse_mb true;
  1158.         else {
  1159.             $bUse_mb false;
  1160.         }
  1161.     }
  1162.  
  1163.     if ($bUse_mb{
  1164.         return mb_substr($string,$start,$length,$charset);
  1165.     }
  1166.     // TODO: add mbstring independent code
  1167.  
  1168.     // use vanilla string functions as last option
  1169.     return substr($string,$start,$length);
  1170. }
  1171.  
  1172. /**
  1173.  * Wrapper that is used to switch between vanilla and multibyte strpos
  1174.  * functions.
  1175.  * @param string $haystack 
  1176.  * @param mixed $needle 
  1177.  * @param integer $offset 
  1178.  * @param string $charset 
  1179.  * @return string 
  1180.  * @since 1.5.1
  1181.  * @link http://www.php.net/strpos
  1182.  * @link http://www.php.net/mb_strpos
  1183.  */
  1184. function sq_strpos($haystack,$needle,$offset,$charset='auto'{
  1185.     // use automatic charset detection, if function call asks for it
  1186.     static $charset_auto$bUse_mb;
  1187.  
  1188.     if ($charset=='auto'{
  1189.         if (!isset($charset_auto)) {
  1190.             global $default_charset$squirrelmail_language;
  1191.             set_my_charset();
  1192.             $charset=$default_charset;
  1193.             if ($squirrelmail_language=='ja_JP'$charset='euc-jp';
  1194.             $charset_auto $charset;
  1195.         else {
  1196.             $charset $charset_auto;
  1197.         }
  1198.     }
  1199.     $charset strtolower($charset);
  1200.  
  1201.     // in_array call is expensive => do it once and use a static var for
  1202.     // storing the results
  1203.     if (!isset($bUse_mb)) {
  1204.         if (in_array($charset,sq_mb_list_encodings())) {
  1205.             $bUse_mb true;
  1206.         else {
  1207.             $bUse_mb false;
  1208.         }
  1209.     }
  1210.     if ($bUse_mb{
  1211.         return mb_strpos($haystack,$needle,$offset,$charset);
  1212.     }
  1213.     // TODO: add mbstring independent code
  1214.  
  1215.     // use vanilla string functions as last option
  1216.     return strpos($haystack,$needle,$offset);
  1217. }
  1218.  
  1219. /**
  1220.  * Wrapper that is used to switch between vanilla and multibyte strtoupper
  1221.  * functions.
  1222.  * @param string $string 
  1223.  * @param string $charset 
  1224.  * @return string 
  1225.  * @since 1.5.1
  1226.  * @link http://www.php.net/strtoupper
  1227.  * @link http://www.php.net/mb_strtoupper
  1228.  */
  1229. function sq_strtoupper($string,$charset='auto'{
  1230.     // use automatic charset detection, if function call asks for it
  1231.     static $charset_auto$bUse_mb;
  1232.  
  1233.     if ($charset=='auto'{
  1234.         if (!isset($charset_auto)) {
  1235.             global $default_charset$squirrelmail_language;
  1236.             set_my_charset();
  1237.             $charset=$default_charset;
  1238.             if ($squirrelmail_language=='ja_JP'$charset='euc-jp';
  1239.             $charset_auto $charset;
  1240.         else {
  1241.             $charset $charset_auto;
  1242.         }
  1243.     }
  1244.     $charset strtolower($charset);
  1245.  
  1246.     // in_array call is expensive => do it once and use a static var for
  1247.     // storing the results
  1248.     if (!isset($bUse_mb)) {
  1249.         if (function_exists('mb_strtoupper'&&
  1250.             in_array($charset,sq_mb_list_encodings())) {
  1251.             $bUse_mb true;
  1252.         else {
  1253.             $bUse_mb false;
  1254.         }
  1255.     }
  1256.  
  1257.     if ($bUse_mb{
  1258.         return mb_strtoupper($string,$charset);
  1259.     }
  1260.     // TODO: add mbstring independent code
  1261.  
  1262.     // use vanilla string functions as last option
  1263.     return strtoupper($string);
  1264. }
  1265.  
  1266. /**
  1267.  * Counts 8bit bytes in string
  1268.  * @param string $string tested string
  1269.  * @return integer number of 8bit bytes
  1270.  */
  1271. function sq_count8bit($string{
  1272.     $count=0;
  1273.     for ($i=0$i<strlen($string)$i++{
  1274.         if (ord($string[$i]127$count++;
  1275.     }
  1276.     return $count;
  1277. }
  1278.  
  1279. /**
  1280.  * Callback function to trim whitespace from a value, to be used in array_walk
  1281.  * @param string $value value to trim
  1282.  * @since 1.5.2 and 1.4.7
  1283.  */
  1284. function sq_trim_value &$value {
  1285.     $value trim($value);
  1286. }

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