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.     <