Cope properly uidvalidity changes
[aox:aox.git] / server / mailbox.cpp
1 // Copyright 2009 The Archiveopteryx Developers <info@aox.org>
2
3 #include "mailbox.h"
4
5 #include "log.h"
6 #include "map.h"
7 #include "dict.h"
8 #include "user.h"
9 #include "query.h"
10 #include "scope.h"
11 #include "event.h"
12 #include "timer.h"
13 #include "estring.h"
14 #include "message.h"
15 #include "fetcher.h"
16 #include "session.h"
17 #include "dbsignal.h"
18 #include "eventloop.h"
19 #include "allocator.h"
20 #include "integerset.h"
21 #include "estringlist.h"
22 #include "transaction.h"
23
24
25 static Map<Mailbox> * mailboxes = 0;
26 static UDict<Mailbox> * mailboxesByName = 0;
27 static bool wiped = false;
28
29
30 class MailboxData
31     : public Garbage
32 {
33 public:
34     MailboxData()
35         : type( Mailbox::Ordinary ), id( 0 ),
36           uidnext( 0 ), uidvalidity( 0 ), owner( 0 ),
37           parent( 0 ), children( 0 ),
38           nextModSeq( 1 )
39     {}
40
41     UString name;
42
43     Mailbox::Type type;
44
45     uint id;
46     uint uidnext;
47     uint uidvalidity;
48     uint owner;
49
50     Mailbox * parent;
51     List< Mailbox > * children;
52
53     int64 nextModSeq;
54 };
55
56
57 /*! \class Mailbox mailbox.h
58     This class represents a node in the global mailbox hierarchy.
59
60     Every Mailbox has a unique name() within the hierarchy. Any
61     Mailbox that can contain messages has a non-zero numeric id() and
62     attributes like uidvalidity() and uidnext(). Mailboxes have a
63     parent() and may have a number of children().
64
65     Some mailboxes aren't quite real. A Mailbox can be deleted(), in
66     which case it can contain no messags. If recreated, a deleted()
67     mailbox preserves its uidvalidity() and uid series.
68
69     This class maintains a tree of mailboxes, based on the contents of
70     the mailboxes table and descriptive messages from the OCServer. It
71     can find() a named mailbox in this hierarchy.
72 */
73
74
75 class MailboxReader
76     : public EventHandler
77 {
78 public:
79     EventHandler * owner;
80     Query * q;
81     bool done;
82
83     MailboxReader( EventHandler * ev, int64 );
84     void execute();
85 };
86
87
88 static List<MailboxReader> * readers = 0;
89
90
91 MailboxReader::MailboxReader( EventHandler * ev, int64 c )
92     : owner( ev ), q( 0 ), done( false )
93 {
94     if ( !::readers ) {
95         ::readers = new List<MailboxReader>;
96         Allocator::addEternal( ::readers, "active mailbox readers" );
97     }
98     ::readers->append( this );
99     q = new Query( "select m.id, m.name, m.deleted, m.owner, "
100                    "m.uidnext, m.nextmodseq, m.uidvalidity "
101                    //"m.change " // better: m.change
102                    "from mailboxes m ",
103                    //"where change>=$1"
104                    this );
105     c = c; //query->bind( 1, c );
106     if ( !::mailboxes )
107         Mailbox::setup();
108 }
109
110
111 void MailboxReader::execute() {
112     while ( q->hasResults() ) {
113         Row * r = q->nextRow();
114
115         UString n = r->getUString( "name" );
116         uint id = r->getInt( "id" );
117         Mailbox * m = ::mailboxes->find( id );
118         if ( !m || m->name() != n ) {
119             m = Mailbox::obtain( n );
120             if ( n != m->d->name )
121                 m->d->name = n;
122             m->setId( id );
123             ::mailboxes->insert( id, m );
124         }
125
126         if ( r->getBoolean( "deleted" ) )
127             m->setType( Mailbox::Deleted );
128         else
129             m->setType( Mailbox::Ordinary );
130
131         uint uidvalidity = r->getInt( "uidvalidity" );
132         if ( m->d->uidvalidity != uidvalidity ) {
133             m->d->uidvalidity = uidvalidity;
134             m->abortSessions();
135         }
136         if ( !r->isNull( "owner" ) )
137             m->setOwner( r->getInt( "owner" ) );
138
139         m->setUidnextAndNextModSeq( r->getInt( "uidnext" ),
140                                     r->getBigint( "nextmodseq" ),
141                                     q->transaction() );
142     }
143
144     if ( !q->done() || done )
145         return;
146
147     done = true;
148     if ( q->transaction() )
149         q->transaction()->commit();
150     ::readers->remove( this );
151     ::wiped = false;
152     if ( q->failed() && !EventLoop::global()->inShutdown() ) {
153         List<Mailbox> * c = Mailbox::root()->children();
154         if ( c && !c->isEmpty() )
155             log( "Couldn't update mailbox tree: " + q->error() );
156         else
157             log( "Couldn't create mailbox tree: " + q->error(),
158                  Log::Disaster );
159     }
160     if ( owner )
161         owner->execute();
162 };
163
164
165 class MailboxesWatcher
166     : public EventHandler
167 {
168 public:
169     MailboxesWatcher(): EventHandler(), t( 0 ), m( 0 ) {
170         (void)new DatabaseSignal( "mailboxes_updated", this );
171     }
172     void execute() {
173         if ( EventLoop::global()->inShutdown() )
174             return;
175
176         if ( !t ) {
177             // use a timer to run only one mailboxreader per 2-3
178             // seconds.
179             t = new Timer( this, 2 );
180         }
181         else if ( t->active() ) {
182             // the timer is already running, so ignore this
183         }
184         else if ( m && !m->done ) {
185             // a mailboxreader is working, and one is enough, so try
186             // again later
187             t = new Timer( this, 2 );
188         }
189         else {
190             // time's out, time to work
191             t = 0;
192             m = new MailboxReader( 0, 0 );
193             m->q->execute();
194         }
195     }
196     Timer * t;
197     MailboxReader * m;
198 };
199
200
201 // this helper class is used to recover when testing tools
202 // violate various database invariants.
203 class MailboxObliterator
204     : public EventHandler
205 {
206 public:
207     MailboxReader * mr;
208     MailboxObliterator(): EventHandler(), mr( 0 ) {
209         setLog( log() );
210         (void)new DatabaseSignal( "obliterated", this );
211     }
212     void execute() {
213         if ( !mr ) {
214             ::mailboxes->clear();
215             ::mailboxesByName->clear();
216             ::wiped = true;
217             (void)Mailbox::root();
218             mr = new MailboxReader( this, 0 );
219             mr->q->execute();
220         }
221
222         if ( !mr->done )
223             return;
224
225         mr = 0;
226     }
227 };
228
229
230 /*! This static function is responsible for building a tree of
231     Mailboxes from the contents of the mailboxes table. It expects to
232     be called by ::main().
233
234     The \a owner (if one is specified) is notified of completion.
235 */
236
237 void Mailbox::setup( EventHandler * owner )
238 {
239     ::wiped = true;
240
241     ::mailboxes = new Map<Mailbox>;
242     Allocator::addEternal( ::mailboxes, "mailbox tree" );
243
244     ::mailboxesByName = new UDict<Mailbox>;
245     Allocator::addEternal( ::mailboxesByName, "mailbox tree" );
246
247     (void)root();
248
249     Scope x( new Log );
250     (new MailboxReader( owner, 0 ))->q->execute();
251
252     (void)new MailboxesWatcher;
253     if ( !Configuration::toggle( Configuration::Security ) )
254         (void)new MailboxObliterator;
255 }
256
257
258 /*! Creates a Mailbox named \a name. This constructor is only meant to
259     be used via Mailbox::obtain(). */
260
261 Mailbox::Mailbox( const UString &name )
262     : d( new MailboxData )
263 {
264     d->name = name;
265 }
266
267
268 /*! Returns the fully qualified name of this Mailbox. */
269
270 UString Mailbox::name() const
271 {
272     return d->name;
273 }
274
275
276 /*! Sets the type of this Mailbox to \a t. The initial value is
277     Ordinary (because it has to be something).
278 */
279
280 void Mailbox::setType( Type t )
281 {
282     d->type = t;
283     if ( t == Deleted )
284         abortSessions();
285 }
286
287
288 /*! Returns the type of this Mailbox. May be Ordinary, Deleted, or
289     View.
290 */
291
292 Mailbox::Type Mailbox::type() const
293 {
294     return d->type;
295 }
296
297
298 /*! Returns the database ID of this Mailbox.
299 */
300
301 uint Mailbox::id() const
302 {
303     return d->id;
304 }
305
306
307 /*! Notifies this Mailbox that its database ID is \a i.
308 */
309
310 void Mailbox::setId( uint i ) const
311 {
312     d->id = i;
313 }
314
315
316 /*! Returns the next UID value that will be used for this mailbox. */
317
318 uint Mailbox::uidnext() const
319 {
320     return d->uidnext;
321 }
322
323
324 /*! Notifies this Mailbox that its correct uidvalidity is \a i. Should
325     generally not be called.
326 */
327
328 void Mailbox::setUidvalidity( uint i )
329 {
330     d->uidvalidity = i;
331 }
332
333
334 /*! Returns the UIDVALIDITY value of this Mailbox. This never changes. */
335
336 uint Mailbox::uidvalidity() const
337 {
338     return d->uidvalidity;
339 }
340
341
342 /*! Returns true if this mailbox isn't "special". */
343
344 bool Mailbox::ordinary() const
345 {
346     return d->type == Ordinary;
347 }
348
349
350 /*! Returns true if this mailbox is currently deleted. */
351
352 bool Mailbox::deleted() const
353 {
354     return d->type == Deleted;
355 }
356
357
358 /*! Returns true if this Mailbox represents a user's "home directory",
359     e.g. /users/ams.
360 */
361
362 bool Mailbox::isHome() const
363 {
364     if ( !d->parent )
365         return true;
366     if ( d->owner && !d->parent->d->owner )
367         return true;
368     return false;
369 }
370
371
372 /*! Returns the numeric user id of the owner of this mailbox, or 0 if
373     the mailbox has no defined owner (or is not yet known to have one).
374 */
375
376 uint Mailbox::owner() const
377 {
378     return d->owner;
379 }
380
381
382 /*! Returns a pointer to the parent of this Mailbox, or 0 if it is the
383     root Mailbox.
384 */
385
386 Mailbox *Mailbox::parent() const
387 {
388     return d->parent;
389 }
390
391
392 /*! Returns a pointer to a List of this Mailbox's children, or 0 if it
393     has none.
394 */
395
396 List< Mailbox >* Mailbox::children() const
397 {
398     return d->children;
399 }
400
401
402 /*! Returns true if this mailbox has at least one real, existing child
403     mailbox, including indirect children, and false if not.
404 */
405
406 bool Mailbox::hasChildren() const
407 {
408     List<Mailbox>::Iterator it( d->children );
409     while ( it ) {
410         if ( !it->deleted() )
411             return true;
412         if ( it->hasChildren() )
413             return true;
414         ++it;
415     }
416     return false;
417 }
418
419
420 /*! Returns a pointer to the Mailbox object at the root of the global
421     hierarchy.
422 */
423
424 Mailbox * Mailbox::root()
425 {
426     UString r;
427     r.append( '/' );
428     return Mailbox::obtain( r, true );
429 }
430
431
432 /*! Returns a pointer to the Mailbox with \a id, or a null pointer if
433     there is no such (known) Mailbox.
434
435     Deleted mailboxes are included in the search.
436 */
437
438 Mailbox * Mailbox::find( uint id )
439 {
440     if ( !::mailboxes )
441         return 0;
442     return ::mailboxes->find( id );
443 }
444
445
446 /*! Returns a pointer to a Mailbox named \a name, or 0 if the named
447     mailbox doesn't exist. If \a deleted is true, deleted mailboxes
448     are included in the search. The \a name must be fully-qualified.
449 */
450
451 Mailbox * Mailbox::find( const UString &name, bool deleted )
452 {
453     Mailbox * m = obtain( name, false );
454     if ( !m )
455         return 0;
456     if ( m->deleted() && !deleted )
457         return 0;
458     return m;
459 }
460
461
462 /*! Returns a pointer to the closest existing parent mailbox for \a
463     name, or a null pointer if \a name doesn't look like a mailbox
464     name at all, or if no parent mailboxes of \a name exist.
465 */
466
467 Mailbox * Mailbox::closestParent( const UString & name )
468 {
469     if ( name[0] != '/' )
470         return 0;
471
472     UString n = name;
473     do {
474         uint i = n.length() - 1;
475         if ( !i )
476             return root();
477         while ( i > 0 && n[i] != '/' )
478             i--;
479         if ( i < 2 )
480             return root();
481         n.truncate( i );
482         Mailbox * m = obtain( n );
483         if ( m->isHome() )
484             return m;
485         if ( !m->deleted() )
486             return m;
487     } while ( true );
488
489     return 0;
490 }
491
492
493 /*! Obtain a mailbox with \a name, creating Mailbox objects as
494     necessary and permitted.
495
496     if \a create is true (this is the default) and there is no such
497     Mailbox, obtain() creates one, including any necessary parents.
498
499     If \a create is false and there is no such Mailbox, obtain()
500     returns null without creating anything.
501 */
502
503 Mailbox * Mailbox::obtain( const UString & name, bool create )
504 {
505     if ( name[0] != '/' )
506         return 0;
507
508     if ( !::mailboxes )
509         setup();
510
511     UString n = name.titlecased();
512     Mailbox * m = ::mailboxesByName->find( n );
513     if ( m || !create )
514         return m;
515     uint i = 0;
516     Mailbox * p = 0;
517     while ( i <= n.length() ) {
518         if ( i >= n.length() || n[i] == '/' ) {
519             uint l = i;
520             if ( !l )
521                 l = 1;
522             m = ::mailboxesByName->find( n.mid( 0, l ) );
523             if ( !m ) {
524                 m = new Mailbox( name.mid( 0, l ) );
525                 ::mailboxesByName->insert( n.mid( 0, l ), m );
526                 if ( p ) {
527                     if ( !p->d->children )
528                         p->d->children = new List<Mailbox>;
529                     p->d->children->append( m );
530                     m->d->parent = p;
531                 }
532             }
533             p = m;
534         }
535         i++;
536     }
537     return m;
538 }
539
540
541 /*! Sets this Mailbox's owner to \a n (which is assumed to be a valid
542     user id).
543 */
544
545 void Mailbox::setOwner( uint n )
546 {
547     d->owner = n;
548 }
549
550
551 /*! Atomically sets both uidnext() to \a n and nextModSeq() to \a
552     m. Uses subtransactions of \a t for all work needed.
553 */
554
555 void Mailbox::setUidnextAndNextModSeq( uint n, int64 m, Transaction * t )
556 {
557     if ( n == d->uidnext && m == d->nextModSeq )
558         return;
559     d->uidnext = n;
560     d->nextModSeq = m;
561
562     (void)new SessionInitialiser( this, t );
563 }
564
565
566 /*! Changes this Mailbox's deletedness to \a del. */
567
568 void Mailbox::setDeleted( bool del )
569 {
570     if ( del )
571         d->type = Deleted;
572     else
573         d->type = Ordinary;
574 }
575
576
577 /*! If this Mailbox does not exist, this function enqueues a Query to
578     create it in the Transaction \a t and returns the Query. Otherwise
579     it returns 0 and does nothing. It does not commit the transaction.
580
581     If \a owner is non-null, the new mailbox is owned by by \a owner.
582 */
583
584 Query * Mailbox::create( Transaction * t, User * owner )
585 {
586     Query * q;
587
588     if ( deleted() ) {
589         q = new Query( "update mailboxes "
590                        "set deleted='f',owner=$2,first_recent=uidnext "
591                        "where id=$1", 0 );
592         q->bind( 1, id() );
593     }
594     else if ( id() == 0 ) {
595         q = new Query( "insert into mailboxes "
596                        "(name,owner,uidnext,uidvalidity,deleted) "
597                        "values ($1,$2,1,1,'f')", 0 );
598         q->bind( 1, name() );
599     }
600     else {
601         return 0;
602     }
603
604     if ( owner )
605         q->bind( 2, owner->id() );
606     else
607         q->bindNull( 2 );
608
609     t->enqueue( q );
610
611     // We assume that the caller has checked permissions.
612
613     Mailbox * m = parent();
614     while ( m ) {
615         Query * q = 0;
616         if ( m->deleted() ) {
617             // Should we leave it be or undelete it?
618         }
619         else if ( m->id() == 0 ) {
620             q = new Query( "insert into mailboxes "
621                            "(name,owner,uidnext,uidvalidity,deleted) "
622                            "values ($1,null,1,1,'f')", 0 );
623             q->bind( 1, m->name() );
624         }
625
626         // We rely on the trigger to set the ownership of the
627         // intermediate mailboxes being created.
628
629         if ( q )
630             t->enqueue( q );
631
632         m = m->parent();
633     }
634
635     t->enqueue( new Query( "notify mailboxes_updated", 0 ) );
636
637     return q;
638 }
639
640
641 /*! If this Mailbox can be deleted, this function enqueues a Query to do
642     so in the Transaction \a t and returns the Query. If not, it returns
643     0 and does nothing. It does not commit the transaction.
644 */
645
646 Query * Mailbox::remove( Transaction * t )
647 {
648     if ( deleted() )
649         return 0;
650
651     Query * q =
652         new Query( "update mailboxes set deleted='t',owner=null "
653                    "where id=$1", 0 );
654     q->bind( 1, id() );
655     t->enqueue( q );
656
657     q = new Query( "delete from permissions where mailbox=$1", 0 );
658     q->bind( 1, id() );
659     t->enqueue( q );
660
661     t->enqueue( new Query( "notify mailboxes_updated", 0 ) );
662
663     return q;
664 }
665
666
667 /*! Adds one or more queries to \a t, to ensure that the Mailbox tree
668     is up to date when \a t is commited.
669 */
670
671 void Mailbox::refreshMailboxes( class Transaction * t )
672 {
673     Scope x( new Log );
674     MailboxReader * mr = new MailboxReader( 0, 0 );
675     Transaction * s = t->subTransaction( mr );
676     s->enqueue( mr->q );
677     s->enqueue( new Query( "notify mailboxes_updated", 0 ) );
678     s->execute();
679 }
680
681
682 /*! Returns a pointer to the sessions on this mailbox. The return
683     value may be a null pointer. In the event of client/network
684     problems it may also include sessions that have recently become
685     invalid.
686 */
687
688 List<Session> * Mailbox::sessions() const
689 {
690     List<Session> * r = 0;
691
692     List<Connection> * connections = EventLoop::global()->connections();
693     List<Connection>::Iterator i( connections );
694     while ( i ) {
695         Session * s = i->session();
696         if ( s && s->mailbox() == this ) {
697             if ( !r )
698                 r = new List<Session>;
699             r->append( s );
700         }
701         ++i;
702     }
703     return r;
704 }
705
706
707 /*! Returns the value last specified by nextModSeq(), or 1 initially. */
708
709 int64 Mailbox::nextModSeq() const
710 {
711     return d->nextModSeq;
712 }
713
714
715 /*! Returns true if \a s is syntactically valid as a mailbox name, and
716     false if not. Empty names are invalid, ones that do not start with
717     '/' are too, etc, etc.
718
719     Notably, the root ("/") is not valid. This is a borderline case -
720     for example "/" is valid as parent for creating new mailboxes, but
721     not as name of a new mailbox.
722 */
723
724 bool Mailbox::validName( const UString & s )
725 {
726     if ( !s.startsWith( "/" ) )
727         return false;
728     if ( s.endsWith( "/" ) )
729         return false;
730     if ( s.contains( "//" ) )
731         return false;
732     return true;
733 }
734
735
736 /*! This extremely slow pattern matching helper checks that \a pattern
737     (starting at character \a p) matches \a name (starting at
738     character \a n), and returns 2 in case of match, 1 if a child of
739     \a name might match, and 0 if neither is the case.
740
741     There are only two wildcards: * matches zero or more characters. %
742     matches zero or more characters, but does not match /.
743
744     Note that this match is case sensitive. Our mailbox names are case
745     insensitive, so the caller typically has to call
746     UString::titlecased() on both arguments.
747 */
748
749 uint Mailbox::match( const UString & pattern, uint p,
750                      const UString & name, uint n )
751 {
752     uint r = 0;
753     while ( p <= pattern.length() ) {
754         if ( pattern[p] == '*' || pattern[p] == '%' ) {
755             bool star = false;
756             while ( pattern[p] == '*' || pattern[p] == '%' ) {
757                 if ( pattern[p] == '*' )
758                     star = true;
759                 p++;
760             }
761             uint i = n;
762             if ( star )
763                 i = name.length();
764             else
765                 while ( i < name.length() && name[i] != '/' )
766                     i++;
767             while ( i >= n && i <= name.length() ) {
768                 uint s = match( pattern, p, name, i );
769                 if ( s == 2 )
770                     return 2;
771                 if ( s == 1 || star )
772                     r = 1;
773                 i--;
774             }
775         }
776         else if ( p == pattern.length() && n == name.length() ) {
777             // ran out of pattern and name at the same time. success.
778             return 2;
779         }
780         else if ( pattern[p] == name[n] ) {
781             // nothing. proceed.
782             p++;
783         }
784         else if ( pattern[p] == '/' && n >= name.length() ) {
785             // we ran out of name and the pattern wants a child.
786             return 1;
787         }
788         else {
789             // plain old mismatch.
790             return r;
791         }
792         n++;
793     }
794     return r;
795 }
796
797
798 /*! Returns true if the Mailbox subsystem is currently in the process
799     of relearning all the Mailbox objects from the database. Never
800     returns true during normal operations, but may if if the database
801     is wiped out by a test rig.
802 */
803
804 bool Mailbox::refreshing()
805 {
806     if ( !::wiped )
807         return false;
808     if ( !::readers )
809         return false;
810     if ( ::readers->isEmpty() )
811         return false;
812     return true;
813 }
814
815
816 /*! Aborts all sessions on this Mailbox. Good to call when a mailbox
817     is deleted.
818 */
819
820 void Mailbox::abortSessions()
821 {
822     List<Connection> * connections = EventLoop::global()->connections();
823     List<Connection>::Iterator i( connections );
824     while ( i ) {
825         Session * s = i->session();
826         if ( s && s->mailbox() == this ) {
827             i->close();
828         }
829         ++i;
830     }
831 }