Rework blogview renderer, so it can build the threads with only the information our...
authorWilfried Goesgens <willi@arangodb.com>
Sat, 26 Dec 2015 23:57:08 +0000 (00:57 +0100)
committerWilfried Goesgens <willi@arangodb.com>
Sat, 26 Dec 2015 23:57:08 +0000 (00:57 +0100)
19 files changed:
webcit/bbsview_renderer.c
webcit/blogview_renderer.c
webcit/calendar.c
webcit/dav_propfind.c
webcit/dav_report.c
webcit/feed_generator.c
webcit/jsonview_renderer.c
webcit/mailview_renderer.c
webcit/messages.c
webcit/messages.h
webcit/msg_renderers.c
webcit/notes.c
webcit/sitemap.c
webcit/smtpqueue.c
webcit/summary.c
webcit/tasks.c
webcit/useredit.c
webcit/vcard_edit.c
webcit/wiki.c

index d9f255a..67f42b1 100644 (file)
@@ -417,6 +417,7 @@ InitModule_BBSVIEWRENDERERS
                NULL, 
                bbsview_LoadMsgFromServer,
                bbsview_RenderView_or_Tail,
-               bbsview_Cleanup
+               bbsview_Cleanup,
+               NULL
        );
 }
index d727650..c742daa 100644 (file)
@@ -22,8 +22,11 @@ typedef struct __BLOG {
        HashList *BLOGPOSTS;
        long p;
        int gotonext;
+       long firstp;
+       long maxp;
        StrBuf *Charset;
        StrBuf *Buf;
+       const StrBuf *FilterTag;
 } BLOG;
 
 /* 
@@ -60,7 +63,7 @@ void sitemap_do_blog(void) {
        Stat.maxload = INT_MAX;
        Stat.lowest_found = (-1);
        Stat.highest_found = (-1);
-       num_msgs = load_msg_ptrs("MSGS ALL", NULL, &Stat, NULL);
+       num_msgs = load_msg_ptrs("MSGS ALL", NULL, NULL, &Stat, NULL, NULL, NULL, NULL, 0);
        if (num_msgs < 1) return;
 
        for (i=0; i<num_msgs; ++i) {
@@ -159,9 +162,9 @@ void blogpost_destroy(blogpost *bp) {
  * Entry point for message read operations.
  */
 int blogview_GetParamsGetServerCall(SharedMessageStatus *Stat, 
-                                  void **ViewSpecific, 
-                                  long oper, 
-                                  char *cmd, 
+                                   void **ViewSpecific, 
+                                   long oper, 
+                                   char *cmd, 
                                    long len,
                                    char *filter,
                                    long flen)
@@ -174,6 +177,11 @@ int blogview_GetParamsGetServerCall(SharedMessageStatus *Stat,
        BL->gotonext = havebstr("gotonext");
        BL->Charset = NewStrBuf();
        BL->Buf = NewStrBuf();
+       BL->FilterTag = sbstr("FilterTag");
+       BL->firstp = lbstr("firstp");   /* start reading at... */
+       BL->maxp   = lbstr("maxp");         /* max posts to show... */
+       if (BL->maxp < 1) BL->maxp = 5;     /* default; move somewhere else? */
+       putlbstr("maxp", BL->maxp);
        *ViewSpecific = BL;
 
        Stat->startmsg = (-1);                                  /* not used here */
@@ -182,83 +190,116 @@ int blogview_GetParamsGetServerCall(SharedMessageStatus *Stat,
        if (Stat->maxmsgs == 0) Stat->maxmsgs = DEFAULT_MAXMSGS;
        
        /* perform a "read all" call to fetch the message list -- we'll cut it down later */
-       rlid[2].cmd(cmd, len);
+       snprintf(cmd, len, "MSGS ALL||2|8\n");
+
        if (BL->gotonext)
                Stat->load_seen = 1;
        return 200;
 }
 
 
-/*
- * This function is called for every message in the list.
- */
-int blogview_LoadMsgFromServer(SharedMessageStatus *Stat, 
-                             void **ViewSpecific, 
-                             message_summary* Msg, 
-                             int is_new, 
-                             int i)
+int blogview_IdentifyBlogposts (StrBuf *Line, 
+                               const char **pos, 
+                               message_summary *Msg, 
+                               StrBuf *ConversionBuffer,
+                               void **ViewSpecific)
 {
        BLOG *BL = (BLOG*) *ViewSpecific;
        blogpost *bp = NULL;
 
-       ReadOneMessageSummary(Msg, BL->Charset, BL->Buf);
-
        /* Stop processing if the viewer is only interested in a single post and
         * that message ID is neither the id nor the refs.
         */
        if ((BL->p != 0) &&
            (BL->p != Msg->reply_inreplyto_hash) &&
            (BL->p != Msg->reply_references_hash)) {
-               return 200;
+               return 0;
        }
 
+       if ((Msg->reply_references_hash == 0) && 
+           (BL->FilterTag != NULL) && 
+           (strstr(ChrPtr(Msg->EnvTo) , ChrPtr(BL->FilterTag)) == NULL)) {
+               /* filtering for tags, blogpost doesn't fit. */
+               return 0;
+       }
+           
        /*
-        * Add our little bundle of blogworthy wonderfulness to the hash table
+        * build up a hashtable of the blogposts.
         */
        if (Msg->reply_references_hash == 0) {
                bp = malloc(sizeof(blogpost));
-               if (!bp) return(200);
+
+               if (bp == NULL) return 0;
+
                memset(bp, 0, sizeof (blogpost));
+
                bp->top_level_id = Msg->reply_inreplyto_hash;
+               bp->alloc_msgs = 1000;
+               bp->msgs = malloc(bp->alloc_msgs * sizeof(long));
+               memset(bp->msgs, 0, (bp->alloc_msgs * sizeof(long)) );
+
+               /* the first one is the blogpost itself, all subequent are comments. */
+               bp->msgs[0] = Msg->msgnum;
+               bp->num_msgs = 1;
+
                Put(BL->BLOGPOSTS,
-                   (const char *)&Msg->reply_inreplyto_hash,
-                   sizeof(Msg->reply_inreplyto_hash),
+                   LKEY(Msg->reply_inreplyto_hash),
                    bp,
                    (DeleteHashDataFunc)blogpost_destroy);
        }
-       else {
+       /*
+        * Comments will be handled on the next iteration.
+        */
+
+       return 1;
+}
+
+
+/*
+ * This function is called for every message in the list.
+ */
+int blogview_LoadMsgFromServer(SharedMessageStatus *Stat, 
+                             void **ViewSpecific, 
+                             message_summary* Msg, 
+                             int is_new, 
+                             int i)
+{
+       blogpost *bp = NULL;
+       BLOG *BL = (BLOG*) *ViewSpecific;
+
+       if (Msg->reply_references_hash != 0) {
+               /* 
+                * this is a comment. try to assign it to a blogpost.
+                */
                GetHash(BL->BLOGPOSTS,
-                       (const char *)&Msg->reply_references_hash,
-                       sizeof(Msg->reply_references_hash),
+                       LKEY(Msg->reply_references_hash),
                        (void *)&bp);
-       }
 
-       /*
-        * Now we have a 'blogpost' to which we can add a message.  It's either the
-        * blog post itself or a comment attached to it; either way, the code is the same from
-        * this point onward.
-        */
-       if (bp != NULL) {
-               if (bp->alloc_msgs == 0) {
-                       bp->alloc_msgs = 1000;
-                       bp->msgs = malloc(bp->alloc_msgs * sizeof(long));
-                       memset(bp->msgs, 0, (bp->alloc_msgs * sizeof(long)) );
-               }
-               if (bp->num_msgs >= bp->alloc_msgs) {
-                       bp->alloc_msgs *= 2;
-                       bp->msgs = realloc(bp->msgs, (bp->alloc_msgs * sizeof(long)));
-                       memset(&bp->msgs[bp->num_msgs], 0,
-                               ((bp->alloc_msgs - bp->num_msgs) * sizeof(long)) );
+               /*
+                * Now we have a 'blogpost' to which we can add the comment.  It's either the
+                * blog post itself or a comment attached to it; either way, the code is the same from
+                * this point onward.
+                */
+               if (bp != NULL) {
+                       if (bp->num_msgs >= bp->alloc_msgs) {
+                               bp->alloc_msgs *= 2;
+                               bp->msgs = realloc(bp->msgs, (bp->alloc_msgs * sizeof(long)));
+                               memset(&bp->msgs[bp->num_msgs], 0,
+                                      ((bp->alloc_msgs - bp->num_msgs) * sizeof(long)) );
+                       }
+                       bp->msgs[bp->num_msgs++] = Msg->msgnum;
+                       if ((Msg->Flags & MSGFLAG_READ) != 0) {
+                               bp->unread_oments++;
+                       }
                }
-               bp->msgs[bp->num_msgs++] = Msg->msgnum;
-               if ((Msg->Flags & MSGFLAG_READ) != 0) {
-                       bp->unread_oments++;
+               else {
+                       /*
+                        * Ok, this comment probably belongs to one of the blogposts
+                        * we ruled out by filters. don't load it.
+                        */
+                       return 200;
                }
        }
-       else {
-               syslog(LOG_DEBUG, "** comment %ld is unparented", Msg->msgnum);
-       }
-
        return 200;
 }
 
@@ -268,11 +309,11 @@ int blogview_LoadMsgFromServer(SharedMessageStatus *Stat,
  * With big thanks to whoever wrote http://www.c.happycodings.com/Sorting_Searching/code14.html
  */
 static int blogview_sortfunc(const void *a, const void *b) { 
-       blogpost * const *one = a;
-       blogpost * const *two = b;
+       blogpost const *one = GetSearchPayload(a);
+       blogpost const *two = GetSearchPayload(b);
 
-       if ( (*one)->msgs[0] > (*two)->msgs[0] ) return(-1);
-       if ( (*one)->msgs[0] < (*two)->msgs[0] ) return(+1);
+       if ( one->msgs[0] > two->msgs[0] ) return(-1);
+       if ( one->msgs[0] < two->msgs[0] ) return(+1);
        return(0);
 }
 
@@ -287,19 +328,24 @@ int blogview_render(SharedMessageStatus *Stat, void **ViewSpecific, long oper)
        BLOG *BL = (BLOG*) *ViewSpecific;
        HashPos *it;
        const char *Key;
+       blogpost *thisBlogpost;
        void *Data;
        long len;
-       int i;
-       blogpost **blogposts = NULL;
        int num_blogposts = 0;
-       int num_blogposts_alloc = 0;
        int with_comments = 0;
-       int firstp = 0;
-       int maxp = 0;
        WCTemplputParams SubTP;
        WCTemplputParams StopSubTP;
        blogpost oneBP;
-
+       long firstPOffset = 0;
+       int count = 0;
+       int totalCount = 0;
+       StrBuf *PrevNext = NULL;
+
+       num_blogposts = GetCount(BL->BLOGPOSTS);
+       if (num_blogposts == 0) {
+               /* Nothing to do... */
+               return 0;
+       }
         memset(&SubTP, 0, sizeof(WCTemplputParams));    
         memset(&StopSubTP, 0, sizeof(WCTemplputParams));    
        memset(&oneBP, 0, sizeof(blogpost));
@@ -307,11 +353,6 @@ int blogview_render(SharedMessageStatus *Stat, void **ViewSpecific, long oper)
        /* Comments are shown if we are only viewing a single blog post */
        with_comments = (BL->p != 0);
 
-       firstp = ibstr("firstp");   /* start reading at... */
-       maxp   = ibstr("maxp");     /* max posts to show... */
-       if (maxp < 1) maxp = 5;     /* default; move somewhere else? */
-       putlbstr("maxp", maxp);
-
        it = GetNewHashPos(BL->BLOGPOSTS, 0);
 
        if ((BL->gotonext) && (BL->p == 0)) {
@@ -334,67 +375,82 @@ int blogview_render(SharedMessageStatus *Stat, void **ViewSpecific, long oper)
                        DeleteHashPos(&it);
                        return 0;
                }
-
-               RewindHashPos(BL->BLOGPOSTS, it, 0);
-       }
-
-       /* Iterate through the hash list and copy the data pointers into an array */
-       while (GetNextHashPos(BL->BLOGPOSTS, it, &len, &Key, &Data)) {
-               if (num_blogposts >= num_blogposts_alloc) {
-                       if (num_blogposts_alloc == 0) {
-                               num_blogposts_alloc = 100;
-                       }
-                       else {
-                               num_blogposts_alloc *= 2;
-                       }
-                       blogposts = realloc(blogposts, (num_blogposts_alloc * sizeof (blogpost *)));
-               }
-               blogposts[num_blogposts++] = (blogpost *) Data;
        }
-       DeleteHashPos(&it);
 
        /* Now we have our array.  It is ONLY an array of pointers.  The objects to
         * which they point are still owned by the hash list.
         */
-       if (num_blogposts > 0) {
-               int start_here = 0;
-               /* Sort newest-to-oldest */
-               qsort(blogposts, num_blogposts, sizeof(void *), blogview_sortfunc);
 
-               /* allow the user to select a starting point in the list */
-               for (i=0; i<num_blogposts; ++i) {
-                       if (blogposts[i]->top_level_id == firstp) {
-                               start_here = i;
+       /* get it into the right sort of order - blogposts may have been edited */
+       SortByPayload(BL->BLOGPOSTS, blogview_sortfunc);
+
+       /* Find the start post to display: */
+       if (BL->firstp != 0) {
+               /* Translate the firstpost id into an offset */
+               RewindHashPos(BL->BLOGPOSTS, it, 0);
+               while (GetNextHashPos(BL->BLOGPOSTS, it, &len, &Key, &Data)) {
+                       thisBlogpost = (blogpost *) Data;
+                       if (thisBlogpost->top_level_id == BL->firstp) {
+                               firstPOffset = count;
+                               break;
                        }
+                       count ++;
                }
+       }
 
-               /* FIXME -- allow the user (or a default setting) to select a maximum number of posts to display */
-
-               /* Now go through the list and render what we've got */
-               for (i=start_here; i<num_blogposts; ++i) {
-                       int j = i - maxp;
-                       if (j < 0) j = 0;
-                       StackContext(NULL, &SubTP, &blogposts[j], CTX_BLOGPOST, 0, NULL);
-                       if ((i > 0) && (i == start_here)) {
-                               StackContext(NULL, &SubTP, &blogposts[j], CTX_BLOGPOST, 0, NULL);
-                               DoTemplate(HKEY("view_blog_post_start"), WCC->WBuf, &SubTP);
-                       }
-                       if (i < (start_here + maxp)) {
-                               blogpost_render(blogposts[i], with_comments, &SubTP);
+       if ((num_blogposts > BL->maxp) || (firstPOffset != 0)){
+               PrevNext = NewStrBuf();
+               if (firstPOffset  > 0) {
+                       const char *k;
+                       long len;
+                       long posPrev = 0;
+                       /* we now need to go up to maxp items back */
+                       if (firstPOffset > BL->maxp) {
+                               posPrev = firstPOffset - BL->maxp;
                        }
-                       else if (i == (start_here + maxp)) {
-                               StackContext(&SubTP, &StopSubTP, &blogposts[i], CTX_BLOGPOST, 0, NULL);
-                               DoTemplate(HKEY("view_blog_post_stop"), WCC->WBuf, &SubTP);
-                               UnStackContext(&StopSubTP);
-                       }
-                       UnStackContext(&SubTP);
+                       GetHashAt(BL->BLOGPOSTS, posPrev, &len, &k, &Data);
+                       thisBlogpost = (blogpost *) Data;
+                       StackContext(NULL, &SubTP, thisBlogpost, CTX_BLOGPOST, 0, NULL);
+                       DoTemplate(HKEY("view_blog_post_start"), PrevNext, &SubTP);
+               }
+               if (firstPOffset + BL->maxp <= num_blogposts) {
+                       const char *k;
+                       long len;
+                       long posNext = firstPOffset + BL->maxp;
+                       GetHashAt(BL->BLOGPOSTS, posNext, &len, &k, &Data);
+                       thisBlogpost = (blogpost *) Data;
+                       StackContext(NULL, &SubTP, thisBlogpost, CTX_BLOGPOST, 0, NULL);
+                       DoTemplate(HKEY("view_blog_post_stop"), PrevNext, &SubTP);
                }
+       }
 
-               /* Done.  We are only freeing the array of pointers; the data itself
-                * will be freed along with the hash list.
-                */
-               free(blogposts);
+       StrBufAppendBuf(WCC->WBuf, PrevNext, 0);
+       count = totalCount = 0;
+       RewindHashPos(BL->BLOGPOSTS, it, 0);
+
+       /* FIXME -- allow the user (or a default setting) to select a maximum number of posts to display */
+       while (GetNextHashPos(BL->BLOGPOSTS, it, &len, &Key, &Data)) {
+               thisBlogpost = (blogpost *) Data;
+
+               /* allow the user to select a starting point in the list */
+               if (totalCount < firstPOffset) {
+                       /* skip all till we found the first valid: */
+                       totalCount ++;
+                       continue;
+               }
+               if (count >= BL->maxp) {
+                       /* enough is enough. */
+                       break;
+               }
+               StackContext(NULL, &SubTP, thisBlogpost, CTX_BLOGPOST, 0, NULL);
+               blogpost_render(thisBlogpost, with_comments, &SubTP);
+               UnStackContext(&SubTP);
+               count ++;
+               totalCount ++;
        }
+       StrBufAppendBuf(WCC->WBuf, PrevNext, 0);
+       FreeStrBuf(&PrevNext);
+       DeleteHashPos(&it);
 
        return(0);
 }
@@ -417,6 +473,12 @@ void
 InitModule_BLOGVIEWRENDERERS
 (void)
 {
+       const char* browseListFields[] = {
+               "msgn",
+               "nvto",
+               "wefw",
+               NULL
+       };
        RegisterCTX(CTX_BLOGPOST);
 
        RegisterReadLoopHandlerset(
@@ -424,10 +486,11 @@ InitModule_BLOGVIEWRENDERERS
                blogview_GetParamsGetServerCall,
                NULL,
                NULL,
-               NULL
+               blogview_IdentifyBlogposts
                blogview_LoadMsgFromServer,
                blogview_render,
-               blogview_Cleanup
+               blogview_Cleanup,
+               browseListFields
        );
 
        RegisterNamespace("BLOG:TOPLEVEL:MSGID", 0, 0, tmplput_blog_toplevel_id, NULL, CTX_BLOGPOST);
index 46ec41b..abb731a 100644 (file)
@@ -915,7 +915,8 @@ InitModule_CALENDAR
                NULL,
                calendar_LoadMsgFromServer,
                calendar_RenderView_or_Tail,
-               calendar_Cleanup);
+               calendar_Cleanup,
+               NULL);
 
        RegisterReadLoopHandlerset(
                VIEW_CALBRIEF,
@@ -925,7 +926,8 @@ InitModule_CALENDAR
                NULL,
                calendar_LoadMsgFromServer,
                calendar_RenderView_or_Tail,
-               calendar_Cleanup);
+               calendar_Cleanup,
+               NULL);
 
 
 
index 64e7a12..3df1342 100644 (file)
@@ -774,7 +774,8 @@ void dav_propfind(void)
 int ParseMessageListHeaders_EUID(StrBuf *Line, 
                                 const char **pos, 
                                 message_summary *Msg, 
-                                StrBuf *ConversionBuffer)
+                                StrBuf *ConversionBuffer,
+                                void **ViewSpecific)
 {
        Msg->euid = NewStrBuf();
        StrBufExtract_NextToken(Msg->euid,  Line, pos, '|');
@@ -834,6 +835,7 @@ InitModule_PROPFIND
                ParseMessageListHeaders_EUID,
                NULL, //// ""
                DavUIDL_RenderView_or_Tail,
-               DavUIDL_Cleanup);
+               DavUIDL_Cleanup,
+               NULL);
 
 }
index bd75eb7..9331ffd 100644 (file)
@@ -80,9 +80,10 @@ void dav_report(void)
 
 
 extern int ParseMessageListHeaders_EUID(StrBuf *Line, 
-                                const char **pos, 
-                                message_summary *Msg, 
-                                StrBuf *ConversionBuffer);
+                                       const char **pos, 
+                                       message_summary *Msg, 
+                                       StrBuf *ConversionBuffer,
+                                       void **ViewSpecific);
 
 extern int DavUIDL_GetParamsGetServerCall(SharedMessageStatus *Stat, 
                                          void **ViewSpecific, 
@@ -112,7 +113,8 @@ InitModule_REPORT
                ParseMessageListHeaders_EUID,
                NULL,
                DavUIDL_RenderView_or_Tail,
-               DavUIDL_Cleanup
+               DavUIDL_Cleanup,
+               NULL
        );
 
 }
index f6cb345..534778c 100644 (file)
@@ -162,7 +162,7 @@ void feed_rss_do_messages(void) {
        Stat.maxload = INT_MAX;
        Stat.lowest_found = (-1);
        Stat.highest_found = (-1);
-       num_msgs = load_msg_ptrs("MSGS ALL", NULL, &Stat, NULL);
+       num_msgs = load_msg_ptrs("MSGS ALL", NULL, NULL, &Stat, NULL, NULL, NULL, NULL, 0);
        if (num_msgs < 1) return;
 
        i = num_msgs;                                   /* convention is to feed newest-to-oldest */
index 7f2f1b7..5a097b0 100644 (file)
@@ -68,6 +68,7 @@ InitModule_JSONRENDERER
                ParseMessageListHeaders_Detail,
                NULL,
                json_RenderView_or_Tail,
-               json_Cleanup);
+               json_Cleanup,
+               NULL);
 
 }
index e1fb6ec..3090951 100644 (file)
@@ -13,7 +13,8 @@ static inline void CheckConvertBufs(struct wcsession *WCC)
 int ParseMessageListHeaders_Detail(StrBuf *Line, 
                                   const char **pos, 
                                   message_summary *Msg, 
-                                  StrBuf *ConversionBuffer)
+                                  StrBuf *ConversionBuffer,
+                                  void **ViewSpecific)
 {
        wcsession *WCC = WC;
        long len;
@@ -117,6 +118,7 @@ InitModule_MAILVIEW_RENDERERS
                ParseMessageListHeaders_Detail,
                NULL,
                NULL,
-               mailview_Cleanup);
+               mailview_Cleanup,
+               NULL);
 
 }
index 732ef03..ac29cd5 100644 (file)
@@ -488,8 +488,13 @@ void display_headers(void) {
  */
 int load_msg_ptrs(const char *servcmd,
                  const char *filter,
+                 StrBuf *FoundCharset,
                  SharedMessageStatus *Stat, 
-                 load_msg_ptrs_detailheaders LH)
+                 void **ViewSpecific,
+                 load_msg_ptrs_detailheaders LH,
+                 StrBuf *FetchMessageList,
+                 eMessageField *MessageFieldList,
+                 long HeaderCount)
 {
         wcsession *WCC = WC;
        message_summary *Msg;
@@ -521,6 +526,10 @@ int load_msg_ptrs(const char *servcmd,
                         serv_puts("000");
                        break;
                }
+               else if (FetchMessageList != NULL) {
+                       serv_putbuf(FetchMessageList);
+                       break;
+               }
                /* fall back to empty filter in case of we were fooled... */
                serv_puts("");
                serv_puts("000");
@@ -543,21 +552,30 @@ int load_msg_ptrs(const char *servcmd,
 
                        Msg->msgnum = StrBufExtractNext_long(Buf, &Ptr, '|');
                        Msg->date = StrBufExtractNext_long(Buf, &Ptr, '|');
-
-                       if (Stat->nummsgs == 0) {
-                               if (Msg->msgnum < Stat->lowest_found) {
-                                       Stat->lowest_found = Msg->msgnum;
-                               }
-                               if (Msg->msgnum > Stat->highest_found) {
-                                       Stat->highest_found = Msg->msgnum;
+                       if (MessageFieldList != NULL) {
+                               long i;
+                               for (i = 0; i < HeaderCount; i++) {
+                                       StrBufExtract_NextToken(Buf2, Buf, &Ptr, '|');
+                                       if (StrLength(Buf2) > 0) {
+                                               EvaluateMsgHdrEnum(MessageFieldList[i], Msg, Buf2, FoundCharset);
+                                       }
                                }
                        }
+                       else {
+                               if (Stat->nummsgs == 0) {
+                                       if (Msg->msgnum < Stat->lowest_found) {
+                                               Stat->lowest_found = Msg->msgnum;
+                                       }
+                                       if (Msg->msgnum > Stat->highest_found) {
+                                               Stat->highest_found = Msg->msgnum;
+                                       }
+                               }
 
-                       if ((Msg->msgnum == 0) && (StrLength(Buf) < 32)) {
-                               free(Msg);
-                               continue;
+                               if ((Msg->msgnum == 0) && (StrLength(Buf) < 32)) {
+                                       free(Msg);
+                                       continue;
+                               }
                        }
-
                        /* 
                         * as citserver probably gives us messages in forward date sorting
                         * nummsgs should be the same order as the message date.
@@ -568,7 +586,7 @@ int load_msg_ptrs(const char *servcmd,
                                        skipit = 1;
                        }
                        if ((!skipit) && (LH != NULL)) {
-                               if (!LH(Buf, &Ptr, Msg, Buf2)){
+                               if (!LH(Buf, &Ptr, Msg, Buf2, ViewSpecific)){
                                        free(Msg);
                                        continue;
                                }                                       
@@ -658,6 +676,9 @@ typedef struct _RoomRenderer{
        RenderView_or_Tail_func RenderView_or_Tail;
        View_Cleanup_func ViewCleanup;
        load_msg_ptrs_detailheaders LHParse;
+       long HeaderCount;
+       StrBuf *FetchMessageList;
+       eMessageField *MessageFieldList;
 } RoomRenderer;
 
 
@@ -739,9 +760,21 @@ void readloop(long oper, eCustomRoomRenderer ForceRenderer)
        }
        if (!IsEmptyStr(cmd)) {
                const char *p = NULL;
+               StrBuf *FoundCharset = NULL;
                if (!IsEmptyStr(filter))
                        p = filter;
-               Stat.nummsgs = load_msg_ptrs(cmd, p, &Stat, ViewMsg->LHParse);
+               if (ViewMsg->HeaderCount > 0) {
+                       FoundCharset = NewStrBuf();
+               }
+               Stat.nummsgs = load_msg_ptrs(cmd, p,
+                                            FoundCharset,
+                                            &Stat,
+                                            &ViewSpecific,
+                                            ViewMsg->LHParse,
+                                            ViewMsg->FetchMessageList,
+                                            ViewMsg->MessageFieldList,
+                                            ViewMsg->HeaderCount);
+               FreeStrBuf(&FoundCharset);
        }
 
        if (Stat.sortit) {
@@ -1537,6 +1570,12 @@ void display_enter(void)
                                        case eMessagePath:
                                        case eSpecialField:
                                        case eTimestamp:
+                                       case eHeaderOnly:
+                                       case eFormatType:
+                                       case eMessagePart:
+                                       case eSubFolder:
+                                       case ePevious:
+                                       case eLastHeader:
                                                break;
 
                                        }
@@ -1992,6 +2031,15 @@ void jsonMessageList(void) {
        readloop(oper, eUseDefault);
 }
 
+void FreeReadLoopHandlerSet(void *v) {
+       RoomRenderer *Handler = (RoomRenderer *) v;
+       FreeStrBuf(&Handler->FetchMessageList);
+       if (Handler->MessageFieldList != NULL) {
+               free(Handler->MessageFieldList);
+       }
+       free(Handler);
+}
+
 void RegisterReadLoopHandlerset(
        int RoomType,
        GetParamsGetServerCall_func GetParamsGetServerCall,
@@ -2000,9 +2048,12 @@ void RegisterReadLoopHandlerset(
        load_msg_ptrs_detailheaders LH,
        LoadMsgFromServer_func LoadMsgFromServer,
        RenderView_or_Tail_func RenderView_or_Tail,
-       View_Cleanup_func ViewCleanup
+       View_Cleanup_func ViewCleanup,
+       const char **browseListFields
        )
 {
+       long count = 0;
+       long i = 0;
        RoomRenderer *Handler;
 
        Handler = (RoomRenderer*) malloc(sizeof(RoomRenderer));
@@ -2016,7 +2067,30 @@ void RegisterReadLoopHandlerset(
        Handler->ViewCleanup = ViewCleanup;
        Handler->LHParse = LH;
 
-       Put(ReadLoopHandler, IKEY(RoomType), Handler, NULL);
+       if (browseListFields != NULL) {
+               while (browseListFields[count] != NULL) {
+                       count ++;
+               }
+               Handler->HeaderCount = count;
+               Handler->MessageFieldList = (eMessageField*) malloc(sizeof(eMessageField) * count);
+               Handler->FetchMessageList = NewStrBufPlain(NULL, 5 * count + 4 + 5);
+               StrBufPlain(Handler->FetchMessageList, HKEY("time\n"));
+               for (i = 0; i < count; i++) {
+                       if (!GetFieldFromMnemonic(&Handler->MessageFieldList[i], browseListFields[i])) {
+                               fprintf(stderr, "Unknown message header: %s\n", browseListFields[i]);
+                               exit(1);
+                       }
+                       StrBufAppendBufPlain(Handler->FetchMessageList, browseListFields[i], 4, 0);
+                       StrBufAppendBufPlain(Handler->FetchMessageList, HKEY("\n"), 0);
+               }
+               StrBufAppendBufPlain(Handler->FetchMessageList, HKEY("000"), 0);
+       }
+       else {
+               Handler->FetchMessageList = NULL;
+               Handler->MessageFieldList = NULL;
+       }
+
+       Put(ReadLoopHandler, IKEY(RoomType), Handler, FreeReadLoopHandlerSet);
 }
 
 void 
index 7dd909c..e9a3ebd 100644 (file)
@@ -14,7 +14,6 @@
 
 extern CtxType CTX_MAILSUM;
 extern CtxType CTX_MIME_ATACH;
-extern HashList *MsgHeaderHandler;
 extern HashList *MimeRenderHandler;
 extern HashList *ReadLoopHandler;
 typedef struct wc_mime_attachment wc_mime_attachment;
@@ -81,6 +80,43 @@ typedef struct _message_summary {
 } message_summary;
 void DestroyMessageSummary(void *vMsg);
 
+/* Maps to msgkeys[] in msgbase.c: */
+
+typedef enum _eMessageField {
+       eAuthor,
+       eXclusivID,
+       erFc822Addr,
+       eHumanNode,
+       emessageId,
+       eJournal,
+       eReplyTo,
+       eListID,
+       eMesageText,
+       eNodeName,
+       eOriginalRoom,
+       eMessagePath,
+       eRecipient,
+       eSpecialField,
+       eTimestamp,
+       eMsgSubject,
+       eenVelopeTo,
+       eWeferences,
+       eCarbonCopY,
+       eHeaderOnly,
+       eFormatType,
+       eMessagePart,
+       ePevious,
+       eSubFolder,
+       eLastHeader
+}eMessageField;
+
+extern const char* fieldMnemonics[];
+
+int GetFieldFromMnemonic(eMessageField *f, const char* c);
+
+int EvaluateMsgHdr(const char *HeaderName, long HdrNLen, message_summary *Msg, StrBuf *HdrLine, StrBuf *FoundCharset);
+int EvaluateMsgHdrEnum(eMessageField f, message_summary *Msg, StrBuf *HdrLine, StrBuf *FoundCharset);
+
 
 
 static inline message_summary* GetMessagePtrAt(int n, HashList *Summ)
@@ -120,12 +156,14 @@ enum {
  * @param Line the raw line with your message data
  * @param Msg put your parser results here...
  * @param ConversionBuffer if you need some workbuffer, don't free me!
+ * @param ViewSpecific your view specific context data
  * @returns 0: failure, trash this message. 1: all right, store it
  */
 typedef int (*load_msg_ptrs_detailheaders) (StrBuf *Line, 
                                            const char **pos, 
                                            message_summary *Msg, 
-                                           StrBuf *ConversionBuffer);
+                                           StrBuf *ConversionBuffer,
+                                           void **ViewSpecific);
 
 typedef void (*readloop_servcmd)(char *buf, long bufsize);
 
@@ -170,8 +208,13 @@ typedef struct _SharedMessageStatus {
 
 int load_msg_ptrs(const char *servcmd,
                  const char *filter,
-                 SharedMessageStatus *Stat, 
-                 load_msg_ptrs_detailheaders LH);
+                 StrBuf *FoundCharset,
+                 SharedMessageStatus *Stat,
+                 void **ViewSpecific,
+                 load_msg_ptrs_detailheaders LH,
+                 StrBuf *FetchMessageList,
+                 eMessageField *MessageFieldList,
+                 long HeaderCount);
 
 typedef int (*GetParamsGetServerCall_func)(SharedMessageStatus *Stat, 
                                           void **ViewSpecific, 
@@ -256,7 +299,12 @@ void RegisterReadLoopHandlerset(
         * VALgrindHALLA.
         * it also should release the content for delivery via end_burst() or wDumpContent(1);
         */
-       View_Cleanup_func ViewCleanup
+       View_Cleanup_func ViewCleanup,
+       /**
+        * brofwseListFields schould be a NULL-terminated list of message field mnemonics
+        * that will be the browse vector for the message header list.
+        */
+       const char **browseListFields
        );
 /*
 GetParamsGetServerCall
@@ -272,9 +320,8 @@ RenderView_or_Tail
 int ParseMessageListHeaders_Detail(StrBuf *Line, 
                                   const char **pos, 
                                   message_summary *Msg, 
-                                  StrBuf *ConversionBuffer);
-
-
+                                  StrBuf *ConversionBuffer,
+                                  void **ViewSpecific);
 
 /**
  * @brief function to register the availability to render a specific message
@@ -297,5 +344,4 @@ void RegisterMimeRenderer(const char *HeaderName, long HdrNLen,
  */
 int ReadOneMessageSummary(message_summary *Msg, StrBuf *FoundCharset, StrBuf *Buf);
 
-
 #endif
index 484a13d..15abfdd 100644 (file)
@@ -7,6 +7,7 @@ CtxType CTX_MIME_ATACH = CTX_NONE;
 
 HashList *MsgHeaderHandler = NULL;
 HashList *DflMsgHeaderHandler = NULL;
+HashList *DflEnumMsgHeaderHandler = NULL;
 
 
 static inline void CheckConvertBufs(struct wcsession *WCC)
@@ -65,6 +66,19 @@ void DestroyMessageSummary(void *vMsg)
        free(Msg);
 }
 
+int EvaluateMsgHdrEnum(eMessageField f, message_summary *Msg, StrBuf *HdrLine, StrBuf *FoundCharset)
+{
+       void *vHdr;
+       headereval* Hdr = NULL;
+       if (GetHash(DflEnumMsgHeaderHandler, IKEY(f), &vHdr) &&
+           (vHdr != NULL)) {
+               Hdr = (headereval*)vHdr;
+       }
+       if (Hdr == NULL)
+               return -1;
+       Hdr->evaluator(Msg, HdrLine, FoundCharset);
+       return Hdr->Type;
+}
 
 int EvaluateMsgHdr(const char *HeaderName, long HdrNLen, message_summary *Msg, StrBuf *HdrLine, StrBuf *FoundCharset)
 {
@@ -97,6 +111,7 @@ void RegisterMsgHdr(const char *HeaderName, long HdrNLen, ExamineMsgHeaderFunc e
                eMessageField f;
                if (GetFieldFromMnemonic(&f, HeaderName)) {
                        Put(DflMsgHeaderHandler, HeaderName, HdrNLen, ev, NULL);
+                       Put(DflEnumMsgHeaderHandler, IKEY(f), ev, reference_free_handler);
                        return;
                }
        }
@@ -273,6 +288,12 @@ void examine_content_encoding(message_summary *Msg, StrBuf *HdrLine, StrBuf *Fou
 /* TODO: do we care? */
 }
 
+
+void examine_exti(message_summary *Msg, StrBuf *HdrLine, StrBuf *FoundCharset)
+{
+       /* we don't care */
+}
+
 void examine_nhdr(message_summary *Msg, StrBuf *HdrLine, StrBuf *FoundCharset)
 {
        Msg->nhdr = 0;
@@ -880,8 +901,6 @@ void examine_content_type(message_summary *Msg, StrBuf *HdrLine, StrBuf *FoundCh
 
 int ReadOneMessageSummary(message_summary *Msg, StrBuf *FoundCharset, StrBuf *Buf)
 {
-       void *vHdr;
-       headereval *Hdr;
        const char *buf;
        const char *ebuf;
        int nBuf;
@@ -903,13 +922,8 @@ int ReadOneMessageSummary(message_summary *Msg, StrBuf *FoundCharset, StrBuf *Bu
                ebuf = strchr(ChrPtr(Buf), '=');
                nBuf = ebuf - buf;
                
-               if (GetHash(MsgHeaderHandler, buf, nBuf, &vHdr) &&
-                   (vHdr != NULL)) {
-                       Hdr = (headereval*)vHdr;
-                       StrBufCutLeft(Buf, nBuf + 1);
-                       Hdr->evaluator(Msg, Buf, FoundCharset);
-               }
-               else syslog(LOG_INFO, "Don't know how to handle Message Headerline [%s]", ChrPtr(Buf));
+               if (EvaluateMsgHdr(buf, nBuf, Msg, Buf, FoundCharset) < 0)
+                       syslog(LOG_INFO, "Don't know how to handle Message Headerline [%s]", ChrPtr(Buf));
        }
        return 1;
 }
@@ -1417,7 +1431,12 @@ const char* fieldMnemonics[] = {
        "subj", /* U -> eMsgSubject   */
        "nvto", /* V -> eenVelopeTo   */
        "wefw", /* W -> eWeferences   */
-       "cccc"  /* Y -> eCarbonCopY   */
+       "cccc", /* Y -> eCarbonCopY   */
+       "nhdr", /* % -> eHeaderOnly   */
+       "type", /* % -> eFormatType   */
+       "part", /* % -> eMessagePart  */
+       "suff", /* % -> eSubFolder    */
+       "pref"  /* % -> ePevious      */
 };
 HashList *msgKeyLookup = NULL;
 
@@ -1433,14 +1452,15 @@ int GetFieldFromMnemonic(eMessageField *f, const char* c)
 
 void FillMsgKeyLookupTable(void)
 {
-       long i;
+       long i = 0;
 
        msgKeyLookup = NewHash (1, FourHash);
 
-       for (i=0; i < 20; i++) {
+       while (i != eLastHeader) {
                if (fieldMnemonics[i] != NULL) {
                        Put(msgKeyLookup, fieldMnemonics[i], 4, (void*)i, reference_free_handler);
                }
+               i++;
        }
 }
 
@@ -1559,10 +1579,9 @@ InitModule_MSGRENDERERS
 #endif
        RegisterMimeRenderer(HKEY(""), render_MAIL_UNKNOWN, 0, 0);
 
-       FillMsgKeyLookupTable();
-
        /* these headers are citserver replies to MSG4 and friends. one evaluator for each */
        RegisterMsgHdr(HKEY("nhdr"), examine_nhdr, 0);
+       RegisterMsgHdr(HKEY("exti"), examine_exti, 0);
        RegisterMsgHdr(HKEY("type"), examine_type, 0);
        RegisterMsgHdr(HKEY("from"), examine_from, 0);
        RegisterMsgHdr(HKEY("subj"), examine_subj, 0);
@@ -1604,15 +1623,21 @@ ServerStartModule_MSGRENDERERS
 (void)
 {
        DflMsgHeaderHandler = NewHash (1, FourHash);
+       DflEnumMsgHeaderHandler = NewHash (1, Flathash);
        MsgHeaderHandler = NewHash(1, NULL);
        MimeRenderHandler = NewHash(1, NULL);
        ReadLoopHandler = NewHash(1, NULL);
+       FillMsgKeyLookupTable();
 }
 
 void 
 ServerShutdownModule_MSGRENDERERS
 (void)
 {
+       DeleteHash(&DflMsgHeaderHandler);
+       DeleteHash(&DflEnumMsgHeaderHandler);
+
+
        DeleteHash(&MsgHeaderHandler);
        DeleteHash(&MimeRenderHandler);
        DeleteHash(&ReadLoopHandler);
index 7dc3249..079bb96 100644 (file)
@@ -487,7 +487,8 @@ InitModule_NOTES
                NULL,
                notes_LoadMsgFromServer,
                NULL,
-               notes_Cleanup);
+               notes_Cleanup,
+               NULL);
 
        WebcitAddUrlHandler(HKEY("add_new_note"), "", 0, add_new_note, 0);
        WebcitAddUrlHandler(HKEY("ajax_update_note"), "", 0, ajax_update_note, 0);
index 8c3ee46..f4b6780 100644 (file)
@@ -30,7 +30,7 @@ void sitemap_do_bbs(void) {
        Stat.maxload = INT_MAX;
        Stat.lowest_found = (-1);
        Stat.highest_found = (-1);
-       num_msgs = load_msg_ptrs("MSGS ALL", NULL, &Stat, NULL);
+       num_msgs = load_msg_ptrs("MSGS ALL", NULL, NULL, &Stat, NULL, NULL, NULL, NULL, 0);
        if (num_msgs < 1) return;
 
        for (i=0; i<num_msgs; i+=20) {
@@ -61,7 +61,7 @@ void sitemap_do_wiki(void) {
        Stat.maxload = INT_MAX;
        Stat.lowest_found = (-1);
        Stat.highest_found = (-1);
-       num_msgs = load_msg_ptrs("MSGS ALL", NULL, &Stat, NULL);
+       num_msgs = load_msg_ptrs("MSGS ALL", NULL, NULL, &Stat, NULL, NULL, NULL, NULL, 0);
        if (num_msgs < 1) return;
 
        for (i=0; i<num_msgs; ++i) {
index b9b6de7..b5c750a 100644 (file)
@@ -448,6 +448,7 @@ InitModule_SMTP_QUEUE
                NULL,
                qview_LoadMsgFromServer,
                qview_RenderView_or_Tail,
-               qview_Cleanup);
+               qview_Cleanup,
+               NULL);
 
 }
index d2eeb2e..faa4f45 100644 (file)
@@ -111,7 +111,7 @@ void tasks_section(void) {
                num_msgs = 0;
        }
        else {
-               num_msgs = load_msg_ptrs("MSGS ALL", NULL, &Stat, NULL);
+               num_msgs = load_msg_ptrs("MSGS ALL", NULL, NULL, &Stat, NULL, NULL, NULL, NULL, 0);
        }
 
        if (num_msgs > 0) {
@@ -160,7 +160,7 @@ void calendar_section(void) {
                num_msgs = 0;
        }
        else {
-               num_msgs = load_msg_ptrs("MSGS ALL", NULL, &Stat, NULL);
+               num_msgs = load_msg_ptrs("MSGS ALL", NULL, NULL, &Stat, NULL, NULL, NULL, NULL, 0);
        }
        calendar_GetParamsGetServerCall(&Stat, 
                                        &v,
index d9afe93..66b05e3 100644 (file)
@@ -758,6 +758,7 @@ InitModule_TASKS
                NULL,
                tasks_LoadMsgFromServer,
                tasks_RenderView_or_Tail,
-               tasks_Cleanup);
+               tasks_Cleanup,
+               NULL);
        WebcitAddUrlHandler(HKEY("save_task"), "", 0, save_task, 0);
 }
index f710513..fd26e8a 100644 (file)
@@ -527,7 +527,7 @@ TRYAGAIN:
        Stat.lowest_found = (-1);
        Stat.highest_found = (-1);
        /* Search for the user's vCard */
-       if (load_msg_ptrs("MSGS ALL||||1", NULL, &Stat, NULL) > 0) {
+       if (load_msg_ptrs("MSGS ALL||||1", NULL, NULL, &Stat, NULL, NULL, NULL, NULL, 0) > 0) {
                at = GetNewHashPos(WCC->summ, 0);
                while (GetNextHashPos(WCC->summ, at, &HKLen, &HashKey, &vMsg)) {
                        Msg = (message_summary*) vMsg;          
index 608d740..69b04ca 100644 (file)
@@ -1147,7 +1147,8 @@ InitModule_VCARD
                NULL, 
                vcard_LoadMsgFromServer,
                vcard_RenderView_or_Tail,
-               vcard_Cleanup);
+               vcard_Cleanup,
+               NULL);
 
        RegisterIterator("MAIL:VCARDS", 0, NULL, CtxGetVcardList, NULL, NULL, CTX_VCARD, CTX_VCARD_LIST, IT_NOFLAG);
 
index 0ea7dd1..c6904c2 100644 (file)
@@ -346,7 +346,8 @@ InitModule_WIKI
                NULL,
                NULL,
                NULL,
-               wiki_Cleanup
+               wiki_Cleanup,
+               NULL
        );
 
        RegisterReadLoopHandlerset(
@@ -357,7 +358,8 @@ InitModule_WIKI
                NULL,
                NULL,
                NULL,
-               wiki_Cleanup
+               wiki_Cleanup,
+               NULL
        );
 
        WebcitAddUrlHandler(HKEY("wiki"), "", 0, display_wiki_page, 0);