1 // Copyright Oryx Mail Systems GmbH. All enquiries to info@oryx.com, please.
12 #include "messageset.h"
13 #include "imapsession.h"
14 #include "permissions.h"
22 : readOnly( false ), annotate( false ), condstore( false ),
23 firstUnseen( 0 ), allFlags( 0 ),
24 mailbox( 0 ), session( 0 ), permissions( 0 )
33 ImapSession * session;
34 Permissions * permissions;
38 /*! \class Select select.h
39 Opens a mailbox for read-write access (RFC 3501 section 6.3.1)
41 This class implements both Select and Examine. The constructor has
42 to tell execute() what to do by setting the readOnly flag.
45 /*! Creates a Select object to handle SELECT if \a ro if false, and to
46 handle EXAMINE if \a ro is true.
49 Select::Select( bool ro )
59 d->mailbox = mailbox();
60 if ( present( " (" ) ) {
62 while ( ok() && more ) {
63 // select-param can be a list or an astring. in our case,
64 // only astring is legal, since we advertise no extension
65 // that permits the list.
66 String param = astring().lower();
67 if ( param == "annotate" )
69 else if ( param == "condstore" )
72 error( Bad, "Unknown select-param: " + param );
73 more = present( " " );
81 void Select::execute()
83 if ( state() != Executing )
86 if ( Flag::id( "\\Deleted" ) == 0 ) {
87 // should only happen when we flush the entire database during
88 // testing, so we don't bother being accurate or fast, but
89 // simply try again in a second.
90 (void)new Timer( this, 1 );
94 if ( !d->permissions ) {
96 imap()->setClientSupports( IMAP::Condstore );
98 imap()->setClientSupports( IMAP::Annotate );
99 if ( d->mailbox->synthetic() )
101 d->mailbox->name().ascii() + " is not in the database" );
102 else if ( d->mailbox->deleted() )
103 error( No, d->mailbox->name().ascii() + " is deleted" );
110 d->permissions = new Permissions( d->mailbox, imap()->user(),
114 if ( d->permissions && !d->session ) {
115 if ( !d->permissions->ready() )
117 if ( !d->permissions->allowed( Permissions::Read ) ) {
118 error( No, d->mailbox->name().ascii() + " is not accessible" );
123 !d->permissions->allowed( Permissions::KeepSeen ) )
128 if ( imap()->session() )
129 imap()->endSession();
130 d->session = new ImapSession( imap(), d->mailbox, d->readOnly );
131 d->session->setPermissions( d->permissions );
132 imap()->beginSession( d->session );
135 if ( !d->allFlags ) {
136 d->allFlags = new Query( "select name from flag_names "
137 "order by lower(name)", this );
138 d->allFlags->execute();
141 if ( !d->session->initialised() )
144 if ( !d->firstUnseen && !d->session->isEmpty() ) {
146 = new Query( "select uid from mailbox_messages mm "
147 "where mailbox=$1 and uid not in "
148 "(select uid from flags f"
149 " join flag_names fn on (f.flag=fn.id)"
150 " where f.mailbox=$1 and fn.name=$2) "
151 "order by uid limit 1", this );
152 d->firstUnseen->bind( 1, d->mailbox->id() );
153 d->firstUnseen->bind( 2, "\\seen" );
154 d->firstUnseen->execute();
157 if ( d->firstUnseen && !d->firstUnseen->done() )
160 if ( d->allFlags && !d->allFlags->done() )
163 d->session->emitUpdates( 0 );
164 // emitUpdates often calls Imap::runCommands, which calls this
165 // function, which will then change its state to Finished. so
166 // check that and don't repeat the last few responses.
167 if ( state() != Executing )
170 respond( "OK [UIDVALIDITY " + fn( d->session->uidvalidity() ) + "]"
173 if ( d->firstUnseen ) {
174 Row * r = d->firstUnseen->nextRow();
177 unseen = r->getInt( "uid" );
179 respond( "OK [UNSEEN " + fn( d->session->msn( unseen ) ) +
183 if ( imap()->clientSupports( IMAP::Condstore ) &&
184 !d->session->isEmpty() ) {
185 uint nms = d->session->nextModSeq();
188 respond( "OK [HIGHESTMODSEQ " + fn( nms-1 ) + "] highest modseq" );
193 while ( d->allFlags->hasResults() )
194 l.append( d->allFlags->nextRow()->getString( "name" ) );
195 String f = l.join( " " );
196 respond( "FLAGS (" + f + ")" );
197 respond( "OK [PERMANENTFLAGS (" + f + " \\*)] permanent flags" );
200 if ( imap()->clientSupports( IMAP::Annotate ) ) {
201 Permissions * p = d->session->permissions();
202 if ( p && p->allowed( Permissions::WriteSharedAnnotation ) )
203 respond( "OK [ANNOTATIONS 262144] Arbitrary limit" );
205 respond( "OK [ANNOTATIONS READ-ONLY] Missing 'n' right" );
208 if ( d->session->readOnly() )
209 setRespTextCode( "READ-ONLY" );
211 setRespTextCode( "READ-WRITE" );
217 /*! \class Examine select.h
218 Opens a mailbox for read-only access (RFC 3501 section 6.3.1)
220 This class merely inherits from Select and sets the readOnly flag.
221 It has no code of its own.
224 /*! Constructs an Examine handler, which is the same as a Select
225 handler, except that it always is read-only.