/**
  * Convert from charset used by LDAP server to charset used by translation
  *
  * Output must be sanitized.
  * @param string string that has to be converted
  * @return string converted string
  */
 function charset_decode($str)
 {
     global $default_charset;
     if ($this->charset != $default_charset) {
         return charset_convert($this->charset, $str, $default_charset, false);
     } else {
         return $str;
     }
 }
Пример #2
0
/**
 * Decodes headers
 *
 * This functions decode strings that is encoded according to
 * RFC1522 (MIME Part Two: Message Header Extensions for Non-ASCII Text).
 * Patched by Christian Schmidt <*****@*****.**>  23/03/2002
 */
function decodeHeader($string, $utfencode = true, $htmlsave = true, $decide = false)
{
    global $languages, $squirrelmail_language, $default_charset;
    if (is_array($string)) {
        $string = implode("\n", $string);
    }
    if (isset($languages[$squirrelmail_language]['XTRA_CODE']) && function_exists($languages[$squirrelmail_language]['XTRA_CODE'])) {
        $string = $languages[$squirrelmail_language]['XTRA_CODE']('decodeheader', $string);
        // Do we need to return at this point?
        // return $string;
    }
    $i = 0;
    $iLastMatch = -2;
    $encoded = false;
    $aString = explode(' ', $string);
    $ret = '';
    foreach ($aString as $chunk) {
        if ($encoded && $chunk === '') {
            continue;
        } elseif ($chunk === '') {
            $ret .= ' ';
            continue;
        }
        $encoded = false;
        /* if encoded words are not separated by a linear-space-white we still catch them */
        $j = $i - 1;
        while ($match = preg_match('/^(.*)=\\?([^?]*)\\?(Q|B)\\?([^?]*)\\?=(.*)$/Ui', $chunk, $res)) {
            /* if the last chunk isn't an encoded string then put back the space, otherwise don't */
            if ($iLastMatch !== $j) {
                if ($htmlsave) {
                    $ret .= '&#32;';
                } else {
                    $ret .= ' ';
                }
            }
            $iLastMatch = $i;
            $j = $i;
            if ($htmlsave) {
                $ret .= htmlspecialchars($res[1]);
            } else {
                $ret .= $res[1];
            }
            $encoding = ucfirst($res[3]);
            /* decide about valid decoding */
            if ($decide && is_conversion_safe($res[2])) {
                $can_be_encoded = true;
            } else {
                $can_be_encoded = false;
            }
            switch ($encoding) {
                case 'B':
                    $replace = base64_decode($res[4]);
                    if ($can_be_encoded) {
                        // string is converted from one charset to another. sanitizing depends on $htmlsave
                        $replace = charset_convert($res[2], $replace, $default_charset, $htmlsave);
                    } elseif ($utfencode) {
                        // string is converted to htmlentities and sanitized
                        $replace = charset_decode($res[2], $replace);
                    } elseif ($htmlsave) {
                        // string is not converted, but still sanitized
                        $replace = htmlspecialchars($replace);
                    }
                    $ret .= $replace;
                    break;
                case 'Q':
                    $replace = str_replace('_', ' ', $res[4]);
                    $replace = preg_replace('/=([0-9a-f]{2})/ie', 'chr(hexdec("\\1"))', $replace);
                    if ($can_be_encoded) {
                        // string is converted from one charset to another. sanitizing depends on $htmlsave
                        $replace = charset_convert($res[2], $replace, $default_charset, $htmlsave);
                    } elseif ($utfencode) {
                        // string is converted to html entities and sanitized
                        $replace = charset_decode($res[2], $replace);
                    } elseif ($htmlsave) {
                        // string is not converted, but still sanizited
                        $replace = htmlspecialchars($replace);
                    }
                    $ret .= $replace;
                    break;
                default:
                    break;
            }
            $chunk = $res[5];
            $encoded = true;
        }
        if (!$encoded) {
            if ($htmlsave) {
                $ret .= '&#32;';
            } else {
                $ret .= ' ';
            }
        }
        if (!$encoded && $htmlsave) {
            $ret .= htmlspecialchars($chunk);
        } else {
            $ret .= $chunk;
        }
        ++$i;
    }
    /* remove the first added space */
    if ($ret) {
        if ($htmlsave) {
            $ret = substr($ret, 5);
        } else {
            $ret = substr($ret, 1);
        }
    }
    return $ret;
}
Пример #3
0
/**
 * Check for UTF-8 URLs; Internet Explorer produces these if you
 * type non-ASCII chars in the URL bar or follow unescaped links.
 * Requires urldecoded pagename.
 * Fixes sf.net bug #953949
 *
 * src: languages/Language.php:checkTitleEncoding() from mediawiki
 */
function fixTitleEncoding($s)
{
    global $charset;
    $s = trim($s);
    // print a warning?
    if (empty($s)) {
        return $s;
    }
    $ishigh = preg_match('/[\\x80-\\xff]/', $s);
    /*
    $isutf = ($ishigh ? preg_match( '/^([\x00-\x7f]|[\xc0-\xdf][\x80-\xbf]|' .
                                    '[\xe0-\xef][\x80-\xbf]{2}|[\xf0-\xf7][\x80-\xbf]{3})+$/', $s ) : true );
    */
    $isutf = $ishigh ? isUtf8String($s) : true;
    $locharset = strtolower($charset);
    if ($locharset != "utf-8" and $ishigh and $isutf) {
        $s = charset_convert('UTF-8', $locharset, $s);
    }
    if ($locharset == "utf-8" and $ishigh and !$isutf) {
        return utf8_encode($s);
    }
    // Other languages can safely leave this function, or replace
    // it with one to detect and convert another legacy encoding.
    return $s;
}
Пример #4
0
function newMail($mailbox = '', $passed_id = '', $passed_ent_id = '', $action = '', $session = '')
{
    global $editor_size, $default_use_priority, $body, $idents, $use_signature, $composesession, $data_dir, $username, $username, $key, $imapServerAddress, $imapPort, $compose_messages, $composeMessage, $body_quote;
    global $languages, $squirrelmail_language, $default_charset;
    /*
     * Set $default_charset to correspond with the user's selection
     * of language interface. $default_charset global is not correct,
     * if message is composed in new window.
     */
    set_my_charset();
    $send_to = $send_to_cc = $send_to_bcc = $subject = $identity = '';
    $mailprio = 3;
    if ($passed_id) {
        $imapConnection = sqimap_login($username, $key, $imapServerAddress, $imapPort, 0);
        sqimap_mailbox_select($imapConnection, $mailbox);
        $message = sqimap_get_message($imapConnection, $passed_id, $mailbox);
        $body = '';
        if ($passed_ent_id) {
            /* redefine the messsage in case of message/rfc822 */
            $message = $message->getEntity($passed_ent_id);
            /* message is an entity which contains the envelope and type0=message
             * and type1=rfc822. The actual entities are childs from
             * $message->entities[0]. That's where the encoding and is located
             */
            $entities = $message->entities[0]->findDisplayEntity(array(), $alt_order = array('text/plain'));
            if (!count($entities)) {
                $entities = $message->entities[0]->findDisplayEntity(array(), $alt_order = array('text/plain', 'html/plain'));
            }
            $orig_header = $message->rfc822_header;
            /* here is the envelope located */
            /* redefine the message for picking up the attachments */
            $message = $message->entities[0];
        } else {
            $entities = $message->findDisplayEntity(array(), $alt_order = array('text/plain'));
            if (!count($entities)) {
                $entities = $message->findDisplayEntity(array(), $alt_order = array('text/plain', 'html/plain'));
            }
            $orig_header = $message->rfc822_header;
        }
        $encoding = $message->header->encoding;
        $type0 = $message->type0;
        $type1 = $message->type1;
        foreach ($entities as $ent) {
            $msg = $message->getEntity($ent);
            $type0 = $msg->type0;
            $type1 = $msg->type1;
            $unencoded_bodypart = mime_fetch_body($imapConnection, $passed_id, $ent);
            $body_part_entity = $message->getEntity($ent);
            $bodypart = decodeBody($unencoded_bodypart, $body_part_entity->header->encoding);
            if ($type1 == 'html') {
                $bodypart = str_replace("\n", ' ', $bodypart);
                $bodypart = preg_replace(array('/<\\/?p>/i', '/<div><\\/div>/i', '/<br\\s*(\\/)*>/i', '/<\\/?div>/i'), "\n", $bodypart);
                $bodypart = str_replace(array('&nbsp;', '&gt;', '&lt;'), array(' ', '>', '<'), $bodypart);
                $bodypart = strip_tags($bodypart);
            }
            if (isset($languages[$squirrelmail_language]['XTRA_CODE']) && function_exists($languages[$squirrelmail_language]['XTRA_CODE'] . '_decode')) {
                if (mb_detect_encoding($bodypart) != 'ASCII') {
                    $bodypart = call_user_func($languages[$squirrelmail_language]['XTRA_CODE'] . '_decode', $bodypart);
                }
            }
            if (isset($body_part_entity->header->parameters['charset'])) {
                $actual = $body_part_entity->header->parameters['charset'];
            } else {
                $actual = 'us-ascii';
            }
            if ($actual && is_conversion_safe($actual) && $actual != $default_charset) {
                $bodypart = charset_convert($actual, $bodypart, $default_charset, false);
            }
            $body .= $bodypart;
        }
        if ($default_use_priority) {
            $mailprio = substr($orig_header->priority, 0, 1);
            if (!$mailprio) {
                $mailprio = 3;
            }
        } else {
            $mailprio = '';
        }
        //ClearAttachments($session);
        $identity = '';
        $from_o = $orig_header->from;
        if (is_array($from_o)) {
            if (isset($from_o[0])) {
                $from_o = $from_o[0];
            }
        }
        if (is_object($from_o)) {
            $orig_from = $from_o->getAddress();
        } else {
            $orig_from = '';
        }
        $identities = array();
        if (count($idents) > 1) {
            foreach ($idents as $nr => $data) {
                $enc_from_name = '"' . $data['full_name'] . '" <' . $data['email_address'] . '>';
                if ($enc_from_name == $orig_from) {
                    $identity = $nr;
                    break;
                }
                $identities[] = $enc_from_name;
            }
            $identity_match = $orig_header->findAddress($identities);
            if ($identity_match) {
                $identity = $identity_match;
            }
        }
        switch ($action) {
            case 'draft':
                $use_signature = FALSE;
                $composeMessage->rfc822_header = $orig_header;
                $send_to = decodeHeader($orig_header->getAddr_s('to'), false, false, true);
                $send_to_cc = decodeHeader($orig_header->getAddr_s('cc'), false, false, true);
                $send_to_bcc = decodeHeader($orig_header->getAddr_s('bcc'), false, false, true);
                $send_from = $orig_header->getAddr_s('from');
                $send_from_parts = new AddressStructure();
                $send_from_parts = $orig_header->parseAddress($send_from);
                $send_from_add = $send_from_parts->mailbox . '@' . $send_from_parts->host;
                $identities = get_identities();
                if (count($identities) > 0) {
                    foreach ($identities as $iddata) {
                        if ($send_from_add == $iddata['email_address']) {
                            $identity = $iddata['index'];
                            break;
                        }
                    }
                }
                $subject = decodeHeader($orig_header->subject, false, false, true);
                /* remember the references and in-reply-to headers in case of an reply */
                $composeMessage->rfc822_header->more_headers['References'] = $orig_header->references;
                $composeMessage->rfc822_header->more_headers['In-Reply-To'] = $orig_header->in_reply_to;
                // rewrap the body to clean up quotations and line lengths
                sqBodyWrap($body, $editor_size);
                $composeMessage = getAttachments($message, $composeMessage, $passed_id, $entities, $imapConnection);
                break;
            case 'edit_as_new':
                $send_to = decodeHeader($orig_header->getAddr_s('to'), false, false, true);
                $send_to_cc = decodeHeader($orig_header->getAddr_s('cc'), false, false, true);
                $send_to_bcc = decodeHeader($orig_header->getAddr_s('bcc'), false, false, true);
                $subject = decodeHeader($orig_header->subject, false, false, true);
                $mailprio = $orig_header->priority;
                $orig_from = '';
                $composeMessage = getAttachments($message, $composeMessage, $passed_id, $entities, $imapConnection);
                // rewrap the body to clean up quotations and line lengths
                sqBodyWrap($body, $editor_size);
                break;
            case 'forward':
                $send_to = '';
                $subject = getforwardSubject(decodeHeader($orig_header->subject, false, false, true));
                $body = getforwardHeader($orig_header) . $body;
                // the logic for calling sqUnWordWrap here would be to allow the browser to wrap the lines
                // forwarded message text should be as undisturbed as possible, so commenting out this call
                // sqUnWordWrap($body);
                $composeMessage = getAttachments($message, $composeMessage, $passed_id, $entities, $imapConnection);
                //add a blank line after the forward headers
                $body = "\n" . $body;
                break;
            case 'forward_as_attachment':
                $subject = getforwardSubject(decodeHeader($orig_header->subject, false, false, true));
                $composeMessage = getMessage_RFC822_Attachment($message, $composeMessage, $passed_id, $passed_ent_id, $imapConnection);
                $body = '';
                break;
            case 'reply_all':
                if (isset($orig_header->mail_followup_to) && $orig_header->mail_followup_to) {
                    $send_to = $orig_header->getAddr_s('mail_followup_to');
                } else {
                    $send_to_cc = replyAllString($orig_header);
                    $send_to_cc = decodeHeader($send_to_cc, false, false, true);
                }
            case 'reply':
                // skip this if send_to was already set right above here
                if (!$send_to) {
                    $send_to = $orig_header->reply_to;
                    if (is_array($send_to) && count($send_to)) {
                        $send_to = $orig_header->getAddr_s('reply_to');
                    } else {
                        if (is_object($send_to)) {
                            /* unneccesarry, just for failsafe purpose */
                            $send_to = $orig_header->getAddr_s('reply_to');
                        } else {
                            $send_to = $orig_header->getAddr_s('from');
                        }
                    }
                }
                $send_to = decodeHeader($send_to, false, false, true);
                $subject = decodeHeader($orig_header->subject, false, false, true);
                $subject = str_replace('"', "'", $subject);
                $subject = trim($subject);
                if (substr(strtolower($subject), 0, 3) != 're:') {
                    $subject = 'Re: ' . $subject;
                }
                /* this corrects some wrapping/quoting problems on replies */
                $rewrap_body = explode("\n", $body);
                $from = is_array($orig_header->from) ? $orig_header->from[0] : $orig_header->from;
                $body = '';
                $strip_sigs = getPref($data_dir, $username, 'strip_sigs');
                foreach ($rewrap_body as $line) {
                    if ($strip_sigs && substr($line, 0, 3) == '-- ') {
                        break;
                    }
                    if (preg_match("/^(>+)/", $line, $matches)) {
                        $gt = $matches[1];
                        $body .= $body_quote . str_replace("\n", "\n{$body_quote}{$gt} ", rtrim($line)) . "\n";
                    } else {
                        $body .= $body_quote . (!empty($body_quote) ? ' ' : '') . str_replace("\n", "\n{$body_quote}" . (!empty($body_quote) ? ' ' : ''), rtrim($line)) . "\n";
                    }
                }
                //rewrap the body to clean up quotations and line lengths
                $body = sqBodyWrap($body, $editor_size);
                $body = getReplyCitation($from, $orig_header->date) . $body;
                $composeMessage->reply_rfc822_header = $orig_header;
                break;
            default:
                break;
        }
        $compose_messages[$session] = $composeMessage;
        sqsession_register($compose_messages, 'compose_messages');
        session_write_close();
        sqimap_logout($imapConnection);
    }
    $ret = array('send_to' => $send_to, 'send_to_cc' => $send_to_cc, 'send_to_bcc' => $send_to_bcc, 'subject' => $subject, 'mailprio' => $mailprio, 'body' => $body, 'identity' => $identity);
    return $ret;
}
Пример #5
0
/**
 * Security alert! We should not allow to import config.ini into our wiki (or from a sister wiki?)
 * because the sql passwords are in plaintext there. And the webserver must be able to read it.
 * Detected by Santtu Jarvi.
 */
function LoadFile(&$request, $filename, $text = false, $mtime = false)
{
    if (preg_match("/config\$/", dirname($filename)) and preg_match("/config.*\\.ini/", basename($filename))) {
        trigger_error(sprintf("Refused to load %s", $filename), E_USER_WARNING);
        return;
    }
    if (!is_string($text)) {
        // Read the file.
        $stat = stat($filename);
        $mtime = $stat[9];
        $text = implode("", file($filename));
    }
    if (!$request->getArg('start_debug')) {
        @set_time_limit(30);
    } else {
        @set_time_limit(240);
    }
    // FIXME: basename("filewithnoslashes") seems to return garbage sometimes.
    $basename = basename("/dummy/" . $filename);
    if (!$mtime) {
        $mtime = time();
    }
    // Last resort.
    // DONE: check source - target charset for content and pagename
    // but only for pgsrc'ed content, not from the browser.
    $default_pagename = rawurldecode($basename);
    if ($parts = ParseMimeifiedPages($text)) {
        if (count($parts) > 1) {
            $overwrite = $request->getArg('overwrite');
        }
        usort($parts, 'SortByPageVersion');
        foreach ($parts as $pageinfo) {
            // force overwrite
            if (count($parts) > 1) {
                $request->setArg('overwrite', 1);
            }
            SavePage($request, $pageinfo, sprintf(_("MIME file %s"), $filename), $basename);
        }
        if (count($parts) > 1) {
            if ($overwrite) {
                $request->setArg('overwrite', $overwrite);
            } else {
                unset($request->_args['overwrite']);
            }
        }
    } else {
        if ($pageinfo = ParseSerializedPage($text, $default_pagename, $request->getUser())) {
            SavePage($request, $pageinfo, sprintf(_("Serialized file %s"), $filename), $basename);
        } else {
            // plain old file
            $user = $request->getUser();
            $file_charset = 'utf-8';
            // compare to target charset
            if ($file_charset != strtolower($GLOBALS['charset'])) {
                $text = charset_convert($file_charset, $GLOBALS['charset'], $text);
                $default_pagename = charset_convert($file_charset, $GLOBALS['charset'], $default_pagename);
            }
            // Assume plain text file.
            $pageinfo = array('pagename' => $default_pagename, 'pagedata' => array(), 'versiondata' => array('author' => $user->getId()), 'content' => preg_replace('/[ \\t\\r]*\\n/', "\n", chop($text)));
            SavePage($request, $pageinfo, sprintf(_("plain file %s"), $filename), $basename);
        }
    }
}
Пример #6
0
function ParseMimeifiedPages($data)
{
    if (!($headers = ParseRFC822Headers($data)) || empty($headers['content-type'])) {
        //trigger_error( sprintf(_("Can't find %s"),'content-type header'),
        //               E_USER_WARNING );
        return false;
    }
    $typeheader = $headers['content-type'];
    if (!(list($type, $subtype, $params) = ParseMimeContentType($typeheader))) {
        trigger_error(sprintf("Can't parse %s: (%s)", 'content-type', $typeheader), E_USER_WARNING);
        return false;
    }
    if ("{$type}/{$subtype}" == 'multipart/mixed') {
        return ParseMimeMultipart($data, $params['boundary']);
    } else {
        if ("{$type}/{$subtype}" != 'application/x-phpwiki') {
            trigger_error(sprintf("Bad %s", "content-type: {$type}/{$subtype}"), E_USER_WARNING);
            return false;
        }
    }
    // FIXME: more sanity checking?
    $page = array();
    $pagedata = array();
    $versiondata = array();
    if (isset($headers['date'])) {
        $pagedata['date'] = strtotime($headers['date']);
    }
    //DONE: support owner and acl
    foreach ($params as $key => $value) {
        if (empty($value)) {
            continue;
        }
        $value = rawurldecode($value);
        switch ($key) {
            case 'pagename':
            case 'version':
                $page[$key] = $value;
                break;
            case 'flags':
                if (preg_match('/PAGE_LOCKED/', $value)) {
                    $pagedata['locked'] = 'yes';
                }
                if (ENABLE_EXTERNAL_PAGES && preg_match('/EXTERNAL_PAGE/', $value)) {
                    $pagedata['external'] = 'yes';
                }
                break;
            case 'owner':
            case 'created':
            case 'hits':
                $pagedata[$key] = $value;
                break;
            case 'acl':
            case 'perm':
                if (class_exists('PagePermission')) {
                    $pagedata['perm'] = ParseMimeifiedPerm($value);
                }
                break;
            case 'lastmodified':
                $versiondata['mtime'] = $value;
                break;
            case 'author':
            case 'author_id':
            case 'summary':
            case 'markup':
            case 'pagetype':
                $versiondata[$key] = $value;
                break;
        }
    }
    // FIXME: do we need to try harder to find a pagename if we
    //        haven't got one yet?
    if (!isset($versiondata['author'])) {
        global $request;
        if (is_object($request)) {
            $user = $request->getUser();
            $versiondata['author'] = $user->getId();
            //FIXME:?
        }
    }
    $encoding = strtolower($headers['content-transfer-encoding']);
    if ($encoding == 'quoted-printable') {
        $data = QuotedPrintableDecode($data);
    } else {
        if ($encoding && $encoding != 'binary') {
            ExitWiki(sprintf("Unknown %s", 'encoding type: $encoding'));
        }
    }
    if (empty($params['charset'])) {
        $params['charset'] = 'utf-8';
    }
    // compare to target charset
    if (strtolower($params['charset']) != strtolower($GLOBALS['charset'])) {
        $data = charset_convert($params['charset'], $GLOBALS['charset'], $data);
        //$page['pagename'] = charset_convert($params['charset'], $GLOBALS['charset'], $page['pagename']);
        if (isset($versiondata['summary'])) {
            $versiondata['summary'] = charset_convert($params['charset'], $GLOBALS['charset'], $versiondata['summary']);
        }
    }
    $data .= GenerateFootnotesFromRefs($params);
    $page['content'] = preg_replace('/[ \\t\\r]*\\n/', "\n", chop($data));
    $page['pagedata'] = $pagedata;
    $page['versiondata'] = $versiondata;
    return array($page);
}
Пример #7
0
function register_changes()
{
    global $CONFIG;
    if (count($_POST) > 0) {
        if (isset($_POST['check'])) {
            $doconvert = 0;
        } else {
            if (isset($_POST['convert'])) {
                $doconvert = 1;
            }
        }
        if (isset($doconvert)) {
            $charsetin = $_POST['charset_in'];
            $charsetout = $_POST['charset_out'];
            // elements of the database that need converting
            // the first element in the array is the id name of the table
            $affected_elements = array($CONFIG['TABLE_ALBUMS'] => array('aid', 'title', 'description', 'keyword'), $CONFIG['TABLE_PICTURES'] => array('pid', 'title', 'caption', 'keywords'), $CONFIG['TABLE_COMMENTS'] => array('msg_id', 'msg_author', 'msg_body'), $CONFIG['TABLE_CATEGORIES'] => array('cid', 'name', 'description'), $CONFIG['TABLE_USERGROUPS'] => array('group_id', 'group_name'), $CONFIG['TABLE_USERS'] => array('user_id', 'user_name', 'user_password', 'user_profile1', 'user_profile2', 'user_profile3', 'user_profile4', 'user_profile5', 'user_profile6'));
            header("Content-Type: text/html; charset={$charsetout}");
            //echo $charsetin . " " .$charsetout;
            if (!$doconvert) {
                $windowtitle = "Charset Manager - 2/3 - Check";
                $title = "2/3 - Checking conversion from <b>{$charsetin}</b> to <b>{$charsetout}</b>";
            } else {
                if ($doconvert) {
                    $windowtitle = "Charset Manager - 3/3 - Conversion";
                    $title = "3/3 - Converting from <b>{$charsetin}</b> to <b>{$charsetout}</b>";
                }
            }
            html_header($windowtitle, $charsetout);
            html_logo();
            echo "<h1>{$title}</h1>";
            echo '<table border="1" class="charsetchecktable" cellpadding="3" cellspacing="0"  style="margin:auto;">';
            if (!$doconvert) {
                echo '<p class="warning">You <b>must check</b> that all the cells in <span class="check">blue</span> are displayed properly.</p>';
            }
            echo "<tr><th>String</th><th>Table</th><th>Column</th><th>Id</th><th>" . ($doconvert ? "Result" : "Query") . "</th></tr>";
            foreach ($affected_elements as $table => $columns) {
                for ($i = 1; $i < count($columns); ++$i) {
                    charset_convert($table, $columns[$i], $columns[0], $charsetin, $charsetout, $doconvert);
                }
            }
            echo '</table>';
            if (!$doconvert) {
                echo '<form action="' . $_SERVER['PHP_SELF'] . '" method="post" name="cpgform" id="cpgform">';
                echo '<input type="hidden" name="charset_in" value="' . $charsetin . "\" />\n";
                echo '<input type="hidden" name="charset_out" value="' . $charsetout . "\" />\n";
                echo <<<EOT
    <div class="warning">
    <p>Before converting you <b>must</b>:</p>
    <ol>
    <li>Make a backup of your database. <span class="bigwarning">A malfunction of this script will result in the partial or complete loss or corruption of your comments and other string data containing non-ascii characters.</span></li>
    <li>Check that all the strings above in <span class="check">blue</span> are displayed correctly.
    </ol>
    </div>
EOT;
                echo '<div class="input"><input type="submit" class="button" name="convert" value="Convert" /></div>';
                echo '</form>';
            }
            if ($doconvert) {
                // the script has succeeded (hopefully): we change the charset accordingly in the database
                set_config('charset', $charsetout);
                echo <<<EOT
                    <div class="warning">
                    <p>The conversion has been carried out.<br/>
                If you did not get any errors, for security reasons, you may now <b>remove the file charsetmgr.php</b>, or make it unaccessible, since you will not need this file anymore.<br/>
                    You may now <a href="index.php">proceed to the main page.</a>
                    </p>
                    </div>
EOT;
            }
            html_footer();
            exit;
        }
    }
}
Пример #8
0
function newMail($mailbox = '', $passed_id = '', $passed_ent_id = '', $action = '', $session = '')
{
    global $editor_size, $default_use_priority, $body, $idents, $use_signature, $data_dir, $username, $key, $imapServerAddress, $imapPort, $imap_stream_options, $composeMessage, $body_quote, $request_mdn, $request_dr, $mdn_user_support, $languages, $squirrelmail_language, $default_charset, $do_not_reply_to_self;
    /*
     * Set $default_charset to correspond with the user's selection
     * of language interface. $default_charset global is not correct,
     * if message is composed in new window.
     */
    set_my_charset();
    $send_to = $send_to_cc = $send_to_bcc = $subject = $identity = '';
    $mailprio = 3;
    if ($passed_id) {
        $imapConnection = sqimap_login($username, false, $imapServerAddress, $imapPort, 0, $imap_stream_options);
        sqimap_mailbox_select($imapConnection, $mailbox);
        $message = sqimap_get_message($imapConnection, $passed_id, $mailbox);
        $body = '';
        if ($passed_ent_id) {
            /* redefine the messsage in case of message/rfc822 */
            $message = $message->getEntity($passed_ent_id);
            /* message is an entity which contains the envelope and type0=message
             * and type1=rfc822. The actual entities are childs from
             * $message->entities[0]. That's where the encoding and is located
             */
            $entities = $message->entities[0]->findDisplayEntity(array(), $alt_order = array('text/plain'));
            if (!count($entities)) {
                $entities = $message->entities[0]->findDisplayEntity(array(), $alt_order = array('text/plain', 'text/html'));
            }
            $orig_header = $message->rfc822_header;
            /* here is the envelope located */
            /* redefine the message for picking up the attachments */
            $message = $message->entities[0];
        } else {
            $entities = $message->findDisplayEntity(array(), $alt_order = array('text/plain'));
            if (!count($entities)) {
                $entities = $message->findDisplayEntity(array(), $alt_order = array('text/plain', 'text/html'));
            }
            $orig_header = $message->rfc822_header;
        }
        $type0 = $message->type0;
        $type1 = $message->type1;
        foreach ($entities as $ent) {
            $msg = $message->getEntity($ent);
            $type0 = $msg->type0;
            $type1 = $msg->type1;
            $unencoded_bodypart = mime_fetch_body($imapConnection, $passed_id, $ent);
            $body_part_entity = $message->getEntity($ent);
            $bodypart = decodeBody($unencoded_bodypart, $body_part_entity->header->encoding);
            if ($type1 == 'html') {
                $bodypart = str_replace("\n", ' ', $bodypart);
                $bodypart = preg_replace(array('/<\\/?p>/i', '/<div><\\/div>/i', '/<br\\s*(\\/)*>/i', '/<\\/?div>/i'), "\n", $bodypart);
                $bodypart = str_replace(array('&nbsp;', '&gt;', '&lt;'), array(' ', '>', '<'), $bodypart);
                $bodypart = strip_tags($bodypart);
            }
            if (isset($languages[$squirrelmail_language]['XTRA_CODE']) && function_exists($languages[$squirrelmail_language]['XTRA_CODE'] . '_decode')) {
                if (mb_detect_encoding($bodypart) != 'ASCII') {
                    $bodypart = call_user_func($languages[$squirrelmail_language]['XTRA_CODE'] . '_decode', $bodypart);
                }
            }
            // charset encoding in compose form stuff
            if (isset($body_part_entity->header->parameters['charset'])) {
                $actual = $body_part_entity->header->parameters['charset'];
            } else {
                $actual = 'us-ascii';
            }
            if ($actual && is_conversion_safe($actual) && $actual != $default_charset) {
                $bodypart = charset_convert($actual, $bodypart, $default_charset, false);
            }
            // end of charset encoding in compose
            $body .= $bodypart;
        }
        if ($default_use_priority) {
            $mailprio = substr($orig_header->priority, 0, 1);
            if (!$mailprio) {
                $mailprio = 3;
            }
        } else {
            $mailprio = '';
        }
        $from_o = $orig_header->from;
        if (is_array($from_o)) {
            if (isset($from_o[0])) {
                $from_o = $from_o[0];
            }
        }
        if (is_object($from_o)) {
            $orig_from = $from_o->getAddress();
        } else {
            $orig_from = '';
        }
        $identities = array();
        if (count($idents) > 1) {
            foreach ($idents as $nr => $data) {
                $enc_from_name = '"' . $data['full_name'] . '" <' . $data['email_address'] . '>';
                $identities[] = $enc_from_name;
            }
            $identity_match = $orig_header->findAddress($identities);
            if ($identity_match !== FALSE) {
                $identity = $identity_match;
            }
        }
        switch ($action) {
            case 'draft':
                $use_signature = FALSE;
                $composeMessage->rfc822_header = $orig_header;
                $send_to = decodeHeader($orig_header->getAddr_s('to'), false, false, true);
                $send_to_cc = decodeHeader($orig_header->getAddr_s('cc'), false, false, true);
                $send_to_bcc = decodeHeader($orig_header->getAddr_s('bcc'), false, false, true);
                $send_from = $orig_header->getAddr_s('from');
                $send_from_parts = new AddressStructure();
                $send_from_parts = $orig_header->parseAddress($send_from);
                $send_from_add = $send_from_parts->mailbox . '@' . $send_from_parts->host;
                $identity = find_identity(array($send_from_add));
                $subject = decodeHeader($orig_header->subject, false, false, true);
                // Remember the receipt settings
                $request_mdn = $mdn_user_support && !empty($orig_header->dnt) ? '1' : '0';
                $request_dr = $mdn_user_support && !empty($orig_header->drnt) ? '1' : '0';
                /* remember the references and in-reply-to headers in case of an reply */
                //FIXME: it would be better to fiddle with headers inside of the message object or possibly when delivering the message to its destination (drafts folder?); is this possible?
                $composeMessage->rfc822_header->more_headers['References'] = $orig_header->references;
                $composeMessage->rfc822_header->more_headers['In-Reply-To'] = $orig_header->in_reply_to;
                // rewrap the body to clean up quotations and line lengths
                sqBodyWrap($body, $editor_size);
                $composeMessage = getAttachments($message, $composeMessage, $passed_id, $entities, $imapConnection);
                break;
            case 'edit_as_new':
                $send_to = decodeHeader($orig_header->getAddr_s('to'), false, false, true);
                $send_to_cc = decodeHeader($orig_header->getAddr_s('cc'), false, false, true);
                $send_to_bcc = decodeHeader($orig_header->getAddr_s('bcc'), false, false, true);
                $subject = decodeHeader($orig_header->subject, false, false, true);
                $mailprio = $orig_header->priority;
                $orig_from = '';
                $composeMessage = getAttachments($message, $composeMessage, $passed_id, $entities, $imapConnection);
                // rewrap the body to clean up quotations and line lengths
                sqBodyWrap($body, $editor_size);
                break;
            case 'forward':
                $send_to = '';
                $subject = getforwardSubject(decodeHeader($orig_header->subject, false, false, true));
                $body = getforwardHeader($orig_header) . $body;
                // the logic for calling sqUnWordWrap here would be to allow the browser to wrap the lines
                // forwarded message text should be as undisturbed as possible, so commenting out this call
                // sqUnWordWrap($body);
                $composeMessage = getAttachments($message, $composeMessage, $passed_id, $entities, $imapConnection);
                //add a blank line after the forward headers
                $body = "\n" . $body;
                break;
            case 'forward_as_attachment':
                $subject = getforwardSubject(decodeHeader($orig_header->subject, false, false, true));
                $composeMessage = getMessage_RFC822_Attachment($message, $composeMessage, $passed_id, $passed_ent_id, $imapConnection);
                $subject = decodeHeader($orig_header->subject, false, false, true);
                $subject = str_replace('"', "'", $subject);
                $subject = trim($subject);
                if (substr(strtolower($subject), 0, 4) != 'fwd:') {
                    $subject = 'Fwd: ' . $subject;
                }
                $body = '';
                break;
            case 'reply_all':
                if (isset($orig_header->mail_followup_to) && $orig_header->mail_followup_to) {
                    $send_to = $orig_header->getAddr_s('mail_followup_to');
                } else {
                    $send_to_cc = replyAllString($orig_header);
                    $send_to_cc = decodeHeader($send_to_cc, false, false, true);
                    $send_to_cc = str_replace('""', '"', $send_to_cc);
                }
            case 'reply':
                // skip this if send_to was already set right above here
                if (!$send_to) {
                    $send_to = $orig_header->reply_to;
                    if (is_array($send_to) && count($send_to)) {
                        $send_to = $orig_header->getAddr_s('reply_to', ',', FALSE, TRUE);
                    } else {
                        if (is_object($send_to)) {
                            /* unneccesarry, just for failsafe purpose */
                            $send_to = $orig_header->getAddr_s('reply_to', ',', FALSE, TRUE);
                        } else {
                            $send_to = $orig_header->getAddr_s('from', ',', FALSE, TRUE);
                        }
                    }
                }
                $send_to = decodeHeader($send_to, false, false, true);
                $send_to = str_replace('""', '"', $send_to);
                // If user doesn't want replies to her own messages
                // going back to herself (instead send again to the
                // original recipient of the message being replied to),
                // then iterate through identities, checking if the TO
                // field is one of them (if the reply is to ourselves)
                //
                // Note we don't bother if the original message doesn't
                // have anything in the TO field itself (because that's
                // what we use if we change the recipient to be that of
                // the previous message)
                //
                if ($do_not_reply_to_self && !empty($orig_header->to)) {
                    $orig_to = '';
                    foreach ($idents as $id) {
                        if (!empty($id['email_address']) && strpos($send_to, $id['email_address']) !== FALSE) {
                            // if this is a reply-all, the original recipient
                            // is already in the CC field, so we can just blank
                            // the recipient (TO field) (as long as the CC field
                            // isn't empty that is)... but then move the CC into
                            // the TO, so TO isn't empty
                            //
                            if ($action == 'reply_all' && !empty($send_to_cc)) {
                                $orig_to = $send_to_cc;
                                $send_to_cc = '';
                                break;
                            }
                            $orig_to = $orig_header->to;
                            if (is_array($orig_to) && count($orig_to)) {
                                $orig_to = $orig_header->getAddr_s('to', ',', FALSE, TRUE);
                            } else {
                                if (is_object($orig_to)) {
                                    /* unneccesarry, just for failsafe purpose */
                                    $orig_to = $orig_header->getAddr_s('to', ',', FALSE, TRUE);
                                } else {
                                    $orig_to = '';
                                }
                            }
                            $orig_to = decodeHeader($orig_to, false, false, true);
                            $orig_to = str_replace('""', '"', $orig_to);
                            break;
                        }
                    }
                    // if the reply was addressed back to ourselves,
                    // we will send it to the TO of the previous message
                    //
                    if (!empty($orig_to)) {
                        $send_to = $orig_to;
                        // in this case, we also want to reset the FROM
                        // identity as well (it should match the original
                        // *FROM* header instead of TO or CC)
                        //
                        if (count($idents) > 1) {
                            $identity = '';
                            foreach ($idents as $i => $id) {
                                if (!empty($id['email_address']) && strpos($orig_from, $id['email_address']) !== FALSE) {
                                    $identity = $i;
                                    break;
                                }
                            }
                        }
                    }
                }
                $subject = decodeHeader($orig_header->subject, false, false, true);
                $subject = str_replace('"', "'", $subject);
                $subject = trim($subject);
                if (substr(strtolower($subject), 0, 3) != 're:') {
                    $subject = 'Re: ' . $subject;
                }
                /* this corrects some wrapping/quoting problems on replies */
                $rewrap_body = explode("\n", $body);
                $from = is_array($orig_header->from) && !empty($orig_header->from) ? $orig_header->from[0] : $orig_header->from;
                $body = '';
                $strip_sigs = getPref($data_dir, $username, 'strip_sigs');
                foreach ($rewrap_body as $line) {
                    if ($strip_sigs && rtrim($line, "\r\n") == '-- ') {
                        break;
                    }
                    if (preg_match("/^(>+)/", $line, $matches)) {
                        $gt = $matches[1];
                        $body .= $body_quote . str_replace("\n", "\n{$body_quote}{$gt} ", rtrim($line)) . "\n";
                    } else {
                        $body .= $body_quote . (!empty($body_quote) ? ' ' : '') . str_replace("\n", "\n{$body_quote}" . (!empty($body_quote) ? ' ' : ''), rtrim($line)) . "\n";
                    }
                }
                //rewrap the body to clean up quotations and line lengths
                $body = sqBodyWrap($body, $editor_size);
                $body = getReplyCitation($from, $orig_header->date) . $body;
                $composeMessage->reply_rfc822_header = $orig_header;
                break;
            default:
                break;
        }
        //FIXME: we used to register $compose_messages in the session here, but not any more - so do we still need the session_write_close() and sqimap_logout() here?  We probably need the IMAP logout, but what about the session closure?
        session_write_close();
        sqimap_logout($imapConnection);
    }
    $ret = array('send_to' => $send_to, 'send_to_cc' => $send_to_cc, 'send_to_bcc' => $send_to_bcc, 'subject' => $subject, 'mailprio' => $mailprio, 'body' => $body, 'identity' => $identity);
    return $ret;
}
Пример #9
0
function newMail($mailbox = '', $passed_id = '', $passed_ent_id = '', $action = '', $session = '')
{
    global $editor_size, $default_use_priority, $body, $idents, $use_signature, $composesession, $data_dir, $username, $username, $key, $imapServerAddress, $imapPort, $compose_messages, $composeMessage, $body_quote;
    global $languages, $squirrelmail_language, $default_charset;
    /*
     * Set $default_charset to correspond with the user's selection
     * of language interface. $default_charset global is not correct,
     * if message is composed in new window.
     */
    set_my_charset();
    $send_to = $send_to_cc = $send_to_bcc = $subject = $identity = '';
    $mailprio = 3;
    if ($passed_id) {
        $imapConnection = sqimap_login($username, $key, $imapServerAddress, $imapPort, 0);
        sqimap_mailbox_select($imapConnection, $mailbox);
        $message = sqimap_get_message($imapConnection, $passed_id, $mailbox);
        $body = '';
        if ($passed_ent_id) {
            /* redefine the messsage in case of message/rfc822 */
            $message = $message->getEntity($passed_ent_id);
            /* message is an entity which contains the envelope and type0=message
             * and type1=rfc822. The actual entities are childs from
             * $message->entities[0]. That's where the encoding and is located
             */
            $entities = $message->entities[0]->findDisplayEntity(array(), $alt_order = array('text/plain'));
            if (!count($entities)) {
                $entities = $message->entities[0]->findDisplayEntity(array(), $alt_order = array('text/plain', 'html/plain'));
            }
            $orig_header = $message->rfc822_header;
            /* here is the envelope located */
            /* redefine the message for picking up the attachments */
            $message = $message->entities[0];
        } else {
            $entities = $message->findDisplayEntity(array(), $alt_order = array('text/plain'));
            if (!count($entities)) {
                $entities = $message->findDisplayEntity(array(), $alt_order = array('text/plain', 'html/plain'));
            }
            $orig_header = $message->rfc822_header;
        }
        $encoding = $message->header->encoding;
        $type0 = $message->type0;
        $type1 = $message->type1;
        foreach ($entities as $ent) {
            $unencoded_bodypart = mime_fetch_body($imapConnection, $passed_id, $ent);
            $body_part_entity = $message->getEntity($ent);
            $bodypart = decodeBody($unencoded_bodypart, $body_part_entity->header->encoding);
            if ($type1 == 'html') {
                $bodypart = str_replace("\n", ' ', $bodypart);
                $bodypart = preg_replace(array('/<p>/i', '/<br\\s*(\\/)*>/i'), "\n", $bodypart);
                $bodypart = str_replace(array('&nbsp;', '&gt;', '&lt;'), array(' ', '>', '<'), $bodypart);
                $bodypart = strip_tags($bodypart);
            }
            if (isset($languages[$squirrelmail_language]['XTRA_CODE']) && function_exists($languages[$squirrelmail_language]['XTRA_CODE'])) {
                if (mb_detect_encoding($bodypart) != 'ASCII') {
                    $bodypart = $languages[$squirrelmail_language]['XTRA_CODE']('decode', $bodypart);
                }
            }
            // charset encoding in compose form stuff
            if (isset($body_part_entity->header->parameters['charset'])) {
                $actual = $body_part_entity->header->parameters['charset'];
            } else {
                $actual = 'us-ascii';
            }
            if ($actual && is_conversion_safe($actual) && $actual != $default_charset) {
                $bodypart = charset_convert($actual, $bodypart, $default_charset, false);
            }
            // end of charset encoding in compose
            $body .= $bodypart;
        }
        if ($default_use_priority) {
            $mailprio = substr($orig_header->priority, 0, 1);
            if (!$mailprio) {
                $mailprio = 3;
            }
        } else {
            $mailprio = '';
        }
        $identity = '';
        $from_o = $orig_header->from;
        if (is_array($from_o)) {
            if (isset($from_o[0])) {
                $from_o = $from_o[0];
            }
        }
        if (is_object($from_o)) {
            $orig_from = $from_o->getAddress();
        } else {
            $orig_from = '';
        }
        $identities = array();
        if (count($idents) > 1) {
            foreach ($idents as $nr => $data) {
                $enc_from_name = '"' . $data['full_name'] . '" <' . $data['email_address'] . '>';
                if ($enc_from_name == $orig_from) {
                    $identity = $nr;
                    break;
                }
                $identities[] = $enc_from_name;
            }
            $identity_match = $orig_header->findAddress($identities);
            if ($identity_match) {
                $identity = $identity_match;
            }
        }
        switch ($action) {
            case 'draft':
                $use_signature = FALSE;
                $composeMessage->rfc822_header = $orig_header;
                $send_to = decodeHeader($orig_header->getAddr_s('to'), false, false, true);
                $send_to_cc = decodeHeader($orig_header->getAddr_s('cc'), false, false, true);
                $send_to_bcc = decodeHeader($orig_header->getAddr_s('bcc'), false, false, true);
                // FIXME: ident support?
                $subject = decodeHeader($orig_header->subject, false, false, true);
                /* remember the references and in-reply-to headers in case of an reply */
                $composeMessage->rfc822_header->more_headers['References'] = $orig_header->references;
                $composeMessage->rfc822_header->more_headers['In-Reply-To'] = $orig_header->in_reply_to;
                $body_ary = explode("\n", $body);
                $cnt = count($body_ary);
                $body = '';
                for ($i = 0; $i < $cnt; $i++) {
                    if (!ereg("^[>\\s]*\$", $body_ary[$i]) || !$body_ary[$i]) {
                        sqWordWrap($body_ary[$i], $editor_size, $default_charset);
                        $body .= $body_ary[$i] . "\n";
                    }
                    unset($body_ary[$i]);
                }
                sqUnWordWrap($body);
                $composeMessage = getAttachments($message, $composeMessage, $passed_id, $entities, $imapConnection);
                break;
            case 'edit_as_new':
                $send_to = decodeHeader($orig_header->getAddr_s('to'), false, false, true);
                $send_to_cc = decodeHeader($orig_header->getAddr_s('cc'), false, false, true);
                $send_to_bcc = decodeHeader($orig_header->getAddr_s('bcc'), false, false, true);
                $subject = decodeHeader($orig_header->subject, false, false, true);
                $mailprio = $orig_header->priority;
                $orig_from = '';
                $composeMessage = getAttachments($message, $composeMessage, $passed_id, $entities, $imapConnection);
                sqUnWordWrap($body);
                break;
            case 'forward':
                $send_to = '';
                $subject = decodeHeader($orig_header->subject, false, false, true);
                if (substr(strtolower($subject), 0, 4) != 'fwd:' && substr(strtolower($subject), 0, 5) != '[fwd:' && substr(strtolower($subject), 0, 6) != '[ fwd:') {
                    $subject = '[Fwd: ' . $subject . ']';
                }
                $body = getforwardHeader($orig_header) . $body;
                $composeMessage = getAttachments($message, $composeMessage, $passed_id, $entities, $imapConnection);
                $body = "\n" . $body;
                break;
            case 'forward_as_attachment':
                $composeMessage = getMessage_RFC822_Attachment($message, $composeMessage, $passed_id, $passed_ent_id, $imapConnection);
                $body = '';
                break;
            case 'reply_all':
                if (isset($orig_header->mail_followup_to) && $orig_header->mail_followup_to) {
                    $send_to = $orig_header->getAddr_s('mail_followup_to');
                } else {
                    $send_to_cc = replyAllString($orig_header);
                    $send_to_cc = decodeHeader($send_to_cc, false, false, true);
                }
            case 'reply':
                if (!$send_to) {
                    $send_to = $orig_header->reply_to;
                    if (is_array($send_to) && count($send_to)) {
                        $send_to = $orig_header->getAddr_s('reply_to');
                    } else {
                        if (is_object($send_to)) {
                            /* unneccesarry, just for failsafe purpose */
                            $send_to = $orig_header->getAddr_s('reply_to');
                        } else {
                            $send_to = $orig_header->getAddr_s('from');
                        }
                    }
                }
                $send_to = decodeHeader($send_to, false, false, true);
                $subject = decodeHeader($orig_header->subject, false, false, true);
                $subject = trim($subject);
                if (substr(strtolower($subject), 0, 3) != 're:') {
                    $subject = 'Re: ' . $subject;
                }
                /* this corrects some wrapping/quoting problems on replies */
                $rewrap_body = explode("\n", $body);
                $from = is_array($orig_header->from) && !empty($orig_header->from) ? $orig_header->from[0] : $orig_header->from;
                sqUnWordWrap($body);
                $body = '';
                $cnt = count($rewrap_body);
                for ($i = 0; $i < $cnt; $i++) {
                    sqWordWrap($rewrap_body[$i], $editor_size, $default_charset);
                    if (preg_match("/^(>+)/", $rewrap_body[$i], $matches)) {
                        $gt = $matches[1];
                        $body .= $body_quote . str_replace("\n", "\n" . $body_quote . "{$gt} ", rtrim($rewrap_body[$i])) . "\n";
                    } else {
                        $body .= $body_quote . (!empty($body_quote) ? ' ' : '') . str_replace("\n", "\n" . $body_quote . (!empty($body_quote) ? ' ' : ''), rtrim($rewrap_body[$i])) . "\n";
                    }
                    unset($rewrap_body[$i]);
                }
                $body = getReplyCitation($from, $orig_header->date) . $body;
                $composeMessage->reply_rfc822_header = $orig_header;
                break;
            default:
                break;
        }
        $compose_messages[$session] = $composeMessage;
        sqsession_register($compose_messages, 'compose_messages');
        session_write_close();
        sqimap_logout($imapConnection);
    }
    $ret = array('send_to' => $send_to, 'send_to_cc' => $send_to_cc, 'send_to_bcc' => $send_to_bcc, 'subject' => $subject, 'mailprio' => $mailprio, 'body' => $body, 'identity' => $identity);
    return $ret;
}
Пример #10
0
/**
 * Decodes headers
 *
 * This function decodes strings that are encoded according to
 * RFC1522 (MIME Part Two: Message Header Extensions for Non-ASCII Text).
 * Patched by Christian Schmidt <*****@*****.**>  23/03/2002
 *
 * @param string $string header string that has to be made readable
 * @param boolean $utfencode change message in order to be readable on user's charset. defaults to true
 * @param boolean $htmlsafe preserve spaces and sanitize html special characters. defaults to true
 * @param boolean $decide decide if string can be utfencoded. defaults to false
 * @return string decoded header string
 */
function decodeHeader($string, $utfencode = true, $htmlsafe = true, $decide = false)
{
    global $languages, $squirrelmail_language, $default_charset;
    if (is_array($string)) {
        $string = implode("\n", $string);
    }
    if (isset($languages[$squirrelmail_language]['XTRA_CODE']) && function_exists($languages[$squirrelmail_language]['XTRA_CODE'] . '_decodeheader')) {
        $string = call_user_func($languages[$squirrelmail_language]['XTRA_CODE'] . '_decodeheader', $string);
        // Do we need to return at this point?
        // return $string;
    }
    $i = 0;
    $iLastMatch = -2;
    $encoded = true;
    // FIXME: spaces are allowed inside quoted-printable encoding, but the following line will bust up any such encoded strings
    $aString = explode(' ', $string);
    $ret = '';
    foreach ($aString as $chunk) {
        if ($encoded && $chunk === '') {
            continue;
        } elseif ($chunk === '') {
            $ret .= ' ';
            continue;
        }
        $encoded = false;
        /* if encoded words are not separated by a linear-space-white we still catch them */
        $j = $i - 1;
        while ($match = preg_match('/^(.*)=\\?([^?]*)\\?(Q|B)\\?([^?]*)\\?=(.*)$/Ui', $chunk, $res)) {
            /* if the last chunk isn't an encoded string then put back the space, otherwise don't */
            if ($iLastMatch !== $j) {
                if ($htmlsafe) {
                    $ret .= '&#32;';
                } else {
                    $ret .= ' ';
                }
            }
            $iLastMatch = $i;
            $j = $i;
            if ($htmlsafe) {
                $ret .= sm_encode_html_special_chars($res[1]);
            } else {
                $ret .= $res[1];
            }
            $encoding = ucfirst($res[3]);
            /* decide about valid decoding */
            if ($decide && is_conversion_safe($res[2])) {
                $utfencode = true;
                $can_be_encoded = true;
            } else {
                $can_be_encoded = false;
            }
            switch ($encoding) {
                case 'B':
                    $replace = base64_decode($res[4]);
                    if ($utfencode) {
                        if ($can_be_encoded) {
                            /* convert string to different charset,
                             * if functions asks for it (usually in compose)
                             */
                            $ret .= charset_convert($res[2], $replace, $default_charset, $htmlsafe);
                        } else {
                            // convert string to html codes in order to display it
                            $ret .= charset_decode($res[2], $replace);
                        }
                    } else {
                        if ($htmlsafe) {
                            $replace = sm_encode_html_special_chars($replace);
                        }
                        $ret .= $replace;
                    }
                    break;
                case 'Q':
                    $replace = str_replace('_', ' ', $res[4]);
                    $replace = preg_replace_callback('/=([0-9a-f]{2})/i', create_function('$matches', 'return chr(hexdec($matches[1]));'), $replace);
                    if ($utfencode) {
                        if ($can_be_encoded) {
                            /* convert string to different charset,
                             * if functions asks for it (usually in compose)
                             */
                            $replace = charset_convert($res[2], $replace, $default_charset, $htmlsafe);
                        } else {
                            // convert string to html codes in order to display it
                            $replace = charset_decode($res[2], $replace);
                        }
                    } else {
                        if ($htmlsafe) {
                            $replace = sm_encode_html_special_chars($replace);
                        }
                    }
                    $ret .= $replace;
                    break;
                default:
                    break;
            }
            $chunk = $res[5];
            $encoded = true;
        }
        if (!$encoded) {
            if ($htmlsafe) {
                $ret .= '&#32;';
            } else {
                $ret .= ' ';
            }
        }
        if (!$encoded && $htmlsafe) {
            $ret .= sm_encode_html_special_chars($chunk);
        } else {
            $ret .= $chunk;
        }
        ++$i;
    }
    /* remove the first added space */
    if ($ret) {
        if ($htmlsafe) {
            $ret = substr($ret, 5);
        } else {
            $ret = substr($ret, 1);
        }
    }
    return $ret;
}