示例#1
0
EString Command::imapQuoted( Mailbox * m, Mailbox * r )
{
    Mailbox * base = 0;
    bool rel = false;
    if ( r )
        base = r;
    else if ( imap()->user() )
        base = imap()->user()->home();
    // find out whether this name can be expressed as a relative name
    if ( base ) {
        Mailbox * p = m;
        while ( p && p != base )
            p = p->parent();
        if ( p )
            rel = true;
        else
            rel = false;
    }
    // if it can, should it? does the client use relative names?
    if ( rel ) {
        if ( r )
            ; // yes, we've explicitly been told to
        else if ( d->usesRelativeMailbox )
            ; // yes, the client likes relative mailboxes
        else if ( d->usesAbsoluteMailbox )
            rel = false; // no, the client sent an absolute name
        else if ( imap()->user() && imap()->user()->inbox() == m )
            rel = true; // the client sent 'inbox'
        else if ( imap()->prefersAbsoluteMailboxes() )
            rel = false; // past commands used absolute names
    }
    // find the actual name to return
    UString n = m->name();
    if ( rel && base != Mailbox::root() )
        n = n.mid( base->name().length() + 1 );
    MUtf7Codec c;
    return imapQuoted( c.fromUnicode( n ), AString );
}
示例#2
0
文件: status.cpp 项目: aox/aox
void Status::execute()
{
    if ( state() != Executing )
        return;

    // first part. set up.
    if ( !permitted() )
        return;

    Session * session = imap()->session();
    Mailbox * current = 0;
    if ( session )
        current = session->mailbox();

    // second part. see if anything has happened, and feed the cache if
    // so. make sure we feed the cache at once.
    if ( d->unseenCount || d->recentCount || d->messageCount ) {
        if ( d->unseenCount && !d->unseenCount->done() )
            return;
        if ( d->messageCount && !d->messageCount->done() )
            return;
        if ( d->recentCount && !d->recentCount->done() )
            return;
    }
    if ( !::cache )
        ::cache = new StatusData::StatusCache;

    if ( d->unseenCount ) {
        while ( d->unseenCount->hasResults() ) {
            Row * r = d->unseenCount->nextRow();
            StatusData::CacheItem * ci =
                ::cache->find( r->getInt( "mailbox" ) );
            if ( ci ) {
                ci->hasUnseen = true;
                ci->unseen = r->getInt( "unseen" );
            }
        }
    }
    if ( d->recentCount ) {
        while ( d->recentCount->hasResults() ) {
            Row * r = d->recentCount->nextRow();
            StatusData::CacheItem * ci =
                ::cache->find( r->getInt( "mailbox" ) );
            if ( ci ) {
                ci->hasRecent = true;
                ci->recent = r->getInt( "recent" );
            }
        }
    }
    if ( d->messageCount ) {
        while ( d->messageCount->hasResults() ) {
            Row * r = d->messageCount->nextRow();
            StatusData::CacheItem * ci =
                ::cache->find( r->getInt( "mailbox" ) );
            if ( ci ) {
                ci->hasMessages = true;
                ci->messages = r->getInt( "messages" );
            }
        }
    }

    // third part. are we processing the first command in a STATUS
    // loop? if so, see if we ought to preload the cache.
    if ( mailboxGroup() && d->cacheState < 3 ) {
        IntegerSet mailboxes;
        if ( d->cacheState < 1 ) {
            // cache state 0: decide which messages
            List<Mailbox>::Iterator i( mailboxGroup()->contents() );
            while ( i ) {
                StatusData::CacheItem * ci = ::cache->provide( i );
                bool need = false;
                if ( d->unseen || d->recent || d->messages )
                    need = true;
                if ( ci->hasUnseen || ci->hasRecent || ci->hasMessages )
                    need = false;
                if ( need )
                    mailboxes.add( i->id() );
                ++i;
            }
            if ( mailboxes.count() < 3 )
                d->cacheState = 3;
        }
        if ( d->cacheState == 1 ) {
            // state 1: send queries
            if ( d->unseen ) {
                d->unseenCount
                    = new Query( "select mailbox, count(uid)::int as unseen "
                                 "from mailbox_messages "
                                 "where mailbox=any($1) and not seen "
                                 "group by mailbox", this );
                d->unseenCount->bind( 1, mailboxes );
                d->unseenCount->execute();
            }
            if ( d->recent ) {
                d->recentCount
                    = new Query( "select id as mailbox, "
                                 "uidnext-first_recent as recent "
                                 "from mailboxes where id=any($1)", this );
                d->recentCount->bind( 1, mailboxes );
                d->recentCount->execute();
            }
            if ( d->messages ) {
                d->messageCount
                    = new Query( "select count(*)::int as messages, mailbox "
                                 "from mailbox_messages where mailbox=any($1) "
                                 "group by mailbox", this );
                d->messageCount->bind( 1, mailboxes );
                d->messageCount->execute();
            }
            d->cacheState = 2;
        }
        if ( d->cacheState == 2 ) {
            // state 2: mark the cache as complete.
            IntegerSet mailboxes;
            List<Mailbox>::Iterator i( mailboxGroup()->contents() );
            while ( i ) {
                StatusData::CacheItem * ci = ::cache->find( i->id() );
                if ( ci && d->unseenCount )
                    ci->hasUnseen = true;
                if ( ci && d->recentCount )
                    ci->hasRecent = true;
                if ( ci && d->messageCount )
                    ci->hasMessages = true;
                ++i;
            }
            // and drop the queries
            d->cacheState = 3;
            d->unseenCount = 0;
            d->recentCount = 0;
            d->messageCount = 0;
        }
    }

    // the cache item we'll actually read from
    StatusData::CacheItem * i = ::cache->provide( d->mailbox );

    // fourth part: send individual queries if there's anything we need
    if ( d->unseen && !d->unseenCount && !i->hasUnseen ) {
        d->unseenCount
            = new Query( "select $1::int as mailbox, "
                         "count(uid)::int as unseen "
                         "from mailbox_messages "
                         "where mailbox=$1 and not seen", this );
        d->unseenCount->bind( 1, d->mailbox->id() );
        d->unseenCount->execute();
    }

    if ( !d->recent ) {
        // nothing doing
    }
    else if ( d->mailbox == current ) {
        // we'll pick it up from the session
    }
    else if ( i->hasRecent ) {
        // the cache has it
    }
    else if ( !d->recentCount ) {
        d->recentCount
            = new Query( "select id as mailbox, "
                         "uidnext-first_recent as recent "
                         "from mailboxes where id=$1", this );
        d->recentCount->bind( 1, d->mailbox->id() );
        d->recentCount->execute();
    }

    if ( !d->messages ) {
        // we don't need to collect
    }
    else if ( d->mailbox == current ) {
        // we'll pick it up
    }
    else if ( i->hasMessages ) {
        // the cache has it
    }
    else if ( d->messages && !d->messageCount ) {
        d->messageCount
            = new Query( "select count(*)::int as messages, "
                         "$1::int as mailbox "
                         "from mailbox_messages where mailbox=$1", this );
        d->messageCount->bind( 1, d->mailbox->id() );
        d->messageCount->execute();
    }

    if ( d->unseenCount || d->recentCount || d->messageCount ) {
        if ( d->unseenCount && !d->unseenCount->done() )
            return;
        if ( d->messageCount && !d->messageCount->done() )
            return;
        if ( d->recentCount && !d->recentCount->done() )
            return;
    }

    // fifth part: return the payload.
    EStringList status;

    if ( d->messages && i->hasMessages )
        status.append( "MESSAGES " + fn( i->messages ) );
    else if ( d->messages && d->mailbox == current )
        status.append( "MESSAGES " + fn( session->messages().count() ) );

    if ( d->recent && i->hasRecent )
        status.append( "RECENT " + fn( i->recent ) );
    else if ( d->recent && d->mailbox == current )
        status.append( "RECENT " + fn( session->recent().count() ) );

    if ( d->uidnext )
        status.append( "UIDNEXT " + fn( d->mailbox->uidnext() ) );

    if ( d->uidvalidity )
        status.append( "UIDVALIDITY " + fn( d->mailbox->uidvalidity() ) );

    if ( d->unseen && i->hasUnseen )
        status.append( "UNSEEN " + fn( i->unseen ) );

    if ( d->modseq ) {
        int64 hms = d->mailbox->nextModSeq();
        // don't like this. an empty mailbox will have a STATUS HMS of
        // 1 before it receives its first message, and also 1 after.
        if ( hms > 1 )
            hms--;
        status.append( "HIGHESTMODSEQ " + fn( hms ) );
    }

    respond( "STATUS " + imapQuoted( d->mailbox ) +
             " (" + status.join( " " ) + ")" );
    finish();
}