indent -kr -i8 -brf -bbb -fnc -l132 -nce on all of webcit-classic
[citadel.git] / webcit / wiki.c
1
2 /*
3  * Functions pertaining to rooms with a wiki view
4  *
5  * Copyright (c) 2009-2021 by the citadel.org team
6  *
7  * This program is open source software.  You can redistribute it and/or
8  * modify it under the terms of the GNU General Public License, version 3.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  */
15
16 #include "webcit.h"
17 #include "dav.h"
18
19 /* 
20  * Convert a string to something suitable as a wiki index
21  */
22 void str_wiki_index(StrBuf * s) {
23         StrBufSanitizeAscii(s, '_');
24         StrBufLowerCase(s);
25 }
26
27 /*
28  * Display a specific page from a wiki room
29  *
30  * "rev" may be set to an empty string to display the current version.
31  * "do_revert" may be set to nonzero to perform a reversion to the specified version.
32  */
33 void display_wiki_page_backend(StrBuf * pagename, char *rev, int do_revert) {
34         const StrBuf *Mime;
35         long msgnum = (-1L);
36         char buf[256];
37
38         if (WC->CurRoom.view != VIEW_WIKI) {
39                 wc_printf(_("'%s' is not a Wiki room."), ChrPtr(WC->CurRoom.name));
40                 return;
41         }
42
43         if (StrLength(pagename) == 0) {
44                 StrBufPlain(pagename, HKEY("home"));
45         }
46
47         str_wiki_index(pagename);       /* convert index name to lowercase and numeric only */
48
49         if ((rev != NULL) && (strlen(rev) > 0)) {
50                 /* read an older revision */
51                 serv_printf("WIKI rev|%s|%s|%s", ChrPtr(pagename), rev, (do_revert ? "revert" : "fetch"));
52                 serv_getln(buf, sizeof buf);
53                 if (buf[0] == '2') {
54                         msgnum = extract_long(&buf[4], 0);
55                 }
56         }
57         else {
58                 /* read the current revision */
59                 msgnum = locate_message_by_uid(ChrPtr(pagename));
60         }
61
62         if (msgnum >= 0L) {
63                 read_message(WC->WBuf, HKEY("view_message"), msgnum, NULL, &Mime, NULL);
64                 return;
65         }
66         putbstr("pagename", pagename);
67         do_template("wiki_empty");
68 }
69
70
71 /*
72  * Display a specific page from a wiki room
73  */
74 void display_wiki_page(void) {
75         StrBuf *pagename;
76         char rev[128];
77         int do_revert = 0;
78
79         output_headers(1, 1, 1, 0, 0, 0);
80         pagename = NewStrBufDup(sbstr("page"));
81         str_wiki_index(pagename);
82         safestrncpy(rev, bstr("rev"), sizeof rev);
83         do_revert = atoi(bstr("revert"));
84         display_wiki_page_backend(pagename, rev, do_revert);
85         wDumpContent(1);
86 }
87
88
89 /*
90  * Display the revision history for a wiki page (template callback)
91  */
92 void tmplput_display_wiki_history(StrBuf * Target, WCTemplputParams * TP) {
93         StrBuf *pagename;
94         StrBuf *Buf;
95         int row = 0;
96
97         pagename = NewStrBufDup(sbstr("page"));
98         str_wiki_index(pagename);
99
100         serv_printf("WIKI history|%s", ChrPtr(pagename));
101         Buf = NewStrBuf();
102         StrBuf_ServGetln(Buf);
103         if (GetServerStatus(Buf, NULL) == 1) {
104
105                 time_t rev_date;
106                 char rev_date_displayed[64];
107                 StrBuf *rev_uuid = NewStrBuf();
108                 StrBuf *author = NewStrBuf();
109                 StrBuf *node = NewStrBuf();
110
111                 wc_printf("<table class=\"wiki_history_background\">");
112
113                 wc_printf("<th>%s</th>", _("Date"));
114                 wc_printf("<th>%s</th>", _("Author"));
115
116                 while ((StrBuf_ServGetln(Buf) >= 0) && strcmp(ChrPtr(Buf), "000")) {
117
118                         rev_date = extract_long(ChrPtr(Buf), 1);
119                         webcit_fmt_date(rev_date_displayed, sizeof rev_date_displayed, rev_date, DATEFMT_FULL);
120                         StrBufExtract_token(author, Buf, 2, '|');
121
122                         wc_printf("<tr bgcolor=\"%s\">", ((row % 2) ? "#FFFFFF" : "#DDDDDD"));
123                         wc_printf("<td>%s</td><td>", rev_date_displayed);
124                         wc_printf("<a href=\"showuser?who=");
125                         urlescputs(ChrPtr(author));
126                         wc_printf("\">");
127                         escputs(ChrPtr(author));
128                         wc_printf("</a></td>");
129
130                         if (row == 0) {
131                                 wc_printf("<td><a href=\"wiki?page=%s", bstr("page"));
132                                 wc_printf("?go=");
133                                 urlescputs(ChrPtr(WC->CurRoom.name));
134                                 wc_printf("\">%s</a></td>", _("(show)"));
135                                 wc_printf("<td>(%s)</td>", _("Current version"));
136                         }
137
138                         else {
139                                 wc_printf("<td><a href=\"wiki?page=%s?rev=%s", bstr("page"), ChrPtr(rev_uuid)
140                                     );
141                                 wc_printf("?go=");
142                                 urlescputs(ChrPtr(WC->CurRoom.name));
143                                 wc_printf("\">%s</a></td>", _("(show)"));
144                                 wc_printf
145                                     ("<td><a href=\"javascript:GetLoggedInFirst(encodeURIComponent('wiki?page=%s?rev=%s?revert=1'))\">%s</a></td>",
146                                      bstr("page"), ChrPtr(rev_uuid), _("(revert)")
147                                     );
148                         }
149                         wc_printf("</tr>\n");
150
151                         /* Extract all fields except the author and date after displaying the row.  This
152                          * is deliberate, because the timestamp reflects when the diff was written, not
153                          * when the version which it reflects was written.  Similarly, the name associated
154                          * with each diff is the author who created the newer version of the page that
155                          * made the diff happen.
156                          */
157                         StrBufExtract_token(rev_uuid, Buf, 0, '|');
158                         StrBufExtract_token(node, Buf, 3, '|');
159                         ++row;
160                 }
161
162                 wc_printf("</table>\n");
163                 FreeStrBuf(&author);
164                 FreeStrBuf(&node);
165                 FreeStrBuf(&rev_uuid);
166         }
167         else {
168                 wc_printf("%s", ChrPtr(Buf));
169         }
170
171         FreeStrBuf(&Buf);
172 }
173
174
175
176 /*
177  * Display the revision history for a wiki page
178  */
179 void display_wiki_history(void) {
180         output_headers(1, 1, 1, 0, 0, 0);
181         do_template("wiki_history");
182         wDumpContent(1);
183 }
184
185
186 /*
187  * Display a list of all pages in a Wiki room (template callback)
188  */
189 void tmplput_display_wiki_pagelist(StrBuf * Target, WCTemplputParams * TP) {
190         StrBuf *Buf;
191         int row = 0;
192
193         if (!IsEmptyStr(bstr("query"))) {
194                 serv_printf("MSGS SEARCH|%s||4", bstr("query"));        /* search-reduced list */
195         }
196         else {
197                 serv_printf("MSGS ALL|||4");    /* full list */
198         }
199
200         Buf = NewStrBuf();
201         StrBuf_ServGetln(Buf);
202         if (GetServerStatus(Buf, NULL) == 1) {
203                 StrBuf *pagetitle = NewStrBuf();
204
205                 wc_printf("<table class=\"wiki_pagelist_background\">");
206                 wc_printf("<th>%s</th>", _("Page title"));
207
208                 while ((StrBuf_ServGetln(Buf) >= 0) && strcmp(ChrPtr(Buf), "000")) {
209                         StrBufExtract_token(pagetitle, Buf, 1, '|');
210
211                         if (!bmstrcasestr((char *) ChrPtr(pagetitle), "_HISTORY_")) {   /* no history pages */
212                                 wc_printf("<tr bgcolor=\"%s\">", ((row % 2) ? "#FFFFFF" : "#DDDDDD"));
213                                 wc_printf("<td><a href=\"wiki?page=");
214                                 urlescputs(ChrPtr(pagetitle));
215                                 wc_printf("\">");
216                                 escputs(ChrPtr(pagetitle));
217                                 wc_printf("</a></td>");
218                                 wc_printf("</tr>\n");
219                                 ++row;
220                         }
221                 }
222                 wc_printf("</table>\n");
223                 FreeStrBuf(&pagetitle);
224         }
225
226         FreeStrBuf(&Buf);
227 }
228
229
230 /*
231  * Display a list of all pages in a Wiki room.  Search requests in a Wiki room also go here.
232  */
233 void display_wiki_pagelist(void) {
234         output_headers(1, 1, 1, 0, 0, 0);
235         do_template("wiki_pagelist");
236         wDumpContent(1);
237 }
238
239
240 int wiki_Cleanup(void **ViewSpecific) {
241         StrBuf *pagename;
242         pagename = NewStrBufDup(sbstr("page"));
243         display_wiki_page_backend(pagename, "", 0);
244         wDumpContent(1);
245         return 0;
246 }
247
248
249 int ConditionalHaveWikiPage(StrBuf * Target, WCTemplputParams * TP) {
250         const char *page;
251         const char *pch;
252         long len;
253
254         page = BSTR("page");
255         GetTemplateTokenString(Target, TP, 2, &pch, &len);
256         return strcasecmp(page, pch) == 0;
257 }
258
259
260 int ConditionalHavewikiType(StrBuf * Target, WCTemplputParams * TP) {
261         const char *pch;
262         long len;
263
264         GetTemplateTokenString(Target, TP, 2, &pch, &len);
265         return bmstrcasestr((char *) ChrPtr(WC->Hdr->HR.ReqLine), pch) != NULL;
266 }
267
268
269 int wiki_PrintHeaderPage(SharedMessageStatus * Stat, void **ViewSpecific) {
270         /* this function was intentionaly left empty. */
271         return 0;
272 }
273
274 int wiki_GetParamsGetServerCall(SharedMessageStatus * Stat,
275                                 void **ViewSpecific, long oper, char *cmd, long len, char *filter, long flen) {
276         if (oper == do_search)
277                 display_wiki_pagelist();
278         else
279                 http_redirect("wiki?page=home");
280
281         return 300;
282 }
283
284
285 void InitModule_WIKI(void) {
286         RegisterReadLoopHandlerset(VIEW_WIKI,
287                                    wiki_GetParamsGetServerCall, wiki_PrintHeaderPage, NULL, NULL, NULL, NULL, wiki_Cleanup, NULL);
288
289         WebcitAddUrlHandler(HKEY("wiki"), "", 0, display_wiki_page, 0);
290         WebcitAddUrlHandler(HKEY("wiki_history"), "", 0, display_wiki_history, 0);
291         WebcitAddUrlHandler(HKEY("wiki_pagelist"), "", 0, display_wiki_pagelist, 0);
292         RegisterNamespace("WIKI:DISPLAYHISTORY", 0, 0, tmplput_display_wiki_history, NULL, CTX_NONE);
293         RegisterNamespace("WIKI:DISPLAYPAGELIST", 0, 0, tmplput_display_wiki_pagelist, NULL, CTX_NONE);
294         RegisterConditional("COND:WIKI:PAGE", 1, ConditionalHaveWikiPage, CTX_NONE);
295         RegisterConditional("COND:WIKI:TYPE", 1, ConditionalHavewikiType, CTX_NONE);
296 }