Example #1
0
/**
 * Displays error messages, if there are errors in responses to
 * commands issues by sqimap_append() and sqimap_append_done() functions.
 * @param string $response
 * @param string $sMailbox
 * @return bool $bDone
 * @since 1.5.1 and 1.4.5
 */
function sqimap_append_checkresponse($response, $sMailbox, $sid = '', $query = '')
{
    // static vars to keep them available when sqimap_append_done calls this function.
    static $imapquery, $imapsid;
    $bDone = false;
    if ($query) {
        $imapquery = $query;
    }
    if ($sid) {
        $imapsid = $sid;
    }
    if ($response[0] == '+') {
        // continuation request triggerd by sqimap_append()
        $bDone = true;
    } else {
        $i = strpos($response, ' ');
        $sRsp = substr($response, 0, $i);
        $sMsg = substr($response, $i + 1);
        $aExtra = array('MAILBOX' => $sMailbox);
        switch ($sRsp) {
            case '*':
                //untagged response
                $i = strpos($sMsg, ' ');
                $sRsp = strtoupper(substr($sMsg, 0, $i));
                $sMsg = substr($sMsg, $i + 1);
                if ($sRsp == 'NO' || $sRsp == 'BAD') {
                    // for the moment disabled. Enable after 1.5.1 release.
                    // Notices could give valueable information about the mailbox
                    // Update: seems this was forgotten, but now it is finally enabled
                    sqm_trigger_imap_error('SQM_IMAP_APPEND_NOTICE', $imapquery, $sRsp, $sMsg);
                }
                $bDone = false;
            case $imapsid:
                // A001 OK message
                // $imapsid<space>$sRsp<space>$sMsg
                $bDone = true;
                $i = strpos($sMsg, ' ');
                $sRsp = strtoupper(substr($sMsg, 0, $i));
                $sMsg = substr($sMsg, $i + 1);
                switch ($sRsp) {
                    case 'NO':
                        if (preg_match("/(.*)(quota)(.*)\$/i", $sMsg, $aMatch)) {
                            sqm_trigger_imap_error('SQM_IMAP_APPEND_QUOTA_ERROR', $imapquery, $sRsp, $sMsg, $aExtra);
                        } else {
                            sqm_trigger_imap_error('SQM_IMAP_APPEND_ERROR', $imapquery, $sRsp, $sMsg, $aExtra);
                        }
                        break;
                    case 'BAD':
                        sqm_trigger_imap_error('SQM_IMAP_ERROR', $imapquery, $sRsp, $sMsg, $aExtra);
                        break;
                    case 'BYE':
                        sqm_trigger_imap_error('SQM_IMAP_BYE', $imapquery, $sRsp, $sMsg, $aExtra);
                        break;
                    case 'OK':
                        break;
                    default:
                        break;
                }
                break;
            default:
                // should be false because of the unexpected response but i'm not sure if
                // that will cause an endless loop in sqimap_append_done
                $bDone = true;
        }
    }
    return $bDone;
}
Example #2
0
/**
 * Returns an array with each element as a string representing one
 * message-thread as returned by the IMAP server.
 * @param resource $imap_stream IMAP socket connection
 * @param string $search optional search string
 * @return array
 * @link http://www.ietf.org/internet-drafts/draft-ietf-imapext-sort-13.txt
 */
function get_thread_sort($imap_stream, $search = 'ALL')
{
    global $sort_by_ref, $default_charset;
    if ($sort_by_ref == 1) {
        $sort_type = 'REFERENCES';
    } else {
        $sort_type = 'ORDEREDSUBJECT';
    }
    $query = "THREAD {$sort_type} " . strtoupper($default_charset) . " {$search}";
    // TODO use sqimap_run_command_list as we do in get_server_sort()
    $sRead = sqimap_run_command($imap_stream, $query, false, $response, $message, TRUE);
    /* fallback to default charset */
    if ($response == 'NO') {
        if (strpos($message, 'BADCHARSET') !== false || strpos($message, 'character') !== false) {
            sqm_trigger_imap_error('SQM_IMAP_BADCHARSET', $query, $response, $message);
            $query = "THREAD {$sort_type} US-ASCII {$search}";
            $sRead = sqimap_run_command($imap_stream, $query, true, $response, $message, TRUE);
        } else {
            sqm_trigger_imap_error('SQM_IMAP_ERROR', $query, $response, $message);
        }
    } elseif ($response == 'BAD') {
        sqm_trigger_imap_error('SQM_IMAP_NO_THREAD', $query, $response, $message);
    }
    $sThreadResponse = '';
    if (isset($sRead[0])) {
        for ($i = 0, $iCnt = count($sRead); $i < $iCnt; ++$i) {
            if (preg_match("/^\\* THREAD (.+)\$/", $sRead[$i], $aMatch)) {
                $sThreadResponse = trim($aMatch[1]);
                break;
            }
        }
    }
    unset($sRead);
    if ($response !== 'OK') {
        return false;
    }
    /* Example response
     *  S: * THREAD (2)(3 6 (4 23)(44 7 96))
     * -- 2
     *
     * -- 3
     *    \-- 6
     *        |-- 4
     *        |   \-- 23
     *        |
     *        \-- 44
     *             \-- 7
     *                 \-- 96
     */
    /*
     * Notes for future work:
     * indent_array should contain: indent_level, parent and flags,
     * sibling nodes ..
     * To achieve that we  need to define the following flags:
     * 0: hasnochildren
     * 1: haschildren
     * 2: is first
     * 4: is last
     * a node has sibling nodes if it's not the last node
     * a node has no sibling nodes if it's the last node
     * By using binary comparations we can store the flag in one var
     *
     * example:
     * -1      par = 0, level = 0, flag = 1 + 2 + 4 = 7 (haschildren,   isfirst, islast)
     *  \-2    par = 1, level = 1, flag = 0 + 2     = 2 (hasnochildren, isfirst)
     *  |-3    par = 1, level = 1, flag = 1 + 4     = 5 (haschildren,   islast)
     *   \-4   par = 3, level = 2, flag = 1 + 2 + 4 = 7 (haschildren,   isfirst, islast)
     *     \-5 par = 4, level = 3, flag = 0 + 2 + 4 = 6 (hasnochildren, isfirst, islast)
     */
    $j = 0;
    $k = 0;
    $l = 0;
    $aUidThread = array();
    $aIndent = array();
    $aUidSubThread = array();
    $aDepthStack = array();
    $sUid = '';
    if ($sThreadResponse) {
        for ($i = 0, $iCnt = strlen($sThreadResponse); $i < $iCnt; ++$i) {
            $cChar = $sThreadResponse[$i];
            switch ($cChar) {
                case '(':
                    // new sub thread
                    // correction for a subthread of a thread with no parents in thread
                    if (!count($aUidSubThread) && $j > 0) {
                        --$l;
                    }
                    $aDepthStack[$j] = $l;
                    ++$j;
                    break;
                case ')':
                    // close sub thread
                    if ($sUid !== '') {
                        $aUidSubThread[] = $sUid;
                        $aIndent[$sUid] = $j + $l - 1;
                        ++$l;
                        $sUid = '';
                    }
                    --$j;
                    if ($j === 0) {
                        // show message that starts the thread first.
                        $aUidSubThread = array_reverse($aUidSubThread);
                        // do not use array_merge because it's extremely slow and is causing timeouts
                        foreach ($aUidSubThread as $iUid) {
                            $aUidThread[] = $iUid;
                        }
                        $aUidSubThread = array();
                        $l = 0;
                        $aDepthStack = array();
                    } else {
                        $l = $aDepthStack[$j];
                    }
                    break;
                case ' ':
                    // new child
                    if ($sUid !== '') {
                        $aUidSubThread[] = $sUid;
                        $aIndent[$sUid] = $j + $l - 1;
                        ++$l;
                        $sUid = '';
                    }
                    break;
                default:
                    // part of UID
                    $sUid .= $cChar;
                    break;
            }
        }
    }
    unset($sThreadResponse);
    // show newest threads first
    $aUidThread = array_reverse($aUidThread);
    return array($aUidThread, $aIndent);
}
Example #3
0
/**
 * Creates and runs the IMAP command to filter messages
 * @param string $imap_stream TODO: Document this parameter
 * @param string $where Which part of the message to search (TO, CC, SUBJECT, etc...)
 * @param string $what String to search for
 * @param string $where_to Folder it will move to
 * @param string $user_scan Whether to search all or just unseen
 * @param string $should_expunge
 * @access private
 */
function filter_search_and_delete($imap_stream, $where, $what, $where_to, $user_scan, $should_expunge)
{
    global $languages, $squirrelmail_language, $allow_charset_search, $imap_server_type;
    //TODO: make use of new mailbox cache. See mailbox_display.phpinfo
    if (strtolower($where_to) == 'inbox') {
        return array();
    }
    if ($user_scan == 'new') {
        $category = 'UNSEEN';
    } else {
        $category = 'ALL';
    }
    $category .= ' UNDELETED';
    if ($allow_charset_search && isset($languages[$squirrelmail_language]['CHARSET']) && $languages[$squirrelmail_language]['CHARSET']) {
        $search_str = 'SEARCH CHARSET ' . strtoupper($languages[$squirrelmail_language]['CHARSET']) . ' ' . $category;
    } else {
        $search_str = 'SEARCH CHARSET US-ASCII ' . $category;
    }
    if ($where == 'Header') {
        $what = explode(':', $what);
        $where = strtoupper($where);
        $where = trim($where . ' ' . $what[0]);
        $what = addslashes(trim($what[1]));
    }
    // see comments in squirrelmail sqimap_search function
    if ($imap_server_type == 'macosx' || $imap_server_type == 'hmailserver') {
        $search_str .= ' ' . $where . ' ' . $what;
        /* read data back from IMAP */
        $read = sqimap_run_command($imap_stream, $search_str, true, $response, $message, TRUE);
    } else {
        $search_str .= ' ' . $where . ' {' . strlen($what) . "}";
        $sid = sqimap_session_id(true);
        fputs($imap_stream, $sid . ' ' . $search_str . "\r\n");
        $read2 = sqimap_fgets($imap_stream);
        # server should respond with Ready for argument, then we will send search text
        #echo "RR2 $read2<br>";
        fputs($imap_stream, "{$what}\r\n");
        #echo "SS $what<br>";
        $read2 = sqimap_fgets($imap_stream);
        #echo "RR2 $read2<br>";
        $read[] = $read2;
        $read3 = sqimap_fgets($imap_stream);
        #echo "RR3 $read3<br>";
        list($rtag, $response, $message) = explode(' ', $read3, 3);
        ##        $read2 = sqimap_retrieve_imap_response($imap_stream, $sid, true,
        ##              $response, $message, $search_str, false, true, false);
        #echo "RR2 $read2 / RESPONSE $response<br>";
    }
    if (isset($read[0])) {
        $ids = array();
        for ($i = 0, $iCnt = count($read); $i < $iCnt; ++$i) {
            if (preg_match("/^\\* SEARCH (.+)\$/", $read[$i], $regs)) {
                $ids += explode(' ', trim($regs[1]));
            }
        }
        if ($response == 'OK' && count($ids)) {
            if (sqimap_mailbox_exists($imap_stream, $where_to)) {
                if (!sqimap_msgs_list_move($imap_stream, $ids, $where_to, false)) {
                    // if errors occurred, don't try to filter again during this session
                    sqsession_register(TRUE, 'filters_error');
                    global $color;
                    error_box(_("A problem occurred filtering messages. Check filter settings and account quota if applicable. Filtering is disabled for the remainder of this login session."), $color);
                }
                // expunge even in the case of errors, in case some
                // messages were filtered before the error happened
                $should_expunge = true;
            }
        } elseif ($response != 'OK') {
            $query = $search_str . "\r\n" . $what . "\r\n";
            if ($response == 'NO') {
                if (strpos($message, 'BADCHARSET') !== false || strpos($message, 'character') !== false) {
                    sqm_trigger_imap_error('SQM_IMAP_BADCHARSET', $query, $response, $message);
                } else {
                    sqm_trigger_imap_error('SQM_IMAP_ERROR', $query, $response, $message);
                }
            } else {
                sqm_trigger_imap_error('SQM_IMAP_ERROR', $query, $response, $message);
            }
        }
    }
    return $should_expunge;
}