OK found the reversal - the file timestamps were messed up.  The
attached should be the right way round and easier to apply.

Jim

On 11/04/2015 21:32, NSS Ltd wrote:
> Hi Arnt,
>
> OK, I've attached a first draft patch set for the status return.  I'm
> emphasizing draft/in-progress.
>
> This patch set also includes my previous patches and code for the
> annotate stuff which is probably redundant so it may be a good idea to
> look over and excise the annotation elements (the patch set may not be
> complete for those as there were some new files too).
>
> The patch set looks reversed to me, so careful using patch to apply it
> and using the reverse option looks necessary.
>
> I've done some basic tests but I don't have a full test set handy to
> properly validate this.  I'm hoping by giving you the patch you can run
> it through your test/validation harness (with added cases) ?
>
> Rather than use the id directly, I opted to add a column to mailboxes of
> type uuid (called guid) and generate uuids via postgresql.  This way the
> values are non-deterministic which I think may be better than allowing
> someone to predict the UUID for a mailbox and hence walk through them
> (i.e. my feeling is this approach is more secure).
>
> So mailboxes table is :
>
>                             Table "public.mailboxes"
>     Column    |  Type   |                      
> Modifiers                       
> --------------+---------+--------------------------------------------------------
>  id           | integer | not null default
> nextval('mailboxes_id_seq'::regclass)
>  name         | text    | not null
>  owner        | integer |
>  uidnext      | integer | not null default 1
>  nextmodseq   | bigint  | not null default 1
>  first_recent | integer | not null default 1
>  uidvalidity  | integer | not null default 1
>  deleted      | boolean | not null default false
>  guid         | uuid    | not null default uuid_generate_v4()   <--- NEW
> COLUMN
>
> Later (>9.3) postresql has some different uuid generation functions but
> I'm using 9.3 here.
>
> This one is a work in progress.
>
> Of course, I also found SOGo uses additional extensions - VANISHED - for
> fetching a message, so looks like that also needs more patching :
>
> Apr 11 14:35:55 email Archiveopteryx: 663/2/2/187 First line: 180 UID
> FETCH 1:* (UID) (CHANGEDSINCE 1 VANISHED)
> Apr 11 14:35:55 email Archiveopteryx: 663/2/2 IMAP::runCommands, 1 commands
> Apr 11 14:35:55 email Archiveopteryx: 663/2/2/187 Execution time 1ms
> Apr 11 14:35:55 email Archiveopteryx: 663/2/2/187 Finished
> Apr 11 14:35:55 email Archiveopteryx: 663/2/2 IMAP::runCommands, 1 commands
> Apr 11 14:35:55 email Archiveopteryx: 663/2/2/187 Retired
> Apr 11 14:35:55 email Archiveopteryx: 663/2/2/187 180 BAD Unknown fetch
> modifier: vanished
>
> Jim
>

Only in aox-jim: AOX
Only in aox-jim/aox: buildinfo.inc
diff -wur aox-master/aox/db.cpp aox-jim/aox/db.cpp
--- aox-master/aox/db.cpp       2014-06-03 09:15:21.000000000 -0400
+++ aox-jim/aox/db.cpp  2015-04-11 08:50:12.579422000 -0400
@@ -723,6 +723,9 @@
         case Column::Timestamp:
             s.append( "(timestamptz)" );
             break;
+               case Column::Uuid:
+                       s.append( "(uuid)");
+                       break;
         case Column::Null:
             s.append( "null" );
             break;
Only in aox-jim: bin
Only in aox-jim: build
diff -wur aox-master/core/estring.h aox-jim/core/estring.h
--- aox-master/core/estring.h   2014-06-03 09:15:21.000000000 -0400
+++ aox-jim/core/estring.h      2014-07-06 12:35:16.379058000 -0400
@@ -40,6 +40,7 @@
     EString & operator=( const EString & );
     EString & operator=( const char * );
     EString & operator+=( const EString & str ) { append( str ); return *this; 
}
+       EString & operator+=( const int64 & num ) { appendNumber(num); return 
*this; }
 
     void operator delete( void * );
 
Only in aox-jim/db: downgrades.inc
diff -wur aox-master/db/pgmessage.cpp aox-jim/db/pgmessage.cpp
--- aox-master/db/pgmessage.cpp 2014-06-03 09:15:21.000000000 -0400
+++ aox-jim/db/pgmessage.cpp    2015-04-11 09:16:33.295422000 -0400
@@ -8,6 +8,7 @@
 #include "buffer.h"
 #include "query.h"
 
+#include "stdio.h"
 
 static bool haveAskedForCitext;
 static int citextOid;
@@ -189,6 +190,53 @@
     return s;
 }
 
+EString PgServerMessage::decodeUUID( uint x ) {
+       EString s = "";
+       
+       if (16 != x) {
+               log("uuid decode should request 16 bytes but instead requested 
" + x );
+               throw Syntax;
+       }
+       
+       uint32 data1 = ( (*buf)[0] << 24 ) |
+            ( (*buf)[1] << 16 ) |
+            ( (*buf)[2] <<  8 ) |
+            ( (*buf)[3]       );
+    buf->remove( 4 );
+    n += 4;
+       
+       uint32 data2 = ((*buf)[0] << 8) | (*buf)[1];
+       buf->remove( 2 );
+    n += 2;
+       
+       uint32 data3 = ((*buf)[0] << 8) | (*buf)[1];
+       buf->remove( 2 );
+    n += 2;
+       
+       uint32 data4 = ((*buf)[0] << 8) | (*buf)[1];
+       buf->remove( 2 );
+    n += 2;
+       
+       uint32 data5 = ((*buf)[0] << 8) | (*buf)[1];
+       buf->remove( 2 );
+    n += 2;
+       
+       
+       uint32 data6 = ( (*buf)[0] << 24 ) |
+            ( (*buf)[1] << 16 ) |
+            ( (*buf)[2] <<  8 ) |
+            ( (*buf)[3]       );
+    buf->remove( 4 );
+    n += 4;
+       
+       char result[37];
+       sprintf( result, "%08x-%04x-%04x-%04x-%04x%08x", data1, data2, data3, 
data4, data5, data6);
+       
+       s = result;
+
+       return s;
+}
+
 
 /*! This function is used by subclasses to assert that they have decoded
     the entire contents of the message. If the size of the decoded data
@@ -898,6 +946,9 @@
         case 1184:
             cv->type = Column::Timestamp;
             break;
+               case 2950:
+                       cv->type = Column::Uuid;
+                       break;
         default:
             if ( it->type == ::citextOid ) { // CITEXT
                 cv->type = Column::Bytes;
@@ -978,6 +1029,9 @@
         case Column::Timestamp:
             cv->s = decodeByten( length );
             break;
+               case Column::Uuid:
+                       cv->s = decodeUUID( length );
+                       break;
         case Column::Null:
             // nothing needed
             break;
diff -wur aox-master/db/pgmessage.h aox-jim/db/pgmessage.h
--- aox-master/db/pgmessage.h   2014-06-03 09:15:21.000000000 -0400
+++ aox-jim/db/pgmessage.h      2015-04-11 07:50:20.871422000 -0400
@@ -33,6 +33,7 @@
     char decodeByte();
     EString decodeString();
     EString decodeByten( uint );
+       EString decodeUUID(uint);
     void end();
 };
 
Only in aox-jim/db: privileges.inc
diff -wur aox-master/db/query.cpp aox-jim/db/query.cpp
--- aox-master/db/query.cpp     2014-06-03 09:15:21.000000000 -0400
+++ aox-jim/db/query.cpp        2015-04-11 09:20:29.359422000 -0400
@@ -855,6 +855,19 @@
     return c->bi;
 }
 
+/*! Returns the string value of the column named \a f i if it exists
+    and is NOT NULL, and an empty string otherwise.
+*/
+
+EString Row::getUUID( const char * f ) const
+{
+    const Column * c = fetch( f, Column::Uuid, true );
+    if ( !c )
+        return "";
+    if ( c->type != Column::Uuid )
+        return "";
+    return c->s;
+}
 
 /*! Returns the string value of the column named \a f i if it exists
     and is NOT NULL, and an empty string otherwise.
@@ -1009,6 +1022,9 @@
     case Timestamp:
         n = "timestamptz";
         break;
+       case Uuid:
+               n = "uuid";
+               break;
     case Null:
         n = "null";
         break;
diff -wur aox-master/db/query.h aox-jim/db/query.h
--- aox-master/db/query.h       2014-06-03 09:15:21.000000000 -0400
+++ aox-jim/db/query.h  2015-04-11 09:19:18.935422000 -0400
@@ -129,7 +129,7 @@
     : public Garbage
 {
 public:
-    enum Type { Unknown, Boolean, Integer, Bigint, Bytes, Timestamp, Null };
+    enum Type { Unknown, Boolean, Integer, Bigint, Bytes, Timestamp, Null, 
Uuid };
 
     Type type;
     EString s;
@@ -153,6 +153,7 @@
     bool getBoolean( const char * ) const;
     EString getEString( const char * ) const;
     UString getUString( const char * ) const;
+       EString getUUID( const char * ) const;
     bool hasColumn( const char * ) const;
     Column::Type columnType( const char * ) const;
 
Only in aox-jim/doc: man
diff -wur aox-master/imap/command.cpp aox-jim/imap/command.cpp
--- aox-master/imap/command.cpp 2014-06-03 09:15:21.000000000 -0400
+++ aox-jim/imap/command.cpp    2014-07-07 08:37:36.395058000 -0400
@@ -51,6 +51,7 @@
 #include "handlers/thread.h"
 #include "handlers/unselect.h"
 #include "handlers/urlfetch.h"
+#include "handlers/folderannotation.h"
 
 #include <sys/time.h> // gettimeofday, struct timeval
 
@@ -263,6 +264,7 @@
         else if ( n == "setquotaroot" )
             c = new SetQuotaRoot();
 
+
         if ( c ) {
             authenticated = true;
             selected = true;
@@ -292,6 +294,10 @@
             c = new Sort( uid );
         else if ( n == "move" )
             c = new Move( uid );
+               else if ( n == "getannotation" )
+            c = new GetAnnotation;
+        else if ( n == "setannotation" )
+            c = new SetAnnotation;
 
         if ( c )
             selected = true;
@@ -1223,6 +1229,11 @@
 UString Command::mailboxName()
 {
     EString n = astring();
+       return mailboxName(n);
+}
+
+UString Command::mailboxName(const EString &source) {
+       EString n = source;
     if ( n.endsWith( "/" ) )
         n = n.mid( 0, n.length() - 1 );
 
diff -wur aox-master/imap/command.h aox-jim/imap/command.h
--- aox-master/imap/command.h   2014-06-03 09:15:21.000000000 -0400
+++ aox-jim/imap/command.h      2014-07-06 10:17:05.475058000 -0400
@@ -82,6 +82,7 @@
     uint msn();
     EString flag();
     class Mailbox * mailbox();
+       UString mailboxName(const EString &);
     UString mailboxName();
 
     void end();
diff -wur aox-master/imap/handlers/capability.cpp 
aox-jim/imap/handlers/capability.cpp
--- aox-master/imap/handlers/capability.cpp     2014-06-03 09:15:21.000000000 
-0400
+++ aox-jim/imap/handlers/capability.cpp        2015-04-07 16:14:14.159422000 
-0400
@@ -77,7 +77,7 @@
 
     if ( all || login ) {
         c.append( "ACL" );
-        c.append( "ANNOTATE-EXPERIMENT-1" );
+        c.append( "ANNOTATE" );
         c.append( "BINARY" );
         c.append( "CATENATE" );
         c.append( "CHILDREN" );
Only in aox-jim/imap/handlers: folderannotation.cpp
Only in aox-jim/imap/handlers: folderannotation.h
diff -wur aox-master/imap/handlers/Jamfile aox-jim/imap/handlers/Jamfile
--- aox-master/imap/handlers/Jamfile    2014-06-03 09:15:21.000000000 -0400
+++ aox-jim/imap/handlers/Jamfile       2014-07-06 06:46:05.047058000 -0400
@@ -37,4 +37,5 @@
     thread.cpp
     unselect.cpp
     urlfetch.cpp
+    folderannotation.cpp
     ;
diff -wur aox-master/imap/handlers/listext.cpp aox-jim/imap/handlers/listext.cpp
--- aox-master/imap/handlers/listext.cpp        2014-06-03 09:15:21.000000000 
-0400
+++ aox-jim/imap/handlers/listext.cpp   2015-04-11 15:58:14.047422000 -0400
@@ -19,19 +19,35 @@
     : public Garbage
 {
 public:
+       class statusInfo : public Garbage {
+       public:
+               uint messages;
+               uint unseen;
+               uint recent;
+               int64 nextmodseq;
+               EString guid;
+               
+                statusInfo() :
+                       messages(0), unseen(0), recent(0), nextmodseq(0) {
+                                       // Empty
+               }
+       };
+
     ListextData():
-        selectQuery( 0 ), permissionsQuery( 0 ),
-        reference( 0 ),
+        selectQuery( 0 ), permissionsQuery( 0 ), statusQuery( 0 ),
+        reference( 0 ), mailboxStatus (0),
         state( 0 ),
         extended( false ),
         returnSubscribed( false ), returnChildren( false ),
         selectSubscribed( false ), selectRemote( false ),
-        selectRecursiveMatch( false )
+        selectRecursiveMatch( false ), returnStatus( false )
     {}
 
     Query * selectQuery;
     Query * permissionsQuery;
+       Query * statusQuery;
     Mailbox * reference;
+       statusInfo * mailboxStatus;
     EString referenceName;
     UStringList patterns;
     uint state;
@@ -64,12 +80,38 @@
     EString previousResponse;
     List<Response> responses;
 
+       // Status Selection Object
+       class statusSelection : public Garbage {
+               public:
+               bool getRecent;
+               bool getMessages;
+               bool getUidNext;
+               bool getUidValidity;
+               bool getUnseen;
+               bool getHighestModSeq;
+               bool getXGuid;
+               
+
+                       statusSelection() :
+                       getRecent(false), getMessages(false), getUidNext(false),
+                       getUidValidity(false), getUnseen (false), 
getHighestModSeq (false),
+                       getXGuid ( false ) {
+                       // Empty Constructor
+               }
+       };
+
+       statusSelection statusRequired;
+       
+
+       
+
     bool extended;
     bool returnSubscribed;
     bool returnChildren;
     bool selectSubscribed;
     bool selectRemote;
     bool selectRecursiveMatch;
+       bool returnStatus;
 };
 
 
@@ -177,7 +219,7 @@
         uint bn = 1;
         EString sel;
         if ( d->selectSubscribed && d->selectRecursiveMatch ) {
-            sel = "select mb.id, mb.name, s.id as sid, "
+            sel = "with q1 as (select mb.id, mb.name, s.id as sid, "
                   "exists(select cmb.id from mailboxes cmb "
                   "join subscriptions cs on"
                   " (cmb.id=cs.mailbox and cs.owner=$1) "
@@ -192,14 +234,14 @@
             bn = 2;
         }
         else if ( d->selectSubscribed ) {
-            sel = "select mb.id, mb.name, s.id as sid from mailboxes mb "
+            sel = "with q1 as (select mb.id, mb.name, s.id as sid from 
mailboxes mb "
                   "join subscriptions s on (mb.id=s.mailbox and s.owner=$1) "
                   "where ";
             d->selectQuery->bind( 1, imap()->user()->id() );
             bn = 2;
         }
         else {
-            sel = "select mb.id, mb.name";
+            sel = "with q1 as (select mb.id, mb.name";
             if ( d->returnSubscribed ) {
                 sel.append( ", s.id as sid from mailboxes mb "
                             "left join subscriptions s on"
@@ -261,6 +303,17 @@
             ++i;
         }
         sel.append( " order by lower(mb.name)||' '" );
+               
+               // Complete Sub-Query And Add Our Own For Additional Status Info
+               sel.append( "), "
+                                       "q2 as (select q1.id, mb.guid, 
uidnext-first_recent as recent from q1 join mailboxes mb using (id)), "
+                                       "q3 as (select q1.id, count(uid) as 
unseen from q1 join mailbox_messages mm on (q1.id=mm.mailbox) where not seen 
group by id), "
+                                       "q4 as (select q1.id, count(*) as 
messages from q1 join mailbox_messages mm on (q1.id=mm.mailbox) group by id) ");
+               
+               // Now Return All Of That As A Single Query Compatible With
+               // The makeResponse Call From Before We Added The Status Feature
+               sel.append( "select * from q1 JOIN q2 using (id) join q3 using 
(id) join q4 using (id)");
+               
         d->selectQuery->setString( sel );
         d->selectQuery->execute();
 
@@ -387,10 +440,46 @@
         d->returnSubscribed = true;
     else if ( option == "children" )
         d->returnChildren = true;
-    else
+       else if ( "status" == option ) {
+               // Status Return Takes A Number Of Status Attributes We Need To 
Parse
+        d->returnStatus = true;
+               
+               require(" (");  // Status Must Be Followed By A SPACE Then (
+               
+               addStatusItem(atom().lower());  // First Status Item Is 
Mandatory
+               while ( present( " " ) )
+            addStatusItem( atom().lower() );   // Handle Any Further Items
+                       
+               require(")");   // To Complete Status, A Closing Bracket Is 
Mandatory
+               
+    } else
         error( Bad, "Unknown return option: " + option );
 }
 
+void Listext::addStatusItem( const EString & statusSelected ) {
+       if ("x-guid" == statusSelected) {
+               // X-GUID
+               d->statusRequired.getXGuid = true;
+       } else if ("messages" == statusSelected) {
+               d->statusRequired.getMessages = true;
+       } else if ("recent" == statusSelected) {
+               d->statusRequired.getRecent = true;
+       } else if ("uidnext" == statusSelected) {
+               d->statusRequired.getUidNext = true;
+       } else if ("uidvalidity" == statusSelected) {
+               d->statusRequired.getUidValidity = true;
+       } else if ("unseen" == statusSelected) {
+               d->statusRequired.getUnseen = true;
+       } else if ("highestmodseq" == statusSelected) {
+               d->statusRequired.getHighestModSeq = true;
+       } else {
+               // Nothing Valid Left - May Just Be We Don't Handle It Rather 
Than
+               // The RFC Stating It Is Illegal/Invalid.  We Log It So, If 
Debug Is
+               // Active, There Will Be A Record Of This Happening To Help
+               // Track It Down.
+               error( Bad, "Unknown status item: " + statusSelected );
+       }
+}
 
 /*! Parses the selection \a option, or emits a suitable error. \a
     option must be lower-cased. */
@@ -449,6 +538,68 @@
 
     EString name = imapQuoted( mailbox );
 
+       // Need To Append Any Extended Attributes Status ?
+       if (d->returnStatus) {
+               // yes - add them to ext
+               ext.append(" (");
+               EString preAppend = "";
+
+               if (d->statusRequired.getXGuid && row->hasColumn("guid") && 
!row->isNull("guid")) {
+                       // We want the guid and the column exists and is not 
null, so it is good to retrieve
+                       EString guid = row->getUUID("guid");
+                       ext.append(preAppend + "X-GUID " + guid);
+                       log("retrieved guid as " + guid);
+                       preAppend = " ";
+               }
+
+               if (d->statusRequired.getRecent && row->hasColumn("recent") && 
!row->isNull("recent")) {
+                       int recent = row->getInt("recent");
+                       ext.append(preAppend + "RECENT ");
+                       ext.appendNumber(recent);
+                       preAppend = " ";
+               }
+       
+               if (d->statusRequired.getUnseen && row->hasColumn("unseen") && 
!row->isNull("unseen")) {
+                       int unseen = row->getInt("unseen");
+                       ext.append(preAppend + "UNSEEN ");
+                       ext.appendNumber(unseen);
+                       preAppend = " ";
+               }
+
+               if (d->statusRequired.getMessages && row->hasColumn("messages") 
&& !row->isNull("messages")) {
+                       int messages = row->getInt("messages");
+                       ext.append(preAppend + "MESSAGES ");
+                       ext.appendNumber(messages);
+                       preAppend = " ";
+               }
+               
+               if (d->statusRequired.getUidNext) {
+                       int uidnext = mailbox->uidnext();
+                       ext.append(preAppend + "UIDNEXT ");
+                       ext.appendNumber(uidnext);
+                       preAppend = " ";
+               }               
+               
+               if (d->statusRequired.getUidValidity) {
+                       int uidvalidity = mailbox->uidvalidity();
+                       ext.append(preAppend + "UIDVALIDITY ");
+                       ext.appendNumber(uidvalidity);
+                       preAppend = " ";
+               }
+               
+               if (d->statusRequired.getHighestModSeq) {
+                       int64 highest = mailbox->nextModSeq();
+                       if (highest > 1)
+                               highest--;
+                               
+                       ext.append(preAppend + "HIGHESTMODSEQ ");
+                       ext.appendNumber(highest);
+                       preAppend = " ";
+               }
+               
+               ext.append(")");
+       }
+
     EString r = "LIST (" + a.join( " " ) + ") \"/\" " + name + ext;
 
     if ( r == d->previousResponse )
diff -wur aox-master/imap/handlers/listext.h aox-jim/imap/handlers/listext.h
--- aox-master/imap/handlers/listext.h  2014-06-03 09:15:21.000000000 -0400
+++ aox-jim/imap/handlers/listext.h     2015-04-10 16:23:50.459422000 -0400
@@ -20,6 +20,7 @@
 private:
     void addReturnOption( const EString & );
     void addSelectOption( const EString & );
+       void addStatusItem( const EString & );
 
     void makeResponse( class Row * );
 
diff -wur aox-master/imap/handlers/sort.cpp aox-jim/imap/handlers/sort.cpp
--- aox-master/imap/handlers/sort.cpp   2014-06-03 09:15:21.000000000 -0400
+++ aox-jim/imap/handlers/sort.cpp      2014-07-06 06:46:05.051058000 -0400
@@ -210,8 +210,8 @@
 {
     switch ( c->t ) {
     case Arrival:
-        addJoin( t, "join messages m on (m.id=mm.message) ",
-                 "m.idate", c->reverse );
+        addJoin( t, "join messages mardt on (mardt.id=mm.message) ",
+                 "mardt.idate", c->reverse );
         break;
     case Cc:
         addJoin( t,
diff -wur aox-master/imap/handlers/status.cpp aox-jim/imap/handlers/status.cpp
--- aox-master/imap/handlers/status.cpp 2014-06-03 09:15:21.000000000 -0400
+++ aox-jim/imap/handlers/status.cpp    2015-04-08 08:38:02.135422000 -0400
@@ -19,16 +19,17 @@
     StatusData() :
         messages( false ), uidnext( false ), uidvalidity( false ),
         recent( false ), unseen( false ),
-        modseq( false ),
+        modseq( false ), x_guid (false),
         mailbox( 0 ),
         unseenCount( 0 ), messageCount( 0 ), recentCount( 0 ),
         cacheState( 0 )
         {}
-    bool messages, uidnext, uidvalidity, recent, unseen, modseq;
+    bool messages, uidnext, uidvalidity, recent, unseen, modseq, x_guid;
     Mailbox * mailbox;
     Query * unseenCount;
     Query * messageCount;
     Query * recentCount;
+       Query * mailbox_x_guid;
     uint cacheState;
 
     class CacheItem
@@ -37,16 +38,19 @@
     public:
         CacheItem():
             hasMessages( false ), hasUnseen( false ), hasRecent( false ),
+                       has_x_guid (false),
             messages( 0 ), unseen( 0 ), recent( 0 ),
             nextmodseq( 0 ), mailbox( 0 )
             {}
         bool hasMessages;
         bool hasUnseen;
         bool hasRecent;
+               bool has_x_guid;
         uint messages;
         uint unseen;
         uint recent;
         int64 nextmodseq;
+               EString x_guid;
         Mailbox * mailbox;
     };
 
@@ -73,6 +77,7 @@
                 i->hasMessages = false;
                 i->hasUnseen = false;
                 i->hasRecent = false;
+                               i->has_x_guid = false;
             }
             return i;
         }
@@ -154,6 +159,8 @@
             d->unseen = true;
         else if ( item == "highestmodseq" )
             d->modseq = true;
+        else if ( "x-guid" == item )
+            d->x_guid = true;
         else
             error( Bad, "Unknown STATUS item: " + item );
 
@@ -189,13 +196,15 @@
 
     // 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->recentCount || d->messageCount || 
d->mailbox_x_guid) {
         if ( d->unseenCount && !d->unseenCount->done() )
             return;
         if ( d->messageCount && !d->messageCount->done() )
             return;
         if ( d->recentCount && !d->recentCount->done() )
             return;
+               if ( d->mailbox_x_guid && !d->mailbox_x_guid->done() )
+                       return;
     }
     if ( !::cache )
         ::cache = new StatusData::StatusCache;
@@ -233,7 +242,18 @@
             }
         }
     }
-
+    if ( d->mailbox_x_guid ) {
+               // Retrieve Mailbox GUID Value And Place Into Cache Item
+        while ( d->mailbox_x_guid->hasResults() ) {
+            Row * r = d->mailbox_x_guid->nextRow();
+            StatusData::CacheItem * ci =
+                ::cache->find( r->getInt( "mailbox" ) );
+            if ( ci ) {
+                ci->has_x_guid = true;
+                ci->x_guid = r->getEString( "guid" );
+            }
+        }
+    }
     // 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 ) {
@@ -244,9 +264,9 @@
             while ( i ) {
                 StatusData::CacheItem * ci = ::cache->provide( i );
                 bool need = false;
-                if ( d->unseen || d->recent || d->messages )
+                if ( d->unseen || d->recent || d->messages || d->x_guid )
                     need = true;
-                if ( ci->hasUnseen || ci->hasRecent || ci->hasMessages )
+                if ( ci->hasUnseen || ci->hasRecent || ci->hasMessages || 
ci->has_x_guid )
                     need = false;
                 if ( need )
                     mailboxes.add( i->id() );
@@ -282,6 +302,16 @@
                 d->messageCount->bind( 1, mailboxes );
                 d->messageCount->execute();
             }
+                       if ( d->x_guid ) {
+                               // Run Query To Get Mailbox GUID Value
+                d->mailbox_x_guid
+                    = new Query( "select guid "
+                                 "from mailboxes where id=any($1) "
+                                 , this );
+                d->mailbox_x_guid->bind( 1, mailboxes );
+                d->mailbox_x_guid->execute();
+            }
+                       
             d->cacheState = 2;
         }
         if ( d->cacheState == 2 ) {
@@ -296,6 +326,8 @@
                     ci->hasRecent = true;
                 if ( ci && d->messageCount )
                     ci->hasMessages = true;
+                if ( ci && d->mailbox_x_guid )
+                    ci->has_x_guid = true;
                 ++i;
             }
             // and drop the queries
@@ -303,6 +335,7 @@
             d->unseenCount = 0;
             d->recentCount = 0;
             d->messageCount = 0;
+                       d->mailbox_x_guid = NULL;       // Null is surely 
better than 0?
         }
     }
 
@@ -356,13 +389,26 @@
         d->messageCount->execute();
     }
 
-    if ( d->unseenCount || d->recentCount || d->messageCount ) {
+       // Individual guid query ?
+    if ( d->x_guid && !d->mailbox_x_guid && !i->has_x_guid ) {
+        d->mailbox_x_guid
+            = new Query( "select guid "
+                                                "from mailboxes where id=$1 "
+                         , this );
+        d->mailbox_x_guid->bind( 1, d->mailbox->id() );
+        d->mailbox_x_guid->execute();
+    }
+
+
+    if ( d->unseenCount || d->recentCount || d->messageCount || 
d->mailbox_x_guid ) {
         if ( d->unseenCount && !d->unseenCount->done() )
             return;
         if ( d->messageCount && !d->messageCount->done() )
             return;
         if ( d->recentCount && !d->recentCount->done() )
             return;
+        if ( d->mailbox_x_guid && !d->mailbox_x_guid->done() )
+            return;
     }
 
     // fifth part: return the payload.
@@ -396,6 +442,9 @@
         status.append( "HIGHESTMODSEQ " + fn( hms ) );
     }
 
+    if ( d->x_guid && i->has_x_guid )
+        status.append( "X-GUID " + i->x_guid );
+
     respond( "STATUS " + imapQuoted( d->mailbox ) +
              " (" + status.join( " " ) + ")" );
     finish();
Only in aox-jim/message: tld.inc
Only in aox-jim: patchset
diff -wur aox-master/sasl/mechanism.cpp aox-jim/sasl/mechanism.cpp
--- aox-master/sasl/mechanism.cpp       2014-06-03 09:15:21.000000000 -0400
+++ aox-jim/sasl/mechanism.cpp  2015-04-07 14:19:38.519422000 -0400
@@ -167,7 +167,8 @@
     d->state = newState;
     switch ( newState ) {
     case AwaitingInitialResponse:
-        // no logging necessary
+        // no logging necessary - but being done anyway since it helps 
debugging
+               log( "Awaiting initial response", Log::Debug );
         break;
     case IssuingChallenge:
         log( "Issuing challenge", Log::Debug );
diff -wur aox-master/sasl/sasllogin.cpp aox-jim/sasl/sasllogin.cpp
--- aox-master/sasl/sasllogin.cpp       2014-06-03 09:15:21.000000000 -0400
+++ aox-jim/sasl/sasllogin.cpp  2015-04-07 12:52:10.983422000 -0400
@@ -22,11 +22,14 @@
 SaslLogin::SaslLogin( EventHandler * c )
     : SaslMechanism( c, SaslMechanism::Login )
 {
+       log( "SASLLOGIN: Debug Info Commenced LOGIN", Log::Error );
+       setState( AwaitingInitialResponse );
 }
 
 
 EString SaslLogin::challenge()
 {
+       log( "SASLLOGIN: In Challenge with login " + login().ascii().quoted(), 
Log::Error );
     if ( login().isEmpty() )
         return "Username:";
     else
@@ -36,6 +39,7 @@
 
 void SaslLogin::parseResponse( const EString &s )
 {
+       log( "SASLLOGIN: Debug Info " + s.quoted(), Log::Error );
     if ( login().isEmpty() ) {
         if ( s.isEmpty() ) {
             setState( Failed );
Only in aox-master/sasl: sasllogin-fixed.cpp

Reply via email to