X-Git-Url: https://code.citadel.org/?a=blobdiff_plain;f=webcit%2Fbbsview_renderer.c;h=8bed3af37ddae02e57728da12e16119607de7b82;hb=4b4dc864ede7c5d8d956febe4a0afb422b78e7c4;hp=11b7734e09c7739fb117f343da46e7222ddbddb2;hpb=6634b8a4dcccacc37535df860f613727b5b2b883;p=citadel.git diff --git a/webcit/bbsview_renderer.c b/webcit/bbsview_renderer.c index 11b7734e0..8bed3af37 100644 --- a/webcit/bbsview_renderer.c +++ b/webcit/bbsview_renderer.c @@ -1,39 +1,79 @@ /* - * $Id$ - * * BBS View renderer module for WebCit * - * Copyright (c) 1996-2010 by the citadel.org team + * Note: we briefly had a dynamic UI for this. I thought it was cool, but + * it was not received well by the user community. If you want to play + * with it, go get commit dcf99fe61379b78436c387ea3f89ebfd4ffaf635 of + * bbsview_renderer.c and have fun. + * + * Copyright (c) 1996-2011 by the citadel.org team * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. + * This program is open source software. You can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 3 of the + * License, or (at your option) any later version. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#define RANGE 5 + #include "webcit.h" #include "webserver.h" -#include "groupdav.h" +#include "dav.h" /* * Data which gets passed around between the various functions in this module + * */ struct bbsview { long *msgs; /* Array of msgnums for messages we are displaying */ int num_msgs; /* Number of msgnums stored in 'msgs' */ + long lastseen; /* The number of the last seen message in this room */ int alloc_msgs; /* Currently allocated size of array */ + int requested_page; /* Which page number did the user request? */ + int num_pages; /* Total number of pages in this room */ + long start_reading_at; /* Start reading at the page containing this message */ }; +/* + * Attempt to determine the closest thing to the "last seen message number" using the + * results of the GTSN command + */ +long bbsview_get_last_seen(void) +{ + char buf[SIZ] = "0"; + + serv_puts("GTSN"); + serv_getln(buf, sizeof buf); + if (buf[0] == '2') { + char *colon_pos; + char *comma_pos; + + comma_pos = strchr(buf, ','); /* kill first comma and everything to its right */ + if (comma_pos) { + *comma_pos = 0; + } + + colon_pos = strchr(buf, ':'); /* kill first colon and everything to its left */ + if (colon_pos) { + strcpy(buf, ++colon_pos); + } + } + + return(atol(buf)); +} + + + /* * Entry point for message read operations. */ @@ -41,40 +81,51 @@ int bbsview_GetParamsGetServerCall(SharedMessageStatus *Stat, void **ViewSpecific, long oper, char *cmd, - long len) + long len, + char *filter, + long flen) { struct bbsview *BBS = malloc(sizeof(struct bbsview)); memset(BBS, 0, sizeof(struct bbsview)); *ViewSpecific = BBS; - Stat->startmsg = -1; - Stat->sortit = 1; - - rlid[oper].cmd(cmd, len); /* this performs the server call to fetch the msg list */ - - if (havebstr("maxmsgs")) { - Stat->maxmsgs = ibstr("maxmsgs"); - } - if (Stat->maxmsgs == 0) Stat->maxmsgs = DEFAULT_MAXMSGS; - Stat->num_displayed = DEFAULT_MAXMSGS; - - if (havebstr("startmsg")) { - Stat->startmsg = lbstr("startmsg"); + Stat->startmsg = (-1); /* not used here */ + Stat->sortit = 1; /* not used here */ + Stat->num_displayed = DEFAULT_MAXMSGS; /* not used here */ + BBS->requested_page = 0; + BBS->lastseen = bbsview_get_last_seen(); + BBS->start_reading_at = 0; + + /* By default, the requested page is the first one. */ + if (havebstr("start_reading_at")) { + BBS->start_reading_at = lbstr("start_reading_at"); + BBS->requested_page = (-4); } - return 200; -} + /* However, if we are asked to start with a specific message number, make sure + * we start on the page containing that message + */ + /* Or, if a specific page was requested, make sure we go there */ + else if (havebstr("page")) { + BBS->requested_page = ibstr("page"); + } -/* - * begin_ajax_response() was moved from bbsview_LoadMsgFromServer() to here ... - */ -int bbsview_PrintViewHeader(SharedMessageStatus *Stat, void **ViewSpecific) -{ - if (WC->is_ajax) { - begin_ajax_response(); /* for non-ajax, headers are output in messages.c */ + /* Otherwise, if this is a "read new" operation, make sure we start on the page + * containing the first new message + */ + else if (oper == 3) { + BBS->requested_page = (-3); } + if (havebstr("maxmsgs")) { + Stat->maxmsgs = ibstr("maxmsgs"); + } + 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); + return 200; } @@ -91,14 +142,16 @@ int bbsview_LoadMsgFromServer(SharedMessageStatus *Stat, struct bbsview *BBS = (struct bbsview *) *ViewSpecific; if (BBS->alloc_msgs == 0) { - BBS->alloc_msgs = Stat->maxmsgs; + BBS->alloc_msgs = 1000; BBS->msgs = malloc(BBS->alloc_msgs * sizeof(long)); + memset(BBS->msgs, 0, (BBS->alloc_msgs * sizeof(long)) ); } - /* Theoretically this never happens because the initial allocation == maxmsgs */ + /* Check our buffer size */ if (BBS->num_msgs >= BBS->alloc_msgs) { BBS->alloc_msgs *= 2; BBS->msgs = realloc(BBS->msgs, (BBS->alloc_msgs * sizeof(long))); + memset(&BBS->msgs[BBS->num_msgs], 0, ((BBS->alloc_msgs - BBS->num_msgs) * sizeof(long)) ); } BBS->msgs[BBS->num_msgs++] = Msg->msgnum; @@ -106,6 +159,7 @@ int bbsview_LoadMsgFromServer(SharedMessageStatus *Stat, return 200; } + int bbsview_sortfunc(const void *s1, const void *s2) { long l1; long l2; @@ -125,161 +179,220 @@ int bbsview_RenderView_or_Tail(SharedMessageStatus *Stat, { struct bbsview *BBS = (struct bbsview *) *ViewSpecific; int i; + int seq; const StrBuf *Mime; - char olderdiv[64]; - char newerdiv[64]; - int doing_older_messages = 0; - int doing_newer_messages = 0; - - int increments[] = { 20, 50, 100 } ; -#define NUM_INCREMENTS (sizeof(increments) / sizeof(int)) + int start_index = 0; + int end_index = 0; + int go_to_the_very_end = 0; - snprintf(olderdiv, sizeof olderdiv, "olderdiv%08lx%08x", time(NULL), rand()); - snprintf(newerdiv, sizeof newerdiv, "newerdiv%08lx%08x", time(NULL), rand()); - - /* Determine whether we are in the middle of a 'click for older messages' or 'click for - * newer messages' operation. If neither, then we are in the initial page load. - */ - if (!strcasecmp(bstr("gt_or_lt"), "lt")) { - doing_older_messages = 1; - doing_newer_messages = 0; + if (Stat->nummsgs > 0) { + syslog(9, "sorting %d messages\n", BBS->num_msgs); + qsort(BBS->msgs, (size_t)(BBS->num_msgs), sizeof(long), bbsview_sortfunc); } - else if (!strcasecmp(bstr("gt_or_lt"), "gt")) { - doing_older_messages = 0; - doing_newer_messages = 1; + + if ((BBS->num_msgs % Stat->maxmsgs) == 0) { + BBS->num_pages = BBS->num_msgs / Stat->maxmsgs; } else { - doing_older_messages = 0; - doing_newer_messages = 0; + BBS->num_pages = (BBS->num_msgs / Stat->maxmsgs) + 1; } - - /* Cut the message list down to the requested size */ - if (Stat->nummsgs > 0) { - lprintf(9, "sorting %d messages\n", BBS->num_msgs); - qsort(BBS->msgs, (size_t)(BBS->num_msgs), sizeof(long), bbsview_sortfunc); - - /* Cut it down to 20 messages (or whatever value Stat->maxmsgs is set to) */ - - if (BBS->num_msgs > Stat->maxmsgs) { - - if (doing_older_messages) { - /* LT ... cut it down to the LAST 20 messages received */ - memcpy(&BBS->msgs[0], &BBS->msgs[BBS->num_msgs - Stat->maxmsgs], - (Stat->maxmsgs * sizeof(long)) - ); - BBS->num_msgs = Stat->maxmsgs; - } - else { - /* GT ... cut it down to the FIRST 20 messages received */ - BBS->num_msgs = Stat->maxmsgs; + /* If the requested page number is -4, + * it means "whichever page on which msg#xxxxx starts" + * Change to the page number which contains that message. + */ + if (BBS->requested_page == (-4)) { + if (BBS->num_msgs == 0) { + BBS->requested_page = 0; + } + else { + for (i=0; inum_msgs; ++i) { + if ( + (BBS->msgs[i] >= BBS->start_reading_at) + && (BBS->requested_page == (-4)) + ) { + BBS->requested_page = (i / Stat->maxmsgs) ; + } } } } - - /* Supply the link to prepend the previous 20 messages */ - - if ((!WC->is_ajax) && (Stat->nummsgs == 0)) { - wc_printf("
", olderdiv); - wc_printf("
"); - for (i=0; i", - olderdiv, - LONG_MAX, - increments[i] - ); - wc_printf("↑ "); - wc_printf(_("Previous %d"), increments[i]); - wc_printf(" ↑"); - wc_printf(""); + /* If the requested page number is -3, + * it means "whichever page on which new messages start" + * Change that to an actual page number now. + */ + if (BBS->requested_page == (-3)) { + if (BBS->num_msgs == 0) { + /* + * The room is empty; just start at the top and leave it there. + */ + BBS->requested_page = 0; } - wc_printf("
"); - wc_printf("

"); - wc_printf(_("No messages here.")); - wc_printf("
\n"); - wc_printf("
"); - } - else if (doing_newer_messages == 0) { - wc_printf("
", olderdiv); - wc_printf("
"); - if (Stat->nummsgs > 0) { - for (i=0; i", - olderdiv, - BBS->msgs[0], - increments[i] - ); - wc_printf("↑ "); - wc_printf(_("Previous %d"), increments[i]); - wc_printf(" ↑"); - wc_printf(""); + else if ( + (BBS->num_msgs > 0) + && (BBS->lastseen <= BBS->msgs[0]) + ) { + /* + * All messages are new; this is probably the user's first visit to the room, + * so start at the last page instead of showing ancient history. + */ + BBS->requested_page = BBS->num_pages - 1; + go_to_the_very_end = 1; + } + else { + /* + * Some messages are old and some are new. Go to the start of new messages. + */ + for (i=0; inum_msgs; ++i) { + if ( + (BBS->msgs[i] > BBS->lastseen) + && ( (i == 0) || (BBS->msgs[i-1] <= BBS->lastseen) ) + ) { + BBS->requested_page = (i / Stat->maxmsgs) ; + } } - wc_printf("
"); } - wc_printf("
"); } - /* Non-empty message set... */ - if (Stat->nummsgs > 0) { - /* Render the messages */ - - for (i=0; inum_msgs; ++i) { - read_message(WC->WBuf, HKEY("view_message"), BBS->msgs[i], NULL, &Mime); + /* Still set to -3 ? If so, that probably means that there are no new messages, + * so we'll go to the *end* of the final page. + */ + if (BBS->requested_page == (-3)) { + if (BBS->num_msgs == 0) { + BBS->requested_page = 0; + } + else { + BBS->requested_page = BBS->num_pages - 1; } - } + /* keep the requested page within bounds */ + if (BBS->requested_page < 0) BBS->requested_page = 0; + if (BBS->requested_page >= BBS->num_pages) BBS->requested_page = BBS->num_pages - 1; + + start_index = BBS->requested_page * Stat->maxmsgs; + if (start_index < 0) start_index = 0; + end_index = start_index + Stat->maxmsgs - 1; + + for (seq = 0; seq < 3; ++seq) { /* cheap & sleazy way of rendering the page numbers twice */ + + if ( (seq == 1) && (Stat->nummsgs > 0)) { + /* display the selected range of messages */ + + for (i=start_index; (i<=end_index && inum_msgs); ++i) { + if ( + (BBS->msgs[i] > BBS->lastseen) + && ( (i == 0) || (BBS->msgs[i-1] <= BBS->lastseen) ) + ) { + /* new messages start here */ + do_template("start_of_new_msgs"); + if (!go_to_the_very_end) { + StrBufAppendPrintf(WC->trailing_javascript, "location.href=\"#newmsgs\";\n"); + } + } + if (BBS->msgs[i] > 0L) { + read_message(WC->WBuf, HKEY("view_message"), BBS->msgs[i], NULL, &Mime); + } + if ( + (i == (BBS->num_msgs - 1)) + && (BBS->msgs[i] <= BBS->lastseen) + ) { + /* no new messages */ + do_template("no_new_msgs"); + if (!go_to_the_very_end) { + StrBufAppendPrintf(WC->trailing_javascript, "location.href=\"#nonewmsgs\";\n"); + } + } + } + } - /* Supply the link to append the next 20 messages */ + else if ( (seq == 0) || (seq == 2) ) { + int first; + int last; + /* Display the selecto-bar with the page numbers */ - if (doing_older_messages == 0) { - wc_printf("
", newerdiv); - if (Stat->nummsgs >= Stat->maxmsgs) { wc_printf("
"); - for (i=0; i", - newerdiv, - BBS->msgs[BBS->num_msgs-1], - increments[i] - ); - wc_printf("↓ "); - wc_printf(_("Next %d"), increments[i]); - wc_printf(" ↓"); - wc_printf(""); + if (seq == 2) { + wc_printf(""); } - wc_printf("
"); - } - else { - long gt = 0; /* if new messages appear later, where will they begin? */ - if (Stat->nummsgs > 0) { - gt = BBS->msgs[BBS->num_msgs-1]; + wc_printf(_("Go to page: ")); + if (seq == 2) { + wc_printf(""); } - else { - gt = atol(bstr("gt")); + + first = 0; + last = BBS->num_pages - 1; + + for (i=0; i<=last; ++i) { + + if ( + (i == first) + || (i == last) + || (i == BBS->requested_page) + || ( + ((BBS->requested_page - i) < RANGE) + && ((BBS->requested_page - i) > (0 - RANGE)) + ) + ) { + + if ( + (i == last) + && (last - BBS->requested_page > RANGE) + ) { + wc_printf("... "); + } + if (i == BBS->requested_page) { + wc_printf("["); + } + else { + wc_printf("CurRoom.name)); + wc_printf("?start_reading_at=%ld\">", + BBS->msgs[i*Stat->maxmsgs] + ); + /* wc_printf("?page=%d\">", i); */ + wc_printf(""); + } + if ( + (i == first) + && (BBS->requested_page > (RANGE + 1)) + ) { + wc_printf(_("First")); + } + else if ( + (i == last) + && (last - BBS->requested_page > RANGE) + ) { + wc_printf(_("Last")); + } + else { + wc_printf("%d", i + 1); /* change to one-based for display */ + } + if (i == BBS->requested_page) { + wc_printf("]"); + } + else { + wc_printf(""); + wc_printf(""); + } + if ( + (i == first) + && (BBS->requested_page > (RANGE + 1)) + ) { + wc_printf(" ..."); + } + if (i != last) { + wc_printf(" "); + } + } } - wc_printf("", - newerdiv, - gt, - Stat->maxmsgs - ); - wc_printf("
"); - wc_printf("↓ "); - wc_printf("%s", _("no more messages")); - wc_printf(" ↓"); - wc_printf("
"); - wc_printf("
"); + wc_printf("
\n"); } - wc_printf(""); } - /* Leave a little padding at the bottom, but only for the initial page load -- don't keep - * adding it every time we extend the visible message set. - */ - if (!WC->is_ajax) { - wc_printf("



"); + if (go_to_the_very_end) { + StrBufAppendPrintf(WC->trailing_javascript, "location.href=\"#end_of_msgs\";\n"); } - return(0); } @@ -293,16 +406,11 @@ int bbsview_Cleanup(void **ViewSpecific) } free(BBS); - if (WC->is_ajax) { - end_ajax_response(); - WC->is_ajax = 0; - } - else { - wDumpContent(1); - } + wDumpContent(1); return 0; } + void InitModule_BBSVIEWRENDERERS (void) @@ -310,8 +418,11 @@ InitModule_BBSVIEWRENDERERS RegisterReadLoopHandlerset( VIEW_BBS, bbsview_GetParamsGetServerCall, - bbsview_PrintViewHeader, + NULL, + NULL, + NULL, bbsview_LoadMsgFromServer, bbsview_RenderView_or_Tail, - bbsview_Cleanup); + bbsview_Cleanup + ); }