* Cleaned up the logic at the end of the bbsview display. Still not sure what we...
[citadel.git] / webcit / bbsview_renderer.c
1 #include "webcit.h"
2 #include "webserver.h"
3 #include "groupdav.h"
4
5
6
7 /* We're jamming both of these in here so I can develop the new BBS view in-tree.
8  * Define NEW_BBS_BIEW to get the new, better, but unfinished and untested version.
9  *
10  */
11
12 #ifndef NEW_BBS_VIEW
13
14
15 /*** Code for the OLD bbs view ***/
16
17
18 typedef struct _bbsview_stuct {
19         StrBuf *BBViewToolBar;
20         StrBuf *MessageDropdown;
21         long *displayed_msgs;
22         int a;
23 } bbsview_struct;
24
25 int bbsview_GetParamsGetServerCall(SharedMessageStatus *Stat, 
26                                    void **ViewSpecific, 
27                                    long oper, 
28                                    char *cmd, 
29                                    long len)
30 {
31         bbsview_struct *VS;
32
33         VS = (bbsview_struct*) malloc(sizeof(bbsview_struct));
34         memset(VS, 0, sizeof(bbsview_struct));
35         *ViewSpecific = (void*)VS;
36         Stat->defaultsortorder = 1;
37         Stat->startmsg = -1;
38         Stat->sortit = 1;
39         
40         rlid[oper].cmd(cmd, len);
41         
42         if (havebstr("maxmsgs"))
43                 Stat->maxmsgs = ibstr("maxmsgs");
44         if (Stat->maxmsgs == 0) Stat->maxmsgs = DEFAULT_MAXMSGS;
45         
46         if (havebstr("startmsg")) {
47                 Stat->startmsg = lbstr("startmsg");
48         }
49         if (lbstr("SortOrder") == 2) {
50                 Stat->reverse = 1;
51                 Stat->num_displayed = -DEFAULT_MAXMSGS;
52         }
53         else {
54                 Stat->reverse = 0;
55                 Stat->num_displayed = DEFAULT_MAXMSGS;
56         }
57
58         return 200;
59 }
60
61 /* startmsg is an index within the message list.
62  * starting_from is the Citadel message number to be supplied to a "MSGS GT" operation
63  */
64 long DrawMessageDropdown(StrBuf *Selector, long maxmsgs, long startmsg, int nMessages, long starting_from)
65 {
66         StrBuf *TmpBuf;
67         wcsession *WCC = WC;
68         void *vMsg;
69         int lo, hi;
70         long ret;
71         long hklen;
72         const char *key;
73         int nItems;
74         HashPos *At;
75         long vector[16];
76         WCTemplputParams SubTP;
77         int wantmore = 1;
78
79         memset(&SubTP, 0, sizeof(WCTemplputParams));
80         SubTP.Filter.ContextType = CTX_LONGVECTOR;
81         SubTP.Context = &vector;
82         TmpBuf = NewStrBufPlain(NULL, SIZ);
83         At = GetNewHashPos(WCC->summ, nMessages);
84         nItems = GetCount(WCC->summ);
85         ret = nMessages;
86         vector[0] = 7;
87         vector[2] = 1;
88         vector[1] = startmsg;
89         vector[3] = 0;
90         vector[7] = starting_from;
91
92         while (wantmore)
93         {
94         
95                 vector[3] = abs(nMessages);
96                 lo = GetHashPosCounter(WCC->summ, At);
97                 wantmore = GetNextHashPos(WCC->summ, At, &hklen, &key, &vMsg);
98                 if (!wantmore)
99                         break;
100                 if (nMessages > 0) {
101                         if (lo + nMessages >= nItems) {
102                                 hi = nItems - 1;
103                                 vector[3] = nItems - lo;
104                                 if (startmsg == lo) 
105                                         ret = vector[3];
106                         }
107                         else {
108                                 hi = lo + nMessages - 1;
109                         }
110                 } else {
111                         if (lo + nMessages < -1) {
112                                 hi = 0;
113                         }
114                         else {
115                                 if ((lo % abs(nMessages)) != 0) {
116                                         int offset = (lo % abs(nMessages) *
117                                                       (nMessages / abs(nMessages)));
118                                         hi = lo + offset;
119                                         vector[3] = abs(offset);
120                                         if (startmsg == lo)
121                                                  ret = offset;
122                                 }
123                                 else
124                                         hi = lo + nMessages;
125                         }
126                 }
127                 
128                 /*
129                  * Bump these because although we're thinking in zero base, the user
130                  * is a drooling idiot and is thinking in one base.
131                  */
132                 vector[4] = lo + 1;
133                 vector[5] = hi + 1;
134                 vector[6] = lo;
135                 FlushStrBuf(TmpBuf);
136                 dbg_print_longvector(vector);
137                 DoTemplate(HKEY("select_messageindex"), TmpBuf, &SubTP);
138                 StrBufAppendBuf(Selector, TmpBuf, 0);
139         }
140         vector[6] = 0;
141         FlushStrBuf(TmpBuf);
142         if (maxmsgs == 9999999) {
143                 vector[1] = 1;
144                 ret = maxmsgs;
145         }
146         else
147                 vector[1] = 0;          
148         vector[2] = 0;
149         dbg_print_longvector(vector);
150         DoTemplate(HKEY("select_messageindex_all"), TmpBuf, &SubTP);
151         StrBufAppendBuf(Selector, TmpBuf, 0);
152         FreeStrBuf(&TmpBuf);
153         DeleteHashPos(&At);
154         return ret;
155 }
156
157
158 int bbsview_PrintViewHeader(SharedMessageStatus *Stat, void **ViewSpecific)
159 {
160         bbsview_struct *VS;
161         WCTemplputParams SubTP;
162
163         VS = (bbsview_struct*)*ViewSpecific;
164
165         VS->BBViewToolBar = NewStrBufPlain(NULL, SIZ);
166         VS->MessageDropdown = NewStrBufPlain(NULL, SIZ);
167
168         /*** startmsg->maxmsgs = **/DrawMessageDropdown(VS->MessageDropdown, 
169                                                         Stat->maxmsgs, 
170                                                         Stat->startmsg,
171                                                         Stat->num_displayed, 
172                                                         Stat->lowest_found-1);
173         if (Stat->num_displayed < 0) {
174                 Stat->startmsg += Stat->maxmsgs;
175                 if (Stat->num_displayed != Stat->maxmsgs)                               
176                         Stat->maxmsgs = abs(Stat->maxmsgs) + 1;
177                 else
178                         Stat->maxmsgs = abs(Stat->maxmsgs);
179
180         }
181         if (Stat->nummsgs > 0) {
182                 memset(&SubTP, 0, sizeof(WCTemplputParams));
183                 SubTP.Filter.ContextType = CTX_STRBUF;
184                 SubTP.Context = VS->MessageDropdown;
185                 DoTemplate(HKEY("msg_listselector_top"), VS->BBViewToolBar, &SubTP);
186                 StrBufAppendBuf(WC->WBuf, VS->BBViewToolBar, 0);
187                 FlushStrBuf(VS->BBViewToolBar);
188         }
189         return 200;
190 }
191
192 int bbsview_LoadMsgFromServer(SharedMessageStatus *Stat, 
193                               void **ViewSpecific, 
194                               message_summary* Msg, 
195                               int is_new, 
196                               int i)
197 {
198         bbsview_struct *VS;
199
200         VS = (bbsview_struct*)*ViewSpecific;
201         if (VS->displayed_msgs == NULL) {
202                 VS->displayed_msgs = malloc(sizeof(long) *
203                                             ((Stat->maxmsgs < Stat->nummsgs) ? 
204                                              Stat->maxmsgs + 1 : 
205                                              Stat->nummsgs + 1));
206         }
207         if ((i >= Stat->startmsg) && (i < Stat->startmsg + Stat->maxmsgs)) {
208                 VS->displayed_msgs[Stat->num_displayed] = Msg->msgnum;
209                 Stat->num_displayed++;
210         }
211         return 200;
212 }
213
214
215 int bbsview_RenderView_or_Tail(SharedMessageStatus *Stat, 
216                                void **ViewSpecific, 
217                                long oper)
218 {
219         wcsession *WCC = WC;
220         bbsview_struct *VS;
221         WCTemplputParams SubTP;
222         const StrBuf *Mime;
223
224         VS = (bbsview_struct*)*ViewSpecific;
225         if (Stat->nummsgs == 0) {
226                 wc_printf("<div class=\"nomsgs\"><br><em>");
227                 switch (oper) {
228                 case readnew:
229                         wc_printf(_("No new messages."));
230                         break;
231                 case readold:
232                         wc_printf(_("No old messages."));
233                         break;
234                 default:
235                         wc_printf(_("No messages here."));
236                 }
237                 wc_printf("</em><br></div>\n");
238         }
239         else 
240         {
241                 if (VS->displayed_msgs != NULL) {
242                         /* if we do a split bbview in the future, begin messages div here */
243                         int a;/// todo  
244                         for (a=0; a < Stat->num_displayed; ++a) {
245                                 read_message(WCC->WBuf, HKEY("view_message"), VS->displayed_msgs[a], NULL, &Mime);
246                         }
247                         
248                         /* if we do a split bbview in the future, end messages div here */
249                         
250                         free(VS->displayed_msgs);
251                         VS->displayed_msgs = NULL;
252                 }
253                 memset(&SubTP, 0, sizeof(WCTemplputParams));
254                 SubTP.Filter.ContextType = CTX_STRBUF;
255                 SubTP.Context = VS->MessageDropdown;
256                 DoTemplate(HKEY("msg_listselector_bottom"), VS->BBViewToolBar, &SubTP);
257                 StrBufAppendBuf(WCC->WBuf, VS->BBViewToolBar, 0);
258         }
259         return 0;
260
261 }
262
263
264 int bbsview_Cleanup(void **ViewSpecific)
265 {
266         bbsview_struct *VS;
267
268         VS = (bbsview_struct*)*ViewSpecific;
269         wDumpContent(1);
270         FreeStrBuf(&VS->BBViewToolBar);
271         FreeStrBuf(&VS->MessageDropdown);
272         free(VS);
273         return 0;
274 }
275
276 void 
277 InitModule_BBSVIEWRENDERERS
278 (void)
279 {
280         RegisterReadLoopHandlerset(
281                 VIEW_BBS,
282                 bbsview_GetParamsGetServerCall,
283                 bbsview_PrintViewHeader,
284                 bbsview_LoadMsgFromServer,
285                 bbsview_RenderView_or_Tail,
286                 bbsview_Cleanup);
287 }
288
289
290
291
292
293 #else /* NEW_BBS_VIEW */
294
295
296 /*** Code for the NEW bbs view ***/
297
298
299
300 /*
301  * Data which gets passed around between the various functions in this module
302  */
303 struct bbsview {
304         long *msgs;             /* Array of msgnums for messages we are displaying */
305         int num_msgs;           /* Number of msgnums stored in 'msgs' */
306         int alloc_msgs;         /* Currently allocated size of array */
307 };
308
309
310 /*
311  * Entry point for message read operations.
312  */
313 int bbsview_GetParamsGetServerCall(SharedMessageStatus *Stat, 
314                                    void **ViewSpecific, 
315                                    long oper, 
316                                    char *cmd, 
317                                    long len)
318 {
319         struct bbsview *BBS = malloc(sizeof(struct bbsview));
320         memset(BBS, 0, sizeof(struct bbsview));
321         *ViewSpecific = BBS;
322
323         Stat->defaultsortorder = 1;
324         Stat->startmsg = -1;
325         Stat->sortit = 1;
326         
327         rlid[oper].cmd(cmd, len);               /* this performs the server call to fetch the msg list */
328         
329         if (havebstr("maxmsgs")) {
330                 Stat->maxmsgs = ibstr("maxmsgs");
331         }
332         if (Stat->maxmsgs == 0) Stat->maxmsgs = DEFAULT_MAXMSGS;
333         
334         if (havebstr("startmsg")) {
335                 Stat->startmsg = lbstr("startmsg");
336         }
337         if (lbstr("SortOrder") == 2) {
338                 Stat->reverse = 1;
339                 Stat->num_displayed = -DEFAULT_MAXMSGS;
340         }
341         else {
342                 Stat->reverse = 0;
343                 Stat->num_displayed = DEFAULT_MAXMSGS;
344         }
345
346         return 200;
347 }
348
349
350 /*
351  * begin_ajax_response() was moved from bbsview_LoadMsgFromServer() to here ...
352  */
353 int bbsview_PrintViewHeader(SharedMessageStatus *Stat, void **ViewSpecific)
354 {
355         lprintf(9, "bbsview_PrintViewHeader() has been called.\n");
356
357         if (WC->is_ajax) {
358                 begin_ajax_response();          /* for non-ajax, headers are output in messages.c */
359         }
360
361         return 200;
362 }
363
364
365 /*
366  * This function is called for every message in the list.
367  */
368 int bbsview_LoadMsgFromServer(SharedMessageStatus *Stat, 
369                               void **ViewSpecific, 
370                               message_summary* Msg, 
371                               int is_new, 
372                               int i)
373 {
374         struct bbsview *BBS = (struct bbsview *) *ViewSpecific;
375
376         lprintf(9, "bbsview_LoadMsgFromServer() has been called.\n");
377
378         if (BBS->num_msgs < Stat->maxmsgs) {
379
380                 if (BBS->alloc_msgs == 0) {
381                         BBS->alloc_msgs = Stat->maxmsgs;
382                         BBS->msgs = malloc(BBS->alloc_msgs * sizeof(long));
383                 }
384         
385                 /* Theoretically this never happens because the initial allocation == maxmsgs */
386                 if (BBS->num_msgs >= BBS->alloc_msgs) {
387                         BBS->alloc_msgs *= 2;
388                         BBS->msgs = realloc(BBS->msgs, (BBS->alloc_msgs * sizeof(long)));
389                 }
390         
391                 BBS->msgs[BBS->num_msgs++] = Msg->msgnum;
392         }
393         return 200;
394 }
395
396 int bbsview_sortfunc_reverse(const void *s1, const void *s2) {
397         long l1;
398         long l2;
399
400         l1 = *(long *)(s1);
401         l2 = *(long *)(s2);
402
403         if (l1 > l2) return(-1);
404         if (l1 < l2) return(+1);
405         return(0);
406 }
407
408
409 int bbsview_sortfunc_forward(const void *s1, const void *s2) {
410         long l1;
411         long l2;
412
413         l1 = *(long *)(s1);
414         l2 = *(long *)(s2);
415
416         if (l1 > l2) return(+1);
417         if (l1 < l2) return(-1);
418         return(0);
419 }
420
421
422 int bbsview_RenderView_or_Tail(SharedMessageStatus *Stat, 
423                                void **ViewSpecific, 
424                                long oper)
425 {
426         struct bbsview *BBS = (struct bbsview *) *ViewSpecific;
427         int i;
428         const StrBuf *Mime;
429         char morediv[64];
430
431         lprintf(9, "starting bbsview_RenderView_or_Tail() - there are %d messages.\n", BBS->num_msgs);
432
433         /* Handle the empty message set gracefully... */
434         if (Stat->nummsgs == 0) {
435                 if (!WC->is_ajax) {
436                         wc_printf("<div class=\"nomsgs\"><br><em>");
437                         wc_printf(_("No messages here."));
438                         wc_printf("</em><br></div>\n");
439                 }
440         }
441
442         /* Non-empty message set... */
443         else {
444                 lprintf(9, "sorting %d messages\n", BBS->num_msgs);
445                 qsort(BBS->msgs, (size_t)(BBS->num_msgs), sizeof(long), (Stat->reverse ? bbsview_sortfunc_reverse : bbsview_sortfunc_forward));
446         
447                 for (i=0; i<BBS->num_msgs; ++i) {
448                         read_message(WC->WBuf, HKEY("view_message"), BBS->msgs[i], NULL, &Mime);
449                 }
450
451         }
452
453         snprintf(morediv, sizeof morediv, "morediv%08lx%08x", time(NULL), rand());
454
455         if (!WC->is_ajax) {     /* only supply the script during the initial page load */
456            StrBufAppendPrintf(WC->trailing_javascript,
457                 "       function moremsgs(target_div, gt, maxmsgs, sortorder) {                         \n"
458                 "               $(target_div).innerHTML = '<div class=\"moreprompt\">%s ... <img src=\"static/throbber.gif\"><br><br><br></div>';       \n"
459                 "               p = 'gt=' + gt + '&maxmsgs=' + maxmsgs                                  \n"
460                 "                       + '&is_summary=0&SortOrder=' + sortorder + '&is_ajax=1'         \n"
461                 "                       + '&r=' + CtdlRandomString();                                   \n"
462                 "               new Ajax.Updater(target_div, 'readgt',                                  \n"
463                 "                       { method: 'get', parameters: p, evalScripts: true } );          \n"
464                 "       }                                                                               \n"
465                 "",
466                 _("Loading")
467            );
468         }
469
470         wc_printf("<div id=\"%s\">", morediv);
471         /* if (Stat->nummsgs > 0) { */
472         if (Stat->nummsgs >= Stat->maxmsgs) {
473                 wc_printf("<a href=\"javascript:moremsgs('%s', %ld, %ld, %d );\">",
474                         morediv,
475                         BBS->msgs[BBS->num_msgs-1],
476                         Stat->maxmsgs,
477                         (Stat->reverse ? 2 : 1)
478                 );
479         
480                 wc_printf("<div class=\"moreprompt\">"
481                         "&darr; &darr; &darr; %s &darr; &darr; &darr;"
482                         "</div>", _("more")
483                 );
484                 wc_printf("</a>");
485         }
486         else {
487                 long gt = 0;    /* if new messages appear later, where will they begin? */
488                 if (Stat->nummsgs > 0) {
489                         gt = BBS->msgs[BBS->num_msgs-1];
490                 }
491                 else {
492                         gt = atol(bstr("gt"));
493                 }
494                 wc_printf("<a href=\"javascript:moremsgs('%s', %ld, %ld, %d );\">",
495                         morediv,
496                         gt,
497                         Stat->maxmsgs,
498                         (Stat->reverse ? 2 : 1)
499                 );
500                 wc_printf("<div class=\"moreprompt\">");
501                 wc_printf("no more ... gt would have been %ld ... FIXME", gt);
502                 wc_printf("</div>");
503                 wc_printf("</a>");
504         }
505         wc_printf("<br><br><br><br></div>");
506
507         return(0);
508 }
509
510
511 int bbsview_Cleanup(void **ViewSpecific)
512 {
513         struct bbsview *BBS = (struct bbsview *) *ViewSpecific;
514         lprintf(9, "bbsview_Cleanup() has been called.\n");
515         free(BBS);
516
517         if (WC->is_ajax) {
518                 lprintf(9, "end_ajax_response() has been called.\n");
519                 end_ajax_response();
520                 WC->is_ajax = 0;
521         }
522         else {
523                 lprintf(9, "wDumpContent() has been called.\n");
524                 wDumpContent(1);
525         }
526         return 0;
527 }
528
529 void 
530 InitModule_BBSVIEWRENDERERS
531 (void)
532 {
533         RegisterReadLoopHandlerset(
534                 VIEW_BBS,
535                 bbsview_GetParamsGetServerCall,
536                 bbsview_PrintViewHeader,
537                 bbsview_LoadMsgFromServer,
538                 bbsview_RenderView_or_Tail,
539                 bbsview_Cleanup);
540 }
541
542
543 #endif /* NEW_BBS_VIEW */