* Cleaned up the look of the 'more' link in the new BBS view
[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  * FIXME do we even need this?
352  */
353 int bbsview_PrintViewHeader(SharedMessageStatus *Stat, void **ViewSpecific)
354 {
355         return 200;
356 }
357
358
359 /*
360  * This function is called for every message in the list.
361  */
362 int bbsview_LoadMsgFromServer(SharedMessageStatus *Stat, 
363                               void **ViewSpecific, 
364                               message_summary* Msg, 
365                               int is_new, 
366                               int i)
367 {
368         struct bbsview *BBS = (struct bbsview *) *ViewSpecific;
369
370         if (WC->is_ajax) {
371                 begin_ajax_response();          /* for non-ajax, headers are output in messages.c */
372         }
373
374         if (BBS->num_msgs < Stat->maxmsgs) {
375
376                 if (BBS->alloc_msgs == 0) {
377                         BBS->alloc_msgs = Stat->maxmsgs;
378                         BBS->msgs = malloc(BBS->alloc_msgs * sizeof(long));
379                 }
380         
381                 /* Theoretically this never happens because the initial allocation == maxmsgs */
382                 if (BBS->num_msgs >= BBS->alloc_msgs) {
383                         BBS->alloc_msgs *= 2;
384                         BBS->msgs = realloc(BBS->msgs, (BBS->alloc_msgs * sizeof(long)));
385                 }
386         
387                 BBS->msgs[BBS->num_msgs++] = Msg->msgnum;
388         }
389         return 200;
390 }
391
392 int bbsview_sortfunc_reverse(const void *s1, const void *s2) {
393         long l1;
394         long l2;
395
396         l1 = *(long *)(s1);
397         l2 = *(long *)(s2);
398
399         if (l1 > l2) return(-1);
400         if (l1 < l2) return(+1);
401         return(0);
402 }
403
404
405 int bbsview_sortfunc_forward(const void *s1, const void *s2) {
406         long l1;
407         long l2;
408
409         l1 = *(long *)(s1);
410         l2 = *(long *)(s2);
411
412         if (l1 > l2) return(+1);
413         if (l1 < l2) return(-1);
414         return(0);
415 }
416
417
418 int bbsview_RenderView_or_Tail(SharedMessageStatus *Stat, 
419                                void **ViewSpecific, 
420                                long oper)
421 {
422         struct bbsview *BBS = (struct bbsview *) *ViewSpecific;
423         int i;
424         const StrBuf *Mime;
425         char morediv[64];
426
427         lprintf(9, "bbsview_RenderView_or_Tail() has been called\n");
428
429         /* Handle the empty message set gracefully... */
430         if (Stat->nummsgs == 0) {
431                 if (!WC->is_ajax) {
432                         wc_printf("<div class=\"nomsgs\"><br><em>");
433                         wc_printf(_("No messages here."));
434                         wc_printf("</em><br></div>\n");
435                 }
436         }
437
438         /* Non-empty message set... */
439         else {
440                 lprintf(9, "sorting %d messages\n", BBS->num_msgs);
441                 qsort(BBS->msgs, (size_t)(BBS->num_msgs), sizeof(long), (Stat->reverse ? bbsview_sortfunc_reverse : bbsview_sortfunc_forward));
442         
443                 for (i=0; i<BBS->num_msgs; ++i) {
444                         read_message(WC->WBuf, HKEY("view_message"), BBS->msgs[i], NULL, &Mime);
445                 }
446
447         }
448
449         snprintf(morediv, sizeof morediv, "morediv%08lx%08x", time(NULL), rand());
450
451         if (!WC->is_ajax) {     /* only supply the script during the initial page load */
452            StrBufAppendPrintf(WC->trailing_javascript,
453                 "       function moremsgs(target_div, gt, maxmsgs, sortorder) {                         \n"
454                 "               $(target_div).innerHTML = '<div class=\"moreprompt\">%s ... <img src=\"static/throbber.gif\"><br><br><br></div>';       \n"
455                 "               p = 'gt=' + gt + '&maxmsgs=' + maxmsgs                                  \n"
456                 "                       + '&is_summary=0&SortOrder=' + sortorder + '&is_ajax=1'         \n"
457                 "                       + '&r=' + CtdlRandomString();                                   \n"
458                 "               new Ajax.Updater(target_div, 'readgt',                                  \n"
459                 "                       { method: 'get', parameters: p, evalScripts: true } );          \n"
460                 "       }                                                                               \n"
461                 "",
462                 _("Loading")
463            );
464         }
465
466         wc_printf("<div id=\"%s\">", morediv);
467         if (Stat->nummsgs > 0) {
468                 wc_printf("<a href=\"javascript:moremsgs('%s', %ld, %ld, %d );\">",
469                         morediv,
470                         BBS->msgs[BBS->num_msgs-1],
471                         Stat->maxmsgs,
472                         (Stat->reverse ? 2 : 1)
473                 );
474         
475                 wc_printf("<div class=\"moreprompt\">"
476                         "&darr; &darr; &darr; %s &darr; &darr; &darr;"
477                         "</div>", _("more"));
478                 wc_printf("</a><br><br><br>");
479         }
480         else {
481                 wc_printf("thththththat's all, folks!<br><br><br><br>");
482         }
483         wc_printf("</div>");
484
485         return(0);
486 }
487
488
489 int bbsview_Cleanup(void **ViewSpecific)
490 {
491         struct bbsview *BBS = (struct bbsview *) *ViewSpecific;
492         lprintf(9, "bbsview_Cleanup() has been called\n");
493         free(BBS);
494
495         if (WC->is_ajax) {
496                 end_ajax_response();
497                 WC->is_ajax = 0;
498         }
499         else {
500                 wDumpContent(1);
501         }
502         return 0;
503 }
504
505 void 
506 InitModule_BBSVIEWRENDERERS
507 (void)
508 {
509         RegisterReadLoopHandlerset(
510                 VIEW_BBS,
511                 bbsview_GetParamsGetServerCall,
512                 bbsview_PrintViewHeader,
513                 bbsview_LoadMsgFromServer,
514                 bbsview_RenderView_or_Tail,
515                 bbsview_Cleanup);
516 }
517
518
519 #endif /* NEW_BBS_VIEW */