Back to index

webcit  8.12-dfsg
bbsview_renderer.c
Go to the documentation of this file.
00001 /* 
00002  * BBS View renderer module for WebCit
00003  *
00004  * Note: we briefly had a dynamic UI for this.  I thought it was cool, but
00005  * it was not received well by the user community.  If you want to play
00006  * with it, go get commit dcf99fe61379b78436c387ea3f89ebfd4ffaf635 of
00007  * bbsview_renderer.c and have fun.
00008  *
00009  * Copyright (c) 1996-2012 by the citadel.org team
00010  *
00011  * This program is open source software.  You can redistribute it and/or
00012  * modify it under the terms of the GNU General Public License, version 3.
00013  *
00014  * This program is distributed in the hope that it will be useful,
00015  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00016  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017  * GNU General Public License for more details.
00018  */
00019 
00020 #define RANGE 5
00021 
00022 #include "webcit.h"
00023 #include "webserver.h"
00024 #include "dav.h"
00025 
00026 /*
00027  * Data which gets passed around between the various functions in this module
00028  *
00029  */
00030 struct bbsview {
00031        long *msgs;          /* Array of msgnums for messages we are displaying */
00032        int num_msgs;        /* Number of msgnums stored in 'msgs' */
00033        long lastseen;              /* The number of the last seen message in this room */
00034        int alloc_msgs;             /* Currently allocated size of array */
00035        int requested_page;  /* Which page number did the user request? */
00036        int num_pages;              /* Total number of pages in this room */
00037        long start_reading_at;      /* Start reading at the page containing this message */
00038 };
00039 
00040 
00041 /*
00042  * Attempt to determine the closest thing to the "last seen message number" using the
00043  * results of the GTSN command
00044  */
00045 long bbsview_get_last_seen(void)
00046 {
00047        char buf[SIZ] = "0";
00048 
00049        serv_puts("GTSN");
00050        serv_getln(buf, sizeof buf);
00051        if (buf[0] == '2') {
00052               char *colon_pos;
00053               char *comma_pos;
00054 
00055               comma_pos = strchr(buf, ',');      /* kill first comma and everything to its right */
00056               if (comma_pos) {
00057                      *comma_pos = 0;
00058               }
00059 
00060               colon_pos = strchr(buf, ':');      /* kill first colon and everything to its left */
00061               if (colon_pos) {
00062                      strcpy(buf, ++colon_pos);
00063               }
00064        }
00065 
00066        return(atol(buf));
00067 }
00068 
00069 
00070 
00071 /*
00072  * Entry point for message read operations.
00073  */
00074 int bbsview_GetParamsGetServerCall(SharedMessageStatus *Stat, 
00075                                void **ViewSpecific, 
00076                                long oper, 
00077                                char *cmd, 
00078                                long len,
00079                                char *filter,
00080                                long flen)
00081 {
00082        struct bbsview *BBS = malloc(sizeof(struct bbsview));
00083        memset(BBS, 0, sizeof(struct bbsview));
00084        *ViewSpecific = BBS;
00085 
00086        Stat->startmsg = (-1);                                  /* not used here */
00087        Stat->sortit = 1;                                /* not used here */
00088        Stat->num_displayed = DEFAULT_MAXMSGS;                  /* not used here */
00089        BBS->requested_page = 0;
00090        BBS->lastseen = bbsview_get_last_seen();
00091        BBS->start_reading_at = 0;
00092 
00093        /* By default, the requested page is the first one. */
00094        if (havebstr("start_reading_at")) {
00095               BBS->start_reading_at = lbstr("start_reading_at");
00096               BBS->requested_page = (-4);
00097        }
00098 
00099        /* However, if we are asked to start with a specific message number, make sure
00100         * we start on the page containing that message
00101         */
00102 
00103        /* Or, if a specific page was requested, make sure we go there */
00104        else if (havebstr("page")) {
00105               BBS->requested_page = ibstr("page");
00106        }
00107 
00108        /* Otherwise, if this is a "read new" operation, make sure we start on the page
00109         * containing the first new message
00110         */
00111        else if (oper == 3) {
00112               BBS->requested_page = (-3);
00113        }
00114 
00115        if (havebstr("maxmsgs")) {
00116               Stat->maxmsgs = ibstr("maxmsgs");
00117        }
00118        if (Stat->maxmsgs == 0) Stat->maxmsgs = DEFAULT_MAXMSGS;
00119        
00120        /* perform a "read all" call to fetch the message list -- we'll cut it down later */
00121        rlid[2].cmd(cmd, len);
00122        
00123        return 200;
00124 }
00125 
00126 
00127 /*
00128  * This function is called for every message in the list.
00129  */
00130 int bbsview_LoadMsgFromServer(SharedMessageStatus *Stat, 
00131                            void **ViewSpecific, 
00132                            message_summary* Msg, 
00133                            int is_new, 
00134                            int i)
00135 {
00136        struct bbsview *BBS = (struct bbsview *) *ViewSpecific;
00137 
00138        if (BBS->alloc_msgs == 0) {
00139               BBS->alloc_msgs = 1000;
00140               BBS->msgs = malloc(BBS->alloc_msgs * sizeof(long));
00141               memset(BBS->msgs, 0, (BBS->alloc_msgs * sizeof(long)) );
00142        }
00143 
00144        /* Check our buffer size */
00145        if (BBS->num_msgs >= BBS->alloc_msgs) {
00146               BBS->alloc_msgs *= 2;
00147               BBS->msgs = realloc(BBS->msgs, (BBS->alloc_msgs * sizeof(long)));
00148               memset(&BBS->msgs[BBS->num_msgs], 0, ((BBS->alloc_msgs - BBS->num_msgs) * sizeof(long)) );
00149        }
00150 
00151        BBS->msgs[BBS->num_msgs++] = Msg->msgnum;
00152 
00153        return 200;
00154 }
00155 
00156 
00157 int bbsview_sortfunc(const void *s1, const void *s2) {
00158        long l1;
00159        long l2;
00160 
00161        l1 = *(long *)(s1);
00162        l2 = *(long *)(s2);
00163 
00164        if (l1 > l2) return(+1);
00165        if (l1 < l2) return(-1);
00166        return(0);
00167 }
00168 
00169 
00170 int bbsview_RenderView_or_Tail(SharedMessageStatus *Stat, 
00171                             void **ViewSpecific, 
00172                             long oper)
00173 {
00174        struct bbsview *BBS = (struct bbsview *) *ViewSpecific;
00175        int i;
00176        int seq;
00177        const StrBuf *Mime;
00178        int start_index = 0;
00179        int end_index = 0;
00180        int go_to_the_very_end = 0;
00181 
00182        if (Stat->nummsgs > 0) {
00183               syslog(9, "sorting %d messages\n", BBS->num_msgs);
00184               qsort(BBS->msgs, (size_t)(BBS->num_msgs), sizeof(long), bbsview_sortfunc);
00185        }
00186 
00187        if ((BBS->num_msgs % Stat->maxmsgs) == 0) {
00188               BBS->num_pages = BBS->num_msgs / Stat->maxmsgs;
00189        }
00190        else {
00191               BBS->num_pages = (BBS->num_msgs / Stat->maxmsgs) + 1;
00192        }
00193 
00194        /* If the requested page number is -4,
00195         * it means "whichever page on which msg#xxxxx starts"
00196         * Change to the page number which contains that message.
00197         */
00198        if (BBS->requested_page == (-4)) {
00199               if (BBS->num_msgs == 0) {
00200                      BBS->requested_page = 0;
00201               }
00202               else {
00203                      for (i=0; i<BBS->num_msgs; ++i) {
00204                             if (
00205                                    (BBS->msgs[i] >= BBS->start_reading_at)
00206                                    && (BBS->requested_page == (-4))
00207                             ) {
00208                                    BBS->requested_page = (i / Stat->maxmsgs) ;
00209                             }
00210                      }
00211               }
00212        }
00213 
00214        /* If the requested page number is -3,
00215         * it means "whichever page on which new messages start"
00216         * Change that to an actual page number now.
00217         */
00218        if (BBS->requested_page == (-3)) {
00219               if (BBS->num_msgs == 0) {
00220                      /*
00221                       * The room is empty; just start at the top and leave it there.
00222                       */
00223                      BBS->requested_page = 0;
00224               }
00225               else if (
00226                      (BBS->num_msgs > 0) 
00227                      && (BBS->lastseen <= BBS->msgs[0])
00228               ) {
00229                      /*
00230                       * All messages are new; this is probably the user's first visit to the room,
00231                       * so start at the last page instead of showing ancient history.
00232                       */
00233                      BBS->requested_page = BBS->num_pages - 1;
00234                      go_to_the_very_end = 1;
00235               }
00236               else {
00237                      /*
00238                       * Some messages are old and some are new.  Go to the start of new messages.
00239                       */
00240                      for (i=0; i<BBS->num_msgs; ++i) {
00241                             if (
00242                                    (BBS->msgs[i] > BBS->lastseen)
00243                                    && ( (i == 0) || (BBS->msgs[i-1] <= BBS->lastseen) )
00244                             ) {
00245                                    BBS->requested_page = (i / Stat->maxmsgs) ;
00246                             }
00247                      }
00248               }
00249        }
00250 
00251        /* Still set to -3 ?  If so, that probably means that there are no new messages,
00252         * so we'll go to the *end* of the final page.
00253         */
00254        if (BBS->requested_page == (-3)) {
00255               if (BBS->num_msgs == 0) {
00256                      BBS->requested_page = 0;
00257               }
00258               else {
00259                      BBS->requested_page = BBS->num_pages - 1;
00260               }
00261        }
00262 
00263        /* keep the requested page within bounds */
00264        if (BBS->requested_page < 0) BBS->requested_page = 0;
00265        if (BBS->requested_page >= BBS->num_pages) BBS->requested_page = BBS->num_pages - 1;
00266 
00267        start_index = BBS->requested_page * Stat->maxmsgs;
00268        if (start_index < 0) start_index = 0;
00269        end_index = start_index + Stat->maxmsgs - 1;
00270 
00271        for (seq = 0; seq < 3; ++seq) {           /* cheap & sleazy way of rendering the page numbers twice */
00272 
00273               if ( (seq == 1) && (Stat->nummsgs > 0)) {
00274                      /* display the selected range of messages */
00275 
00276                      for (i=start_index; (i<=end_index && i<BBS->num_msgs); ++i) {
00277                             if (
00278                                    (BBS->msgs[i] > BBS->lastseen)
00279                                    && ( (i == 0) || (BBS->msgs[i-1] <= BBS->lastseen) )
00280                             ) {
00281                                    /* new messages start here */
00282                                    do_template("start_of_new_msgs");
00283                                    if (!go_to_the_very_end) {
00284                                           StrBufAppendPrintf(WC->trailing_javascript, "location.href=\"#newmsgs\";\n");
00285                                    }
00286                             }
00287                             if (BBS->msgs[i] > 0L) {
00288                                    read_message(WC->WBuf, HKEY("view_message"), BBS->msgs[i], NULL, &Mime);
00289                             }
00290                             if (
00291                                    (i == (BBS->num_msgs - 1))
00292                                    && (BBS->msgs[i] <= BBS->lastseen)
00293                             ) {
00294                                    /* no new messages */
00295                                    do_template("no_new_msgs");
00296                                    if (!go_to_the_very_end) {
00297                                           StrBufAppendPrintf(WC->trailing_javascript, "location.href=\"#nonewmsgs\";\n");
00298                                    }
00299                             }
00300                      }
00301               }
00302 
00303               else if ( (seq == 0) || (seq == 2) ) {
00304                      int first;
00305                      int last;
00306                      /* Display the selecto-bar with the page numbers */
00307 
00308                      wc_printf("<div class=\"moreprompt\">");
00309                      if (seq == 2) {
00310                             wc_printf("<a name=\"end_of_msgs\">");
00311                      }
00312                      wc_printf(_("Go to page: "));
00313                      if (seq == 2) {
00314                             wc_printf("</a>");
00315                      }
00316 
00317                      first = 0;
00318                      last = BBS->num_pages - 1;
00319 
00320                      for (i=0; i<=last; ++i) {
00321 
00322                             if (
00323                                    (i == first)
00324                                    || (i == last)
00325                                    || (i == BBS->requested_page)
00326                                    || (
00327                                           ((BBS->requested_page - i) < RANGE)
00328                                           && ((BBS->requested_page - i) > (0 - RANGE))
00329                                    )
00330                             ) {
00331 
00332                                    if (
00333                                           (i == last) 
00334                                           && (last - BBS->requested_page > RANGE)
00335                                    ) {
00336                                           wc_printf("...&nbsp;");
00337                                    }
00338                                    if (i == BBS->requested_page) {
00339                                           wc_printf("[");
00340                                    }
00341                                    else {
00342                                           wc_printf("<a href=\"readfwd?go=");
00343                                           urlescputs(ChrPtr(WC->CurRoom.name));
00344                                           wc_printf("?start_reading_at=%ld\">",
00345                                                  BBS->msgs[i*Stat->maxmsgs]
00346                                           );
00347                                           /* wc_printf("?page=%d\">", i); */
00348                                           wc_printf("<span class=\"moreprompt_link\">");
00349                                    }
00350                                    if (
00351                                           (i == first)
00352                                           && (BBS->requested_page > (RANGE + 1))
00353                                    ) {
00354                                           wc_printf(_("First"));
00355                                    }
00356                                    else if (
00357                                           (i == last)
00358                                           && (last - BBS->requested_page > RANGE)
00359                                    ) {
00360                                           wc_printf(_("Last"));
00361                                    }
00362                                    else {
00363                                           wc_printf("%d", i + 1);     /* change to one-based for display */
00364                                    }
00365                                    if (i == BBS->requested_page) {
00366                                           wc_printf("]");
00367                                    }
00368                                    else {
00369                                           wc_printf("</span>");
00370                                           wc_printf("</a>");
00371                                    }
00372                                    if (
00373                                           (i == first)
00374                                           && (BBS->requested_page > (RANGE + 1))
00375                                    ) {
00376                                           wc_printf("&nbsp;...");
00377                                    }
00378                                    if (i != last) {
00379                                           wc_printf("&nbsp;");
00380                                    }
00381                             }
00382                      }
00383                      wc_printf("</div>\n");
00384               }
00385        }
00386 
00387        if (go_to_the_very_end) {
00388               StrBufAppendPrintf(WC->trailing_javascript, "location.href=\"#end_of_msgs\";\n");
00389        }
00390        return(0);
00391 }
00392 
00393 
00394 int bbsview_Cleanup(void **ViewSpecific)
00395 {
00396        struct bbsview *BBS = (struct bbsview *) *ViewSpecific;
00397 
00398        if (BBS->alloc_msgs != 0) {
00399               free(BBS->msgs);
00400        }
00401        free(BBS);
00402 
00403        wDumpContent(1);
00404        return 0;
00405 }
00406 
00407 
00408 void 
00409 InitModule_BBSVIEWRENDERERS
00410 (void)
00411 {
00412        RegisterReadLoopHandlerset(
00413               VIEW_BBS,
00414               bbsview_GetParamsGetServerCall,
00415               NULL,
00416               NULL,
00417               NULL, 
00418               bbsview_LoadMsgFromServer,
00419               bbsview_RenderView_or_Tail,
00420               bbsview_Cleanup
00421        );
00422 }