Fossil SCM

Add the ability to edit Wiki pages as either Fossil Wiki, or Markdown, or Plain Text.

drh 2013-05-28 00:45 trunk
Commit a5a5524659ed6fe6426e9d598bea3ddf1584df54
3 files changed +2 -2 +1 -1 +142 -24
+2 -2
--- src/doc.c
+++ src/doc.c
@@ -271,11 +271,11 @@
271271
{ "viv", 3, "video/vnd.vivo" },
272272
{ "vivo", 4, "video/vnd.vivo" },
273273
{ "vrml", 4, "model/vrml" },
274274
{ "wav", 3, "audio/x-wav" },
275275
{ "wax", 3, "audio/x-ms-wax" },
276
- { "wiki", 4, "application/x-fossil-wiki" },
276
+ { "wiki", 4, "text/x-fossil-wiki" },
277277
{ "wma", 3, "audio/x-ms-wma" },
278278
{ "wmv", 3, "video/x-ms-wmv" },
279279
{ "wmx", 3, "video/x-ms-wmx" },
280280
{ "wrl", 3, "model/vrml" },
281281
{ "wvx", 3, "video/x-ms-wvx" },
@@ -495,11 +495,11 @@
495495
Th_Store("doc_name", zName);
496496
Th_Store("doc_version", db_text(0, "SELECT '[' || substr(uuid,1,10) || ']'"
497497
" FROM blob WHERE rid=%d", vid));
498498
Th_Store("doc_date", db_text(0, "SELECT datetime(mtime) FROM event"
499499
" WHERE objid=%d AND type='ci'", vid));
500
- if( fossil_strcmp(zMime, "application/x-fossil-wiki")==0 ){
500
+ if( fossil_strcmp(zMime, "text/x-fossil-wiki")==0 ){
501501
Blob title, tail;
502502
if( wiki_find_title(&filebody, &title, &tail) ){
503503
style_header(blob_str(&title));
504504
wiki_convert(&tail, 0, WIKI_BUTTONS);
505505
}else{
506506
--- src/doc.c
+++ src/doc.c
@@ -271,11 +271,11 @@
271 { "viv", 3, "video/vnd.vivo" },
272 { "vivo", 4, "video/vnd.vivo" },
273 { "vrml", 4, "model/vrml" },
274 { "wav", 3, "audio/x-wav" },
275 { "wax", 3, "audio/x-ms-wax" },
276 { "wiki", 4, "application/x-fossil-wiki" },
277 { "wma", 3, "audio/x-ms-wma" },
278 { "wmv", 3, "video/x-ms-wmv" },
279 { "wmx", 3, "video/x-ms-wmx" },
280 { "wrl", 3, "model/vrml" },
281 { "wvx", 3, "video/x-ms-wvx" },
@@ -495,11 +495,11 @@
495 Th_Store("doc_name", zName);
496 Th_Store("doc_version", db_text(0, "SELECT '[' || substr(uuid,1,10) || ']'"
497 " FROM blob WHERE rid=%d", vid));
498 Th_Store("doc_date", db_text(0, "SELECT datetime(mtime) FROM event"
499 " WHERE objid=%d AND type='ci'", vid));
500 if( fossil_strcmp(zMime, "application/x-fossil-wiki")==0 ){
501 Blob title, tail;
502 if( wiki_find_title(&filebody, &title, &tail) ){
503 style_header(blob_str(&title));
504 wiki_convert(&tail, 0, WIKI_BUTTONS);
505 }else{
506
--- src/doc.c
+++ src/doc.c
@@ -271,11 +271,11 @@
271 { "viv", 3, "video/vnd.vivo" },
272 { "vivo", 4, "video/vnd.vivo" },
273 { "vrml", 4, "model/vrml" },
274 { "wav", 3, "audio/x-wav" },
275 { "wax", 3, "audio/x-ms-wax" },
276 { "wiki", 4, "text/x-fossil-wiki" },
277 { "wma", 3, "audio/x-ms-wma" },
278 { "wmv", 3, "video/x-ms-wmv" },
279 { "wmx", 3, "video/x-ms-wmx" },
280 { "wrl", 3, "model/vrml" },
281 { "wvx", 3, "video/x-ms-wvx" },
@@ -495,11 +495,11 @@
495 Th_Store("doc_name", zName);
496 Th_Store("doc_version", db_text(0, "SELECT '[' || substr(uuid,1,10) || ']'"
497 " FROM blob WHERE rid=%d", vid));
498 Th_Store("doc_date", db_text(0, "SELECT datetime(mtime) FROM event"
499 " WHERE objid=%d AND type='ci'", vid));
500 if( fossil_strcmp(zMime, "text/x-fossil-wiki")==0 ){
501 Blob title, tail;
502 if( wiki_find_title(&filebody, &title, &tail) ){
503 style_header(blob_str(&title));
504 wiki_convert(&tail, 0, WIKI_BUTTONS);
505 }else{
506
+1 -1
--- src/info.c
+++ src/info.c
@@ -1611,11 +1611,11 @@
16111611
}else{
16121612
renderAsHtml = 1;
16131613
style_submenu_element("Text", "Text",
16141614
"%s/artifact/%s?txt=1", g.zTop, zUuid);
16151615
}
1616
- }else if( fossil_strcmp(zMime, "application/x-fossil-wiki")==0 ){
1616
+ }else if( fossil_strcmp(zMime, "text/x-fossil-wiki")==0 ){
16171617
if( asText ){
16181618
style_submenu_element("Wiki", "Wiki",
16191619
"%s/artifact/%s", g.zTop, zUuid);
16201620
}else{
16211621
renderAsWiki = 1;
16221622
--- src/info.c
+++ src/info.c
@@ -1611,11 +1611,11 @@
1611 }else{
1612 renderAsHtml = 1;
1613 style_submenu_element("Text", "Text",
1614 "%s/artifact/%s?txt=1", g.zTop, zUuid);
1615 }
1616 }else if( fossil_strcmp(zMime, "application/x-fossil-wiki")==0 ){
1617 if( asText ){
1618 style_submenu_element("Wiki", "Wiki",
1619 "%s/artifact/%s", g.zTop, zUuid);
1620 }else{
1621 renderAsWiki = 1;
1622
--- src/info.c
+++ src/info.c
@@ -1611,11 +1611,11 @@
1611 }else{
1612 renderAsHtml = 1;
1613 style_submenu_element("Text", "Text",
1614 "%s/artifact/%s?txt=1", g.zTop, zUuid);
1615 }
1616 }else if( fossil_strcmp(zMime, "text/x-fossil-wiki")==0 ){
1617 if( asText ){
1618 style_submenu_element("Wiki", "Wiki",
1619 "%s/artifact/%s", g.zTop, zUuid);
1620 }else{
1621 renderAsWiki = 1;
1622
+142 -24
--- src/wiki.c
+++ src/wiki.c
@@ -118,10 +118,48 @@
118118
*/
119119
static int is_sandbox(const char *zPagename){
120120
return fossil_stricmp(zPagename,"sandbox")==0 ||
121121
fossil_stricmp(zPagename,"sand box")==0;
122122
}
123
+
124
+/*
125
+** Only allow certain mimetypes through.
126
+** All others become "text/x-fossil-wiki"
127
+*/
128
+const char *wiki_filter_mimetypes(const char *zMimetype){
129
+ if( zMimetype!=0 &&
130
+ ( fossil_strcmp(zMimetype, "text/x-markdown")==0
131
+ || fossil_strcmp(zMimetype, "text/plain")==0 )
132
+ ){
133
+ return zMimetype;
134
+ }
135
+ return "text/x-fossil-wiki";
136
+}
137
+
138
+/*
139
+** Render wiki text according to its mimetype
140
+*/
141
+void wiki_render_by_mimetype(Blob *pWiki, const char *zMimetype){
142
+ if( zMimetype==0 || fossil_strcmp(zMimetype, "text/x-fossil-wiki")==0 ){
143
+ wiki_convert(pWiki, 0, 0);
144
+ }else if( fossil_strcmp(zMimetype, "text/x-markdown")==0 ){
145
+ Blob title = BLOB_INITIALIZER;
146
+ Blob tail = BLOB_INITIALIZER;
147
+ markdown_to_html(pWiki, &title, &tail);
148
+ if( blob_size(&title)>0 ){
149
+ @ <h1>%s(blob_str(&title))</h1>
150
+ }
151
+ @ %s(blob_str(&tail))
152
+ blob_reset(&title);
153
+ blob_reset(&tail);
154
+ }else{
155
+ @ <pre>
156
+ @ %h(blob_str(pWiki))
157
+ @ </pre>
158
+ }
159
+}
160
+
123161
124162
/*
125163
** WEBPAGE: wiki
126164
** URL: /wiki?name=PAGENAME
127165
*/
@@ -131,10 +169,11 @@
131169
int isSandbox;
132170
char *zUuid;
133171
Blob wiki;
134172
Manifest *pWiki = 0;
135173
const char *zPageName;
174
+ const char *zMimetype;
136175
char *zBody = mprintf("%s","<i>Empty Page</i>");
137176
138177
login_check_credentials();
139178
if( !g.perm.RdWiki ){ login_needed(); return; }
140179
zPageName = P("name");
@@ -173,10 +212,11 @@
173212
}
174213
if( check_name(zPageName) ) return;
175214
isSandbox = is_sandbox(zPageName);
176215
if( isSandbox ){
177216
zBody = db_get("sandbox",zBody);
217
+ zMimetype = db_get("sandbox-mimetype","text/x-fossil-wiki");
178218
rid = 0;
179219
}else{
180220
zTag = mprintf("wiki-%s", zPageName);
181221
rid = db_int(0,
182222
"SELECT rid FROM tagxref"
@@ -185,12 +225,14 @@
185225
);
186226
free(zTag);
187227
pWiki = manifest_get(rid, CFTYPE_WIKI);
188228
if( pWiki ){
189229
zBody = pWiki->zWiki;
230
+ zMimetype = pWiki->zMimetype;
190231
}
191232
}
233
+ zMimetype = wiki_filter_mimetypes(zMimetype);
192234
if( !g.isHome ){
193235
if( rid ){
194236
style_submenu_element("Diff", "Last change",
195237
"%R/wdiff?name=%T&a=%d", zPageName, rid);
196238
zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
@@ -212,22 +254,23 @@
212254
style_submenu_element("Attach", "Add An Attachment",
213255
"%s/attachadd?page=%T&from=%s/wiki%%3fname=%T",
214256
g.zTop, zPageName, g.zTop, zPageName);
215257
}
216258
if( rid && g.perm.ApndWiki ){
217
- style_submenu_element("Append", "Add A Comment", "%s/wikiappend?name=%T",
218
- g.zTop, zPageName);
259
+ style_submenu_element("Append", "Add A Comment",
260
+ "%s/wikiappend?name=%T&mimetype=%s",
261
+ g.zTop, zPageName, zMimetype);
219262
}
220263
if( g.perm.Hyperlink ){
221264
style_submenu_element("History", "History", "%s/whistory?name=%T",
222265
g.zTop, zPageName);
223266
}
224267
}
225268
style_set_current_page("%s?name=%T", g.zPath, zPageName);
226269
style_header(zPageName);
227270
blob_init(&wiki, zBody, -1);
228
- wiki_convert(&wiki, 0, 0);
271
+ wiki_render_by_mimetype(&wiki, zMimetype);
229272
blob_reset(&wiki);
230273
attachment_list(zPageName, "<hr /><h2>Attachments:</h2><ul>");
231274
manifest_destroy(pWiki);
232275
style_footer();
233276
}
@@ -247,10 +290,49 @@
247290
}
248291
db_multi_exec("INSERT OR IGNORE INTO unsent VALUES(%d)", nrid);
249292
db_multi_exec("INSERT OR IGNORE INTO unclustered VALUES(%d);", nrid);
250293
manifest_crosslink(nrid, pWiki);
251294
}
295
+
296
+/*
297
+** Formal names and common names for the various wiki styles.
298
+*/
299
+static const char *azStyles[] = {
300
+ "text/x-fossil-wiki", "Fossil Wiki",
301
+ "text/x-markdown", "Markdown",
302
+ "text/plain", "Plain Text"
303
+};
304
+
305
+/*
306
+** Output a selection box from which the user can select the
307
+** wiki mimetype.
308
+*/
309
+static void mimetype_option_menu(const char *zMimetype){
310
+ unsigned i;
311
+ @ Markup style: <select name="mimetype" size="1">
312
+ for(i=0; i<sizeof(azStyles)/sizeof(azStyles[0]); i+=2){
313
+ if( fossil_strcmp(zMimetype,azStyles[i])==0 ){
314
+ @ <option value="%s(azStyles[i])" selected>%s(azStyles[i+1])</option>
315
+ }else{
316
+ @ <option value="%s(azStyles[i])">%s(azStyles[i+1])</option>
317
+ }
318
+ }
319
+ @ </select>
320
+}
321
+
322
+/*
323
+** Given a mimetype, return its common name.
324
+*/
325
+static const char *mimetype_common_name(const char *zMimetype){
326
+ int i;
327
+ for(i=4; i>=2; i-=2){
328
+ if( zMimetype && fossil_strcmp(zMimetype, azStyles[i])==0 ){
329
+ return azStyles[i+1];
330
+ }
331
+ }
332
+ return azStyles[1];
333
+}
252334
253335
/*
254336
** WEBPAGE: wikiedit
255337
** URL: /wikiedit?name=PAGENAME
256338
*/
@@ -262,10 +344,11 @@
262344
Manifest *pWiki = 0;
263345
const char *zPageName;
264346
int n;
265347
const char *z;
266348
char *zBody = (char*)P("w");
349
+ const char *zMimetype = wiki_filter_mimetypes(P("mimetype"));
267350
int isWysiwyg = P("wysiwyg")!=0;
268351
int goodCaptcha = 1;
269352
270353
if( P("edit-wysiwyg")!=0 ){ isWysiwyg = 1; zBody = 0; }
271354
if( P("edit-markup")!=0 ){ isWysiwyg = 0; zBody = 0; }
@@ -288,10 +371,11 @@
288371
login_needed();
289372
return;
290373
}
291374
if( zBody==0 ){
292375
zBody = db_get("sandbox","");
376
+ zMimetype = db_get("sandbox-mimetype","text/x-fossil-wiki");
293377
}
294378
}else{
295379
zTag = mprintf("wiki-%s", zPageName);
296380
rid = db_int(0,
297381
"SELECT rid FROM tagxref"
@@ -303,10 +387,11 @@
303387
login_needed();
304388
return;
305389
}
306390
if( zBody==0 && (pWiki = manifest_get(rid, CFTYPE_WIKI))!=0 ){
307391
zBody = pWiki->zWiki;
392
+ zMimetype = pWiki->zMimetype;
308393
}
309394
}
310395
if( P("submit")!=0 && zBody!=0
311396
&& (goodCaptcha = captcha_is_correct())
312397
){
@@ -314,16 +399,20 @@
314399
Blob cksum;
315400
blob_zero(&wiki);
316401
db_begin_transaction();
317402
if( isSandbox ){
318403
db_set("sandbox",zBody,0);
404
+ db_set("sandbox-mimetype",zMimetype,0);
319405
}else{
320406
login_verify_csrf_secret();
321407
zDate = date_in_standard_format("now");
322408
blob_appendf(&wiki, "D %s\n", zDate);
323409
free(zDate);
324410
blob_appendf(&wiki, "L %F\n", zPageName);
411
+ if( fossil_strcmp(zMimetype,"text/x-fossil-wiki")!=0 ){
412
+ blob_appendf(&wiki, "N %s\n", zMimetype);
413
+ }
325414
if( rid ){
326415
char *zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
327416
blob_appendf(&wiki, "P %s\n", zUuid);
328417
free(zUuid);
329418
}
@@ -353,11 +442,11 @@
353442
}
354443
blob_zero(&wiki);
355444
blob_append(&wiki, zBody, -1);
356445
if( P("preview")!=0 ){
357446
@ Preview:<hr />
358
- wiki_convert(&wiki, 0, 0);
447
+ wiki_render_by_mimetype(&wiki, zMimetype);
359448
@ <hr />
360449
blob_reset(&wiki);
361450
}
362451
for(n=2, z=zBody; z[0]; z++){
363452
if( z[0]=='\n' ) n++;
@@ -366,11 +455,12 @@
366455
if( n>30 ) n = 30;
367456
if( !isWysiwyg ){
368457
/* Traditional markup-only editing */
369458
form_begin(0, "%R/wikiedit");
370459
@ <div>
371
- @ <textarea name="w" class="wikiedit" cols="80"
460
+ mimetype_option_menu(zMimetype);
461
+ @ <br /><textarea name="w" class="wikiedit" cols="80"
372462
@ rows="%d(n)" wrap="virtual">%h(zBody)</textarea>
373463
@ <br />
374464
if( db_get_boolean("wysiwyg-wiki", 0) ){
375465
@ <input type="submit" name="edit-wysiwyg" value="Wysiwyg Editor"
376466
@ onclick='return confirm("Switching to WYSIWYG-mode\nwill erase your markup\nedits. Continue?")' />
@@ -413,30 +503,35 @@
413503
** Prompt the user to enter the name of a new wiki page. Then redirect
414504
** to the wikiedit screen for that new page.
415505
*/
416506
void wikinew_page(void){
417507
const char *zName;
508
+ const char *zMimetype;
418509
login_check_credentials();
419510
if( !g.perm.NewWiki ){
420511
login_needed();
421512
return;
422513
}
423514
zName = PD("name","");
515
+ zMimetype = wiki_filter_mimetypes(P("mimetype"));
424516
if( zName[0] && wiki_name_is_wellformed((const unsigned char *)zName) ){
425
- if( db_get_boolean("wysiwyg-wiki", 0) ){
517
+ if( fossil_strcmp(zMimetype,"text/x-fossil-wiki")==0
518
+ && db_get_boolean("wysiwyg-wiki", 0)
519
+ ){
426520
cgi_redirectf("wikiedit?name=%T&wysiwyg=1", zName);
427521
}else{
428
- cgi_redirectf("wikiedit?name=%T", zName);
522
+ cgi_redirectf("wikiedit?name=%T&mimetype=%s", zName, zMimetype);
429523
}
430524
}
431525
style_header("Create A New Wiki Page");
432526
@ <p>Rules for wiki page names:</p>
433527
well_formed_wiki_name_rules();
434528
form_begin(0, "%R/wikinew");
435529
@ <p>Name of new wiki page:
436
- @ <input style="width: 35;" type="text" name="name" value="%h(zName)" />
437
- @ <input type="submit" value="Create" />
530
+ @ <input style="width: 35;" type="text" name="name" value="%h(zName)" /><br />
531
+ mimetype_option_menu("text/x-fossil-wiki");
532
+ @ <br /><input type="submit" value="Create" />
438533
@ </p></form>
439534
if( zName[0] ){
440535
@ <p><span class="wikiError">
441536
@ "%h(zName)" is not a valid wiki page name!</span></p>
442537
}
@@ -445,43 +540,61 @@
445540
446541
447542
/*
448543
** Append the wiki text for an remark to the end of the given BLOB.
449544
*/
450
-static void appendRemark(Blob *p){
545
+static void appendRemark(Blob *p, const char *zMimetype){
451546
char *zDate;
452547
const char *zUser;
453548
const char *zRemark;
454549
char *zId;
455550
456551
zDate = db_text(0, "SELECT datetime('now')");
457
- zId = db_text(0, "SELECT lower(hex(randomblob(8)))");
458
- blob_appendf(p, "\n\n<hr><div id=\"%s\"><i>On %s UTC %h",
459
- zId, zDate, g.zLogin);
460
- free(zDate);
552
+ zRemark = PD("r","");
461553
zUser = PD("u",g.zLogin);
462
- if( zUser[0] && fossil_strcmp(zUser,g.zLogin) ){
463
- blob_appendf(p, " (claiming to be %h)", zUser);
554
+ if( fossil_strcmp(zMimetype, "text/x-fossil-wiki")==0 ){
555
+ zId = db_text(0, "SELECT lower(hex(randomblob(8)))");
556
+ blob_appendf(p, "\n\n<hr><div id=\"%s\"><i>On %s UTC %h",
557
+ zId, zDate, g.zLogin);
558
+ if( zUser[0] && fossil_strcmp(zUser,g.zLogin) ){
559
+ blob_appendf(p, " (claiming to be %h)", zUser);
560
+ }
561
+ blob_appendf(p, " added:</i><br />\n%s</div id=\"%s\">", zRemark, zId);
562
+ }else if( fossil_strcmp(zMimetype, "text/x-markdown")==0 ){
563
+ blob_appendf(p, "\n\n------\n*On %s UTC %h", zDate, g.zLogin);
564
+ if( zUser[0] && fossil_strcmp(zUser,g.zLogin) ){
565
+ blob_appendf(p, " (claiming to be %h)", zUser);
566
+ }
567
+ blob_appendf(p, " added:*\n\n%s\n", zRemark);
568
+ }else{
569
+ blob_appendf(p, "\n\n------------------------------------------------\n"
570
+ "On %s UTC %s", zDate, g.zLogin);
571
+ if( zUser[0] && fossil_strcmp(zUser,g.zLogin) ){
572
+ blob_appendf(p, " (claiming to be %s)", zUser);
573
+ }
574
+ blob_appendf(p, " added:\n\n%s\n", zRemark);
464575
}
465
- zRemark = PD("r","");
466
- blob_appendf(p, " added:</i><br />\n%s</div id=\"%s\">", zRemark, zId);
576
+ fossil_free(zDate);
467577
}
468578
469579
/*
470580
** WEBPAGE: wikiappend
471
-** URL: /wikiappend?name=PAGENAME
581
+** URL: /wikiappend?name=PAGENAME&mimetype=MIMETYPE
472582
*/
473583
void wikiappend_page(void){
474584
char *zTag;
475585
int rid = 0;
476586
int isSandbox;
477587
const char *zPageName;
478588
const char *zUser;
589
+ const char *zMimetype;
479590
int goodCaptcha = 1;
591
+ const char *zFormat;
480592
481593
login_check_credentials();
482594
zPageName = PD("name","");
595
+ zMimetype = wiki_filter_mimetypes(P("mimetype"));
483596
if( check_name(zPageName) ) return;
484597
isSandbox = is_sandbox(zPageName);
485598
if( !isSandbox ){
486599
zTag = mprintf("wiki-%s", zPageName);
487600
rid = db_int(0,
@@ -509,11 +622,11 @@
509622
Manifest *pWiki = 0;
510623
511624
blob_zero(&body);
512625
if( isSandbox ){
513626
blob_appendf(&body, db_get("sandbox",""));
514
- appendRemark(&body);
627
+ appendRemark(&body, zMimetype);
515628
db_set("sandbox", blob_str(&body), 0);
516629
}else{
517630
login_verify_csrf_secret();
518631
pWiki = manifest_get(rid, CFTYPE_WIKI);
519632
if( pWiki ){
@@ -523,19 +636,22 @@
523636
blob_zero(&wiki);
524637
db_begin_transaction();
525638
zDate = date_in_standard_format("now");
526639
blob_appendf(&wiki, "D %s\n", zDate);
527640
blob_appendf(&wiki, "L %F\n", zPageName);
641
+ if( fossil_strcmp(zMimetype, "text/x-fossil-wiki")!=0 ){
642
+ blob_appendf(&wiki, "N %s\n", zMimetype);
643
+ }
528644
if( rid ){
529645
char *zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
530646
blob_appendf(&wiki, "P %s\n", zUuid);
531647
free(zUuid);
532648
}
533649
if( g.zLogin ){
534650
blob_appendf(&wiki, "U %F\n", g.zLogin);
535651
}
536
- appendRemark(&body);
652
+ appendRemark(&body, zMimetype);
537653
blob_appendf(&wiki, "W %d\n%s\n", blob_size(&body), blob_str(&body));
538654
md5sum_blob(&wiki, &cksum);
539655
blob_appendf(&wiki, "Z %b\n", &cksum);
540656
blob_reset(&cksum);
541657
wiki_put(&wiki, rid);
@@ -553,23 +669,25 @@
553669
@ <p class="generalError">Error: Incorrect security code.</p>
554670
}
555671
if( P("preview")!=0 ){
556672
Blob preview;
557673
blob_zero(&preview);
558
- appendRemark(&preview);
674
+ appendRemark(&preview, zMimetype);
559675
@ Preview:<hr>
560
- wiki_convert(&preview, 0, 0);
676
+ wiki_render_by_mimetype(&preview, zMimetype);
561677
@ <hr>
562678
blob_reset(&preview);
563679
}
564680
zUser = PD("u", g.zLogin);
565681
form_begin(0, "%R/wikiappend");
566682
login_insert_csrf_secret();
567683
@ <input type="hidden" name="name" value="%h(zPageName)" />
684
+ @ <input type="hidden" name="mimetype" value="%h(zMimetype)" />
568685
@ Your Name:
569686
@ <input type="text" name="u" size="20" value="%h(zUser)" /><br />
570
- @ Comment to append:<br />
687
+ zFormat = mimetype_common_name(zMimetype);
688
+ @ Comment to append (formatted as %s(zFormat)):<br />
571689
@ <textarea name="r" class="wikiedit" cols="80"
572690
@ rows="10" wrap="virtual">%h(PD("r",""))</textarea>
573691
@ <br />
574692
@ <input type="submit" name="preview" value="Preview Your Comment" />
575693
@ <input type="submit" name="submit" value="Append Your Changes" />
576694
--- src/wiki.c
+++ src/wiki.c
@@ -118,10 +118,48 @@
118 */
119 static int is_sandbox(const char *zPagename){
120 return fossil_stricmp(zPagename,"sandbox")==0 ||
121 fossil_stricmp(zPagename,"sand box")==0;
122 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
123
124 /*
125 ** WEBPAGE: wiki
126 ** URL: /wiki?name=PAGENAME
127 */
@@ -131,10 +169,11 @@
131 int isSandbox;
132 char *zUuid;
133 Blob wiki;
134 Manifest *pWiki = 0;
135 const char *zPageName;
 
136 char *zBody = mprintf("%s","<i>Empty Page</i>");
137
138 login_check_credentials();
139 if( !g.perm.RdWiki ){ login_needed(); return; }
140 zPageName = P("name");
@@ -173,10 +212,11 @@
173 }
174 if( check_name(zPageName) ) return;
175 isSandbox = is_sandbox(zPageName);
176 if( isSandbox ){
177 zBody = db_get("sandbox",zBody);
 
178 rid = 0;
179 }else{
180 zTag = mprintf("wiki-%s", zPageName);
181 rid = db_int(0,
182 "SELECT rid FROM tagxref"
@@ -185,12 +225,14 @@
185 );
186 free(zTag);
187 pWiki = manifest_get(rid, CFTYPE_WIKI);
188 if( pWiki ){
189 zBody = pWiki->zWiki;
 
190 }
191 }
 
192 if( !g.isHome ){
193 if( rid ){
194 style_submenu_element("Diff", "Last change",
195 "%R/wdiff?name=%T&a=%d", zPageName, rid);
196 zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
@@ -212,22 +254,23 @@
212 style_submenu_element("Attach", "Add An Attachment",
213 "%s/attachadd?page=%T&from=%s/wiki%%3fname=%T",
214 g.zTop, zPageName, g.zTop, zPageName);
215 }
216 if( rid && g.perm.ApndWiki ){
217 style_submenu_element("Append", "Add A Comment", "%s/wikiappend?name=%T",
218 g.zTop, zPageName);
 
219 }
220 if( g.perm.Hyperlink ){
221 style_submenu_element("History", "History", "%s/whistory?name=%T",
222 g.zTop, zPageName);
223 }
224 }
225 style_set_current_page("%s?name=%T", g.zPath, zPageName);
226 style_header(zPageName);
227 blob_init(&wiki, zBody, -1);
228 wiki_convert(&wiki, 0, 0);
229 blob_reset(&wiki);
230 attachment_list(zPageName, "<hr /><h2>Attachments:</h2><ul>");
231 manifest_destroy(pWiki);
232 style_footer();
233 }
@@ -247,10 +290,49 @@
247 }
248 db_multi_exec("INSERT OR IGNORE INTO unsent VALUES(%d)", nrid);
249 db_multi_exec("INSERT OR IGNORE INTO unclustered VALUES(%d);", nrid);
250 manifest_crosslink(nrid, pWiki);
251 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
252
253 /*
254 ** WEBPAGE: wikiedit
255 ** URL: /wikiedit?name=PAGENAME
256 */
@@ -262,10 +344,11 @@
262 Manifest *pWiki = 0;
263 const char *zPageName;
264 int n;
265 const char *z;
266 char *zBody = (char*)P("w");
 
267 int isWysiwyg = P("wysiwyg")!=0;
268 int goodCaptcha = 1;
269
270 if( P("edit-wysiwyg")!=0 ){ isWysiwyg = 1; zBody = 0; }
271 if( P("edit-markup")!=0 ){ isWysiwyg = 0; zBody = 0; }
@@ -288,10 +371,11 @@
288 login_needed();
289 return;
290 }
291 if( zBody==0 ){
292 zBody = db_get("sandbox","");
 
293 }
294 }else{
295 zTag = mprintf("wiki-%s", zPageName);
296 rid = db_int(0,
297 "SELECT rid FROM tagxref"
@@ -303,10 +387,11 @@
303 login_needed();
304 return;
305 }
306 if( zBody==0 && (pWiki = manifest_get(rid, CFTYPE_WIKI))!=0 ){
307 zBody = pWiki->zWiki;
 
308 }
309 }
310 if( P("submit")!=0 && zBody!=0
311 && (goodCaptcha = captcha_is_correct())
312 ){
@@ -314,16 +399,20 @@
314 Blob cksum;
315 blob_zero(&wiki);
316 db_begin_transaction();
317 if( isSandbox ){
318 db_set("sandbox",zBody,0);
 
319 }else{
320 login_verify_csrf_secret();
321 zDate = date_in_standard_format("now");
322 blob_appendf(&wiki, "D %s\n", zDate);
323 free(zDate);
324 blob_appendf(&wiki, "L %F\n", zPageName);
 
 
 
325 if( rid ){
326 char *zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
327 blob_appendf(&wiki, "P %s\n", zUuid);
328 free(zUuid);
329 }
@@ -353,11 +442,11 @@
353 }
354 blob_zero(&wiki);
355 blob_append(&wiki, zBody, -1);
356 if( P("preview")!=0 ){
357 @ Preview:<hr />
358 wiki_convert(&wiki, 0, 0);
359 @ <hr />
360 blob_reset(&wiki);
361 }
362 for(n=2, z=zBody; z[0]; z++){
363 if( z[0]=='\n' ) n++;
@@ -366,11 +455,12 @@
366 if( n>30 ) n = 30;
367 if( !isWysiwyg ){
368 /* Traditional markup-only editing */
369 form_begin(0, "%R/wikiedit");
370 @ <div>
371 @ <textarea name="w" class="wikiedit" cols="80"
 
372 @ rows="%d(n)" wrap="virtual">%h(zBody)</textarea>
373 @ <br />
374 if( db_get_boolean("wysiwyg-wiki", 0) ){
375 @ <input type="submit" name="edit-wysiwyg" value="Wysiwyg Editor"
376 @ onclick='return confirm("Switching to WYSIWYG-mode\nwill erase your markup\nedits. Continue?")' />
@@ -413,30 +503,35 @@
413 ** Prompt the user to enter the name of a new wiki page. Then redirect
414 ** to the wikiedit screen for that new page.
415 */
416 void wikinew_page(void){
417 const char *zName;
 
418 login_check_credentials();
419 if( !g.perm.NewWiki ){
420 login_needed();
421 return;
422 }
423 zName = PD("name","");
 
424 if( zName[0] && wiki_name_is_wellformed((const unsigned char *)zName) ){
425 if( db_get_boolean("wysiwyg-wiki", 0) ){
 
 
426 cgi_redirectf("wikiedit?name=%T&wysiwyg=1", zName);
427 }else{
428 cgi_redirectf("wikiedit?name=%T", zName);
429 }
430 }
431 style_header("Create A New Wiki Page");
432 @ <p>Rules for wiki page names:</p>
433 well_formed_wiki_name_rules();
434 form_begin(0, "%R/wikinew");
435 @ <p>Name of new wiki page:
436 @ <input style="width: 35;" type="text" name="name" value="%h(zName)" />
437 @ <input type="submit" value="Create" />
 
438 @ </p></form>
439 if( zName[0] ){
440 @ <p><span class="wikiError">
441 @ "%h(zName)" is not a valid wiki page name!</span></p>
442 }
@@ -445,43 +540,61 @@
445
446
447 /*
448 ** Append the wiki text for an remark to the end of the given BLOB.
449 */
450 static void appendRemark(Blob *p){
451 char *zDate;
452 const char *zUser;
453 const char *zRemark;
454 char *zId;
455
456 zDate = db_text(0, "SELECT datetime('now')");
457 zId = db_text(0, "SELECT lower(hex(randomblob(8)))");
458 blob_appendf(p, "\n\n<hr><div id=\"%s\"><i>On %s UTC %h",
459 zId, zDate, g.zLogin);
460 free(zDate);
461 zUser = PD("u",g.zLogin);
462 if( zUser[0] && fossil_strcmp(zUser,g.zLogin) ){
463 blob_appendf(p, " (claiming to be %h)", zUser);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
464 }
465 zRemark = PD("r","");
466 blob_appendf(p, " added:</i><br />\n%s</div id=\"%s\">", zRemark, zId);
467 }
468
469 /*
470 ** WEBPAGE: wikiappend
471 ** URL: /wikiappend?name=PAGENAME
472 */
473 void wikiappend_page(void){
474 char *zTag;
475 int rid = 0;
476 int isSandbox;
477 const char *zPageName;
478 const char *zUser;
 
479 int goodCaptcha = 1;
 
480
481 login_check_credentials();
482 zPageName = PD("name","");
 
483 if( check_name(zPageName) ) return;
484 isSandbox = is_sandbox(zPageName);
485 if( !isSandbox ){
486 zTag = mprintf("wiki-%s", zPageName);
487 rid = db_int(0,
@@ -509,11 +622,11 @@
509 Manifest *pWiki = 0;
510
511 blob_zero(&body);
512 if( isSandbox ){
513 blob_appendf(&body, db_get("sandbox",""));
514 appendRemark(&body);
515 db_set("sandbox", blob_str(&body), 0);
516 }else{
517 login_verify_csrf_secret();
518 pWiki = manifest_get(rid, CFTYPE_WIKI);
519 if( pWiki ){
@@ -523,19 +636,22 @@
523 blob_zero(&wiki);
524 db_begin_transaction();
525 zDate = date_in_standard_format("now");
526 blob_appendf(&wiki, "D %s\n", zDate);
527 blob_appendf(&wiki, "L %F\n", zPageName);
 
 
 
528 if( rid ){
529 char *zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
530 blob_appendf(&wiki, "P %s\n", zUuid);
531 free(zUuid);
532 }
533 if( g.zLogin ){
534 blob_appendf(&wiki, "U %F\n", g.zLogin);
535 }
536 appendRemark(&body);
537 blob_appendf(&wiki, "W %d\n%s\n", blob_size(&body), blob_str(&body));
538 md5sum_blob(&wiki, &cksum);
539 blob_appendf(&wiki, "Z %b\n", &cksum);
540 blob_reset(&cksum);
541 wiki_put(&wiki, rid);
@@ -553,23 +669,25 @@
553 @ <p class="generalError">Error: Incorrect security code.</p>
554 }
555 if( P("preview")!=0 ){
556 Blob preview;
557 blob_zero(&preview);
558 appendRemark(&preview);
559 @ Preview:<hr>
560 wiki_convert(&preview, 0, 0);
561 @ <hr>
562 blob_reset(&preview);
563 }
564 zUser = PD("u", g.zLogin);
565 form_begin(0, "%R/wikiappend");
566 login_insert_csrf_secret();
567 @ <input type="hidden" name="name" value="%h(zPageName)" />
 
568 @ Your Name:
569 @ <input type="text" name="u" size="20" value="%h(zUser)" /><br />
570 @ Comment to append:<br />
 
571 @ <textarea name="r" class="wikiedit" cols="80"
572 @ rows="10" wrap="virtual">%h(PD("r",""))</textarea>
573 @ <br />
574 @ <input type="submit" name="preview" value="Preview Your Comment" />
575 @ <input type="submit" name="submit" value="Append Your Changes" />
576
--- src/wiki.c
+++ src/wiki.c
@@ -118,10 +118,48 @@
118 */
119 static int is_sandbox(const char *zPagename){
120 return fossil_stricmp(zPagename,"sandbox")==0 ||
121 fossil_stricmp(zPagename,"sand box")==0;
122 }
123
124 /*
125 ** Only allow certain mimetypes through.
126 ** All others become "text/x-fossil-wiki"
127 */
128 const char *wiki_filter_mimetypes(const char *zMimetype){
129 if( zMimetype!=0 &&
130 ( fossil_strcmp(zMimetype, "text/x-markdown")==0
131 || fossil_strcmp(zMimetype, "text/plain")==0 )
132 ){
133 return zMimetype;
134 }
135 return "text/x-fossil-wiki";
136 }
137
138 /*
139 ** Render wiki text according to its mimetype
140 */
141 void wiki_render_by_mimetype(Blob *pWiki, const char *zMimetype){
142 if( zMimetype==0 || fossil_strcmp(zMimetype, "text/x-fossil-wiki")==0 ){
143 wiki_convert(pWiki, 0, 0);
144 }else if( fossil_strcmp(zMimetype, "text/x-markdown")==0 ){
145 Blob title = BLOB_INITIALIZER;
146 Blob tail = BLOB_INITIALIZER;
147 markdown_to_html(pWiki, &title, &tail);
148 if( blob_size(&title)>0 ){
149 @ <h1>%s(blob_str(&title))</h1>
150 }
151 @ %s(blob_str(&tail))
152 blob_reset(&title);
153 blob_reset(&tail);
154 }else{
155 @ <pre>
156 @ %h(blob_str(pWiki))
157 @ </pre>
158 }
159 }
160
161
162 /*
163 ** WEBPAGE: wiki
164 ** URL: /wiki?name=PAGENAME
165 */
@@ -131,10 +169,11 @@
169 int isSandbox;
170 char *zUuid;
171 Blob wiki;
172 Manifest *pWiki = 0;
173 const char *zPageName;
174 const char *zMimetype;
175 char *zBody = mprintf("%s","<i>Empty Page</i>");
176
177 login_check_credentials();
178 if( !g.perm.RdWiki ){ login_needed(); return; }
179 zPageName = P("name");
@@ -173,10 +212,11 @@
212 }
213 if( check_name(zPageName) ) return;
214 isSandbox = is_sandbox(zPageName);
215 if( isSandbox ){
216 zBody = db_get("sandbox",zBody);
217 zMimetype = db_get("sandbox-mimetype","text/x-fossil-wiki");
218 rid = 0;
219 }else{
220 zTag = mprintf("wiki-%s", zPageName);
221 rid = db_int(0,
222 "SELECT rid FROM tagxref"
@@ -185,12 +225,14 @@
225 );
226 free(zTag);
227 pWiki = manifest_get(rid, CFTYPE_WIKI);
228 if( pWiki ){
229 zBody = pWiki->zWiki;
230 zMimetype = pWiki->zMimetype;
231 }
232 }
233 zMimetype = wiki_filter_mimetypes(zMimetype);
234 if( !g.isHome ){
235 if( rid ){
236 style_submenu_element("Diff", "Last change",
237 "%R/wdiff?name=%T&a=%d", zPageName, rid);
238 zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
@@ -212,22 +254,23 @@
254 style_submenu_element("Attach", "Add An Attachment",
255 "%s/attachadd?page=%T&from=%s/wiki%%3fname=%T",
256 g.zTop, zPageName, g.zTop, zPageName);
257 }
258 if( rid && g.perm.ApndWiki ){
259 style_submenu_element("Append", "Add A Comment",
260 "%s/wikiappend?name=%T&mimetype=%s",
261 g.zTop, zPageName, zMimetype);
262 }
263 if( g.perm.Hyperlink ){
264 style_submenu_element("History", "History", "%s/whistory?name=%T",
265 g.zTop, zPageName);
266 }
267 }
268 style_set_current_page("%s?name=%T", g.zPath, zPageName);
269 style_header(zPageName);
270 blob_init(&wiki, zBody, -1);
271 wiki_render_by_mimetype(&wiki, zMimetype);
272 blob_reset(&wiki);
273 attachment_list(zPageName, "<hr /><h2>Attachments:</h2><ul>");
274 manifest_destroy(pWiki);
275 style_footer();
276 }
@@ -247,10 +290,49 @@
290 }
291 db_multi_exec("INSERT OR IGNORE INTO unsent VALUES(%d)", nrid);
292 db_multi_exec("INSERT OR IGNORE INTO unclustered VALUES(%d);", nrid);
293 manifest_crosslink(nrid, pWiki);
294 }
295
296 /*
297 ** Formal names and common names for the various wiki styles.
298 */
299 static const char *azStyles[] = {
300 "text/x-fossil-wiki", "Fossil Wiki",
301 "text/x-markdown", "Markdown",
302 "text/plain", "Plain Text"
303 };
304
305 /*
306 ** Output a selection box from which the user can select the
307 ** wiki mimetype.
308 */
309 static void mimetype_option_menu(const char *zMimetype){
310 unsigned i;
311 @ Markup style: <select name="mimetype" size="1">
312 for(i=0; i<sizeof(azStyles)/sizeof(azStyles[0]); i+=2){
313 if( fossil_strcmp(zMimetype,azStyles[i])==0 ){
314 @ <option value="%s(azStyles[i])" selected>%s(azStyles[i+1])</option>
315 }else{
316 @ <option value="%s(azStyles[i])">%s(azStyles[i+1])</option>
317 }
318 }
319 @ </select>
320 }
321
322 /*
323 ** Given a mimetype, return its common name.
324 */
325 static const char *mimetype_common_name(const char *zMimetype){
326 int i;
327 for(i=4; i>=2; i-=2){
328 if( zMimetype && fossil_strcmp(zMimetype, azStyles[i])==0 ){
329 return azStyles[i+1];
330 }
331 }
332 return azStyles[1];
333 }
334
335 /*
336 ** WEBPAGE: wikiedit
337 ** URL: /wikiedit?name=PAGENAME
338 */
@@ -262,10 +344,11 @@
344 Manifest *pWiki = 0;
345 const char *zPageName;
346 int n;
347 const char *z;
348 char *zBody = (char*)P("w");
349 const char *zMimetype = wiki_filter_mimetypes(P("mimetype"));
350 int isWysiwyg = P("wysiwyg")!=0;
351 int goodCaptcha = 1;
352
353 if( P("edit-wysiwyg")!=0 ){ isWysiwyg = 1; zBody = 0; }
354 if( P("edit-markup")!=0 ){ isWysiwyg = 0; zBody = 0; }
@@ -288,10 +371,11 @@
371 login_needed();
372 return;
373 }
374 if( zBody==0 ){
375 zBody = db_get("sandbox","");
376 zMimetype = db_get("sandbox-mimetype","text/x-fossil-wiki");
377 }
378 }else{
379 zTag = mprintf("wiki-%s", zPageName);
380 rid = db_int(0,
381 "SELECT rid FROM tagxref"
@@ -303,10 +387,11 @@
387 login_needed();
388 return;
389 }
390 if( zBody==0 && (pWiki = manifest_get(rid, CFTYPE_WIKI))!=0 ){
391 zBody = pWiki->zWiki;
392 zMimetype = pWiki->zMimetype;
393 }
394 }
395 if( P("submit")!=0 && zBody!=0
396 && (goodCaptcha = captcha_is_correct())
397 ){
@@ -314,16 +399,20 @@
399 Blob cksum;
400 blob_zero(&wiki);
401 db_begin_transaction();
402 if( isSandbox ){
403 db_set("sandbox",zBody,0);
404 db_set("sandbox-mimetype",zMimetype,0);
405 }else{
406 login_verify_csrf_secret();
407 zDate = date_in_standard_format("now");
408 blob_appendf(&wiki, "D %s\n", zDate);
409 free(zDate);
410 blob_appendf(&wiki, "L %F\n", zPageName);
411 if( fossil_strcmp(zMimetype,"text/x-fossil-wiki")!=0 ){
412 blob_appendf(&wiki, "N %s\n", zMimetype);
413 }
414 if( rid ){
415 char *zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
416 blob_appendf(&wiki, "P %s\n", zUuid);
417 free(zUuid);
418 }
@@ -353,11 +442,11 @@
442 }
443 blob_zero(&wiki);
444 blob_append(&wiki, zBody, -1);
445 if( P("preview")!=0 ){
446 @ Preview:<hr />
447 wiki_render_by_mimetype(&wiki, zMimetype);
448 @ <hr />
449 blob_reset(&wiki);
450 }
451 for(n=2, z=zBody; z[0]; z++){
452 if( z[0]=='\n' ) n++;
@@ -366,11 +455,12 @@
455 if( n>30 ) n = 30;
456 if( !isWysiwyg ){
457 /* Traditional markup-only editing */
458 form_begin(0, "%R/wikiedit");
459 @ <div>
460 mimetype_option_menu(zMimetype);
461 @ <br /><textarea name="w" class="wikiedit" cols="80"
462 @ rows="%d(n)" wrap="virtual">%h(zBody)</textarea>
463 @ <br />
464 if( db_get_boolean("wysiwyg-wiki", 0) ){
465 @ <input type="submit" name="edit-wysiwyg" value="Wysiwyg Editor"
466 @ onclick='return confirm("Switching to WYSIWYG-mode\nwill erase your markup\nedits. Continue?")' />
@@ -413,30 +503,35 @@
503 ** Prompt the user to enter the name of a new wiki page. Then redirect
504 ** to the wikiedit screen for that new page.
505 */
506 void wikinew_page(void){
507 const char *zName;
508 const char *zMimetype;
509 login_check_credentials();
510 if( !g.perm.NewWiki ){
511 login_needed();
512 return;
513 }
514 zName = PD("name","");
515 zMimetype = wiki_filter_mimetypes(P("mimetype"));
516 if( zName[0] && wiki_name_is_wellformed((const unsigned char *)zName) ){
517 if( fossil_strcmp(zMimetype,"text/x-fossil-wiki")==0
518 && db_get_boolean("wysiwyg-wiki", 0)
519 ){
520 cgi_redirectf("wikiedit?name=%T&wysiwyg=1", zName);
521 }else{
522 cgi_redirectf("wikiedit?name=%T&mimetype=%s", zName, zMimetype);
523 }
524 }
525 style_header("Create A New Wiki Page");
526 @ <p>Rules for wiki page names:</p>
527 well_formed_wiki_name_rules();
528 form_begin(0, "%R/wikinew");
529 @ <p>Name of new wiki page:
530 @ <input style="width: 35;" type="text" name="name" value="%h(zName)" /><br />
531 mimetype_option_menu("text/x-fossil-wiki");
532 @ <br /><input type="submit" value="Create" />
533 @ </p></form>
534 if( zName[0] ){
535 @ <p><span class="wikiError">
536 @ "%h(zName)" is not a valid wiki page name!</span></p>
537 }
@@ -445,43 +540,61 @@
540
541
542 /*
543 ** Append the wiki text for an remark to the end of the given BLOB.
544 */
545 static void appendRemark(Blob *p, const char *zMimetype){
546 char *zDate;
547 const char *zUser;
548 const char *zRemark;
549 char *zId;
550
551 zDate = db_text(0, "SELECT datetime('now')");
552 zRemark = PD("r","");
 
 
 
553 zUser = PD("u",g.zLogin);
554 if( fossil_strcmp(zMimetype, "text/x-fossil-wiki")==0 ){
555 zId = db_text(0, "SELECT lower(hex(randomblob(8)))");
556 blob_appendf(p, "\n\n<hr><div id=\"%s\"><i>On %s UTC %h",
557 zId, zDate, g.zLogin);
558 if( zUser[0] && fossil_strcmp(zUser,g.zLogin) ){
559 blob_appendf(p, " (claiming to be %h)", zUser);
560 }
561 blob_appendf(p, " added:</i><br />\n%s</div id=\"%s\">", zRemark, zId);
562 }else if( fossil_strcmp(zMimetype, "text/x-markdown")==0 ){
563 blob_appendf(p, "\n\n------\n*On %s UTC %h", zDate, g.zLogin);
564 if( zUser[0] && fossil_strcmp(zUser,g.zLogin) ){
565 blob_appendf(p, " (claiming to be %h)", zUser);
566 }
567 blob_appendf(p, " added:*\n\n%s\n", zRemark);
568 }else{
569 blob_appendf(p, "\n\n------------------------------------------------\n"
570 "On %s UTC %s", zDate, g.zLogin);
571 if( zUser[0] && fossil_strcmp(zUser,g.zLogin) ){
572 blob_appendf(p, " (claiming to be %s)", zUser);
573 }
574 blob_appendf(p, " added:\n\n%s\n", zRemark);
575 }
576 fossil_free(zDate);
 
577 }
578
579 /*
580 ** WEBPAGE: wikiappend
581 ** URL: /wikiappend?name=PAGENAME&mimetype=MIMETYPE
582 */
583 void wikiappend_page(void){
584 char *zTag;
585 int rid = 0;
586 int isSandbox;
587 const char *zPageName;
588 const char *zUser;
589 const char *zMimetype;
590 int goodCaptcha = 1;
591 const char *zFormat;
592
593 login_check_credentials();
594 zPageName = PD("name","");
595 zMimetype = wiki_filter_mimetypes(P("mimetype"));
596 if( check_name(zPageName) ) return;
597 isSandbox = is_sandbox(zPageName);
598 if( !isSandbox ){
599 zTag = mprintf("wiki-%s", zPageName);
600 rid = db_int(0,
@@ -509,11 +622,11 @@
622 Manifest *pWiki = 0;
623
624 blob_zero(&body);
625 if( isSandbox ){
626 blob_appendf(&body, db_get("sandbox",""));
627 appendRemark(&body, zMimetype);
628 db_set("sandbox", blob_str(&body), 0);
629 }else{
630 login_verify_csrf_secret();
631 pWiki = manifest_get(rid, CFTYPE_WIKI);
632 if( pWiki ){
@@ -523,19 +636,22 @@
636 blob_zero(&wiki);
637 db_begin_transaction();
638 zDate = date_in_standard_format("now");
639 blob_appendf(&wiki, "D %s\n", zDate);
640 blob_appendf(&wiki, "L %F\n", zPageName);
641 if( fossil_strcmp(zMimetype, "text/x-fossil-wiki")!=0 ){
642 blob_appendf(&wiki, "N %s\n", zMimetype);
643 }
644 if( rid ){
645 char *zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
646 blob_appendf(&wiki, "P %s\n", zUuid);
647 free(zUuid);
648 }
649 if( g.zLogin ){
650 blob_appendf(&wiki, "U %F\n", g.zLogin);
651 }
652 appendRemark(&body, zMimetype);
653 blob_appendf(&wiki, "W %d\n%s\n", blob_size(&body), blob_str(&body));
654 md5sum_blob(&wiki, &cksum);
655 blob_appendf(&wiki, "Z %b\n", &cksum);
656 blob_reset(&cksum);
657 wiki_put(&wiki, rid);
@@ -553,23 +669,25 @@
669 @ <p class="generalError">Error: Incorrect security code.</p>
670 }
671 if( P("preview")!=0 ){
672 Blob preview;
673 blob_zero(&preview);
674 appendRemark(&preview, zMimetype);
675 @ Preview:<hr>
676 wiki_render_by_mimetype(&preview, zMimetype);
677 @ <hr>
678 blob_reset(&preview);
679 }
680 zUser = PD("u", g.zLogin);
681 form_begin(0, "%R/wikiappend");
682 login_insert_csrf_secret();
683 @ <input type="hidden" name="name" value="%h(zPageName)" />
684 @ <input type="hidden" name="mimetype" value="%h(zMimetype)" />
685 @ Your Name:
686 @ <input type="text" name="u" size="20" value="%h(zUser)" /><br />
687 zFormat = mimetype_common_name(zMimetype);
688 @ Comment to append (formatted as %s(zFormat)):<br />
689 @ <textarea name="r" class="wikiedit" cols="80"
690 @ rows="10" wrap="virtual">%h(PD("r",""))</textarea>
691 @ <br />
692 @ <input type="submit" name="preview" value="Preview Your Comment" />
693 @ <input type="submit" name="submit" value="Append Your Changes" />
694

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button