From 4d0a622d2d3ae20770258981c6062f58c9fc01a3 Mon Sep 17 00:00:00 2001 From: Wilfried Goesgens Date: Sun, 27 Dec 2015 00:57:08 +0100 Subject: [PATCH] Rework blogview renderer, so it can build the threads with only the information our new MSGS with parametrized headers demanded gives us. --- webcit/bbsview_renderer.c | 3 +- webcit/blogview_renderer.c | 287 ++++++++++++++++++++++--------------- webcit/calendar.c | 6 +- webcit/dav_propfind.c | 6 +- webcit/dav_report.c | 10 +- webcit/feed_generator.c | 2 +- webcit/jsonview_renderer.c | 3 +- webcit/mailview_renderer.c | 6 +- webcit/messages.c | 106 +++++++++++--- webcit/messages.h | 64 +++++++-- webcit/msg_renderers.c | 53 +++++-- webcit/notes.c | 3 +- webcit/sitemap.c | 4 +- webcit/smtpqueue.c | 3 +- webcit/summary.c | 4 +- webcit/tasks.c | 3 +- webcit/useredit.c | 2 +- webcit/vcard_edit.c | 3 +- webcit/wiki.c | 6 +- 19 files changed, 399 insertions(+), 175 deletions(-) diff --git a/webcit/bbsview_renderer.c b/webcit/bbsview_renderer.c index d9f255ac0..67f42b12f 100644 --- a/webcit/bbsview_renderer.c +++ b/webcit/bbsview_renderer.c @@ -417,6 +417,7 @@ InitModule_BBSVIEWRENDERERS NULL, bbsview_LoadMsgFromServer, bbsview_RenderView_or_Tail, - bbsview_Cleanup + bbsview_Cleanup, + NULL ); } diff --git a/webcit/blogview_renderer.c b/webcit/blogview_renderer.c index d727650bf..c742daa9e 100644 --- a/webcit/blogview_renderer.c +++ b/webcit/blogview_renderer.c @@ -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; igotonext = 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; itop_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 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); diff --git a/webcit/calendar.c b/webcit/calendar.c index 46ec41bd6..abb731a53 100644 --- a/webcit/calendar.c +++ b/webcit/calendar.c @@ -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); diff --git a/webcit/dav_propfind.c b/webcit/dav_propfind.c index 64e7a1297..3df13423e 100644 --- a/webcit/dav_propfind.c +++ b/webcit/dav_propfind.c @@ -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); } diff --git a/webcit/dav_report.c b/webcit/dav_report.c index bd75eb772..9331ffd49 100644 --- a/webcit/dav_report.c +++ b/webcit/dav_report.c @@ -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 ); } diff --git a/webcit/feed_generator.c b/webcit/feed_generator.c index f6cb345a0..534778c1d 100644 --- a/webcit/feed_generator.c +++ b/webcit/feed_generator.c @@ -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 */ diff --git a/webcit/jsonview_renderer.c b/webcit/jsonview_renderer.c index 7f2f1b7be..5a097b0a4 100644 --- a/webcit/jsonview_renderer.c +++ b/webcit/jsonview_renderer.c @@ -68,6 +68,7 @@ InitModule_JSONRENDERER ParseMessageListHeaders_Detail, NULL, json_RenderView_or_Tail, - json_Cleanup); + json_Cleanup, + NULL); } diff --git a/webcit/mailview_renderer.c b/webcit/mailview_renderer.c index e1fb6ecdc..309095130 100644 --- a/webcit/mailview_renderer.c +++ b/webcit/mailview_renderer.c @@ -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); } diff --git a/webcit/messages.c b/webcit/messages.c index 732ef03b8..ac29cd5d7 100644 --- a/webcit/messages.c +++ b/webcit/messages.c @@ -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 diff --git a/webcit/messages.h b/webcit/messages.h index 7dd909c33..e9a3ebdc9 100644 --- a/webcit/messages.h +++ b/webcit/messages.h @@ -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 diff --git a/webcit/msg_renderers.c b/webcit/msg_renderers.c index 484a13d8b..15abfddf5 100644 --- a/webcit/msg_renderers.c +++ b/webcit/msg_renderers.c @@ -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); diff --git a/webcit/notes.c b/webcit/notes.c index 7dc3249be..079bb960b 100644 --- a/webcit/notes.c +++ b/webcit/notes.c @@ -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); diff --git a/webcit/sitemap.c b/webcit/sitemap.c index 8c3ee463e..f4b67805f 100644 --- a/webcit/sitemap.c +++ b/webcit/sitemap.c @@ -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 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, diff --git a/webcit/tasks.c b/webcit/tasks.c index d9afe93a1..66b05e3e0 100644 --- a/webcit/tasks.c +++ b/webcit/tasks.c @@ -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); } diff --git a/webcit/useredit.c b/webcit/useredit.c index f710513cb..fd26e8a39 100644 --- a/webcit/useredit.c +++ b/webcit/useredit.c @@ -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; diff --git a/webcit/vcard_edit.c b/webcit/vcard_edit.c index 608d74025..69b04ca40 100644 --- a/webcit/vcard_edit.c +++ b/webcit/vcard_edit.c @@ -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); diff --git a/webcit/wiki.c b/webcit/wiki.c index 0ea7dd120..c6904c2bd 100644 --- a/webcit/wiki.c +++ b/webcit/wiki.c @@ -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); -- 2.30.2