Fossil SCM

Progress toward getting the forum to actually work. This is an incremental check-in.

drh 2018-06-16 13:36 UTC forum-brainstorm-1
Commit 4814c41a9a9be4044fc96f88e9635f28d8741e4569df7b18d7c1153129cff992
+7 -2
--- src/cgi.c
+++ src/cgi.c
@@ -1101,10 +1101,11 @@
11011101
const char *zIn;
11021102
char *zOut;
11031103
int i;
11041104
zIn = cgi_parameter(zName, 0);
11051105
if( zIn==0 ) zIn = zDefault;
1106
+ if( zIn==0 ) return 0;
11061107
while( fossil_isspace(zIn[0]) ) zIn++;
11071108
zOut = fossil_strdup(zIn);
11081109
for(i=0; zOut[i]; i++){}
11091110
while( i>0 && fossil_isspace(zOut[i-1]) ) zOut[--i] = 0;
11101111
return zOut;
@@ -1181,20 +1182,24 @@
11811182
** Print all query parameters on standard output. Format the
11821183
** parameters as HTML. This is used for testing and debugging.
11831184
**
11841185
** Omit the values of the cookies unless showAll is true.
11851186
*/
1186
-void cgi_print_all(int showAll){
1187
+void cgi_print_all(int showAll, int onConsole){
11871188
int i;
11881189
cgi_parameter("",""); /* Force the parameters into sorted order */
11891190
for(i=0; i<nUsedQP; i++){
11901191
const char *zName = aParamQP[i].zName;
11911192
if( !showAll ){
11921193
if( fossil_stricmp("HTTP_COOKIE",zName)==0 ) continue;
11931194
if( fossil_strnicmp("fossil-",zName,7)==0 ) continue;
11941195
}
1195
- cgi_printf("%h = %h <br />\n", zName, aParamQP[i].zValue);
1196
+ if( onConsole ){
1197
+ fossil_trace("%s = %s\n", zName, aParamQP[i].zValue);
1198
+ }else{
1199
+ cgi_printf("%h = %h <br />\n", zName, aParamQP[i].zValue);
1200
+ }
11961201
}
11971202
}
11981203
11991204
/*
12001205
** Export all untagged query parameters (but not cookies or environment
12011206
--- src/cgi.c
+++ src/cgi.c
@@ -1101,10 +1101,11 @@
1101 const char *zIn;
1102 char *zOut;
1103 int i;
1104 zIn = cgi_parameter(zName, 0);
1105 if( zIn==0 ) zIn = zDefault;
 
1106 while( fossil_isspace(zIn[0]) ) zIn++;
1107 zOut = fossil_strdup(zIn);
1108 for(i=0; zOut[i]; i++){}
1109 while( i>0 && fossil_isspace(zOut[i-1]) ) zOut[--i] = 0;
1110 return zOut;
@@ -1181,20 +1182,24 @@
1181 ** Print all query parameters on standard output. Format the
1182 ** parameters as HTML. This is used for testing and debugging.
1183 **
1184 ** Omit the values of the cookies unless showAll is true.
1185 */
1186 void cgi_print_all(int showAll){
1187 int i;
1188 cgi_parameter("",""); /* Force the parameters into sorted order */
1189 for(i=0; i<nUsedQP; i++){
1190 const char *zName = aParamQP[i].zName;
1191 if( !showAll ){
1192 if( fossil_stricmp("HTTP_COOKIE",zName)==0 ) continue;
1193 if( fossil_strnicmp("fossil-",zName,7)==0 ) continue;
1194 }
1195 cgi_printf("%h = %h <br />\n", zName, aParamQP[i].zValue);
 
 
 
 
1196 }
1197 }
1198
1199 /*
1200 ** Export all untagged query parameters (but not cookies or environment
1201
--- src/cgi.c
+++ src/cgi.c
@@ -1101,10 +1101,11 @@
1101 const char *zIn;
1102 char *zOut;
1103 int i;
1104 zIn = cgi_parameter(zName, 0);
1105 if( zIn==0 ) zIn = zDefault;
1106 if( zIn==0 ) return 0;
1107 while( fossil_isspace(zIn[0]) ) zIn++;
1108 zOut = fossil_strdup(zIn);
1109 for(i=0; zOut[i]; i++){}
1110 while( i>0 && fossil_isspace(zOut[i-1]) ) zOut[--i] = 0;
1111 return zOut;
@@ -1181,20 +1182,24 @@
1182 ** Print all query parameters on standard output. Format the
1183 ** parameters as HTML. This is used for testing and debugging.
1184 **
1185 ** Omit the values of the cookies unless showAll is true.
1186 */
1187 void cgi_print_all(int showAll, int onConsole){
1188 int i;
1189 cgi_parameter("",""); /* Force the parameters into sorted order */
1190 for(i=0; i<nUsedQP; i++){
1191 const char *zName = aParamQP[i].zName;
1192 if( !showAll ){
1193 if( fossil_stricmp("HTTP_COOKIE",zName)==0 ) continue;
1194 if( fossil_strnicmp("fossil-",zName,7)==0 ) continue;
1195 }
1196 if( onConsole ){
1197 fossil_trace("%s = %s\n", zName, aParamQP[i].zValue);
1198 }else{
1199 cgi_printf("%h = %h <br />\n", zName, aParamQP[i].zValue);
1200 }
1201 }
1202 }
1203
1204 /*
1205 ** Export all untagged query parameters (but not cookies or environment
1206
+1 -1
--- src/db.c
+++ src/db.c
@@ -272,11 +272,11 @@
272272
db.nPrepare++;
273273
if( flags & DB_PREPARE_PERSISTENT ){
274274
prepFlags = SQLITE_PREPARE_PERSISTENT;
275275
}
276276
rc = sqlite3_prepare_v3(g.db, zSql, -1, prepFlags, &pStmt->pStmt, 0);
277
- if( rc!=0 && (flags & DB_PREPARE_IGNORE_ERROR)!=0 ){
277
+ if( rc!=0 && (flags & DB_PREPARE_IGNORE_ERROR)==0 ){
278278
db_err("%s\n%s", sqlite3_errmsg(g.db), zSql);
279279
}
280280
pStmt->pNext = pStmt->pPrev = 0;
281281
pStmt->nStep = 0;
282282
pStmt->rc = rc;
283283
--- src/db.c
+++ src/db.c
@@ -272,11 +272,11 @@
272 db.nPrepare++;
273 if( flags & DB_PREPARE_PERSISTENT ){
274 prepFlags = SQLITE_PREPARE_PERSISTENT;
275 }
276 rc = sqlite3_prepare_v3(g.db, zSql, -1, prepFlags, &pStmt->pStmt, 0);
277 if( rc!=0 && (flags & DB_PREPARE_IGNORE_ERROR)!=0 ){
278 db_err("%s\n%s", sqlite3_errmsg(g.db), zSql);
279 }
280 pStmt->pNext = pStmt->pPrev = 0;
281 pStmt->nStep = 0;
282 pStmt->rc = rc;
283
--- src/db.c
+++ src/db.c
@@ -272,11 +272,11 @@
272 db.nPrepare++;
273 if( flags & DB_PREPARE_PERSISTENT ){
274 prepFlags = SQLITE_PREPARE_PERSISTENT;
275 }
276 rc = sqlite3_prepare_v3(g.db, zSql, -1, prepFlags, &pStmt->pStmt, 0);
277 if( rc!=0 && (flags & DB_PREPARE_IGNORE_ERROR)==0 ){
278 db_err("%s\n%s", sqlite3_errmsg(g.db), zSql);
279 }
280 pStmt->pNext = pStmt->pPrev = 0;
281 pStmt->nStep = 0;
282 pStmt->rc = rc;
283
--- src/default_css.txt
+++ src/default_css.txt
@@ -631,5 +631,29 @@
631631
table.label-value th {
632632
vertical-align: top;
633633
text-align: right;
634634
padding: 0.2ex 1ex;
635635
}
636
+table.forum_post {
637
+ top-margin: 1ex;
638
+ bottom-margin: 1ex;
639
+ left-margin: 0;
640
+ right-margin: 0;
641
+ border-spacing: 0;
642
+}
643
+span.forum_author {
644
+ color: #888;
645
+}
646
+span.forum_age {
647
+ color: #888;
648
+ font-size: 75%;
649
+}
650
+span.forum_buttons {
651
+ font-size: 75%;
652
+}
653
+span.forum_npost {
654
+ color: #888;
655
+ font-size: 75%;
656
+}
657
+table.forumeditform td {
658
+ vertical-align: top;
659
+}
636660
--- src/default_css.txt
+++ src/default_css.txt
@@ -631,5 +631,29 @@
631 table.label-value th {
632 vertical-align: top;
633 text-align: right;
634 padding: 0.2ex 1ex;
635 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
636
--- src/default_css.txt
+++ src/default_css.txt
@@ -631,5 +631,29 @@
631 table.label-value th {
632 vertical-align: top;
633 text-align: right;
634 padding: 0.2ex 1ex;
635 }
636 table.forum_post {
637 top-margin: 1ex;
638 bottom-margin: 1ex;
639 left-margin: 0;
640 right-margin: 0;
641 border-spacing: 0;
642 }
643 span.forum_author {
644 color: #888;
645 }
646 span.forum_age {
647 color: #888;
648 font-size: 75%;
649 }
650 span.forum_buttons {
651 font-size: 75%;
652 }
653 span.forum_npost {
654 color: #888;
655 font-size: 75%;
656 }
657 table.forumeditform td {
658 vertical-align: top;
659 }
660
+85 -28
--- src/forum.c
+++ src/forum.c
@@ -76,27 +76,32 @@
7676
if( !g.perm.RdForum ){ login_needed(g.anon.RdForum); return; }
7777
forum_verify_schema();
7878
style_header("Forum");
7979
itemId = atoi(PD("item","0"));
8080
if( itemId>0 ){
81
+ int iUp;
82
+ style_submenu_element("Topics", "%R/forum");
83
+ iUp = db_int(0, "SELECT inreplyto FROM forumpost WHERE mpostid=%d", itemId);
84
+ if( iUp ){
85
+ style_submenu_element("Parent", "%R/forum?item=%d", iUp);
86
+ }
8187
double rNow = db_double(0.0, "SELECT julianday('now')");
8288
/* Show the post given by itemId and all its descendents */
8389
db_prepare(&q,
8490
"WITH RECURSIVE"
8591
" post(id,uname,mstat,mime,ipaddr,parent,mbody,depth,mtime) AS ("
8692
" SELECT mpostid, uname, mstatus, mimetype, ipaddr, inreplyto, mbody,"
87
- " 0, 1 FROM forumpost WHERE mpostid=%d"
93
+ " 0, mtime FROM forumpost WHERE mpostid=%d"
8894
" UNION"
8995
" SELECT f.mpostid, f.uname, f.mstatus, f.mimetype, f.ipaddr,"
9096
" f.inreplyto, f.mbody, p.depth+1 AS xdepth, f.mtime AS xtime"
9197
" FROM forumpost AS f, post AS p"
92
- " WHERE forumpost.inreplyto=post.id"
98
+ " WHERE f.inreplyto=p.id"
9399
" ORDER BY xdepth DESC, xtime ASC"
94100
") SELECT * FROM post;",
95101
itemId
96102
);
97
- @ <table border=0 class="forumtable">
98103
while( db_step(&q)==SQLITE_ROW ){
99104
int id = db_column_int(&q, 0);
100105
const char *zUser = db_column_text(&q, 1);
101106
const char *zStat = db_column_text(&q, 2);
102107
const char *zMime = db_column_text(&q, 3);
@@ -104,29 +109,32 @@
104109
int iDepth = db_column_int(&q, 7);
105110
double rMTime = db_column_double(&q, 8);
106111
char *zAge = db_timespan_name(rNow - rMTime);
107112
Blob body;
108113
@ <!-- Forum post %d(id) -->
114
+ @ <table class="forum_post">
109115
@ <tr>
110
- @ <td class="forum_margin" width="%d((iDepth-1)*10)" rowspan="3"></td>
111
- @ <td>%h(zUser) %z(zAge) ago</td>
112
- @ </tr>
113
- @ <tr><td class="forum_body">
114
- blob_init(&body, db_column_text(&q,6), db_column_bytes(&q,6));
115
- wiki_render_by_mimetype(&body, zMime);
116
- blob_reset(&body);
117
- @ </td></tr>
118
- @ <tr><td class="forum_buttons">
116
+ @ <td class="forum_margin" width="%d(iDepth*25)" rowspan="2">
117
+ @ <td><span class="forum_author">%h(zUser)</span>
118
+ @ <span class="forum_age">%s(zAge) ago</span>
119
+ sqlite3_free(zAge);
119120
if( g.perm.WrForum ){
121
+ @ <span class="forum_buttons">
120122
if( g.perm.AdminForum || fossil_strcmp(g.zLogin, zUser)==0 ){
121123
@ <a href='%R/forumedit?item=%d(id)'>Edit</a>
122124
}
123125
@ <a href='%R/forumedit?replyto=%d(id)'>Reply</a>
126
+ @ </span>
124127
}
125
- @ </td></tr>
128
+ @ </tr>
129
+ @ <tr><td><div class="forum_body">
130
+ blob_init(&body, db_column_text(&q,6), db_column_bytes(&q,6));
131
+ wiki_render_by_mimetype(&body, zMime);
132
+ blob_reset(&body);
133
+ @ </div></td></tr>
134
+ @ </table>
126135
}
127
- @ </table>
128136
}else{
129137
/* If we reach this point, that means the users wants a list of
130138
** recent threads.
131139
*/
132140
i = 0;
@@ -138,21 +146,21 @@
138146
" ORDER BY a.mtime DESC LIMIT 40"
139147
);
140148
if( g.perm.WrForum ){
141149
style_submenu_element("New", "%R/forumedit");
142150
}
143
- @ <h1>Recent Forum Threads</h>
144
- while( db_step(&q)==SQLITE_OK ){
151
+ @ <h1>Recent Forum Threads</h1>
152
+ while( db_step(&q)==SQLITE_ROW ){
145153
int n = db_column_int(&q,1);
146154
int itemid = db_column_int(&q,2);
147155
const char *zTitle = db_column_text(&q,0);
148
- if( i==0 ){
156
+ if( (i++)==0 ){
149157
@ <ol>
150158
}
151
- @ <li>
152
- @ %z(href("%R/forum?item=%d",itemid))%h(zTitle)</a><br>
153
- @ %d(n) post%s(n==1?"":"s")</li>
159
+ @ <li><span class="forum_title">
160
+ @ %z(href("%R/forum?item=%d",itemid))%h(zTitle)</a></span>
161
+ @ <span class="forum_npost">%d(n) post%s(n==1?"":"s")</span></li>
154162
}
155163
if( i ){
156164
@ </ol>
157165
}
158166
}
@@ -175,10 +183,11 @@
175183
*/
176184
static int forum_post(int itemId, int parentId, char **pzErr){
177185
const char *zSubject = 0;
178186
int threadId;
179187
double rNow = db_double(0.0, "SELECT julianday('now')");
188
+ const char *zMime = wiki_filter_mimetypes(P("m"));
180189
if( itemId==0 && parentId==0 ){
181190
/* Start a new thread. Subject required. */
182191
sqlite3_uint64 r1, r2;
183192
zSubject = PT("s");
184193
if( zSubject==0 || zSubject[0]==0 ){
@@ -191,12 +200,22 @@
191200
"INSERT INTO forumthread(mthreadhash, mtitle, mtime, npost)"
192201
"VALUES(lower(hex(randomblob(32))),%Q,%!.17g,1)",
193202
zSubject, rNow
194203
);
195204
threadId = db_last_insert_rowid();
205
+ }else{
206
+ threadId = db_int(0, "SELECT mthreadid FROM forumpost"
207
+ " WHERE mpostid=%d", itemId ? itemId : parentId);
196208
}
197209
if( itemId ){
210
+ if( db_int(0, "SELECT inreplyto IS NULL FROM forumpost"
211
+ " WHERE mpostid=%d", itemId) ){
212
+ db_multi_exec(
213
+ "UPDATE forumthread SET mtitle=%Q WHERE mthreadid=%d",
214
+ PT("s"), threadId
215
+ );
216
+ }
198217
db_multi_exec(
199218
"UPDATE forumpost SET"
200219
" mtime=%!.17g,"
201220
" mimetype=%Q,"
202221
" ipaddr=%Q,"
@@ -206,17 +225,17 @@
206225
);
207226
}else{
208227
db_multi_exec(
209228
"INSERT INTO forumpost(mposthash,mthreadid,uname,mtime,"
210229
" mstatus,mimetype,ipaddr,inreplyto,mbody) VALUES"
211
- " (lower(hex(randomblob(32))),%d,%Q,%!.17g,%Q,%Q,%Q,NULL,%Q)",
212
- threadId,g.zLogin,rNow,NULL,P("m"),P("REMOTE_ADDR"),P("b"));
230
+ " (lower(hex(randomblob(32))),%d,%Q,%!.17g,%Q,%Q,%Q,nullif(%d,0),%Q)",
231
+ threadId,g.zLogin,rNow,NULL,zMime,P("REMOTE_ADDR"),parentId,P("b"));
213232
itemId = db_last_insert_rowid();
214233
}
215234
if( zSubject==0 ){
216235
db_multi_exec(
217
- "UPDATE forumthread SET mtime=%!.17g"
236
+ "UPDATE forumthread SET mtime=%!.17g, npost=npost+1"
218237
" WHERE mthreadid=(SELECT mthreadid FROM forumpost WHERE mpostid=%d)",
219238
rNow, itemId
220239
);
221240
}
222241
return itemId;
@@ -233,31 +252,42 @@
233252
** b=BODY Body of the post
234253
** m=MIMETYPE Mimetype for the body of the post
235254
** x Submit changes
236255
** p Preview changes
237256
*/
238
-static void forum_reply_page(void){
257
+void forum_edit_page(void){
239258
int itemId;
240259
int parentId;
241
- const char *zErr = 0;
260
+ char *zErr = 0;
242261
login_check_credentials();
243262
const char *zBody;
244263
const char *zMime;
245264
const char *zSub;
246265
if( !g.perm.WrForum ){ login_needed(g.anon.WrForum); return; }
247266
forum_verify_schema();
248267
itemId = atoi(PD("item","0"));
249268
parentId = atoi(PD("replyto","0"));
269
+ if( P("cancel")!=0 ){
270
+ cgi_redirectf("%R/forum?item=%d", itemId ? itemId : parentId);
271
+ return;
272
+ }
250273
if( P("x")!=0 && cgi_csrf_safe(1) ){
251274
itemId = forum_post(itemId,parentId,&zErr);
252275
if( itemId ){
253276
cgi_redirectf("%R/forum?item=%d",itemId);
254277
return;
255278
}
256279
}
257
- style_header("Edit Forum Post");
258
- @ <form method="POST">
280
+ zMime = wiki_filter_mimetypes(P("m"));
281
+ if( itemId>0 ){
282
+ style_header("Edit Forum Post");
283
+ }else if( parentId>0 ){
284
+ style_header("Comment On Forum Post");
285
+ }else{
286
+ style_header("New Forum Thread");
287
+ }
288
+ @ <form action="%R/forumedit" method="POST">
259289
if( itemId ){
260290
@ <input type="hidden" name="item" value="%d(itemId)">
261291
}
262292
if( parentId ){
263293
@ <input type="hidden" name="replyto" value="%d(parentId)">
@@ -272,14 +302,41 @@
272302
blob_init(&x, PT("b"), -1);
273303
wiki_render_by_mimetype(&x, PT("m"));
274304
blob_reset(&x);
275305
@ </div>
276306
@ </div>
307
+ @ <hr>
277308
}
278309
@ <table border="0" class="forumeditform">
279
- if( itemId==0 && parentId==0 ){
310
+ if( zErr ){
311
+ @ <tr><td colspan="2">
312
+ @ <span class='forumFormErr'>%h(zErr)</span>
313
+ }
314
+ if( (itemId==0 && parentId==0)
315
+ || (itemId && db_int(0, "SELECT inreplyto IS NULL FROM forumpost"
316
+ " WHERE mpostid=%d", itemId))
317
+ ){
280318
zSub = PT("s");
319
+ if( zSub==0 && itemId ){
320
+ zSub = db_text("",
321
+ "SELECT mtitle FROM forumthread"
322
+ " WHERE mthreadid=(SELECT mthreadid FROM forumpost"
323
+ " WHERE mpostid=%d)", itemId);
324
+ }
325
+ @ <tr><td>Subject:</td>
326
+ @ <td><input type='text' class='forumFormSubject' name='s' value='%h(zSub)'>
327
+ }
328
+ @ <tr><td>Markup:</td><td>
329
+ mimetype_option_menu(zMime);
330
+ @ <tr><td>Comment:</td><td>
331
+ @ <textarea name="b" class="wikiedit" cols="80"\
332
+ @ rows="20" wrap="virtual">%h(PD("b",""))</textarea></td>
333
+ @ <tr><td></td><td>
334
+ @ <input type="submit" name="p" value="Preview">
335
+ if( P("p")!=0 ){
336
+ @ <input type="submit" name="x" value="Submit">
281337
}
338
+ @ <input type="submit" name="cancel" value="Cancel">
282339
@ </table>
283340
@ </form>
284341
style_footer();
285342
}
286343
--- src/forum.c
+++ src/forum.c
@@ -76,27 +76,32 @@
76 if( !g.perm.RdForum ){ login_needed(g.anon.RdForum); return; }
77 forum_verify_schema();
78 style_header("Forum");
79 itemId = atoi(PD("item","0"));
80 if( itemId>0 ){
 
 
 
 
 
 
81 double rNow = db_double(0.0, "SELECT julianday('now')");
82 /* Show the post given by itemId and all its descendents */
83 db_prepare(&q,
84 "WITH RECURSIVE"
85 " post(id,uname,mstat,mime,ipaddr,parent,mbody,depth,mtime) AS ("
86 " SELECT mpostid, uname, mstatus, mimetype, ipaddr, inreplyto, mbody,"
87 " 0, 1 FROM forumpost WHERE mpostid=%d"
88 " UNION"
89 " SELECT f.mpostid, f.uname, f.mstatus, f.mimetype, f.ipaddr,"
90 " f.inreplyto, f.mbody, p.depth+1 AS xdepth, f.mtime AS xtime"
91 " FROM forumpost AS f, post AS p"
92 " WHERE forumpost.inreplyto=post.id"
93 " ORDER BY xdepth DESC, xtime ASC"
94 ") SELECT * FROM post;",
95 itemId
96 );
97 @ <table border=0 class="forumtable">
98 while( db_step(&q)==SQLITE_ROW ){
99 int id = db_column_int(&q, 0);
100 const char *zUser = db_column_text(&q, 1);
101 const char *zStat = db_column_text(&q, 2);
102 const char *zMime = db_column_text(&q, 3);
@@ -104,29 +109,32 @@
104 int iDepth = db_column_int(&q, 7);
105 double rMTime = db_column_double(&q, 8);
106 char *zAge = db_timespan_name(rNow - rMTime);
107 Blob body;
108 @ <!-- Forum post %d(id) -->
 
109 @ <tr>
110 @ <td class="forum_margin" width="%d((iDepth-1)*10)" rowspan="3"></td>
111 @ <td>%h(zUser) %z(zAge) ago</td>
112 @ </tr>
113 @ <tr><td class="forum_body">
114 blob_init(&body, db_column_text(&q,6), db_column_bytes(&q,6));
115 wiki_render_by_mimetype(&body, zMime);
116 blob_reset(&body);
117 @ </td></tr>
118 @ <tr><td class="forum_buttons">
119 if( g.perm.WrForum ){
 
120 if( g.perm.AdminForum || fossil_strcmp(g.zLogin, zUser)==0 ){
121 @ <a href='%R/forumedit?item=%d(id)'>Edit</a>
122 }
123 @ <a href='%R/forumedit?replyto=%d(id)'>Reply</a>
 
124 }
125 @ </td></tr>
 
 
 
 
 
 
126 }
127 @ </table>
128 }else{
129 /* If we reach this point, that means the users wants a list of
130 ** recent threads.
131 */
132 i = 0;
@@ -138,21 +146,21 @@
138 " ORDER BY a.mtime DESC LIMIT 40"
139 );
140 if( g.perm.WrForum ){
141 style_submenu_element("New", "%R/forumedit");
142 }
143 @ <h1>Recent Forum Threads</h>
144 while( db_step(&q)==SQLITE_OK ){
145 int n = db_column_int(&q,1);
146 int itemid = db_column_int(&q,2);
147 const char *zTitle = db_column_text(&q,0);
148 if( i==0 ){
149 @ <ol>
150 }
151 @ <li>
152 @ %z(href("%R/forum?item=%d",itemid))%h(zTitle)</a><br>
153 @ %d(n) post%s(n==1?"":"s")</li>
154 }
155 if( i ){
156 @ </ol>
157 }
158 }
@@ -175,10 +183,11 @@
175 */
176 static int forum_post(int itemId, int parentId, char **pzErr){
177 const char *zSubject = 0;
178 int threadId;
179 double rNow = db_double(0.0, "SELECT julianday('now')");
 
180 if( itemId==0 && parentId==0 ){
181 /* Start a new thread. Subject required. */
182 sqlite3_uint64 r1, r2;
183 zSubject = PT("s");
184 if( zSubject==0 || zSubject[0]==0 ){
@@ -191,12 +200,22 @@
191 "INSERT INTO forumthread(mthreadhash, mtitle, mtime, npost)"
192 "VALUES(lower(hex(randomblob(32))),%Q,%!.17g,1)",
193 zSubject, rNow
194 );
195 threadId = db_last_insert_rowid();
 
 
 
196 }
197 if( itemId ){
 
 
 
 
 
 
 
198 db_multi_exec(
199 "UPDATE forumpost SET"
200 " mtime=%!.17g,"
201 " mimetype=%Q,"
202 " ipaddr=%Q,"
@@ -206,17 +225,17 @@
206 );
207 }else{
208 db_multi_exec(
209 "INSERT INTO forumpost(mposthash,mthreadid,uname,mtime,"
210 " mstatus,mimetype,ipaddr,inreplyto,mbody) VALUES"
211 " (lower(hex(randomblob(32))),%d,%Q,%!.17g,%Q,%Q,%Q,NULL,%Q)",
212 threadId,g.zLogin,rNow,NULL,P("m"),P("REMOTE_ADDR"),P("b"));
213 itemId = db_last_insert_rowid();
214 }
215 if( zSubject==0 ){
216 db_multi_exec(
217 "UPDATE forumthread SET mtime=%!.17g"
218 " WHERE mthreadid=(SELECT mthreadid FROM forumpost WHERE mpostid=%d)",
219 rNow, itemId
220 );
221 }
222 return itemId;
@@ -233,31 +252,42 @@
233 ** b=BODY Body of the post
234 ** m=MIMETYPE Mimetype for the body of the post
235 ** x Submit changes
236 ** p Preview changes
237 */
238 static void forum_reply_page(void){
239 int itemId;
240 int parentId;
241 const char *zErr = 0;
242 login_check_credentials();
243 const char *zBody;
244 const char *zMime;
245 const char *zSub;
246 if( !g.perm.WrForum ){ login_needed(g.anon.WrForum); return; }
247 forum_verify_schema();
248 itemId = atoi(PD("item","0"));
249 parentId = atoi(PD("replyto","0"));
 
 
 
 
250 if( P("x")!=0 && cgi_csrf_safe(1) ){
251 itemId = forum_post(itemId,parentId,&zErr);
252 if( itemId ){
253 cgi_redirectf("%R/forum?item=%d",itemId);
254 return;
255 }
256 }
257 style_header("Edit Forum Post");
258 @ <form method="POST">
 
 
 
 
 
 
 
259 if( itemId ){
260 @ <input type="hidden" name="item" value="%d(itemId)">
261 }
262 if( parentId ){
263 @ <input type="hidden" name="replyto" value="%d(parentId)">
@@ -272,14 +302,41 @@
272 blob_init(&x, PT("b"), -1);
273 wiki_render_by_mimetype(&x, PT("m"));
274 blob_reset(&x);
275 @ </div>
276 @ </div>
 
277 }
278 @ <table border="0" class="forumeditform">
279 if( itemId==0 && parentId==0 ){
 
 
 
 
 
 
 
280 zSub = PT("s");
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
281 }
 
282 @ </table>
283 @ </form>
284 style_footer();
285 }
286
--- src/forum.c
+++ src/forum.c
@@ -76,27 +76,32 @@
76 if( !g.perm.RdForum ){ login_needed(g.anon.RdForum); return; }
77 forum_verify_schema();
78 style_header("Forum");
79 itemId = atoi(PD("item","0"));
80 if( itemId>0 ){
81 int iUp;
82 style_submenu_element("Topics", "%R/forum");
83 iUp = db_int(0, "SELECT inreplyto FROM forumpost WHERE mpostid=%d", itemId);
84 if( iUp ){
85 style_submenu_element("Parent", "%R/forum?item=%d", iUp);
86 }
87 double rNow = db_double(0.0, "SELECT julianday('now')");
88 /* Show the post given by itemId and all its descendents */
89 db_prepare(&q,
90 "WITH RECURSIVE"
91 " post(id,uname,mstat,mime,ipaddr,parent,mbody,depth,mtime) AS ("
92 " SELECT mpostid, uname, mstatus, mimetype, ipaddr, inreplyto, mbody,"
93 " 0, mtime FROM forumpost WHERE mpostid=%d"
94 " UNION"
95 " SELECT f.mpostid, f.uname, f.mstatus, f.mimetype, f.ipaddr,"
96 " f.inreplyto, f.mbody, p.depth+1 AS xdepth, f.mtime AS xtime"
97 " FROM forumpost AS f, post AS p"
98 " WHERE f.inreplyto=p.id"
99 " ORDER BY xdepth DESC, xtime ASC"
100 ") SELECT * FROM post;",
101 itemId
102 );
 
103 while( db_step(&q)==SQLITE_ROW ){
104 int id = db_column_int(&q, 0);
105 const char *zUser = db_column_text(&q, 1);
106 const char *zStat = db_column_text(&q, 2);
107 const char *zMime = db_column_text(&q, 3);
@@ -104,29 +109,32 @@
109 int iDepth = db_column_int(&q, 7);
110 double rMTime = db_column_double(&q, 8);
111 char *zAge = db_timespan_name(rNow - rMTime);
112 Blob body;
113 @ <!-- Forum post %d(id) -->
114 @ <table class="forum_post">
115 @ <tr>
116 @ <td class="forum_margin" width="%d(iDepth*25)" rowspan="2">
117 @ <td><span class="forum_author">%h(zUser)</span>
118 @ <span class="forum_age">%s(zAge) ago</span>
119 sqlite3_free(zAge);
 
 
 
 
 
120 if( g.perm.WrForum ){
121 @ <span class="forum_buttons">
122 if( g.perm.AdminForum || fossil_strcmp(g.zLogin, zUser)==0 ){
123 @ <a href='%R/forumedit?item=%d(id)'>Edit</a>
124 }
125 @ <a href='%R/forumedit?replyto=%d(id)'>Reply</a>
126 @ </span>
127 }
128 @ </tr>
129 @ <tr><td><div class="forum_body">
130 blob_init(&body, db_column_text(&q,6), db_column_bytes(&q,6));
131 wiki_render_by_mimetype(&body, zMime);
132 blob_reset(&body);
133 @ </div></td></tr>
134 @ </table>
135 }
 
136 }else{
137 /* If we reach this point, that means the users wants a list of
138 ** recent threads.
139 */
140 i = 0;
@@ -138,21 +146,21 @@
146 " ORDER BY a.mtime DESC LIMIT 40"
147 );
148 if( g.perm.WrForum ){
149 style_submenu_element("New", "%R/forumedit");
150 }
151 @ <h1>Recent Forum Threads</h1>
152 while( db_step(&q)==SQLITE_ROW ){
153 int n = db_column_int(&q,1);
154 int itemid = db_column_int(&q,2);
155 const char *zTitle = db_column_text(&q,0);
156 if( (i++)==0 ){
157 @ <ol>
158 }
159 @ <li><span class="forum_title">
160 @ %z(href("%R/forum?item=%d",itemid))%h(zTitle)</a></span>
161 @ <span class="forum_npost">%d(n) post%s(n==1?"":"s")</span></li>
162 }
163 if( i ){
164 @ </ol>
165 }
166 }
@@ -175,10 +183,11 @@
183 */
184 static int forum_post(int itemId, int parentId, char **pzErr){
185 const char *zSubject = 0;
186 int threadId;
187 double rNow = db_double(0.0, "SELECT julianday('now')");
188 const char *zMime = wiki_filter_mimetypes(P("m"));
189 if( itemId==0 && parentId==0 ){
190 /* Start a new thread. Subject required. */
191 sqlite3_uint64 r1, r2;
192 zSubject = PT("s");
193 if( zSubject==0 || zSubject[0]==0 ){
@@ -191,12 +200,22 @@
200 "INSERT INTO forumthread(mthreadhash, mtitle, mtime, npost)"
201 "VALUES(lower(hex(randomblob(32))),%Q,%!.17g,1)",
202 zSubject, rNow
203 );
204 threadId = db_last_insert_rowid();
205 }else{
206 threadId = db_int(0, "SELECT mthreadid FROM forumpost"
207 " WHERE mpostid=%d", itemId ? itemId : parentId);
208 }
209 if( itemId ){
210 if( db_int(0, "SELECT inreplyto IS NULL FROM forumpost"
211 " WHERE mpostid=%d", itemId) ){
212 db_multi_exec(
213 "UPDATE forumthread SET mtitle=%Q WHERE mthreadid=%d",
214 PT("s"), threadId
215 );
216 }
217 db_multi_exec(
218 "UPDATE forumpost SET"
219 " mtime=%!.17g,"
220 " mimetype=%Q,"
221 " ipaddr=%Q,"
@@ -206,17 +225,17 @@
225 );
226 }else{
227 db_multi_exec(
228 "INSERT INTO forumpost(mposthash,mthreadid,uname,mtime,"
229 " mstatus,mimetype,ipaddr,inreplyto,mbody) VALUES"
230 " (lower(hex(randomblob(32))),%d,%Q,%!.17g,%Q,%Q,%Q,nullif(%d,0),%Q)",
231 threadId,g.zLogin,rNow,NULL,zMime,P("REMOTE_ADDR"),parentId,P("b"));
232 itemId = db_last_insert_rowid();
233 }
234 if( zSubject==0 ){
235 db_multi_exec(
236 "UPDATE forumthread SET mtime=%!.17g, npost=npost+1"
237 " WHERE mthreadid=(SELECT mthreadid FROM forumpost WHERE mpostid=%d)",
238 rNow, itemId
239 );
240 }
241 return itemId;
@@ -233,31 +252,42 @@
252 ** b=BODY Body of the post
253 ** m=MIMETYPE Mimetype for the body of the post
254 ** x Submit changes
255 ** p Preview changes
256 */
257 void forum_edit_page(void){
258 int itemId;
259 int parentId;
260 char *zErr = 0;
261 login_check_credentials();
262 const char *zBody;
263 const char *zMime;
264 const char *zSub;
265 if( !g.perm.WrForum ){ login_needed(g.anon.WrForum); return; }
266 forum_verify_schema();
267 itemId = atoi(PD("item","0"));
268 parentId = atoi(PD("replyto","0"));
269 if( P("cancel")!=0 ){
270 cgi_redirectf("%R/forum?item=%d", itemId ? itemId : parentId);
271 return;
272 }
273 if( P("x")!=0 && cgi_csrf_safe(1) ){
274 itemId = forum_post(itemId,parentId,&zErr);
275 if( itemId ){
276 cgi_redirectf("%R/forum?item=%d",itemId);
277 return;
278 }
279 }
280 zMime = wiki_filter_mimetypes(P("m"));
281 if( itemId>0 ){
282 style_header("Edit Forum Post");
283 }else if( parentId>0 ){
284 style_header("Comment On Forum Post");
285 }else{
286 style_header("New Forum Thread");
287 }
288 @ <form action="%R/forumedit" method="POST">
289 if( itemId ){
290 @ <input type="hidden" name="item" value="%d(itemId)">
291 }
292 if( parentId ){
293 @ <input type="hidden" name="replyto" value="%d(parentId)">
@@ -272,14 +302,41 @@
302 blob_init(&x, PT("b"), -1);
303 wiki_render_by_mimetype(&x, PT("m"));
304 blob_reset(&x);
305 @ </div>
306 @ </div>
307 @ <hr>
308 }
309 @ <table border="0" class="forumeditform">
310 if( zErr ){
311 @ <tr><td colspan="2">
312 @ <span class='forumFormErr'>%h(zErr)</span>
313 }
314 if( (itemId==0 && parentId==0)
315 || (itemId && db_int(0, "SELECT inreplyto IS NULL FROM forumpost"
316 " WHERE mpostid=%d", itemId))
317 ){
318 zSub = PT("s");
319 if( zSub==0 && itemId ){
320 zSub = db_text("",
321 "SELECT mtitle FROM forumthread"
322 " WHERE mthreadid=(SELECT mthreadid FROM forumpost"
323 " WHERE mpostid=%d)", itemId);
324 }
325 @ <tr><td>Subject:</td>
326 @ <td><input type='text' class='forumFormSubject' name='s' value='%h(zSub)'>
327 }
328 @ <tr><td>Markup:</td><td>
329 mimetype_option_menu(zMime);
330 @ <tr><td>Comment:</td><td>
331 @ <textarea name="b" class="wikiedit" cols="80"\
332 @ rows="20" wrap="virtual">%h(PD("b",""))</textarea></td>
333 @ <tr><td></td><td>
334 @ <input type="submit" name="p" value="Preview">
335 if( P("p")!=0 ){
336 @ <input type="submit" name="x" value="Submit">
337 }
338 @ <input type="submit" name="cancel" value="Cancel">
339 @ </table>
340 @ </form>
341 style_footer();
342 }
343
+9 -2
--- src/main.c
+++ src/main.c
@@ -138,11 +138,12 @@
138138
char *zLocalRoot; /* The directory holding the local database */
139139
int minPrefix; /* Number of digits needed for a distinct UUID */
140140
int eHashPolicy; /* Current hash policy. One of HPOLICY_* */
141141
int fSqlTrace; /* True if --sqltrace flag is present */
142142
int fSqlStats; /* True if --sqltrace or --sqlstats are present */
143
- int fSqlPrint; /* True if -sqlprint flag is present */
143
+ int fSqlPrint; /* True if --sqlprint flag is present */
144
+ int fCgiTrace; /* True if --cgitrace is enabled */
144145
int fQuiet; /* True if -quiet flag is present */
145146
int fJail; /* True if running with a chroot jail */
146147
int fHttpTrace; /* Trace outbound HTTP requests */
147148
int fAnyTrace; /* Any kind of tracing */
148149
char *zHttpAuth; /* HTTP Authorization user:pass information */
@@ -649,18 +650,20 @@
649650
g.fQuiet = find_option("quiet", 0, 0)!=0;
650651
g.fSqlTrace = find_option("sqltrace", 0, 0)!=0;
651652
g.fSqlStats = find_option("sqlstats", 0, 0)!=0;
652653
g.fSystemTrace = find_option("systemtrace", 0, 0)!=0;
653654
g.fSshTrace = find_option("sshtrace", 0, 0)!=0;
655
+ g.fCgiTrace = find_option("cgitrace", 0, 0)!=0;
654656
g.fSshClient = 0;
655657
g.zSshCmd = 0;
656658
if( g.fSqlTrace ) g.fSqlStats = 1;
657659
g.fHttpTrace = find_option("httptrace", 0, 0)!=0;
658660
#ifdef FOSSIL_ENABLE_TH1_HOOKS
659661
g.fNoThHook = find_option("no-th-hook", 0, 0)!=0;
660662
#endif
661
- g.fAnyTrace = g.fSqlTrace|g.fSystemTrace|g.fSshTrace|g.fHttpTrace;
663
+ g.fAnyTrace = g.fSqlTrace|g.fSystemTrace|g.fSshTrace|
664
+ g.fHttpTrace|g.fCgiTrace;
662665
g.zHttpAuth = 0;
663666
g.zLogin = find_option("user", "U", 1);
664667
g.zSSLIdentity = find_option("ssl-identity", 0, 1);
665668
g.zErrlog = find_option("errorlog", 0, 1);
666669
fossil_init_flags_from_options();
@@ -1765,10 +1768,14 @@
17651768
@ <h1>Server Configuration Error</h1>
17661769
@ <p>The database schema on the server is out-of-date. Please ask
17671770
@ the administrator to run <b>fossil rebuild</b>.</p>
17681771
}
17691772
}else{
1773
+ if( g.fCgiTrace ){
1774
+ fossil_trace("######## Calling %s #########\n", pCmd->zName);
1775
+ cgi_print_all(1, 1);
1776
+ }
17701777
#ifdef FOSSIL_ENABLE_TH1_HOOKS
17711778
/*
17721779
** The TH1 return codes from the hook will be handled as follows:
17731780
**
17741781
** TH_OK: The xFunc() and the TH1 notification will both be executed.
17751782
--- src/main.c
+++ src/main.c
@@ -138,11 +138,12 @@
138 char *zLocalRoot; /* The directory holding the local database */
139 int minPrefix; /* Number of digits needed for a distinct UUID */
140 int eHashPolicy; /* Current hash policy. One of HPOLICY_* */
141 int fSqlTrace; /* True if --sqltrace flag is present */
142 int fSqlStats; /* True if --sqltrace or --sqlstats are present */
143 int fSqlPrint; /* True if -sqlprint flag is present */
 
144 int fQuiet; /* True if -quiet flag is present */
145 int fJail; /* True if running with a chroot jail */
146 int fHttpTrace; /* Trace outbound HTTP requests */
147 int fAnyTrace; /* Any kind of tracing */
148 char *zHttpAuth; /* HTTP Authorization user:pass information */
@@ -649,18 +650,20 @@
649 g.fQuiet = find_option("quiet", 0, 0)!=0;
650 g.fSqlTrace = find_option("sqltrace", 0, 0)!=0;
651 g.fSqlStats = find_option("sqlstats", 0, 0)!=0;
652 g.fSystemTrace = find_option("systemtrace", 0, 0)!=0;
653 g.fSshTrace = find_option("sshtrace", 0, 0)!=0;
 
654 g.fSshClient = 0;
655 g.zSshCmd = 0;
656 if( g.fSqlTrace ) g.fSqlStats = 1;
657 g.fHttpTrace = find_option("httptrace", 0, 0)!=0;
658 #ifdef FOSSIL_ENABLE_TH1_HOOKS
659 g.fNoThHook = find_option("no-th-hook", 0, 0)!=0;
660 #endif
661 g.fAnyTrace = g.fSqlTrace|g.fSystemTrace|g.fSshTrace|g.fHttpTrace;
 
662 g.zHttpAuth = 0;
663 g.zLogin = find_option("user", "U", 1);
664 g.zSSLIdentity = find_option("ssl-identity", 0, 1);
665 g.zErrlog = find_option("errorlog", 0, 1);
666 fossil_init_flags_from_options();
@@ -1765,10 +1768,14 @@
1765 @ <h1>Server Configuration Error</h1>
1766 @ <p>The database schema on the server is out-of-date. Please ask
1767 @ the administrator to run <b>fossil rebuild</b>.</p>
1768 }
1769 }else{
 
 
 
 
1770 #ifdef FOSSIL_ENABLE_TH1_HOOKS
1771 /*
1772 ** The TH1 return codes from the hook will be handled as follows:
1773 **
1774 ** TH_OK: The xFunc() and the TH1 notification will both be executed.
1775
--- src/main.c
+++ src/main.c
@@ -138,11 +138,12 @@
138 char *zLocalRoot; /* The directory holding the local database */
139 int minPrefix; /* Number of digits needed for a distinct UUID */
140 int eHashPolicy; /* Current hash policy. One of HPOLICY_* */
141 int fSqlTrace; /* True if --sqltrace flag is present */
142 int fSqlStats; /* True if --sqltrace or --sqlstats are present */
143 int fSqlPrint; /* True if --sqlprint flag is present */
144 int fCgiTrace; /* True if --cgitrace is enabled */
145 int fQuiet; /* True if -quiet flag is present */
146 int fJail; /* True if running with a chroot jail */
147 int fHttpTrace; /* Trace outbound HTTP requests */
148 int fAnyTrace; /* Any kind of tracing */
149 char *zHttpAuth; /* HTTP Authorization user:pass information */
@@ -649,18 +650,20 @@
650 g.fQuiet = find_option("quiet", 0, 0)!=0;
651 g.fSqlTrace = find_option("sqltrace", 0, 0)!=0;
652 g.fSqlStats = find_option("sqlstats", 0, 0)!=0;
653 g.fSystemTrace = find_option("systemtrace", 0, 0)!=0;
654 g.fSshTrace = find_option("sshtrace", 0, 0)!=0;
655 g.fCgiTrace = find_option("cgitrace", 0, 0)!=0;
656 g.fSshClient = 0;
657 g.zSshCmd = 0;
658 if( g.fSqlTrace ) g.fSqlStats = 1;
659 g.fHttpTrace = find_option("httptrace", 0, 0)!=0;
660 #ifdef FOSSIL_ENABLE_TH1_HOOKS
661 g.fNoThHook = find_option("no-th-hook", 0, 0)!=0;
662 #endif
663 g.fAnyTrace = g.fSqlTrace|g.fSystemTrace|g.fSshTrace|
664 g.fHttpTrace|g.fCgiTrace;
665 g.zHttpAuth = 0;
666 g.zLogin = find_option("user", "U", 1);
667 g.zSSLIdentity = find_option("ssl-identity", 0, 1);
668 g.zErrlog = find_option("errorlog", 0, 1);
669 fossil_init_flags_from_options();
@@ -1765,10 +1768,14 @@
1768 @ <h1>Server Configuration Error</h1>
1769 @ <p>The database schema on the server is out-of-date. Please ask
1770 @ the administrator to run <b>fossil rebuild</b>.</p>
1771 }
1772 }else{
1773 if( g.fCgiTrace ){
1774 fossil_trace("######## Calling %s #########\n", pCmd->zName);
1775 cgi_print_all(1, 1);
1776 }
1777 #ifdef FOSSIL_ENABLE_TH1_HOOKS
1778 /*
1779 ** The TH1 return codes from the hook will be handled as follows:
1780 **
1781 ** TH_OK: The xFunc() and the TH1 notification will both be executed.
1782
+1 -1
--- src/style.c
+++ src/style.c
@@ -939,11 +939,11 @@
939939
@ g.zRepositoryName = %h(g.zRepositoryName)<br />
940940
@ load_average() = %f(load_average())<br />
941941
@ cgi_csrf_safe(0) = %d(cgi_csrf_safe(0))<br />
942942
@ <hr />
943943
P("HTTP_USER_AGENT");
944
- cgi_print_all(showAll);
944
+ cgi_print_all(showAll, 0);
945945
if( showAll && blob_size(&g.httpHeader)>0 ){
946946
@ <hr />
947947
@ <pre>
948948
@ %h(blob_str(&g.httpHeader))
949949
@ </pre>
950950
--- src/style.c
+++ src/style.c
@@ -939,11 +939,11 @@
939 @ g.zRepositoryName = %h(g.zRepositoryName)<br />
940 @ load_average() = %f(load_average())<br />
941 @ cgi_csrf_safe(0) = %d(cgi_csrf_safe(0))<br />
942 @ <hr />
943 P("HTTP_USER_AGENT");
944 cgi_print_all(showAll);
945 if( showAll && blob_size(&g.httpHeader)>0 ){
946 @ <hr />
947 @ <pre>
948 @ %h(blob_str(&g.httpHeader))
949 @ </pre>
950
--- src/style.c
+++ src/style.c
@@ -939,11 +939,11 @@
939 @ g.zRepositoryName = %h(g.zRepositoryName)<br />
940 @ load_average() = %f(load_average())<br />
941 @ cgi_csrf_safe(0) = %d(cgi_csrf_safe(0))<br />
942 @ <hr />
943 P("HTTP_USER_AGENT");
944 cgi_print_all(showAll, 0);
945 if( showAll && blob_size(&g.httpHeader)>0 ){
946 @ <hr />
947 @ <pre>
948 @ %h(blob_str(&g.httpHeader))
949 @ </pre>
950

Keyboard Shortcuts

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