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; }
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() ); }
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; } } }
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 ); } }
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(); }
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; }