Exemple #1
0
void ImapSession::emitUpdates( Transaction * t )
{
    if ( d->emitting )
        return;
    d->emitting = true;
    bool work = false;

    Scope x( d->l );

    IntegerSet e;
    e.add( expunged() );
    e.remove( d->expungesReported );
    if ( !e.isEmpty() ) {
        d->expungesReported.add( e );
        while ( !e.isEmpty() ) {
            (void)new ImapExpungeResponse( e.smallest(), this );
            work = true;
            e.remove( e.smallest() );
        }
    }

    emitFlagUpdates( t );

    if ( d->uidnext < uidnext() ) {
        if ( !d->existsResponse ) {
            d->existsResponse =
                new ImapSessionData::ExistsResponse( this, d );
            work = true;
        }
        if ( !d->recentResponse ) {
            d->recentResponse =
                new ImapSessionData::RecentResponse( this, d );
            work = true;
        }
        if ( !d->uidnextResponse ) {
            d->uidnextResponse =
                new ImapSessionData::UidnextResponse( this, d );
            work = true;
        }
    }

    if ( d->nms < nextModSeq() )
        d->nms = nextModSeq();
    if ( d->changed.isEmpty() )
        d->cms = d->nms;

    if ( work )
        d->i->unblockCommands();
    d->i->emitResponses();

    d->emitting = false;
}
Exemple #2
0
void ImapSession::recordExpungedFetch( const IntegerSet & set )
{
    IntegerSet already = set.intersection( d->expungedFetched );
    d->expungedFetched.add( set );
    if ( already.isEmpty() )
        return;

    (void)new ImapByeResponse( d->i,
                               "BYE [CLIENTBUG] "
                               "These messages have been expunged: " +
                               set.set() );
}
Exemple #3
0
void MaildirMailbox::readSubDir( const EString & sub )
{
    DIR * dir = opendir( ( d->path + "/" + sub ).cstr() );
    if ( !dir )
        return;

    Map<EStringList> files;
    IntegerSet times;

    struct dirent * de = readdir( dir );
    while ( de ) {
        if ( de->d_name[0] >= '0' && de->d_name[0] <= '9' ) {
            EString n( de->d_name );
            int i = n.find( '.' );
            bool ok = false;
            if ( i > 0 )
                i = n.mid( 0, i ).number( &ok );
            if ( ok ) {
                EString * f = new EString ( sub );
                f->append( "/" );
                f->append( n );
                EStringList * l = 0;
                l = files.find( i );
                if ( !l ) {
                    l = new EStringList;
                    files.insert( i, l );
                    times.add( i ); // XXX: how very evil
                }
                l->append( f );
            }
            else {
                // no dot in the name... what is it?
            }
        }
        de = readdir( dir );
    }
    closedir( dir );

    while ( !times.isEmpty() ) {
        uint n = times.smallest();
        times.remove( n );
        EStringList * l = files.find( n );
        EStringList::Iterator i( *l );
        while ( i ) {
            d->messages.append( *i );
            ++i;
        }
    }
}
Exemple #4
0
void SessionInitialiser::recordExpunges()
{
    if ( !d->expunges )
        return;
    Row * r = 0;
    IntegerSet uids;
    while ( (r=d->expunges->nextRow()) != 0 )
        uids.add( r->getInt( "uid" ) );
    if ( uids.isEmpty() )
        return;

    List<Session>::Iterator i( d->sessions );
    while ( i ) {
        Session * s = i;
        ++i;
        s->expunge( uids );
    }
}
Exemple #5
0
void SpoolManager::execute()
{
    // Fetch a list of spooled messages, and the next time we can try
    // to deliver each of them.

    uint delay = UINT_MAX;

    if ( !d->q ) {
        IntegerSet have;
        List<DeliveryAgent>::Iterator a( d->agents );
        while ( a ) {
            if ( a->working() ) {
                have.add( a->messageId() );
                delay = 900;
                ++a;
            }
            else {
                d->agents.take( a );
            }
        }

        log( "Starting queue run" );
        d->again = false;
        reset();
        EString s( "select d.message, "
                   "extract(epoch from"
                   " min(coalesce(dr.last_attempt+interval '900 s',"
                   " d.deliver_after,"
                   " current_timestamp)))::bigint"
                   "-extract(epoch from current_timestamp)::bigint as delay "
                   "from deliveries d "
                   "join delivery_recipients dr on (d.id=dr.delivery) "
                   "where (dr.action=$1 or dr.action=$2) " );
        if ( !have.isEmpty() )
            s.append( "and not d.message=any($3) " );
        s.append( "group by d.message "
                  "order by delay" );
        d->q = new Query( s, this );
        d->q->bind( 1, Recipient::Unknown );
        d->q->bind( 2, Recipient::Delayed );
        if ( !have.isEmpty() )
            d->q->bind( 3, have );
        d->q->execute();
    }

    if ( d->q && !d->q->done() )
        return;

    // Is there anything we might do?

    if ( d->q && !d->q->rows() ) {
        // No. Just finish.
        reset();
        log( "Ending queue run" );
        return;
    }

    // Yes. What?

    if ( d->q ) {
        while ( d->q->hasResults() ) {
            Row * r = d->q->nextRow();
            int64 deliverableAt = r->getBigint( "delay" );
            if ( deliverableAt <= 0 ) {
                DeliveryAgent * a
                    = new DeliveryAgent( r->getInt( "message" ) );
                (void)new Timer( a, d->agents.count() * 5 );
                d->agents.append( a );
            }
            else if ( delay > deliverableAt )
                delay = deliverableAt;
        }
        if ( delay < UINT_MAX ) {
            log( "Will process the queue again in " +
                 fn( delay ) + " seconds" );
            d->t = new Timer( this, delay );
        }
        d->q = 0;
    }

    reset();
}
Exemple #6
0
bool PopCommand::session()
{
    if ( !d->mailbox ) {
        d->mailbox = d->pop->user()->inbox();
        log( "Attempting to start a session on " +
             d->mailbox->name().ascii() );
        d->permissions =
            new Permissions( d->mailbox, d->pop->user(), this );
    }

    if ( !d->permissions->ready() )
        return false;

    if ( !d->session ) {
        if ( !d->permissions->allowed( Permissions::Read ) ) {
            d->pop->err( "Insufficient privileges" );
            return true;
        }
        else {
            bool ro = true;
            if ( d->permissions->allowed( Permissions::KeepSeen ) &&
                 d->permissions->allowed( Permissions::DeleteMessages ) &&
                 d->permissions->allowed( Permissions::Expunge ) )
                ro = false;
            d->session =
                new PopCommandData::PopSession( d->mailbox, ro, this );
            d->session->setPermissions( d->permissions );
            d->pop->setSession( d->session );
        }
    }

    if ( !d->session->initialised() )
        return false;

    if ( !d->map ) {
        d->session->clearUnannounced();
        IntegerSet s( d->session->messages() );
        IntegerSet r;
        d->map = new Map<Message>;
        while ( !s.isEmpty() ) {
            uint uid = s.smallest();
            s.remove( uid );
            Message * m = MessageCache::provide( d->mailbox, uid );
            if ( !m->databaseId() )
                r.add( uid );
            d->map->insert( uid, m );
        }
        if ( !r.isEmpty() ) {
            d->findIds = new Query( "select message, uid "
                                    "from mailbox_messages "
                                    "where mailbox=$1 and uid=any($2)",
                                    this );
            d->findIds->bind( 1, d->mailbox->id() );
            d->findIds->bind( 2, r );
            d->findIds->execute();
        }
    }
    if ( d->findIds && !d->findIds->done() )
        return false;
    while ( d->findIds && d->findIds->hasResults() ) {
        Row * r = d->findIds->nextRow();
        Message * m = d->map->find( r->getInt( "uid" ) );
        if ( m )
            m->setDatabaseId( r->getInt( "message" ) );
    }

    d->session->clearUnannounced();
    d->pop->setMessageMap( d->map );
    d->pop->setState( POP::Transaction );
    d->pop->ok( "Done" );
    return true;
}