Fossil SCM

Move the enhanced spider-defense mechanism into the trunk.

drh 2012-04-28 08:05 trunk merge
Commit 433cde1ce8d1d503a9f86a3ac3022ecfaee7bf54
+2 -2
--- src/attach.c
+++ src/attach.c
@@ -75,13 +75,13 @@
7575
zFilename = &zFilename[i+1];
7676
i = -1;
7777
}
7878
}
7979
if( strlen(zTarget)==UUID_SIZE && validate16(zTarget,UUID_SIZE) ){
80
- zUrlTail = mprintf("tkt=%s&file=%t", zTarget, zFilename);
80
+ zUrlTail = mprintf("tkt=%s&file=%t", zTarget, zFilename);
8181
}else{
82
- zUrlTail = mprintf("page=%t&file=%t", zTarget, zFilename);
82
+ zUrlTail = mprintf("page=%t&file=%t", zTarget, zFilename);
8383
}
8484
@
8585
@ <p><a href="/attachview?%s(zUrlTail)">%h(zFilename)</a>
8686
@ [<a href="/attachdownload/%t(zFilename)?%s(zUrlTail)">download</a>]<br />
8787
if( zComment ) while( fossil_isspace(zComment[0]) ) zComment++;
8888
--- src/attach.c
+++ src/attach.c
@@ -75,13 +75,13 @@
75 zFilename = &zFilename[i+1];
76 i = -1;
77 }
78 }
79 if( strlen(zTarget)==UUID_SIZE && validate16(zTarget,UUID_SIZE) ){
80 zUrlTail = mprintf("tkt=%s&amp;file=%t", zTarget, zFilename);
81 }else{
82 zUrlTail = mprintf("page=%t&amp;file=%t", zTarget, zFilename);
83 }
84 @
85 @ <p><a href="/attachview?%s(zUrlTail)">%h(zFilename)</a>
86 @ [<a href="/attachdownload/%t(zFilename)?%s(zUrlTail)">download</a>]<br />
87 if( zComment ) while( fossil_isspace(zComment[0]) ) zComment++;
88
--- src/attach.c
+++ src/attach.c
@@ -75,13 +75,13 @@
75 zFilename = &zFilename[i+1];
76 i = -1;
77 }
78 }
79 if( strlen(zTarget)==UUID_SIZE && validate16(zTarget,UUID_SIZE) ){
80 zUrlTail = mprintf("tkt=%s&file=%t", zTarget, zFilename);
81 }else{
82 zUrlTail = mprintf("page=%t&file=%t", zTarget, zFilename);
83 }
84 @
85 @ <p><a href="/attachview?%s(zUrlTail)">%h(zFilename)</a>
86 @ [<a href="/attachdownload/%t(zFilename)?%s(zUrlTail)">download</a>]<br />
87 if( zComment ) while( fossil_isspace(zComment[0]) ) zComment++;
88
+7 -9
--- src/branch.c
+++ src/branch.c
@@ -321,18 +321,18 @@
321321
style_submenu_element("All", "All", "brlist?all");
322322
}
323323
login_anonymous_available();
324324
style_sidebox_begin("Nomenclature:", "33%");
325325
@ <ol>
326
- @ <li> An <div class="sideboxDescribed"><a href="brlist">
326
+ @ <li> An <div class="sideboxDescribed">%z(href("brlist"))
327327
@ open branch</a></div> is a branch that has one or
328
- @ more <a href="leaves">open leaves.</a>
328
+ @ more %z(href("leaves"))open leaves.</a>
329329
@ The presence of open leaves presumably means
330330
@ that the branch is still being extended with new check-ins.</li>
331
- @ <li> A <div class="sideboxDescribed"><a href="brlist?closed">
331
+ @ <li> A <div class="sideboxDescribed">%z(href("brlist?closed"))
332332
@ closed branch</a></div> is a branch with only
333
- @ <div class="sideboxDescribed"><a href="leaves?closed">
333
+ @ <div class="sideboxDescribed">%z(href("leaves?closed"))
334334
@ closed leaves</a></div>.
335335
@ Closed branches are fixed and do not change (unless they are first
336336
@ reopened)</li>
337337
@ </ol>
338338
style_sidebox_end();
@@ -356,14 +356,12 @@
356356
}
357357
if( colorTest ){
358358
const char *zColor = hash_color(zBr);
359359
@ <li><span style="background-color: %s(zColor)">
360360
@ %h(zBr) &rarr; %s(zColor)</span></li>
361
- }else if( g.perm.History ){
362
- @ <li><a href="%s(g.zTop)/timeline?r=%T(zBr)")>%h(zBr)</a></li>
363361
}else{
364
- @ <li><b>%h(zBr)</b></li>
362
+ @ <li>%z(href("%R/timeline?r=%T",zBr))%h(zBr)</a></li>
365363
}
366364
}
367365
if( cnt ){
368366
@ </ul>
369367
}
@@ -382,11 +380,11 @@
382380
** the timeline of a "brlist" page. Add some additional hyperlinks
383381
** to the end of the line.
384382
*/
385383
static void brtimeline_extra(int rid){
386384
Stmt q;
387
- if( !g.perm.History ) return;
385
+ if( !g.perm.Hyperlink ) return;
388386
db_prepare(&q,
389387
"SELECT substr(tagname,5) FROM tagxref, tag"
390388
" WHERE tagxref.rid=%d"
391389
" AND tagxref.tagid=tag.tagid"
392390
" AND tagxref.tagtype>0"
@@ -393,11 +391,11 @@
393391
" AND tag.tagname GLOB 'sym-*'",
394392
rid
395393
);
396394
while( db_step(&q)==SQLITE_ROW ){
397395
const char *zTagName = db_column_text(&q, 0);
398
- @ <a href="%s(g.zTop)/timeline?r=%T(zTagName)">[timeline]</a>
396
+ @ %z(href("%R/timeline?r=%T",zTagName))[timeline]</a>
399397
}
400398
db_finalize(&q);
401399
}
402400
403401
/*
404402
--- src/branch.c
+++ src/branch.c
@@ -321,18 +321,18 @@
321 style_submenu_element("All", "All", "brlist?all");
322 }
323 login_anonymous_available();
324 style_sidebox_begin("Nomenclature:", "33%");
325 @ <ol>
326 @ <li> An <div class="sideboxDescribed"><a href="brlist">
327 @ open branch</a></div> is a branch that has one or
328 @ more <a href="leaves">open leaves.</a>
329 @ The presence of open leaves presumably means
330 @ that the branch is still being extended with new check-ins.</li>
331 @ <li> A <div class="sideboxDescribed"><a href="brlist?closed">
332 @ closed branch</a></div> is a branch with only
333 @ <div class="sideboxDescribed"><a href="leaves?closed">
334 @ closed leaves</a></div>.
335 @ Closed branches are fixed and do not change (unless they are first
336 @ reopened)</li>
337 @ </ol>
338 style_sidebox_end();
@@ -356,14 +356,12 @@
356 }
357 if( colorTest ){
358 const char *zColor = hash_color(zBr);
359 @ <li><span style="background-color: %s(zColor)">
360 @ %h(zBr) &rarr; %s(zColor)</span></li>
361 }else if( g.perm.History ){
362 @ <li><a href="%s(g.zTop)/timeline?r=%T(zBr)")>%h(zBr)</a></li>
363 }else{
364 @ <li><b>%h(zBr)</b></li>
365 }
366 }
367 if( cnt ){
368 @ </ul>
369 }
@@ -382,11 +380,11 @@
382 ** the timeline of a "brlist" page. Add some additional hyperlinks
383 ** to the end of the line.
384 */
385 static void brtimeline_extra(int rid){
386 Stmt q;
387 if( !g.perm.History ) return;
388 db_prepare(&q,
389 "SELECT substr(tagname,5) FROM tagxref, tag"
390 " WHERE tagxref.rid=%d"
391 " AND tagxref.tagid=tag.tagid"
392 " AND tagxref.tagtype>0"
@@ -393,11 +391,11 @@
393 " AND tag.tagname GLOB 'sym-*'",
394 rid
395 );
396 while( db_step(&q)==SQLITE_ROW ){
397 const char *zTagName = db_column_text(&q, 0);
398 @ <a href="%s(g.zTop)/timeline?r=%T(zTagName)">[timeline]</a>
399 }
400 db_finalize(&q);
401 }
402
403 /*
404
--- src/branch.c
+++ src/branch.c
@@ -321,18 +321,18 @@
321 style_submenu_element("All", "All", "brlist?all");
322 }
323 login_anonymous_available();
324 style_sidebox_begin("Nomenclature:", "33%");
325 @ <ol>
326 @ <li> An <div class="sideboxDescribed">%z(href("brlist"))
327 @ open branch</a></div> is a branch that has one or
328 @ more %z(href("leaves"))open leaves.</a>
329 @ The presence of open leaves presumably means
330 @ that the branch is still being extended with new check-ins.</li>
331 @ <li> A <div class="sideboxDescribed">%z(href("brlist?closed"))
332 @ closed branch</a></div> is a branch with only
333 @ <div class="sideboxDescribed">%z(href("leaves?closed"))
334 @ closed leaves</a></div>.
335 @ Closed branches are fixed and do not change (unless they are first
336 @ reopened)</li>
337 @ </ol>
338 style_sidebox_end();
@@ -356,14 +356,12 @@
356 }
357 if( colorTest ){
358 const char *zColor = hash_color(zBr);
359 @ <li><span style="background-color: %s(zColor)">
360 @ %h(zBr) &rarr; %s(zColor)</span></li>
 
 
361 }else{
362 @ <li>%z(href("%R/timeline?r=%T",zBr))%h(zBr)</a></li>
363 }
364 }
365 if( cnt ){
366 @ </ul>
367 }
@@ -382,11 +380,11 @@
380 ** the timeline of a "brlist" page. Add some additional hyperlinks
381 ** to the end of the line.
382 */
383 static void brtimeline_extra(int rid){
384 Stmt q;
385 if( !g.perm.Hyperlink ) return;
386 db_prepare(&q,
387 "SELECT substr(tagname,5) FROM tagxref, tag"
388 " WHERE tagxref.rid=%d"
389 " AND tagxref.tagid=tag.tagid"
390 " AND tagxref.tagtype>0"
@@ -393,11 +391,11 @@
391 " AND tag.tagname GLOB 'sym-*'",
392 rid
393 );
394 while( db_step(&q)==SQLITE_ROW ){
395 const char *zTagName = db_column_text(&q, 0);
396 @ %z(href("%R/timeline?r=%T",zTagName))[timeline]</a>
397 }
398 db_finalize(&q);
399 }
400
401 /*
402
+23 -22
--- src/browse.c
+++ src/browse.c
@@ -77,17 +77,19 @@
7777
int i, j;
7878
char *zSep = "";
7979
8080
for(i=0; zPath[i]; i=j){
8181
for(j=i; zPath[j] && zPath[j]!='/'; j++){}
82
- if( zPath[j] && g.perm.History ){
82
+ if( zPath[j] && g.perm.Hyperlink ){
8383
if( zCI ){
84
- blob_appendf(pOut, "%s<a href=\"%s/dir?ci=%S&amp;name=%#T\">%#h</a>",
85
- zSep, g.zTop, zCI, j, zPath, j-i, &zPath[i]);
84
+ char *zLink = href("%R/dir?ci=%S&name=%#T", zCI, j, zPath);
85
+ blob_appendf(pOut, "%s%z%#h</a>",
86
+ zSep, zLink, j-i, &zPath[i]);
8687
}else{
87
- blob_appendf(pOut, "%s<a href=\"%s/dir?name=%#T\">%#h</a>",
88
- zSep, g.zTop, j, zPath, j-i, &zPath[i]);
88
+ char *zLink = href("%R/dir?name=%#T", j, zPath);
89
+ blob_appendf(pOut, "%s%z%#h</a>",
90
+ zSep, zLink, j-i, &zPath[i]);
8991
}
9092
}else{
9193
blob_appendf(pOut, "%s%#h", zSep, j-i, &zPath[i]);
9294
}
9395
zSep = "/";
@@ -118,11 +120,11 @@
118120
Blob dirname;
119121
Manifest *pM = 0;
120122
const char *zSubdirLink;
121123
122124
login_check_credentials();
123
- if( !g.perm.History ){ login_needed(); return; }
125
+ if( !g.perm.Hyperlink ){ login_needed(); return; }
124126
while( nD>1 && zD[nD-2]=='/' ){ zD[(--nD)-1] = 0; }
125127
style_header("File List");
126128
sqlite3_create_function(g.db, "pathelement", 2, SQLITE_UTF8, 0,
127129
pathelementFunc, 0, 0);
128130
@@ -155,39 +157,38 @@
155157
}
156158
if( zCI ){
157159
char zShort[20];
158160
memcpy(zShort, zUuid, 10);
159161
zShort[10] = 0;
160
- @ <h2>Files of check-in [<a href="vinfo?name=%T(zUuid)">%s(zShort)</a>]
162
+ @ <h2>Files of check-in [%z(href("vinfo?name=%T",zUuid))%s(zShort)</a>]
161163
@ %s(blob_str(&dirname))</h2>
162
- zSubdirLink = mprintf("%s/dir?ci=%S&amp;name=%T", g.zTop, zUuid, zPrefix);
164
+ zSubdirLink = mprintf("%R/dir?ci=%S&name=%T", zUuid, zPrefix);
163165
if( zD ){
164
- style_submenu_element("Top", "Top", "%s/dir?ci=%S", g.zTop, zUuid);
165
- style_submenu_element("All", "All", "%s/dir?name=%t", g.zTop, zD);
166
+ style_submenu_element("Top", "Top", "%R/dir?ci=%S", zUuid);
167
+ style_submenu_element("All", "All", "%R/dir?name=%t", zD);
166168
}else{
167
- style_submenu_element("All", "All", "%s/dir", g.zTop);
169
+ style_submenu_element("All", "All", "%R/dir");
168170
}
169171
}else{
170172
int hasTrunk;
171173
@ <h2>The union of all files from all check-ins
172174
@ %s(blob_str(&dirname))</h2>
173175
hasTrunk = db_exists(
174176
"SELECT 1 FROM tagxref WHERE tagid=%d AND value='trunk'",
175177
TAG_BRANCH);
176
- zSubdirLink = mprintf("%s/dir?name=%T", g.zTop, zPrefix);
178
+ zSubdirLink = mprintf("%R/dir?name=%T", zPrefix);
177179
if( zD ){
178
- style_submenu_element("Top", "Top", "%s/dir", g.zTop);
179
- style_submenu_element("Tip", "Tip", "%s/dir?name=%t&amp;ci=tip",
180
- g.zTop, zD);
180
+ style_submenu_element("Top", "Top", "%R/dir");
181
+ style_submenu_element("Tip", "Tip", "%R/dir?name=%t&ci=tip", zD);
181182
if( hasTrunk ){
182
- style_submenu_element("Trunk", "Trunk", "%s/dir?name=%t&amp;ci=trunk",
183
- g.zTop,zD);
183
+ style_submenu_element("Trunk", "Trunk", "%R/dir?name=%t&ci=trunk",
184
+ zD);
184185
}
185186
}else{
186
- style_submenu_element("Tip", "Tip", "%s/dir?ci=tip", g.zTop);
187
+ style_submenu_element("Tip", "Tip", "%R/dir?ci=tip");
187188
if( hasTrunk ){
188
- style_submenu_element("Trunk", "Trunk", "%s/dir?ci=trunk", g.zTop);
189
+ style_submenu_element("Trunk", "Trunk", "%R/dir?ci=trunk");
189190
}
190191
}
191192
}
192193
193194
/* Compute the temporary table "localfiles" containing the names
@@ -278,19 +279,19 @@
278279
}
279280
i++;
280281
zFN = db_column_text(&q, 0);
281282
if( zFN[0]=='/' ){
282283
zFN++;
283
- @ <li><a href="%s(zSubdirLink)%T(zFN)">%h(zFN)/</a></li>
284
+ @ <li>%z(href("%s%T",zSubdirLink,zFN))%h(zFN)</a></li>
284285
}else if( zCI ){
285286
const char *zUuid = db_column_text(&q, 1);
286
- @ <li><a href="%s(g.zTop)/artifact/%s(zUuid)">%h(zFN)</a></li>
287
+ @ <li>%z(href("%R/artifact/%s",zUuid))%h(zFN)</a></li>
287288
}else{
288
- @ <li><a href="%s(g.zTop)/finfo?name=%T(zPrefix)%T(zFN)">%h(zFN)
289
+ @ <li>%z(href("%R/finfo?name=%T%T",zPrefix,zFN))%h(zFN)
289290
@ </a></li>
290291
}
291292
}
292293
db_finalize(&q);
293294
manifest_destroy(pM);
294295
@ </ul></td></tr></table>
295296
style_footer();
296297
}
297298
--- src/browse.c
+++ src/browse.c
@@ -77,17 +77,19 @@
77 int i, j;
78 char *zSep = "";
79
80 for(i=0; zPath[i]; i=j){
81 for(j=i; zPath[j] && zPath[j]!='/'; j++){}
82 if( zPath[j] && g.perm.History ){
83 if( zCI ){
84 blob_appendf(pOut, "%s<a href=\"%s/dir?ci=%S&amp;name=%#T\">%#h</a>",
85 zSep, g.zTop, zCI, j, zPath, j-i, &zPath[i]);
 
86 }else{
87 blob_appendf(pOut, "%s<a href=\"%s/dir?name=%#T\">%#h</a>",
88 zSep, g.zTop, j, zPath, j-i, &zPath[i]);
 
89 }
90 }else{
91 blob_appendf(pOut, "%s%#h", zSep, j-i, &zPath[i]);
92 }
93 zSep = "/";
@@ -118,11 +120,11 @@
118 Blob dirname;
119 Manifest *pM = 0;
120 const char *zSubdirLink;
121
122 login_check_credentials();
123 if( !g.perm.History ){ login_needed(); return; }
124 while( nD>1 && zD[nD-2]=='/' ){ zD[(--nD)-1] = 0; }
125 style_header("File List");
126 sqlite3_create_function(g.db, "pathelement", 2, SQLITE_UTF8, 0,
127 pathelementFunc, 0, 0);
128
@@ -155,39 +157,38 @@
155 }
156 if( zCI ){
157 char zShort[20];
158 memcpy(zShort, zUuid, 10);
159 zShort[10] = 0;
160 @ <h2>Files of check-in [<a href="vinfo?name=%T(zUuid)">%s(zShort)</a>]
161 @ %s(blob_str(&dirname))</h2>
162 zSubdirLink = mprintf("%s/dir?ci=%S&amp;name=%T", g.zTop, zUuid, zPrefix);
163 if( zD ){
164 style_submenu_element("Top", "Top", "%s/dir?ci=%S", g.zTop, zUuid);
165 style_submenu_element("All", "All", "%s/dir?name=%t", g.zTop, zD);
166 }else{
167 style_submenu_element("All", "All", "%s/dir", g.zTop);
168 }
169 }else{
170 int hasTrunk;
171 @ <h2>The union of all files from all check-ins
172 @ %s(blob_str(&dirname))</h2>
173 hasTrunk = db_exists(
174 "SELECT 1 FROM tagxref WHERE tagid=%d AND value='trunk'",
175 TAG_BRANCH);
176 zSubdirLink = mprintf("%s/dir?name=%T", g.zTop, zPrefix);
177 if( zD ){
178 style_submenu_element("Top", "Top", "%s/dir", g.zTop);
179 style_submenu_element("Tip", "Tip", "%s/dir?name=%t&amp;ci=tip",
180 g.zTop, zD);
181 if( hasTrunk ){
182 style_submenu_element("Trunk", "Trunk", "%s/dir?name=%t&amp;ci=trunk",
183 g.zTop,zD);
184 }
185 }else{
186 style_submenu_element("Tip", "Tip", "%s/dir?ci=tip", g.zTop);
187 if( hasTrunk ){
188 style_submenu_element("Trunk", "Trunk", "%s/dir?ci=trunk", g.zTop);
189 }
190 }
191 }
192
193 /* Compute the temporary table "localfiles" containing the names
@@ -278,19 +279,19 @@
278 }
279 i++;
280 zFN = db_column_text(&q, 0);
281 if( zFN[0]=='/' ){
282 zFN++;
283 @ <li><a href="%s(zSubdirLink)%T(zFN)">%h(zFN)/</a></li>
284 }else if( zCI ){
285 const char *zUuid = db_column_text(&q, 1);
286 @ <li><a href="%s(g.zTop)/artifact/%s(zUuid)">%h(zFN)</a></li>
287 }else{
288 @ <li><a href="%s(g.zTop)/finfo?name=%T(zPrefix)%T(zFN)">%h(zFN)
289 @ </a></li>
290 }
291 }
292 db_finalize(&q);
293 manifest_destroy(pM);
294 @ </ul></td></tr></table>
295 style_footer();
296 }
297
--- src/browse.c
+++ src/browse.c
@@ -77,17 +77,19 @@
77 int i, j;
78 char *zSep = "";
79
80 for(i=0; zPath[i]; i=j){
81 for(j=i; zPath[j] && zPath[j]!='/'; j++){}
82 if( zPath[j] && g.perm.Hyperlink ){
83 if( zCI ){
84 char *zLink = href("%R/dir?ci=%S&name=%#T", zCI, j, zPath);
85 blob_appendf(pOut, "%s%z%#h</a>",
86 zSep, zLink, j-i, &zPath[i]);
87 }else{
88 char *zLink = href("%R/dir?name=%#T", j, zPath);
89 blob_appendf(pOut, "%s%z%#h</a>",
90 zSep, zLink, j-i, &zPath[i]);
91 }
92 }else{
93 blob_appendf(pOut, "%s%#h", zSep, j-i, &zPath[i]);
94 }
95 zSep = "/";
@@ -118,11 +120,11 @@
120 Blob dirname;
121 Manifest *pM = 0;
122 const char *zSubdirLink;
123
124 login_check_credentials();
125 if( !g.perm.Hyperlink ){ login_needed(); return; }
126 while( nD>1 && zD[nD-2]=='/' ){ zD[(--nD)-1] = 0; }
127 style_header("File List");
128 sqlite3_create_function(g.db, "pathelement", 2, SQLITE_UTF8, 0,
129 pathelementFunc, 0, 0);
130
@@ -155,39 +157,38 @@
157 }
158 if( zCI ){
159 char zShort[20];
160 memcpy(zShort, zUuid, 10);
161 zShort[10] = 0;
162 @ <h2>Files of check-in [%z(href("vinfo?name=%T",zUuid))%s(zShort)</a>]
163 @ %s(blob_str(&dirname))</h2>
164 zSubdirLink = mprintf("%R/dir?ci=%S&name=%T", zUuid, zPrefix);
165 if( zD ){
166 style_submenu_element("Top", "Top", "%R/dir?ci=%S", zUuid);
167 style_submenu_element("All", "All", "%R/dir?name=%t", zD);
168 }else{
169 style_submenu_element("All", "All", "%R/dir");
170 }
171 }else{
172 int hasTrunk;
173 @ <h2>The union of all files from all check-ins
174 @ %s(blob_str(&dirname))</h2>
175 hasTrunk = db_exists(
176 "SELECT 1 FROM tagxref WHERE tagid=%d AND value='trunk'",
177 TAG_BRANCH);
178 zSubdirLink = mprintf("%R/dir?name=%T", zPrefix);
179 if( zD ){
180 style_submenu_element("Top", "Top", "%R/dir");
181 style_submenu_element("Tip", "Tip", "%R/dir?name=%t&ci=tip", zD);
 
182 if( hasTrunk ){
183 style_submenu_element("Trunk", "Trunk", "%R/dir?name=%t&ci=trunk",
184 zD);
185 }
186 }else{
187 style_submenu_element("Tip", "Tip", "%R/dir?ci=tip");
188 if( hasTrunk ){
189 style_submenu_element("Trunk", "Trunk", "%R/dir?ci=trunk");
190 }
191 }
192 }
193
194 /* Compute the temporary table "localfiles" containing the names
@@ -278,19 +279,19 @@
279 }
280 i++;
281 zFN = db_column_text(&q, 0);
282 if( zFN[0]=='/' ){
283 zFN++;
284 @ <li>%z(href("%s%T",zSubdirLink,zFN))%h(zFN)</a></li>
285 }else if( zCI ){
286 const char *zUuid = db_column_text(&q, 1);
287 @ <li>%z(href("%R/artifact/%s",zUuid))%h(zFN)</a></li>
288 }else{
289 @ <li>%z(href("%R/finfo?name=%T%T",zPrefix,zFN))%h(zFN)
290 @ </a></li>
291 }
292 }
293 db_finalize(&q);
294 manifest_destroy(pM);
295 @ </ul></td></tr></table>
296 style_footer();
297 }
298
+3 -3
--- src/diff.c
+++ src/diff.c
@@ -1778,12 +1778,12 @@
17781778
const char *zUuid = db_column_text(&q, 1);
17791779
const char *zDate = db_column_text(&q, 2);
17801780
const char *zUser = db_column_text(&q, 3);
17811781
if( webLabel ){
17821782
zLabel = mprintf(
1783
- "<a href='%s/info/%s' target='infowindow'>%.10s</a> %s %13.13s",
1784
- g.zTop, zUuid, zUuid, zDate, zUser
1783
+ "<a href='%R/info/%s' target='infowindow'>%.10s</a> %s %13.13s",
1784
+ zUuid, zUuid, zDate, zUser
17851785
);
17861786
}else{
17871787
zLabel = mprintf("%.10s %s %13.13s", zUuid, zDate, zUser);
17881788
}
17891789
p->nVers++;
@@ -1821,11 +1821,11 @@
18211821
if( !db_exists("SELECT 1 FROM mlink WHERE mid=%d AND fnid=%d",mid,fnid) ){
18221822
fossil_redirect_home();
18231823
}
18241824
style_header("File Annotation");
18251825
if( P("filevers") ) annFlags |= ANN_FILE_VERS;
1826
- annotate_file(&ann, fnid, mid, g.perm.History, iLimit, annFlags);
1826
+ annotate_file(&ann, fnid, mid, g.perm.Hyperlink, iLimit, annFlags);
18271827
if( P("log") ){
18281828
int i;
18291829
@ <h2>Versions analyzed:</h2>
18301830
@ <ol>
18311831
for(i=0; i<ann.nVers; i++){
18321832
--- src/diff.c
+++ src/diff.c
@@ -1778,12 +1778,12 @@
1778 const char *zUuid = db_column_text(&q, 1);
1779 const char *zDate = db_column_text(&q, 2);
1780 const char *zUser = db_column_text(&q, 3);
1781 if( webLabel ){
1782 zLabel = mprintf(
1783 "<a href='%s/info/%s' target='infowindow'>%.10s</a> %s %13.13s",
1784 g.zTop, zUuid, zUuid, zDate, zUser
1785 );
1786 }else{
1787 zLabel = mprintf("%.10s %s %13.13s", zUuid, zDate, zUser);
1788 }
1789 p->nVers++;
@@ -1821,11 +1821,11 @@
1821 if( !db_exists("SELECT 1 FROM mlink WHERE mid=%d AND fnid=%d",mid,fnid) ){
1822 fossil_redirect_home();
1823 }
1824 style_header("File Annotation");
1825 if( P("filevers") ) annFlags |= ANN_FILE_VERS;
1826 annotate_file(&ann, fnid, mid, g.perm.History, iLimit, annFlags);
1827 if( P("log") ){
1828 int i;
1829 @ <h2>Versions analyzed:</h2>
1830 @ <ol>
1831 for(i=0; i<ann.nVers; i++){
1832
--- src/diff.c
+++ src/diff.c
@@ -1778,12 +1778,12 @@
1778 const char *zUuid = db_column_text(&q, 1);
1779 const char *zDate = db_column_text(&q, 2);
1780 const char *zUser = db_column_text(&q, 3);
1781 if( webLabel ){
1782 zLabel = mprintf(
1783 "<a href='%R/info/%s' target='infowindow'>%.10s</a> %s %13.13s",
1784 zUuid, zUuid, zDate, zUser
1785 );
1786 }else{
1787 zLabel = mprintf("%.10s %s %13.13s", zUuid, zDate, zUser);
1788 }
1789 p->nVers++;
@@ -1821,11 +1821,11 @@
1821 if( !db_exists("SELECT 1 FROM mlink WHERE mid=%d AND fnid=%d",mid,fnid) ){
1822 fossil_redirect_home();
1823 }
1824 style_header("File Annotation");
1825 if( P("filevers") ) annFlags |= ANN_FILE_VERS;
1826 annotate_file(&ann, fnid, mid, g.perm.Hyperlink, iLimit, annFlags);
1827 if( P("log") ){
1828 int i;
1829 @ <h2>Versions analyzed:</h2>
1830 @ <ol>
1831 for(i=0; i<ann.nVers; i++){
1832
+1 -1
--- src/diffcmd.c
+++ src/diffcmd.c
@@ -541,11 +541,11 @@
541541
}
542542
}
543543
544544
/*
545545
** WEBPAGE: vpatch
546
-** URL vpatch?from=UUID&amp;to=UUID
546
+** URL vpatch?from=UUID&to=UUID
547547
*/
548548
void vpatch_page(void){
549549
const char *zFrom = P("from");
550550
const char *zTo = P("to");
551551
login_check_credentials();
552552
--- src/diffcmd.c
+++ src/diffcmd.c
@@ -541,11 +541,11 @@
541 }
542 }
543
544 /*
545 ** WEBPAGE: vpatch
546 ** URL vpatch?from=UUID&amp;to=UUID
547 */
548 void vpatch_page(void){
549 const char *zFrom = P("from");
550 const char *zTo = P("to");
551 login_check_credentials();
552
--- src/diffcmd.c
+++ src/diffcmd.c
@@ -541,11 +541,11 @@
541 }
542 }
543
544 /*
545 ** WEBPAGE: vpatch
546 ** URL vpatch?from=UUID&to=UUID
547 */
548 void vpatch_page(void){
549 const char *zFrom = P("from");
550 const char *zTo = P("to");
551 login_check_credentials();
552
+10 -17
--- src/event.c
+++ src/event.c
@@ -31,20 +31,13 @@
3131
/*
3232
** Output a hyperlink to an event given its tagid.
3333
*/
3434
void hyperlink_to_event_tagid(int tagid){
3535
char *zEventId;
36
- char zShort[12];
37
-
3836
zEventId = db_text(0, "SELECT substr(tagname, 7) FROM tag WHERE tagid=%d",
3937
tagid);
40
- sqlite3_snprintf(sizeof(zShort), zShort, "%.10s", zEventId);
41
- if( g.perm.History ){
42
- @ [<a href="%s(g.zTop)/event?name=%s(zEventId)">%s(zShort)</a>]
43
- }else{
44
- @ [%s(zShort)]
45
- }
38
+ @ [%z(href("%R/event/%s",zEventId))%S(zEventId)</a>]
4639
free(zEventId);
4740
}
4841
4942
/*
5043
** WEBPAGE: event
@@ -130,47 +123,47 @@
130123
g.zTop, zEventId);
131124
}
132125
zETime = db_text(0, "SELECT datetime(%.17g)", pEvent->rEventDate);
133126
style_submenu_element("Context", "Context", "%s/timeline?c=%T",
134127
g.zTop, zETime);
135
- if( g.perm.History ){
128
+ if( g.perm.Hyperlink ){
136129
if( showDetail ){
137
- style_submenu_element("Plain", "Plain", "%s/event?name=%s&amp;aid=%s",
130
+ style_submenu_element("Plain", "Plain", "%s/event?name=%s&aid=%s",
138131
g.zTop, zEventId, zUuid);
139132
if( nextRid ){
140133
char *zNext;
141134
zNext = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", nextRid);
142135
style_submenu_element("Next", "Next",
143
- "%s/event?name=%s&amp;aid=%s&amp;detail=1",
136
+ "%s/event?name=%s&aid=%s&detail=1",
144137
g.zTop, zEventId, zNext);
145138
free(zNext);
146139
}
147140
if( prevRid ){
148141
char *zPrev;
149142
zPrev = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", prevRid);
150143
style_submenu_element("Prev", "Prev",
151
- "%s/event?name=%s&amp;aid=%s&amp;detail=1",
144
+ "%s/event?name=%s&aid=%s&detail=1",
152145
g.zTop, zEventId, zPrev);
153146
free(zPrev);
154147
}
155148
}else{
156149
style_submenu_element("Detail", "Detail",
157
- "%s/event?name=%s&amp;aid=%s&amp;detail=1",
150
+ "%s/event?name=%s&aid=%s&detail=1",
158151
g.zTop, zEventId, zUuid);
159152
}
160153
}
161154
162
- if( showDetail && g.perm.History ){
155
+ if( showDetail && g.perm.Hyperlink ){
163156
int i;
164157
const char *zClr = 0;
165158
Blob comment;
166159
167160
zATime = db_text(0, "SELECT datetime(%.17g)", pEvent->rDate);
168
- @ <p>Event [<a href="%s(g.zTop)/artifact/%s(zUuid)">%S(zUuid)</a>] at
169
- @ [<a href="%s(g.zTop)/timeline?c=%T(zETime)">%s(zETime)</a>]
161
+ @ <p>Event [%z(href("%R/artifact/%s",zUuid))%S(zUuid)</a>] at
162
+ @ [%z(href("%R/timeline?c=%T",zETime))%s(zETime)</a>]
170163
@ entered by user <b>%h(pEvent->zUser)</b> on
171
- @ [<a href="%s(g.zTop)/timeline?c=%T(zATime)">%s(zATime)</a>]:</p>
164
+ @ [%z(href("%R/timeline?c=%T",zATime))%s(zATime)</a>]:</p>
172165
@ <blockquote>
173166
for(i=0; i<pEvent->nTag; i++){
174167
if( fossil_strcmp(pEvent->aTag[i].zName,"+bgcolor")==0 ){
175168
zClr = pEvent->aTag[i].zValue;
176169
}
177170
--- src/event.c
+++ src/event.c
@@ -31,20 +31,13 @@
31 /*
32 ** Output a hyperlink to an event given its tagid.
33 */
34 void hyperlink_to_event_tagid(int tagid){
35 char *zEventId;
36 char zShort[12];
37
38 zEventId = db_text(0, "SELECT substr(tagname, 7) FROM tag WHERE tagid=%d",
39 tagid);
40 sqlite3_snprintf(sizeof(zShort), zShort, "%.10s", zEventId);
41 if( g.perm.History ){
42 @ [<a href="%s(g.zTop)/event?name=%s(zEventId)">%s(zShort)</a>]
43 }else{
44 @ [%s(zShort)]
45 }
46 free(zEventId);
47 }
48
49 /*
50 ** WEBPAGE: event
@@ -130,47 +123,47 @@
130 g.zTop, zEventId);
131 }
132 zETime = db_text(0, "SELECT datetime(%.17g)", pEvent->rEventDate);
133 style_submenu_element("Context", "Context", "%s/timeline?c=%T",
134 g.zTop, zETime);
135 if( g.perm.History ){
136 if( showDetail ){
137 style_submenu_element("Plain", "Plain", "%s/event?name=%s&amp;aid=%s",
138 g.zTop, zEventId, zUuid);
139 if( nextRid ){
140 char *zNext;
141 zNext = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", nextRid);
142 style_submenu_element("Next", "Next",
143 "%s/event?name=%s&amp;aid=%s&amp;detail=1",
144 g.zTop, zEventId, zNext);
145 free(zNext);
146 }
147 if( prevRid ){
148 char *zPrev;
149 zPrev = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", prevRid);
150 style_submenu_element("Prev", "Prev",
151 "%s/event?name=%s&amp;aid=%s&amp;detail=1",
152 g.zTop, zEventId, zPrev);
153 free(zPrev);
154 }
155 }else{
156 style_submenu_element("Detail", "Detail",
157 "%s/event?name=%s&amp;aid=%s&amp;detail=1",
158 g.zTop, zEventId, zUuid);
159 }
160 }
161
162 if( showDetail && g.perm.History ){
163 int i;
164 const char *zClr = 0;
165 Blob comment;
166
167 zATime = db_text(0, "SELECT datetime(%.17g)", pEvent->rDate);
168 @ <p>Event [<a href="%s(g.zTop)/artifact/%s(zUuid)">%S(zUuid)</a>] at
169 @ [<a href="%s(g.zTop)/timeline?c=%T(zETime)">%s(zETime)</a>]
170 @ entered by user <b>%h(pEvent->zUser)</b> on
171 @ [<a href="%s(g.zTop)/timeline?c=%T(zATime)">%s(zATime)</a>]:</p>
172 @ <blockquote>
173 for(i=0; i<pEvent->nTag; i++){
174 if( fossil_strcmp(pEvent->aTag[i].zName,"+bgcolor")==0 ){
175 zClr = pEvent->aTag[i].zValue;
176 }
177
--- src/event.c
+++ src/event.c
@@ -31,20 +31,13 @@
31 /*
32 ** Output a hyperlink to an event given its tagid.
33 */
34 void hyperlink_to_event_tagid(int tagid){
35 char *zEventId;
 
 
36 zEventId = db_text(0, "SELECT substr(tagname, 7) FROM tag WHERE tagid=%d",
37 tagid);
38 @ [%z(href("%R/event/%s",zEventId))%S(zEventId)</a>]
 
 
 
 
 
39 free(zEventId);
40 }
41
42 /*
43 ** WEBPAGE: event
@@ -130,47 +123,47 @@
123 g.zTop, zEventId);
124 }
125 zETime = db_text(0, "SELECT datetime(%.17g)", pEvent->rEventDate);
126 style_submenu_element("Context", "Context", "%s/timeline?c=%T",
127 g.zTop, zETime);
128 if( g.perm.Hyperlink ){
129 if( showDetail ){
130 style_submenu_element("Plain", "Plain", "%s/event?name=%s&aid=%s",
131 g.zTop, zEventId, zUuid);
132 if( nextRid ){
133 char *zNext;
134 zNext = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", nextRid);
135 style_submenu_element("Next", "Next",
136 "%s/event?name=%s&aid=%s&detail=1",
137 g.zTop, zEventId, zNext);
138 free(zNext);
139 }
140 if( prevRid ){
141 char *zPrev;
142 zPrev = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", prevRid);
143 style_submenu_element("Prev", "Prev",
144 "%s/event?name=%s&aid=%s&detail=1",
145 g.zTop, zEventId, zPrev);
146 free(zPrev);
147 }
148 }else{
149 style_submenu_element("Detail", "Detail",
150 "%s/event?name=%s&aid=%s&detail=1",
151 g.zTop, zEventId, zUuid);
152 }
153 }
154
155 if( showDetail && g.perm.Hyperlink ){
156 int i;
157 const char *zClr = 0;
158 Blob comment;
159
160 zATime = db_text(0, "SELECT datetime(%.17g)", pEvent->rDate);
161 @ <p>Event [%z(href("%R/artifact/%s",zUuid))%S(zUuid)</a>] at
162 @ [%z(href("%R/timeline?c=%T",zETime))%s(zETime)</a>]
163 @ entered by user <b>%h(pEvent->zUser)</b> on
164 @ [%z(href("%R/timeline?c=%T",zATime))%s(zATime)</a>]:</p>
165 @ <blockquote>
166 for(i=0; i<pEvent->nTag; i++){
167 if( fossil_strcmp(pEvent->aTag[i].zName,"+bgcolor")==0 ){
168 zClr = pEvent->aTag[i].zValue;
169 }
170
+5 -10
--- src/finfo.c
+++ src/finfo.c
@@ -305,39 +305,34 @@
305305
@ </td></tr>
306306
}
307307
memcpy(zTime, &zDate[11], 5);
308308
zTime[5] = 0;
309309
@ <tr><td class="timelineTime">
310
- @ <a href="%s(g.zTop)/timeline?c=%t(zDate)">%s(zTime)</a></td>
310
+ @ %z(href("%R/timeline?c=%t",zDate))%s(zTime)</a></td>
311311
@ <td class="timelineGraph"><div id="m%d(gidx)"></div></td>
312312
if( zBgClr && zBgClr[0] ){
313313
@ <td class="timelineTableCell" style="background-color: %h(zBgClr);">
314314
}else{
315315
@ <td class="timelineTableCell">
316316
}
317317
sqlite3_snprintf(sizeof(zShort), zShort, "%.10s", zUuid);
318318
sqlite3_snprintf(sizeof(zShortCkin), zShortCkin, "%.10s", zCkin);
319319
if( zUuid ){
320
- if( g.perm.History ){
321
- @ <a href="%s(g.zTop)/artifact/%s(zUuid)">[%S(zUuid)]</a>
322
- }else{
323
- @ [%S(zUuid)]
324
- }
325
- @ part of check-in
320
+ @ %z(href("%R/artifact/%s",zUuid))[%S(zUuid)]</a> part of check-in
326321
}else{
327322
@ <b>Deleted</b> by check-in
328323
}
329324
hyperlink_to_uuid(zShortCkin);
330325
@ %h(zCom) (user:
331326
hyperlink_to_user(zUser, zDate, "");
332327
@ branch: %h(zBr))
333
- if( g.perm.History && zUuid ){
328
+ if( g.perm.Hyperlink && zUuid ){
334329
const char *z = zFilename;
335330
if( fpid ){
336
- @ <a href="%s(g.zTop)/fdiff?v1=%s(zPUuid)&amp;v2=%s(zUuid)">[diff]</a>
331
+ @ %z(href("%R/fdiff?v1=%s&v2=%s",zPUuid,zUuid))[diff]</a>
337332
}
338
- @ <a href="%s(g.zTop)/annotate?checkin=%S(zCkin)&amp;filename=%h(z)">
333
+ @ %z(href("%R/annotate?checkin=%S&filename=%h",zCkin,z))
339334
@ [annotate]</a>
340335
}
341336
@ </td></tr>
342337
}
343338
db_finalize(&q);
344339
--- src/finfo.c
+++ src/finfo.c
@@ -305,39 +305,34 @@
305 @ </td></tr>
306 }
307 memcpy(zTime, &zDate[11], 5);
308 zTime[5] = 0;
309 @ <tr><td class="timelineTime">
310 @ <a href="%s(g.zTop)/timeline?c=%t(zDate)">%s(zTime)</a></td>
311 @ <td class="timelineGraph"><div id="m%d(gidx)"></div></td>
312 if( zBgClr && zBgClr[0] ){
313 @ <td class="timelineTableCell" style="background-color: %h(zBgClr);">
314 }else{
315 @ <td class="timelineTableCell">
316 }
317 sqlite3_snprintf(sizeof(zShort), zShort, "%.10s", zUuid);
318 sqlite3_snprintf(sizeof(zShortCkin), zShortCkin, "%.10s", zCkin);
319 if( zUuid ){
320 if( g.perm.History ){
321 @ <a href="%s(g.zTop)/artifact/%s(zUuid)">[%S(zUuid)]</a>
322 }else{
323 @ [%S(zUuid)]
324 }
325 @ part of check-in
326 }else{
327 @ <b>Deleted</b> by check-in
328 }
329 hyperlink_to_uuid(zShortCkin);
330 @ %h(zCom) (user:
331 hyperlink_to_user(zUser, zDate, "");
332 @ branch: %h(zBr))
333 if( g.perm.History && zUuid ){
334 const char *z = zFilename;
335 if( fpid ){
336 @ <a href="%s(g.zTop)/fdiff?v1=%s(zPUuid)&amp;v2=%s(zUuid)">[diff]</a>
337 }
338 @ <a href="%s(g.zTop)/annotate?checkin=%S(zCkin)&amp;filename=%h(z)">
339 @ [annotate]</a>
340 }
341 @ </td></tr>
342 }
343 db_finalize(&q);
344
--- src/finfo.c
+++ src/finfo.c
@@ -305,39 +305,34 @@
305 @ </td></tr>
306 }
307 memcpy(zTime, &zDate[11], 5);
308 zTime[5] = 0;
309 @ <tr><td class="timelineTime">
310 @ %z(href("%R/timeline?c=%t",zDate))%s(zTime)</a></td>
311 @ <td class="timelineGraph"><div id="m%d(gidx)"></div></td>
312 if( zBgClr && zBgClr[0] ){
313 @ <td class="timelineTableCell" style="background-color: %h(zBgClr);">
314 }else{
315 @ <td class="timelineTableCell">
316 }
317 sqlite3_snprintf(sizeof(zShort), zShort, "%.10s", zUuid);
318 sqlite3_snprintf(sizeof(zShortCkin), zShortCkin, "%.10s", zCkin);
319 if( zUuid ){
320 @ %z(href("%R/artifact/%s",zUuid))[%S(zUuid)]</a> part of check-in
 
 
 
 
 
321 }else{
322 @ <b>Deleted</b> by check-in
323 }
324 hyperlink_to_uuid(zShortCkin);
325 @ %h(zCom) (user:
326 hyperlink_to_user(zUser, zDate, "");
327 @ branch: %h(zBr))
328 if( g.perm.Hyperlink && zUuid ){
329 const char *z = zFilename;
330 if( fpid ){
331 @ %z(href("%R/fdiff?v1=%s&v2=%s",zPUuid,zUuid))[diff]</a>
332 }
333 @ %z(href("%R/annotate?checkin=%S&filename=%h",zCkin,z))
334 @ [annotate]</a>
335 }
336 @ </td></tr>
337 }
338 db_finalize(&q);
339
+65 -80
--- src/info.c
+++ src/info.c
@@ -261,11 +261,11 @@
261261
@ propagates to descendants
262262
}
263263
#if 0
264264
if( zValue && fossil_strcmp(zTagname,"branch")==0 ){
265265
@ &nbsp;&nbsp;
266
- @ <a href="%s(g.zTop)/timeline?r=%T(zValue)">branch timeline</a>
266
+ @ %z(href("%R/timeline?r=%T",zValue))branch timeline</a>
267267
}
268268
#endif
269269
}
270270
if( zSrcUuid && zSrcUuid[0] ){
271271
if( tagtype==0 ){
@@ -333,11 +333,11 @@
333333
const char *zNew, /* blob.uuid after change. NULL for deletes */
334334
const char *zOldName, /* Prior name. NULL if no name change. */
335335
int diffFlags, /* Flags for text_diff(). Zero to omit diffs */
336336
int mperm /* executable or symlink permission for zNew */
337337
){
338
- if( !g.perm.History ){
338
+ if( !g.perm.Hyperlink ){
339339
if( zNew==0 ){
340340
@ <p>Deleted %h(zName)</p>
341341
}else if( zOld==0 ){
342342
@ <p>Added %h(zName)</p>
343343
}else if( zOldName!=0 && fossil_strcmp(zName,zOldName)!=0 ){
@@ -354,35 +354,35 @@
354354
@ </pre>
355355
}
356356
}else{
357357
if( zOld && zNew ){
358358
if( fossil_strcmp(zOld, zNew)!=0 ){
359
- @ <p>Modified <a href="%s(g.zTop)/finfo?name=%T(zName)">%h(zName)</a>
360
- @ from <a href="%s(g.zTop)/artifact/%s(zOld)">[%S(zOld)]</a>
361
- @ to <a href="%s(g.zTop)/artifact/%s(zNew)">[%S(zNew)].</a>
359
+ @ <p>Modified %z(href("%R/finfo?name=%T",zName))%h(zName)</a>
360
+ @ from %z(href("%R/artifact/%s",zOld))[%S(zOld)]</a>
361
+ @ to %z(href("%R/artifact/%s",zNew))[%S(zNew)].</a>
362362
}else if( zOldName!=0 && fossil_strcmp(zName,zOldName)!=0 ){
363363
@ <p>Name change from
364
- @ from <a href="%s(g.zTop)/finfo?name=%T(zOldName)">%h(zOldName)</a>
365
- @ to <a href="%s(g.zTop)/finfo?name=%T(zName)">%h(zName)</a>.
364
+ @ from %z(href("%R/finfo?name=%T",zOldName))%h(zOldName)</a>
365
+ @ to %z(href("%R/finfo?name=%T",zName))%h(zName)</a>.
366366
}else{
367367
@ <p>Execute permission %s(( mperm==PERM_EXE )?"set":"cleared") for
368
- @ <a href="%s(g.zTop)/finfo?name=%T(zName)">%h(zName)</a>
368
+ @ %z(href("%R/finfo?name=%T",zName))%h(zName)</a>
369369
}
370370
}else if( zOld ){
371
- @ <p>Deleted <a href="%s(g.zTop)/finfo?name=%T(zName)">%h(zName)</a>
372
- @ version <a href="%s(g.zTop)/artifact/%s(zOld)">[%S(zOld)]</a>
371
+ @ <p>Deleted %z(href("%s/finfo?name=%T",g.zTop,zName))%h(zName)</a>
372
+ @ version %z(href("%R/artifact/%s",zOld))[%S(zOld)]</a>
373373
}else{
374
- @ <p>Added <a href="%s(g.zTop)/finfo?name=%T(zName)">%h(zName)</a>
375
- @ version <a href="%s(g.zTop)/artifact/%s(zNew)">[%S(zNew)]</a>
374
+ @ <p>Added %z(href("%R/finfo?name=%T",zName))%h(zName)</a>
375
+ @ version %z(href("%R/artifact/%s",zNew))[%S(zNew)]</a>
376376
}
377377
if( diffFlags ){
378378
@ <pre style="white-space:pre;">
379379
append_diff(zOld, zNew, diffFlags);
380380
@ </pre>
381381
}else if( zOld && zNew && fossil_strcmp(zOld,zNew)!=0 ){
382382
@ &nbsp;&nbsp;
383
- @ <a href="%s(g.zTop)/fdiff?v1=%S(zOld)&amp;v2=%S(zNew)">[diff]</a>
383
+ @ %z(href("%R/fdiff?v1=%S&v2=%S",zOld,zNew))[diff]</a>
384384
}
385385
@ </p>
386386
}
387387
}
388388
@@ -535,47 +535,47 @@
535535
@ <tr><th>Received&nbsp;From:</th>
536536
@ <td>%h(zUser) @ %h(zIpAddr) on %s(zDate)</td></tr>
537537
}
538538
db_finalize(&q);
539539
}
540
- if( g.perm.History ){
540
+ if( g.perm.Hyperlink ){
541541
const char *zProjName = db_get("project-name", "unnamed");
542542
@ <tr><th>Timelines:</th><td>
543
- @ <a href="%s(g.zTop)/timeline?f=%S(zUuid)">family</a>
543
+ @ %z(href("%R/timeline?f=%S",zUuid))family</a>
544544
if( zParent ){
545
- @ | <a href="%s(g.zTop)/timeline?p=%S(zUuid)">ancestors</a>
545
+ @ | %z(href("%R/timeline?p=%S",zUuid))ancestors</a>
546546
}
547547
if( !isLeaf ){
548
- @ | <a href="%s(g.zTop)/timeline?d=%S(zUuid)">descendants</a>
548
+ @ | %z(href("%R/timeline?d=%S",zUuid))descendants</a>
549549
}
550550
if( zParent && !isLeaf ){
551
- @ | <a href="%s(g.zTop)/timeline?dp=%S(zUuid)">both</a>
551
+ @ | %z(href("%R/timeline?dp=%S",zUuid))both</a>
552552
}
553553
db_prepare(&q, "SELECT substr(tag.tagname,5) FROM tagxref, tag "
554554
" WHERE rid=%d AND tagtype>0 "
555555
" AND tag.tagid=tagxref.tagid "
556556
" AND +tag.tagname GLOB 'sym-*'", rid);
557557
while( db_step(&q)==SQLITE_ROW ){
558558
const char *zTagName = db_column_text(&q, 0);
559
- @ | <a href="%s(g.zTop)/timeline?r=%T(zTagName)">%h(zTagName)</a>
559
+ @ | %z(href("%R/timeline?r=%T",zTagName))%h(zTagName)</a>
560560
}
561561
db_finalize(&q);
562562
@ </td></tr>
563563
@ <tr><th>Other&nbsp;Links:</th>
564564
@ <td>
565
- @ <a href="%s(g.zTop)/dir?ci=%S(zUuid)">files</a>
565
+ @ %z(href("%R/dir?ci=%S",zUuid))files</a>
566566
if( g.perm.Zip ){
567
- char *zUrl = mprintf("%s/tarball/%s-%S.tar.gz?uuid=%s",
568
- g.zTop, zProjName, zUuid, zUuid);
569
- @ | <a href="%s(zUrl)">Tarball</a>
570
- @ | <a href="%s(g.zTop)/zip/%s(zProjName)-%S(zUuid).zip?uuid=%s(zUuid)">
567
+ char *zUrl = mprintf("%R/tarball/%s-%S.tar.gz?uuid=%s",
568
+ zProjName, zUuid, zUuid);
569
+ @ | %z(href("%s",zUrl))Tarball</a>
570
+ @ | %z(href("%R/zip/%s-%S.zip?uuid=%s",zProjName,zUuid,zUuid))
571571
@ ZIP archive</a>
572572
fossil_free(zUrl);
573573
}
574
- @ | <a href="%s(g.zTop)/artifact/%S(zUuid)">manifest</a>
574
+ @ | %z(href("%R/artifact/%S",zUuid))manifest</a>
575575
if( g.perm.Write ){
576
- @ | <a href="%s(g.zTop)/ci_edit?r=%S(zUuid)">edit</a>
576
+ @ | %z(href("%R/ci_edit?r=%S",zUuid))edit</a>
577577
}
578578
@ </td>
579579
@ </tr>
580580
}
581581
@ </table>
@@ -590,43 +590,43 @@
590590
@ <div class="sectionmenu">
591591
showDiff = g.zPath[0]!='c';
592592
if( db_get_boolean("show-version-diffs", 0)==0 ){
593593
showDiff = !showDiff;
594594
if( showDiff ){
595
- @ <a class="button" href="%s(g.zTop)/vinfo/%T(zName)">
595
+ @ %z(xhref("class='button'","%R/vinfo/%T",zName)))
596596
@ hide&nbsp;diffs</a>
597597
if( sideBySide ){
598
- @ <a class="button" href="%s(g.zTop)/ci/%T(zName)?sbs=0">
598
+ @ %z(xhref("class='button'","%R/ci/%T?sbs=0",zName))
599599
@ unified&nbsp;diffs</a>
600600
}else{
601
- @ <a class="button" href="%s(g.zTop)/ci/%T(zName)?sbs=1">
601
+ @ %z(xhref("class='button'","%R/ci/%T?sbs=1",zName))
602602
@ side-by-side&nbsp;diffs</a>
603603
}
604604
}else{
605
- @ <a class="button" href="%s(g.zTop)/ci/%T(zName)?sbs=0">
605
+ @ %z(xhref("class='button'","%R/ci/%T?sbs=0",zName))
606606
@ show&nbsp;unified&nbsp;diffs</a>
607
- @ <a class="button" href="%s(g.zTop)/ci/%T(zName)?sbs=1">
607
+ @ %z(xhref("class='button'","%R/ci/%T?sbs=1",zName))
608608
@ show&nbsp;side-by-side&nbsp;diffs</a>
609609
}
610610
}else{
611611
if( showDiff ){
612
- @ <a class="button" href="%s(g.zTop)/ci/%T(zName)">hide&nbsp;diffs</a>
612
+ @ %z(xhref("class='button'","%R/ci/%T",zName))hide&nbsp;diffs</a>
613613
if( sideBySide ){
614
- @ <a class="button" href="%s(g.zTop)/info/%T(zName)?sbs=0">
614
+ @ %z(xhref("class='button'","%R/info/%T?sbs=0",zName))
615615
@ unified&nbsp;diffs</a>
616616
}else{
617
- @ <a class="button" href="%s(g.zTop)/info/%T(zName)?sbs=1">
617
+ @ %z(xhref("class='button'","%R/info/%T?sbs=1",zName))
618618
@ side-by-side&nbsp;diffs</a>
619619
}
620620
}else{
621
- @ <a class="button" href="%s(g.zTop)/vinfo/%T(zName)?sbs=0">
621
+ @ %z(xhref("class='button'","%R/vinfo/%T?sbs=0",zName))
622622
@ show&nbsp;unified&nbsp;diffs</a>
623
- @ <a class="button" href="%s(g.zTop)/vinfo/%T(zName)?sbs=1">
623
+ @ %z(xhref("class='button'","%R/vinfo/%T?sbs=1",zName))
624624
@ show&nbsp;side-by-side&nbsp;diffs</a>
625625
}
626626
}
627
- @ <a class="button" href="%s(g.zTop)/vpatch?from=%S(zParent)&to=%S(zUuid)">
627
+ @ %z(xhref("class='button'","%R/vpatch?from=%S&to=%S",zParent,zUuid))
628628
@ patch</a></div>
629629
db_prepare(&q,
630630
"SELECT name,"
631631
" mperm,"
632632
" (SELECT uuid FROM blob WHERE rid=mlink.pid),"
@@ -698,15 +698,15 @@
698698
if( g.perm.Setup ){
699699
@ <tr><th>Record ID:</th><td>%d(rid)</td></tr>
700700
}
701701
@ <tr><th>Original&nbsp;User:</th><td>
702702
hyperlink_to_user(zUser, zDate, "</td></tr>");
703
- if( g.perm.History ){
703
+ if( g.perm.Hyperlink ){
704704
@ <tr><th>Commands:</th>
705705
@ <td>
706
- @ <a href="%s(g.zTop)/whistory?name=%t(zName)">history</a>
707
- @ | <a href="%s(g.zTop)/artifact/%S(zUuid)">raw-text</a>
706
+ @ &z(href("%R/whistory?name=%t",zName))history</a>
707
+ @ | %z(href("%R/artifact/%S",zUuid))raw-text</a>
708708
@ </td>
709709
@ </tr>
710710
}
711711
@ </table></p>
712712
}else{
@@ -792,11 +792,11 @@
792792
}
793793
794794
795795
/*
796796
** WEBPAGE: vdiff
797
-** URL: /vdiff?from=UUID&amp;to=UUID&amp;detail=BOOLEAN;sbs=BOOLEAN
797
+** URL: /vdiff?from=UUID&to=UUID&detail=BOOLEAN;sbs=BOOLEAN
798798
**
799799
** Show all differences between two checkins.
800800
*/
801801
void vdiff_page(void){
802802
int ridFrom, ridTo;
@@ -936,34 +936,26 @@
936936
}else if( mPerm==PERM_EXE ){
937937
@ <li>Executable file
938938
}else{
939939
@ <li>File
940940
}
941
- if( g.perm.History ){
942
- @ <a href="%s(g.zTop)/finfo?name=%T(zName)">%h(zName)</a>
943
- }else{
944
- @ %h(zName)
945
- }
941
+ @ %z(href("%R/finfo?name=%T",zName))%h(zName)</a>
946942
@ <ul>
947943
prevName = fossil_strdup(zName);
948944
}
949945
@ <li>
950946
hyperlink_to_date(zDate,"");
951947
@ - part of checkin
952948
hyperlink_to_uuid(zVers);
953949
if( zBr && zBr[0] ){
954
- if( g.perm.History ){
955
- @ on branch <a href="%s(g.zTop)/timeline?r=%T(zBr)">%h(zBr)</a>
956
- }else{
957
- @ on branch %h(zBr)
958
- }
950
+ @ on branch %z(href("%R/timeline?r=%T",zBr))%h(zBr)</a>
959951
}
960952
@ - %w(zCom) (user:
961953
hyperlink_to_user(zUser,zDate,"");
962954
@ )
963
- if( g.perm.History ){
964
- @ <a href="%s(g.zTop)/annotate?checkin=%S(zVers)&filename=%T(zName)">
955
+ if( g.perm.Hyperlink ){
956
+ @ %z(href("%R/annotate?checkin=%S&filename=%T",zVers,zName))
965957
@ [annotate]</a>
966958
}
967959
cnt++;
968960
if( pDownloadName && blob_size(pDownloadName)==0 ){
969961
blob_append(pDownloadName, zName, -1);
@@ -989,16 +981,11 @@
989981
if( cnt>0 ){
990982
@ Also wiki page
991983
}else{
992984
@ Wiki page
993985
}
994
- if( g.perm.History ){
995
- @ [<a href="%s(g.zTop)/wiki?name=%t(zPagename)">%h(zPagename)</a>]
996
- }else{
997
- @ [%h(zPagename)]
998
- }
999
- @ by
986
+ @ [%z(href("%R/wiki?name=%t",zPagename))%h(zPagename)</a>] by
1000987
hyperlink_to_user(zUser,zDate," on");
1001988
hyperlink_to_date(zDate,".");
1002989
nWiki++;
1003990
cnt++;
1004991
if( pDownloadName && blob_size(pDownloadName)==0 ){
@@ -1065,18 +1052,18 @@
10651052
@ Also attachment "%h(zFilename)" to
10661053
}else{
10671054
@ Attachment "%h(zFilename)" to
10681055
}
10691056
if( strlen(zTarget)==UUID_SIZE && validate16(zTarget,UUID_SIZE) ){
1070
- if( g.perm.History && g.perm.RdTkt ){
1071
- @ ticket [<a href="%s(g.zTop)/tktview?name=%S(zTarget)">%S(zTarget)</a>]
1057
+ if( g.perm.Hyperlink && g.perm.RdTkt ){
1058
+ @ ticket [%z(href("%R/tktview?name=%S",zTarget))%S(zTarget)</a>]
10721059
}else{
10731060
@ ticket [%S(zTarget)]
10741061
}
10751062
}else{
1076
- if( g.perm.History && g.perm.RdWiki ){
1077
- @ wiki page [<a href="%s(g.zTop)/wiki?name=%t(zTarget)">%h(zTarget)</a>]
1063
+ if( g.perm.Hyperlink && g.perm.RdWiki ){
1064
+ @ wiki page [%z(href("%R/wiki?name=%t",zTarget)))%h(zTarget)</a>]
10781065
}else{
10791066
@ wiki page [%h(zTarget)]
10801067
}
10811068
}
10821069
@ added by
@@ -1091,12 +1078,12 @@
10911078
if( cnt==0 ){
10921079
@ Control artifact.
10931080
if( pDownloadName && blob_size(pDownloadName)==0 ){
10941081
blob_appendf(pDownloadName, "%.10s.txt", zUuid);
10951082
}
1096
- }else if( linkToView && g.perm.History ){
1097
- @ <a href="%s(g.zTop)/artifact/%S(zUuid)">[view]</a>
1083
+ }else if( linkToView && g.perm.Hyperlink ){
1084
+ @ %z(href("%R/artifact/%S",zUuid))[view]</a>
10981085
}
10991086
}
11001087
11011088
11021089
/*
@@ -1160,18 +1147,17 @@
11601147
g.zTop, P("v1"), P("v2"));
11611148
}
11621149
11631150
if( P("smhdr")!=0 ){
11641151
@ <h2>Differences From Artifact
1165
- @ <a href="%s(g.zTop)/artifact/%S(zV1)">[%S(zV1)]</a> To
1166
- @ <a href="%s(g.zTop)/artifact/%S(zV2)">[%S(zV2)]</a>.</h2>
1152
+ @ %z(href("%R/artifact/%S",zV1))[%S(zV1)]</a> To
1153
+ @ %z(href("%R/artifact/%S",zV2))[%S(zV2)]</a>.</h2>
11671154
}else{
11681155
@ <h2>Differences From
1169
- @ Artifact <a href="%s(g.zTop)/artifact/%S(zV1)">[%S(zV1)]</a>:</h2>
1156
+ @ Artifact %z(href("%R/artifact/%S",zV1))[%S(zV1)]</a>:</h2>
11701157
object_description(v1, 0, 0);
1171
- @ <h2>To Artifact
1172
- @ <a href="%s(g.zTop)/artifact/%S(zV2)">[%S(zV2)]</a>:</h2>
1158
+ @ <h2>To Artifact %z(href("%R/artifact/%S",zV2))[%S(zV2)]</a>:</h2>
11731159
object_description(v2, 0, 0);
11741160
}
11751161
@ <hr />
11761162
@ <div class="%s(zStyle)">
11771163
@ %s(blob_str(&diff))
@@ -1272,11 +1258,11 @@
12721258
if( !g.perm.Read ){ login_needed(); return; }
12731259
if( rid==0 ) fossil_redirect_home();
12741260
if( g.perm.Admin ){
12751261
const char *zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d", rid);
12761262
if( db_exists("SELECT 1 FROM shun WHERE uuid='%s'", zUuid) ){
1277
- style_submenu_element("Unshun","Unshun", "%s/shun?uuid=%s&amp;sub=1",
1263
+ style_submenu_element("Unshun","Unshun", "%s/shun?uuid=%s&sub=1",
12781264
g.zTop, zUuid);
12791265
}else{
12801266
style_submenu_element("Shun","Shun", "%s/shun?shun=%s#addshun",
12811267
g.zTop, zUuid);
12821268
}
@@ -1419,11 +1405,11 @@
14191405
if( !g.perm.Read ){ login_needed(); return; }
14201406
if( rid==0 ) fossil_redirect_home();
14211407
if( g.perm.Admin ){
14221408
const char *zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d", rid);
14231409
if( db_exists("SELECT 1 FROM shun WHERE uuid='%s'", zUuid) ){
1424
- style_submenu_element("Unshun","Unshun", "%s/shun?uuid=%s&amp;sub=1",
1410
+ style_submenu_element("Unshun","Unshun", "%s/shun?uuid=%s&sub=1",
14251411
g.zTop, zUuid);
14261412
}else{
14271413
style_submenu_element("Shun","Shun", "%s/shun?shun=%s#addshun",
14281414
g.zTop, zUuid);
14291415
}
@@ -1478,11 +1464,11 @@
14781464
@ <pre>
14791465
@ %h(z)
14801466
@ </pre>
14811467
}
14821468
}else if( strncmp(zMime, "image/", 6)==0 ){
1483
- @ <img src="%s(g.zTop)/raw?name=%s(zUuid)&amp;m=%s(zMime)"></img>
1469
+ @ <img src="%s(g.zTop)/raw?name=%s(zUuid)&m=%s(zMime)"></img>
14841470
}else{
14851471
@ <i>(file is %d(blob_size(&content)) bytes of binary data)</i>
14861472
}
14871473
@ </blockquote>
14881474
}
@@ -1507,11 +1493,11 @@
15071493
rid = name_to_rid_www("name");
15081494
if( rid==0 ){ fossil_redirect_home(); }
15091495
zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d", rid);
15101496
if( g.perm.Admin ){
15111497
if( db_exists("SELECT 1 FROM shun WHERE uuid='%s'", zUuid) ){
1512
- style_submenu_element("Unshun","Unshun", "%s/shun?uuid=%s&amp;sub=1",
1498
+ style_submenu_element("Unshun","Unshun", "%s/shun?uuid=%s&sub=1",
15131499
g.zTop, zUuid);
15141500
}else{
15151501
style_submenu_element("Shun","Shun", "%s/shun?shun=%s#addshun",
15161502
g.zTop, zUuid);
15171503
}
@@ -1522,18 +1508,17 @@
15221508
}
15231509
style_header("Ticket Change Details");
15241510
zDate = db_text(0, "SELECT datetime(%.12f)", pTktChng->rDate);
15251511
memcpy(zTktName, pTktChng->zTicketUuid, 10);
15261512
zTktName[10] = 0;
1527
- if( g.perm.History ){
1513
+ if( g.perm.Hyperlink ){
15281514
@ <h2>Changes to ticket
1529
- @ <a href="%s(pTktChng->zTicketUuid)">%s(zTktName)</a></h2>
1515
+ @ %z(href("%R/tktview/%s",pTktChng->zTicketUuid)))%s(zTktName)</a></h2>
15301516
@
15311517
@ <p>By %h(pTktChng->zUser) on %s(zDate). See also:
1532
- @ <a href="%s(g.zTop)/artifact/%T(zUuid)">artifact content</a>, and
1533
- @ <a href="%s(g.zTop)/tkthistory/%s(pTktChng->zTicketUuid)">ticket
1534
- @ history</a></p>
1518
+ @ %z(href("%R/artifact/%T",zUuid))artifact content</a>, and
1519
+ @ %z(href("%R/tkthistory/%s",pTktChng->zTicketUuid))ticket history</a></p>
15351520
}else{
15361521
@ <h2>Changes to ticket %s(zTktName)</h2>
15371522
@
15381523
@ <p>By %h(pTktChng->zUser) on %s(zDate).
15391524
@ </p>
@@ -1965,11 +1950,11 @@
19651950
@ </blockquote>
19661951
@ <hr />
19671952
blob_reset(&suffix);
19681953
}
19691954
@ <p>Make changes to attributes of check-in
1970
- @ [<a href="ci?name=%s(zUuid)">%s(zUuid)</a>]:</p>
1955
+ @ [%z(href("%R/ci/%s",zUuid))%s(zUuid)</a>]:</p>
19711956
@ <form action="%s(g.zTop)/ci_edit" method="post"><div>
19721957
login_insert_csrf_secret();
19731958
@ <input type="hidden" name="r" value="%S(zUuid)" />
19741959
@ <table border="0" cellspacing="10">
19751960
19761961
--- src/info.c
+++ src/info.c
@@ -261,11 +261,11 @@
261 @ propagates to descendants
262 }
263 #if 0
264 if( zValue && fossil_strcmp(zTagname,"branch")==0 ){
265 @ &nbsp;&nbsp;
266 @ <a href="%s(g.zTop)/timeline?r=%T(zValue)">branch timeline</a>
267 }
268 #endif
269 }
270 if( zSrcUuid && zSrcUuid[0] ){
271 if( tagtype==0 ){
@@ -333,11 +333,11 @@
333 const char *zNew, /* blob.uuid after change. NULL for deletes */
334 const char *zOldName, /* Prior name. NULL if no name change. */
335 int diffFlags, /* Flags for text_diff(). Zero to omit diffs */
336 int mperm /* executable or symlink permission for zNew */
337 ){
338 if( !g.perm.History ){
339 if( zNew==0 ){
340 @ <p>Deleted %h(zName)</p>
341 }else if( zOld==0 ){
342 @ <p>Added %h(zName)</p>
343 }else if( zOldName!=0 && fossil_strcmp(zName,zOldName)!=0 ){
@@ -354,35 +354,35 @@
354 @ </pre>
355 }
356 }else{
357 if( zOld && zNew ){
358 if( fossil_strcmp(zOld, zNew)!=0 ){
359 @ <p>Modified <a href="%s(g.zTop)/finfo?name=%T(zName)">%h(zName)</a>
360 @ from <a href="%s(g.zTop)/artifact/%s(zOld)">[%S(zOld)]</a>
361 @ to <a href="%s(g.zTop)/artifact/%s(zNew)">[%S(zNew)].</a>
362 }else if( zOldName!=0 && fossil_strcmp(zName,zOldName)!=0 ){
363 @ <p>Name change from
364 @ from <a href="%s(g.zTop)/finfo?name=%T(zOldName)">%h(zOldName)</a>
365 @ to <a href="%s(g.zTop)/finfo?name=%T(zName)">%h(zName)</a>.
366 }else{
367 @ <p>Execute permission %s(( mperm==PERM_EXE )?"set":"cleared") for
368 @ <a href="%s(g.zTop)/finfo?name=%T(zName)">%h(zName)</a>
369 }
370 }else if( zOld ){
371 @ <p>Deleted <a href="%s(g.zTop)/finfo?name=%T(zName)">%h(zName)</a>
372 @ version <a href="%s(g.zTop)/artifact/%s(zOld)">[%S(zOld)]</a>
373 }else{
374 @ <p>Added <a href="%s(g.zTop)/finfo?name=%T(zName)">%h(zName)</a>
375 @ version <a href="%s(g.zTop)/artifact/%s(zNew)">[%S(zNew)]</a>
376 }
377 if( diffFlags ){
378 @ <pre style="white-space:pre;">
379 append_diff(zOld, zNew, diffFlags);
380 @ </pre>
381 }else if( zOld && zNew && fossil_strcmp(zOld,zNew)!=0 ){
382 @ &nbsp;&nbsp;
383 @ <a href="%s(g.zTop)/fdiff?v1=%S(zOld)&amp;v2=%S(zNew)">[diff]</a>
384 }
385 @ </p>
386 }
387 }
388
@@ -535,47 +535,47 @@
535 @ <tr><th>Received&nbsp;From:</th>
536 @ <td>%h(zUser) @ %h(zIpAddr) on %s(zDate)</td></tr>
537 }
538 db_finalize(&q);
539 }
540 if( g.perm.History ){
541 const char *zProjName = db_get("project-name", "unnamed");
542 @ <tr><th>Timelines:</th><td>
543 @ <a href="%s(g.zTop)/timeline?f=%S(zUuid)">family</a>
544 if( zParent ){
545 @ | <a href="%s(g.zTop)/timeline?p=%S(zUuid)">ancestors</a>
546 }
547 if( !isLeaf ){
548 @ | <a href="%s(g.zTop)/timeline?d=%S(zUuid)">descendants</a>
549 }
550 if( zParent && !isLeaf ){
551 @ | <a href="%s(g.zTop)/timeline?dp=%S(zUuid)">both</a>
552 }
553 db_prepare(&q, "SELECT substr(tag.tagname,5) FROM tagxref, tag "
554 " WHERE rid=%d AND tagtype>0 "
555 " AND tag.tagid=tagxref.tagid "
556 " AND +tag.tagname GLOB 'sym-*'", rid);
557 while( db_step(&q)==SQLITE_ROW ){
558 const char *zTagName = db_column_text(&q, 0);
559 @ | <a href="%s(g.zTop)/timeline?r=%T(zTagName)">%h(zTagName)</a>
560 }
561 db_finalize(&q);
562 @ </td></tr>
563 @ <tr><th>Other&nbsp;Links:</th>
564 @ <td>
565 @ <a href="%s(g.zTop)/dir?ci=%S(zUuid)">files</a>
566 if( g.perm.Zip ){
567 char *zUrl = mprintf("%s/tarball/%s-%S.tar.gz?uuid=%s",
568 g.zTop, zProjName, zUuid, zUuid);
569 @ | <a href="%s(zUrl)">Tarball</a>
570 @ | <a href="%s(g.zTop)/zip/%s(zProjName)-%S(zUuid).zip?uuid=%s(zUuid)">
571 @ ZIP archive</a>
572 fossil_free(zUrl);
573 }
574 @ | <a href="%s(g.zTop)/artifact/%S(zUuid)">manifest</a>
575 if( g.perm.Write ){
576 @ | <a href="%s(g.zTop)/ci_edit?r=%S(zUuid)">edit</a>
577 }
578 @ </td>
579 @ </tr>
580 }
581 @ </table>
@@ -590,43 +590,43 @@
590 @ <div class="sectionmenu">
591 showDiff = g.zPath[0]!='c';
592 if( db_get_boolean("show-version-diffs", 0)==0 ){
593 showDiff = !showDiff;
594 if( showDiff ){
595 @ <a class="button" href="%s(g.zTop)/vinfo/%T(zName)">
596 @ hide&nbsp;diffs</a>
597 if( sideBySide ){
598 @ <a class="button" href="%s(g.zTop)/ci/%T(zName)?sbs=0">
599 @ unified&nbsp;diffs</a>
600 }else{
601 @ <a class="button" href="%s(g.zTop)/ci/%T(zName)?sbs=1">
602 @ side-by-side&nbsp;diffs</a>
603 }
604 }else{
605 @ <a class="button" href="%s(g.zTop)/ci/%T(zName)?sbs=0">
606 @ show&nbsp;unified&nbsp;diffs</a>
607 @ <a class="button" href="%s(g.zTop)/ci/%T(zName)?sbs=1">
608 @ show&nbsp;side-by-side&nbsp;diffs</a>
609 }
610 }else{
611 if( showDiff ){
612 @ <a class="button" href="%s(g.zTop)/ci/%T(zName)">hide&nbsp;diffs</a>
613 if( sideBySide ){
614 @ <a class="button" href="%s(g.zTop)/info/%T(zName)?sbs=0">
615 @ unified&nbsp;diffs</a>
616 }else{
617 @ <a class="button" href="%s(g.zTop)/info/%T(zName)?sbs=1">
618 @ side-by-side&nbsp;diffs</a>
619 }
620 }else{
621 @ <a class="button" href="%s(g.zTop)/vinfo/%T(zName)?sbs=0">
622 @ show&nbsp;unified&nbsp;diffs</a>
623 @ <a class="button" href="%s(g.zTop)/vinfo/%T(zName)?sbs=1">
624 @ show&nbsp;side-by-side&nbsp;diffs</a>
625 }
626 }
627 @ <a class="button" href="%s(g.zTop)/vpatch?from=%S(zParent)&to=%S(zUuid)">
628 @ patch</a></div>
629 db_prepare(&q,
630 "SELECT name,"
631 " mperm,"
632 " (SELECT uuid FROM blob WHERE rid=mlink.pid),"
@@ -698,15 +698,15 @@
698 if( g.perm.Setup ){
699 @ <tr><th>Record ID:</th><td>%d(rid)</td></tr>
700 }
701 @ <tr><th>Original&nbsp;User:</th><td>
702 hyperlink_to_user(zUser, zDate, "</td></tr>");
703 if( g.perm.History ){
704 @ <tr><th>Commands:</th>
705 @ <td>
706 @ <a href="%s(g.zTop)/whistory?name=%t(zName)">history</a>
707 @ | <a href="%s(g.zTop)/artifact/%S(zUuid)">raw-text</a>
708 @ </td>
709 @ </tr>
710 }
711 @ </table></p>
712 }else{
@@ -792,11 +792,11 @@
792 }
793
794
795 /*
796 ** WEBPAGE: vdiff
797 ** URL: /vdiff?from=UUID&amp;to=UUID&amp;detail=BOOLEAN;sbs=BOOLEAN
798 **
799 ** Show all differences between two checkins.
800 */
801 void vdiff_page(void){
802 int ridFrom, ridTo;
@@ -936,34 +936,26 @@
936 }else if( mPerm==PERM_EXE ){
937 @ <li>Executable file
938 }else{
939 @ <li>File
940 }
941 if( g.perm.History ){
942 @ <a href="%s(g.zTop)/finfo?name=%T(zName)">%h(zName)</a>
943 }else{
944 @ %h(zName)
945 }
946 @ <ul>
947 prevName = fossil_strdup(zName);
948 }
949 @ <li>
950 hyperlink_to_date(zDate,"");
951 @ - part of checkin
952 hyperlink_to_uuid(zVers);
953 if( zBr && zBr[0] ){
954 if( g.perm.History ){
955 @ on branch <a href="%s(g.zTop)/timeline?r=%T(zBr)">%h(zBr)</a>
956 }else{
957 @ on branch %h(zBr)
958 }
959 }
960 @ - %w(zCom) (user:
961 hyperlink_to_user(zUser,zDate,"");
962 @ )
963 if( g.perm.History ){
964 @ <a href="%s(g.zTop)/annotate?checkin=%S(zVers)&filename=%T(zName)">
965 @ [annotate]</a>
966 }
967 cnt++;
968 if( pDownloadName && blob_size(pDownloadName)==0 ){
969 blob_append(pDownloadName, zName, -1);
@@ -989,16 +981,11 @@
989 if( cnt>0 ){
990 @ Also wiki page
991 }else{
992 @ Wiki page
993 }
994 if( g.perm.History ){
995 @ [<a href="%s(g.zTop)/wiki?name=%t(zPagename)">%h(zPagename)</a>]
996 }else{
997 @ [%h(zPagename)]
998 }
999 @ by
1000 hyperlink_to_user(zUser,zDate," on");
1001 hyperlink_to_date(zDate,".");
1002 nWiki++;
1003 cnt++;
1004 if( pDownloadName && blob_size(pDownloadName)==0 ){
@@ -1065,18 +1052,18 @@
1065 @ Also attachment "%h(zFilename)" to
1066 }else{
1067 @ Attachment "%h(zFilename)" to
1068 }
1069 if( strlen(zTarget)==UUID_SIZE && validate16(zTarget,UUID_SIZE) ){
1070 if( g.perm.History && g.perm.RdTkt ){
1071 @ ticket [<a href="%s(g.zTop)/tktview?name=%S(zTarget)">%S(zTarget)</a>]
1072 }else{
1073 @ ticket [%S(zTarget)]
1074 }
1075 }else{
1076 if( g.perm.History && g.perm.RdWiki ){
1077 @ wiki page [<a href="%s(g.zTop)/wiki?name=%t(zTarget)">%h(zTarget)</a>]
1078 }else{
1079 @ wiki page [%h(zTarget)]
1080 }
1081 }
1082 @ added by
@@ -1091,12 +1078,12 @@
1091 if( cnt==0 ){
1092 @ Control artifact.
1093 if( pDownloadName && blob_size(pDownloadName)==0 ){
1094 blob_appendf(pDownloadName, "%.10s.txt", zUuid);
1095 }
1096 }else if( linkToView && g.perm.History ){
1097 @ <a href="%s(g.zTop)/artifact/%S(zUuid)">[view]</a>
1098 }
1099 }
1100
1101
1102 /*
@@ -1160,18 +1147,17 @@
1160 g.zTop, P("v1"), P("v2"));
1161 }
1162
1163 if( P("smhdr")!=0 ){
1164 @ <h2>Differences From Artifact
1165 @ <a href="%s(g.zTop)/artifact/%S(zV1)">[%S(zV1)]</a> To
1166 @ <a href="%s(g.zTop)/artifact/%S(zV2)">[%S(zV2)]</a>.</h2>
1167 }else{
1168 @ <h2>Differences From
1169 @ Artifact <a href="%s(g.zTop)/artifact/%S(zV1)">[%S(zV1)]</a>:</h2>
1170 object_description(v1, 0, 0);
1171 @ <h2>To Artifact
1172 @ <a href="%s(g.zTop)/artifact/%S(zV2)">[%S(zV2)]</a>:</h2>
1173 object_description(v2, 0, 0);
1174 }
1175 @ <hr />
1176 @ <div class="%s(zStyle)">
1177 @ %s(blob_str(&diff))
@@ -1272,11 +1258,11 @@
1272 if( !g.perm.Read ){ login_needed(); return; }
1273 if( rid==0 ) fossil_redirect_home();
1274 if( g.perm.Admin ){
1275 const char *zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d", rid);
1276 if( db_exists("SELECT 1 FROM shun WHERE uuid='%s'", zUuid) ){
1277 style_submenu_element("Unshun","Unshun", "%s/shun?uuid=%s&amp;sub=1",
1278 g.zTop, zUuid);
1279 }else{
1280 style_submenu_element("Shun","Shun", "%s/shun?shun=%s#addshun",
1281 g.zTop, zUuid);
1282 }
@@ -1419,11 +1405,11 @@
1419 if( !g.perm.Read ){ login_needed(); return; }
1420 if( rid==0 ) fossil_redirect_home();
1421 if( g.perm.Admin ){
1422 const char *zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d", rid);
1423 if( db_exists("SELECT 1 FROM shun WHERE uuid='%s'", zUuid) ){
1424 style_submenu_element("Unshun","Unshun", "%s/shun?uuid=%s&amp;sub=1",
1425 g.zTop, zUuid);
1426 }else{
1427 style_submenu_element("Shun","Shun", "%s/shun?shun=%s#addshun",
1428 g.zTop, zUuid);
1429 }
@@ -1478,11 +1464,11 @@
1478 @ <pre>
1479 @ %h(z)
1480 @ </pre>
1481 }
1482 }else if( strncmp(zMime, "image/", 6)==0 ){
1483 @ <img src="%s(g.zTop)/raw?name=%s(zUuid)&amp;m=%s(zMime)"></img>
1484 }else{
1485 @ <i>(file is %d(blob_size(&content)) bytes of binary data)</i>
1486 }
1487 @ </blockquote>
1488 }
@@ -1507,11 +1493,11 @@
1507 rid = name_to_rid_www("name");
1508 if( rid==0 ){ fossil_redirect_home(); }
1509 zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d", rid);
1510 if( g.perm.Admin ){
1511 if( db_exists("SELECT 1 FROM shun WHERE uuid='%s'", zUuid) ){
1512 style_submenu_element("Unshun","Unshun", "%s/shun?uuid=%s&amp;sub=1",
1513 g.zTop, zUuid);
1514 }else{
1515 style_submenu_element("Shun","Shun", "%s/shun?shun=%s#addshun",
1516 g.zTop, zUuid);
1517 }
@@ -1522,18 +1508,17 @@
1522 }
1523 style_header("Ticket Change Details");
1524 zDate = db_text(0, "SELECT datetime(%.12f)", pTktChng->rDate);
1525 memcpy(zTktName, pTktChng->zTicketUuid, 10);
1526 zTktName[10] = 0;
1527 if( g.perm.History ){
1528 @ <h2>Changes to ticket
1529 @ <a href="%s(pTktChng->zTicketUuid)">%s(zTktName)</a></h2>
1530 @
1531 @ <p>By %h(pTktChng->zUser) on %s(zDate). See also:
1532 @ <a href="%s(g.zTop)/artifact/%T(zUuid)">artifact content</a>, and
1533 @ <a href="%s(g.zTop)/tkthistory/%s(pTktChng->zTicketUuid)">ticket
1534 @ history</a></p>
1535 }else{
1536 @ <h2>Changes to ticket %s(zTktName)</h2>
1537 @
1538 @ <p>By %h(pTktChng->zUser) on %s(zDate).
1539 @ </p>
@@ -1965,11 +1950,11 @@
1965 @ </blockquote>
1966 @ <hr />
1967 blob_reset(&suffix);
1968 }
1969 @ <p>Make changes to attributes of check-in
1970 @ [<a href="ci?name=%s(zUuid)">%s(zUuid)</a>]:</p>
1971 @ <form action="%s(g.zTop)/ci_edit" method="post"><div>
1972 login_insert_csrf_secret();
1973 @ <input type="hidden" name="r" value="%S(zUuid)" />
1974 @ <table border="0" cellspacing="10">
1975
1976
--- src/info.c
+++ src/info.c
@@ -261,11 +261,11 @@
261 @ propagates to descendants
262 }
263 #if 0
264 if( zValue && fossil_strcmp(zTagname,"branch")==0 ){
265 @ &nbsp;&nbsp;
266 @ %z(href("%R/timeline?r=%T",zValue))branch timeline</a>
267 }
268 #endif
269 }
270 if( zSrcUuid && zSrcUuid[0] ){
271 if( tagtype==0 ){
@@ -333,11 +333,11 @@
333 const char *zNew, /* blob.uuid after change. NULL for deletes */
334 const char *zOldName, /* Prior name. NULL if no name change. */
335 int diffFlags, /* Flags for text_diff(). Zero to omit diffs */
336 int mperm /* executable or symlink permission for zNew */
337 ){
338 if( !g.perm.Hyperlink ){
339 if( zNew==0 ){
340 @ <p>Deleted %h(zName)</p>
341 }else if( zOld==0 ){
342 @ <p>Added %h(zName)</p>
343 }else if( zOldName!=0 && fossil_strcmp(zName,zOldName)!=0 ){
@@ -354,35 +354,35 @@
354 @ </pre>
355 }
356 }else{
357 if( zOld && zNew ){
358 if( fossil_strcmp(zOld, zNew)!=0 ){
359 @ <p>Modified %z(href("%R/finfo?name=%T",zName))%h(zName)</a>
360 @ from %z(href("%R/artifact/%s",zOld))[%S(zOld)]</a>
361 @ to %z(href("%R/artifact/%s",zNew))[%S(zNew)].</a>
362 }else if( zOldName!=0 && fossil_strcmp(zName,zOldName)!=0 ){
363 @ <p>Name change from
364 @ from %z(href("%R/finfo?name=%T",zOldName))%h(zOldName)</a>
365 @ to %z(href("%R/finfo?name=%T",zName))%h(zName)</a>.
366 }else{
367 @ <p>Execute permission %s(( mperm==PERM_EXE )?"set":"cleared") for
368 @ %z(href("%R/finfo?name=%T",zName))%h(zName)</a>
369 }
370 }else if( zOld ){
371 @ <p>Deleted %z(href("%s/finfo?name=%T",g.zTop,zName))%h(zName)</a>
372 @ version %z(href("%R/artifact/%s",zOld))[%S(zOld)]</a>
373 }else{
374 @ <p>Added %z(href("%R/finfo?name=%T",zName))%h(zName)</a>
375 @ version %z(href("%R/artifact/%s",zNew))[%S(zNew)]</a>
376 }
377 if( diffFlags ){
378 @ <pre style="white-space:pre;">
379 append_diff(zOld, zNew, diffFlags);
380 @ </pre>
381 }else if( zOld && zNew && fossil_strcmp(zOld,zNew)!=0 ){
382 @ &nbsp;&nbsp;
383 @ %z(href("%R/fdiff?v1=%S&v2=%S",zOld,zNew))[diff]</a>
384 }
385 @ </p>
386 }
387 }
388
@@ -535,47 +535,47 @@
535 @ <tr><th>Received&nbsp;From:</th>
536 @ <td>%h(zUser) @ %h(zIpAddr) on %s(zDate)</td></tr>
537 }
538 db_finalize(&q);
539 }
540 if( g.perm.Hyperlink ){
541 const char *zProjName = db_get("project-name", "unnamed");
542 @ <tr><th>Timelines:</th><td>
543 @ %z(href("%R/timeline?f=%S",zUuid))family</a>
544 if( zParent ){
545 @ | %z(href("%R/timeline?p=%S",zUuid))ancestors</a>
546 }
547 if( !isLeaf ){
548 @ | %z(href("%R/timeline?d=%S",zUuid))descendants</a>
549 }
550 if( zParent && !isLeaf ){
551 @ | %z(href("%R/timeline?dp=%S",zUuid))both</a>
552 }
553 db_prepare(&q, "SELECT substr(tag.tagname,5) FROM tagxref, tag "
554 " WHERE rid=%d AND tagtype>0 "
555 " AND tag.tagid=tagxref.tagid "
556 " AND +tag.tagname GLOB 'sym-*'", rid);
557 while( db_step(&q)==SQLITE_ROW ){
558 const char *zTagName = db_column_text(&q, 0);
559 @ | %z(href("%R/timeline?r=%T",zTagName))%h(zTagName)</a>
560 }
561 db_finalize(&q);
562 @ </td></tr>
563 @ <tr><th>Other&nbsp;Links:</th>
564 @ <td>
565 @ %z(href("%R/dir?ci=%S",zUuid))files</a>
566 if( g.perm.Zip ){
567 char *zUrl = mprintf("%R/tarball/%s-%S.tar.gz?uuid=%s",
568 zProjName, zUuid, zUuid);
569 @ | %z(href("%s",zUrl))Tarball</a>
570 @ | %z(href("%R/zip/%s-%S.zip?uuid=%s",zProjName,zUuid,zUuid))
571 @ ZIP archive</a>
572 fossil_free(zUrl);
573 }
574 @ | %z(href("%R/artifact/%S",zUuid))manifest</a>
575 if( g.perm.Write ){
576 @ | %z(href("%R/ci_edit?r=%S",zUuid))edit</a>
577 }
578 @ </td>
579 @ </tr>
580 }
581 @ </table>
@@ -590,43 +590,43 @@
590 @ <div class="sectionmenu">
591 showDiff = g.zPath[0]!='c';
592 if( db_get_boolean("show-version-diffs", 0)==0 ){
593 showDiff = !showDiff;
594 if( showDiff ){
595 @ %z(xhref("class='button'","%R/vinfo/%T",zName)))
596 @ hide&nbsp;diffs</a>
597 if( sideBySide ){
598 @ %z(xhref("class='button'","%R/ci/%T?sbs=0",zName))
599 @ unified&nbsp;diffs</a>
600 }else{
601 @ %z(xhref("class='button'","%R/ci/%T?sbs=1",zName))
602 @ side-by-side&nbsp;diffs</a>
603 }
604 }else{
605 @ %z(xhref("class='button'","%R/ci/%T?sbs=0",zName))
606 @ show&nbsp;unified&nbsp;diffs</a>
607 @ %z(xhref("class='button'","%R/ci/%T?sbs=1",zName))
608 @ show&nbsp;side-by-side&nbsp;diffs</a>
609 }
610 }else{
611 if( showDiff ){
612 @ %z(xhref("class='button'","%R/ci/%T",zName))hide&nbsp;diffs</a>
613 if( sideBySide ){
614 @ %z(xhref("class='button'","%R/info/%T?sbs=0",zName))
615 @ unified&nbsp;diffs</a>
616 }else{
617 @ %z(xhref("class='button'","%R/info/%T?sbs=1",zName))
618 @ side-by-side&nbsp;diffs</a>
619 }
620 }else{
621 @ %z(xhref("class='button'","%R/vinfo/%T?sbs=0",zName))
622 @ show&nbsp;unified&nbsp;diffs</a>
623 @ %z(xhref("class='button'","%R/vinfo/%T?sbs=1",zName))
624 @ show&nbsp;side-by-side&nbsp;diffs</a>
625 }
626 }
627 @ %z(xhref("class='button'","%R/vpatch?from=%S&to=%S",zParent,zUuid))
628 @ patch</a></div>
629 db_prepare(&q,
630 "SELECT name,"
631 " mperm,"
632 " (SELECT uuid FROM blob WHERE rid=mlink.pid),"
@@ -698,15 +698,15 @@
698 if( g.perm.Setup ){
699 @ <tr><th>Record ID:</th><td>%d(rid)</td></tr>
700 }
701 @ <tr><th>Original&nbsp;User:</th><td>
702 hyperlink_to_user(zUser, zDate, "</td></tr>");
703 if( g.perm.Hyperlink ){
704 @ <tr><th>Commands:</th>
705 @ <td>
706 @ &z(href("%R/whistory?name=%t",zName))history</a>
707 @ | %z(href("%R/artifact/%S",zUuid))raw-text</a>
708 @ </td>
709 @ </tr>
710 }
711 @ </table></p>
712 }else{
@@ -792,11 +792,11 @@
792 }
793
794
795 /*
796 ** WEBPAGE: vdiff
797 ** URL: /vdiff?from=UUID&to=UUID&detail=BOOLEAN;sbs=BOOLEAN
798 **
799 ** Show all differences between two checkins.
800 */
801 void vdiff_page(void){
802 int ridFrom, ridTo;
@@ -936,34 +936,26 @@
936 }else if( mPerm==PERM_EXE ){
937 @ <li>Executable file
938 }else{
939 @ <li>File
940 }
941 @ %z(href("%R/finfo?name=%T",zName))%h(zName)</a>
 
 
 
 
942 @ <ul>
943 prevName = fossil_strdup(zName);
944 }
945 @ <li>
946 hyperlink_to_date(zDate,"");
947 @ - part of checkin
948 hyperlink_to_uuid(zVers);
949 if( zBr && zBr[0] ){
950 @ on branch %z(href("%R/timeline?r=%T",zBr))%h(zBr)</a>
 
 
 
 
951 }
952 @ - %w(zCom) (user:
953 hyperlink_to_user(zUser,zDate,"");
954 @ )
955 if( g.perm.Hyperlink ){
956 @ %z(href("%R/annotate?checkin=%S&filename=%T",zVers,zName))
957 @ [annotate]</a>
958 }
959 cnt++;
960 if( pDownloadName && blob_size(pDownloadName)==0 ){
961 blob_append(pDownloadName, zName, -1);
@@ -989,16 +981,11 @@
981 if( cnt>0 ){
982 @ Also wiki page
983 }else{
984 @ Wiki page
985 }
986 @ [%z(href("%R/wiki?name=%t",zPagename))%h(zPagename)</a>] by
 
 
 
 
 
987 hyperlink_to_user(zUser,zDate," on");
988 hyperlink_to_date(zDate,".");
989 nWiki++;
990 cnt++;
991 if( pDownloadName && blob_size(pDownloadName)==0 ){
@@ -1065,18 +1052,18 @@
1052 @ Also attachment "%h(zFilename)" to
1053 }else{
1054 @ Attachment "%h(zFilename)" to
1055 }
1056 if( strlen(zTarget)==UUID_SIZE && validate16(zTarget,UUID_SIZE) ){
1057 if( g.perm.Hyperlink && g.perm.RdTkt ){
1058 @ ticket [%z(href("%R/tktview?name=%S",zTarget))%S(zTarget)</a>]
1059 }else{
1060 @ ticket [%S(zTarget)]
1061 }
1062 }else{
1063 if( g.perm.Hyperlink && g.perm.RdWiki ){
1064 @ wiki page [%z(href("%R/wiki?name=%t",zTarget)))%h(zTarget)</a>]
1065 }else{
1066 @ wiki page [%h(zTarget)]
1067 }
1068 }
1069 @ added by
@@ -1091,12 +1078,12 @@
1078 if( cnt==0 ){
1079 @ Control artifact.
1080 if( pDownloadName && blob_size(pDownloadName)==0 ){
1081 blob_appendf(pDownloadName, "%.10s.txt", zUuid);
1082 }
1083 }else if( linkToView && g.perm.Hyperlink ){
1084 @ %z(href("%R/artifact/%S",zUuid))[view]</a>
1085 }
1086 }
1087
1088
1089 /*
@@ -1160,18 +1147,17 @@
1147 g.zTop, P("v1"), P("v2"));
1148 }
1149
1150 if( P("smhdr")!=0 ){
1151 @ <h2>Differences From Artifact
1152 @ %z(href("%R/artifact/%S",zV1))[%S(zV1)]</a> To
1153 @ %z(href("%R/artifact/%S",zV2))[%S(zV2)]</a>.</h2>
1154 }else{
1155 @ <h2>Differences From
1156 @ Artifact %z(href("%R/artifact/%S",zV1))[%S(zV1)]</a>:</h2>
1157 object_description(v1, 0, 0);
1158 @ <h2>To Artifact %z(href("%R/artifact/%S",zV2))[%S(zV2)]</a>:</h2>
 
1159 object_description(v2, 0, 0);
1160 }
1161 @ <hr />
1162 @ <div class="%s(zStyle)">
1163 @ %s(blob_str(&diff))
@@ -1272,11 +1258,11 @@
1258 if( !g.perm.Read ){ login_needed(); return; }
1259 if( rid==0 ) fossil_redirect_home();
1260 if( g.perm.Admin ){
1261 const char *zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d", rid);
1262 if( db_exists("SELECT 1 FROM shun WHERE uuid='%s'", zUuid) ){
1263 style_submenu_element("Unshun","Unshun", "%s/shun?uuid=%s&sub=1",
1264 g.zTop, zUuid);
1265 }else{
1266 style_submenu_element("Shun","Shun", "%s/shun?shun=%s#addshun",
1267 g.zTop, zUuid);
1268 }
@@ -1419,11 +1405,11 @@
1405 if( !g.perm.Read ){ login_needed(); return; }
1406 if( rid==0 ) fossil_redirect_home();
1407 if( g.perm.Admin ){
1408 const char *zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d", rid);
1409 if( db_exists("SELECT 1 FROM shun WHERE uuid='%s'", zUuid) ){
1410 style_submenu_element("Unshun","Unshun", "%s/shun?uuid=%s&sub=1",
1411 g.zTop, zUuid);
1412 }else{
1413 style_submenu_element("Shun","Shun", "%s/shun?shun=%s#addshun",
1414 g.zTop, zUuid);
1415 }
@@ -1478,11 +1464,11 @@
1464 @ <pre>
1465 @ %h(z)
1466 @ </pre>
1467 }
1468 }else if( strncmp(zMime, "image/", 6)==0 ){
1469 @ <img src="%s(g.zTop)/raw?name=%s(zUuid)&m=%s(zMime)"></img>
1470 }else{
1471 @ <i>(file is %d(blob_size(&content)) bytes of binary data)</i>
1472 }
1473 @ </blockquote>
1474 }
@@ -1507,11 +1493,11 @@
1493 rid = name_to_rid_www("name");
1494 if( rid==0 ){ fossil_redirect_home(); }
1495 zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d", rid);
1496 if( g.perm.Admin ){
1497 if( db_exists("SELECT 1 FROM shun WHERE uuid='%s'", zUuid) ){
1498 style_submenu_element("Unshun","Unshun", "%s/shun?uuid=%s&sub=1",
1499 g.zTop, zUuid);
1500 }else{
1501 style_submenu_element("Shun","Shun", "%s/shun?shun=%s#addshun",
1502 g.zTop, zUuid);
1503 }
@@ -1522,18 +1508,17 @@
1508 }
1509 style_header("Ticket Change Details");
1510 zDate = db_text(0, "SELECT datetime(%.12f)", pTktChng->rDate);
1511 memcpy(zTktName, pTktChng->zTicketUuid, 10);
1512 zTktName[10] = 0;
1513 if( g.perm.Hyperlink ){
1514 @ <h2>Changes to ticket
1515 @ %z(href("%R/tktview/%s",pTktChng->zTicketUuid)))%s(zTktName)</a></h2>
1516 @
1517 @ <p>By %h(pTktChng->zUser) on %s(zDate). See also:
1518 @ %z(href("%R/artifact/%T",zUuid))artifact content</a>, and
1519 @ %z(href("%R/tkthistory/%s",pTktChng->zTicketUuid))ticket history</a></p>
 
1520 }else{
1521 @ <h2>Changes to ticket %s(zTktName)</h2>
1522 @
1523 @ <p>By %h(pTktChng->zUser) on %s(zDate).
1524 @ </p>
@@ -1965,11 +1950,11 @@
1950 @ </blockquote>
1951 @ <hr />
1952 blob_reset(&suffix);
1953 }
1954 @ <p>Make changes to attributes of check-in
1955 @ [%z(href("%R/ci/%s",zUuid))%s(zUuid)</a>]:</p>
1956 @ <form action="%s(g.zTop)/ci_edit" method="post"><div>
1957 login_insert_csrf_secret();
1958 @ <input type="hidden" name="r" value="%S(zUuid)" />
1959 @ <table border="0" cellspacing="10">
1960
1961
+1 -1
--- src/json_dir.c
+++ src/json_dir.c
@@ -66,11 +66,11 @@
6666
char * zUuid = NULL;
6767
char const * zCI = NULL;
6868
Manifest * pM = NULL;
6969
Stmt q = empty_Stmt;
7070
int rid = 0;
71
- if( !g.perm.History ){
71
+ if( !g.perm.Hyperlink ){
7272
json_set_err(FSL_JSON_E_DENIED, "Requires 'h' permissions.");
7373
return NULL;
7474
}
7575
zCI = json_find_option_cstr("checkin",NULL,"ci" );
7676
7777
--- src/json_dir.c
+++ src/json_dir.c
@@ -66,11 +66,11 @@
66 char * zUuid = NULL;
67 char const * zCI = NULL;
68 Manifest * pM = NULL;
69 Stmt q = empty_Stmt;
70 int rid = 0;
71 if( !g.perm.History ){
72 json_set_err(FSL_JSON_E_DENIED, "Requires 'h' permissions.");
73 return NULL;
74 }
75 zCI = json_find_option_cstr("checkin",NULL,"ci" );
76
77
--- src/json_dir.c
+++ src/json_dir.c
@@ -66,11 +66,11 @@
66 char * zUuid = NULL;
67 char const * zCI = NULL;
68 Manifest * pM = NULL;
69 Stmt q = empty_Stmt;
70 int rid = 0;
71 if( !g.perm.Hyperlink ){
72 json_set_err(FSL_JSON_E_DENIED, "Requires 'h' permissions.");
73 return NULL;
74 }
75 zCI = json_find_option_cstr("checkin",NULL,"ci" );
76
77
--- src/json_timeline.c
+++ src/json_timeline.c
@@ -53,11 +53,11 @@
5353
#if 0
5454
/* The original timeline code does not require 'h' access,
5555
but it arguably should. For JSON mode i think one could argue
5656
that History permissions are required.
5757
*/
58
- if(! g.perm.History && !g.perm.Read ){
58
+ if(! g.perm.Hyperlink && !g.perm.Read ){
5959
json_set_err(FSL_JSON_E_DENIED, "Timeline requires 'h' or 'o' access.");
6060
return NULL;
6161
}
6262
#endif
6363
return json_page_dispatch_helper(&JsonPageDefs_Timeline[0]);
@@ -426,11 +426,11 @@
426426
int check = 0;
427427
char showFiles = -1/*magic number*/;
428428
Stmt q = empty_Stmt;
429429
char warnRowToJsonFailed = 0;
430430
Blob sql = empty_blob;
431
- if( !g.perm.History ){
431
+ if( !g.perm.Hyperlink ){
432432
/* Reminder to self: HTML impl requires 'o' (Read)
433433
rights.
434434
*/
435435
json_set_err( FSL_JSON_E_DENIED, "Checkin timeline requires 'h' access." );
436436
return NULL;
437437
--- src/json_timeline.c
+++ src/json_timeline.c
@@ -53,11 +53,11 @@
53 #if 0
54 /* The original timeline code does not require 'h' access,
55 but it arguably should. For JSON mode i think one could argue
56 that History permissions are required.
57 */
58 if(! g.perm.History && !g.perm.Read ){
59 json_set_err(FSL_JSON_E_DENIED, "Timeline requires 'h' or 'o' access.");
60 return NULL;
61 }
62 #endif
63 return json_page_dispatch_helper(&JsonPageDefs_Timeline[0]);
@@ -426,11 +426,11 @@
426 int check = 0;
427 char showFiles = -1/*magic number*/;
428 Stmt q = empty_Stmt;
429 char warnRowToJsonFailed = 0;
430 Blob sql = empty_blob;
431 if( !g.perm.History ){
432 /* Reminder to self: HTML impl requires 'o' (Read)
433 rights.
434 */
435 json_set_err( FSL_JSON_E_DENIED, "Checkin timeline requires 'h' access." );
436 return NULL;
437
--- src/json_timeline.c
+++ src/json_timeline.c
@@ -53,11 +53,11 @@
53 #if 0
54 /* The original timeline code does not require 'h' access,
55 but it arguably should. For JSON mode i think one could argue
56 that History permissions are required.
57 */
58 if(! g.perm.Hyperlink && !g.perm.Read ){
59 json_set_err(FSL_JSON_E_DENIED, "Timeline requires 'h' or 'o' access.");
60 return NULL;
61 }
62 #endif
63 return json_page_dispatch_helper(&JsonPageDefs_Timeline[0]);
@@ -426,11 +426,11 @@
426 int check = 0;
427 char showFiles = -1/*magic number*/;
428 Stmt q = empty_Stmt;
429 char warnRowToJsonFailed = 0;
430 Blob sql = empty_blob;
431 if( !g.perm.Hyperlink ){
432 /* Reminder to self: HTML impl requires 'o' (Read)
433 rights.
434 */
435 json_set_err( FSL_JSON_E_DENIED, "Checkin timeline requires 'h' access." );
436 return NULL;
437
+1 -1
--- src/json_wiki.c
+++ src/json_wiki.c
@@ -492,11 +492,11 @@
492492
Manifest * pW1 = NULL, *pW2 = NULL;
493493
Blob w1 = empty_blob, w2 = empty_blob, d = empty_blob;
494494
char const * zErrTag = NULL;
495495
int diffFlags;
496496
char * zUuid = NULL;
497
- if( !g.perm.History ){
497
+ if( !g.perm.Hyperlink ){
498498
json_set_err(FSL_JSON_E_DENIED,
499499
"Requires 'h' permissions.");
500500
return NULL;
501501
}
502502
503503
--- src/json_wiki.c
+++ src/json_wiki.c
@@ -492,11 +492,11 @@
492 Manifest * pW1 = NULL, *pW2 = NULL;
493 Blob w1 = empty_blob, w2 = empty_blob, d = empty_blob;
494 char const * zErrTag = NULL;
495 int diffFlags;
496 char * zUuid = NULL;
497 if( !g.perm.History ){
498 json_set_err(FSL_JSON_E_DENIED,
499 "Requires 'h' permissions.");
500 return NULL;
501 }
502
503
--- src/json_wiki.c
+++ src/json_wiki.c
@@ -492,11 +492,11 @@
492 Manifest * pW1 = NULL, *pW2 = NULL;
493 Blob w1 = empty_blob, w2 = empty_blob, d = empty_blob;
494 char const * zErrTag = NULL;
495 int diffFlags;
496 char * zUuid = NULL;
497 if( !g.perm.Hyperlink ){
498 json_set_err(FSL_JSON_E_DENIED,
499 "Requires 'h' permissions.");
500 return NULL;
501 }
502
503
+16 -15
--- src/login.c
+++ src/login.c
@@ -562,11 +562,11 @@
562562
redirect_to_g();
563563
}
564564
}
565565
style_header("Login/Logout");
566566
@ %s(zErrMsg)
567
- if( zGoto ){
567
+ if( zGoto && P("anon")==0 ){
568568
@ <p>A login is required for <a href="%h(zGoto)">%h(zGoto)</a>.</p>
569569
}
570570
@ <form action="login" method="post">
571571
if( zGoto ){
572572
@ <input type="hidden" name="g" value="%h(zGoto)" />
@@ -911,13 +911,15 @@
911911
}
912912
913913
/* Set the capabilities */
914914
login_replace_capabilities(zCap, 0);
915915
login_set_anon_nobody_capabilities();
916
- if( zCap[0] && !g.perm.History && db_get_boolean("auto-enable-hyperlinks",1)
916
+ if( zCap[0] && !g.perm.Hyperlink
917
+ && db_get_boolean("auto-enable-hyperlinks",1)
917918
&& isHuman(P("HTTP_USER_AGENT")) ){
918
- g.perm.History = 1;
919
+ g.perm.Hyperlink = 1;
920
+ g.javascriptHyperlink = 1;
919921
}
920922
921923
/* If the public-pages glob pattern is defined and REQUEST_URI matches
922924
** one of the globs in public-pages, then also add in all default-perms
923925
** permissions.
@@ -973,21 +975,21 @@
973975
}
974976
for(i=0; zCap[i]; i++){
975977
switch( zCap[i] ){
976978
case 's': g.perm.Setup = 1; /* Fall thru into Admin */
977979
case 'a': g.perm.Admin = g.perm.RdTkt = g.perm.WrTkt = g.perm.Zip =
978
- g.perm.RdWiki = g.perm.WrWiki = g.perm.NewWiki =
979
- g.perm.ApndWiki = g.perm.History = g.perm.Clone =
980
- g.perm.NewTkt = g.perm.Password = g.perm.RdAddr =
981
- g.perm.TktFmt = g.perm.Attach = g.perm.ApndTkt = 1;
982
- /* Fall thru into Read/Write */
980
+ g.perm.RdWiki = g.perm.WrWiki = g.perm.NewWiki =
981
+ g.perm.ApndWiki = g.perm.Hyperlink = g.perm.Clone =
982
+ g.perm.NewTkt = g.perm.Password = g.perm.RdAddr =
983
+ g.perm.TktFmt = g.perm.Attach = g.perm.ApndTkt = 1;
984
+ /* Fall thru into Read/Write */
983985
case 'i': g.perm.Read = g.perm.Write = 1; break;
984986
case 'o': g.perm.Read = 1; break;
985987
case 'z': g.perm.Zip = 1; break;
986988
987989
case 'd': g.perm.Delete = 1; break;
988
- case 'h': g.perm.History = 1; break;
990
+ case 'h': g.perm.Hyperlink = 1; break;
989991
case 'g': g.perm.Clone = 1; break;
990992
case 'p': g.perm.Password = 1; break;
991993
992994
case 'j': g.perm.RdWiki = 1; break;
993995
case 'k': g.perm.WrWiki = g.perm.RdWiki = g.perm.ApndWiki =1; break;
@@ -1053,15 +1055,14 @@
10531055
case 'c': rc = g.perm.ApndTkt; break;
10541056
case 'd': rc = g.perm.Delete; break;
10551057
case 'e': rc = g.perm.RdAddr; break;
10561058
case 'f': rc = g.perm.NewWiki; break;
10571059
case 'g': rc = g.perm.Clone; break;
1058
- case 'h': rc = g.perm.History; break;
1060
+ case 'h': rc = g.perm.Hyperlink; break;
10591061
case 'i': rc = g.perm.Write; break;
10601062
case 'j': rc = g.perm.RdWiki; break;
10611063
case 'k': rc = g.perm.WrWiki; break;
1062
- /* case 'l': */
10631064
case 'm': rc = g.perm.ApndWiki; break;
10641065
case 'n': rc = g.perm.NewTkt; break;
10651066
case 'o': rc = g.perm.Read; break;
10661067
case 'p': rc = g.perm.Password; break;
10671068
/* case 'q': */
@@ -1129,23 +1130,23 @@
11291130
assert(0);
11301131
}
11311132
}
11321133
11331134
/*
1134
-** Call this routine if the user lacks okHistory permission. If
1135
-** the anonymous user has okHistory permission, then paint a mesage
1135
+** Call this routine if the user lacks g.perm.Hyperlink permission. If
1136
+** the anonymous user has Hyperlink permission, then paint a mesage
11361137
** to inform the user that much more information is available by
11371138
** logging in as anonymous.
11381139
*/
11391140
void login_anonymous_available(void){
1140
- if( !g.perm.History &&
1141
+ if( !g.perm.Hyperlink &&
11411142
db_exists("SELECT 1 FROM user"
11421143
" WHERE login='anonymous'"
11431144
" AND cap LIKE '%%h%%'") ){
11441145
const char *zUrl = PD("REQUEST_URI", "index");
11451146
@ <p>Many <span class="disabled">hyperlinks are disabled.</span><br />
1146
- @ Use <a href="%s(g.zTop)/login?anon=1&amp;g=%T(zUrl)">anonymous login</a>
1147
+ @ Use <a href="%s(g.zTop)/login?anon=1&g=%T(zUrl)">anonymous login</a>
11471148
@ to enable hyperlinks.</p>
11481149
}
11491150
}
11501151
11511152
/*
11521153
--- src/login.c
+++ src/login.c
@@ -562,11 +562,11 @@
562 redirect_to_g();
563 }
564 }
565 style_header("Login/Logout");
566 @ %s(zErrMsg)
567 if( zGoto ){
568 @ <p>A login is required for <a href="%h(zGoto)">%h(zGoto)</a>.</p>
569 }
570 @ <form action="login" method="post">
571 if( zGoto ){
572 @ <input type="hidden" name="g" value="%h(zGoto)" />
@@ -911,13 +911,15 @@
911 }
912
913 /* Set the capabilities */
914 login_replace_capabilities(zCap, 0);
915 login_set_anon_nobody_capabilities();
916 if( zCap[0] && !g.perm.History && db_get_boolean("auto-enable-hyperlinks",1)
 
917 && isHuman(P("HTTP_USER_AGENT")) ){
918 g.perm.History = 1;
 
919 }
920
921 /* If the public-pages glob pattern is defined and REQUEST_URI matches
922 ** one of the globs in public-pages, then also add in all default-perms
923 ** permissions.
@@ -973,21 +975,21 @@
973 }
974 for(i=0; zCap[i]; i++){
975 switch( zCap[i] ){
976 case 's': g.perm.Setup = 1; /* Fall thru into Admin */
977 case 'a': g.perm.Admin = g.perm.RdTkt = g.perm.WrTkt = g.perm.Zip =
978 g.perm.RdWiki = g.perm.WrWiki = g.perm.NewWiki =
979 g.perm.ApndWiki = g.perm.History = g.perm.Clone =
980 g.perm.NewTkt = g.perm.Password = g.perm.RdAddr =
981 g.perm.TktFmt = g.perm.Attach = g.perm.ApndTkt = 1;
982 /* Fall thru into Read/Write */
983 case 'i': g.perm.Read = g.perm.Write = 1; break;
984 case 'o': g.perm.Read = 1; break;
985 case 'z': g.perm.Zip = 1; break;
986
987 case 'd': g.perm.Delete = 1; break;
988 case 'h': g.perm.History = 1; break;
989 case 'g': g.perm.Clone = 1; break;
990 case 'p': g.perm.Password = 1; break;
991
992 case 'j': g.perm.RdWiki = 1; break;
993 case 'k': g.perm.WrWiki = g.perm.RdWiki = g.perm.ApndWiki =1; break;
@@ -1053,15 +1055,14 @@
1053 case 'c': rc = g.perm.ApndTkt; break;
1054 case 'd': rc = g.perm.Delete; break;
1055 case 'e': rc = g.perm.RdAddr; break;
1056 case 'f': rc = g.perm.NewWiki; break;
1057 case 'g': rc = g.perm.Clone; break;
1058 case 'h': rc = g.perm.History; break;
1059 case 'i': rc = g.perm.Write; break;
1060 case 'j': rc = g.perm.RdWiki; break;
1061 case 'k': rc = g.perm.WrWiki; break;
1062 /* case 'l': */
1063 case 'm': rc = g.perm.ApndWiki; break;
1064 case 'n': rc = g.perm.NewTkt; break;
1065 case 'o': rc = g.perm.Read; break;
1066 case 'p': rc = g.perm.Password; break;
1067 /* case 'q': */
@@ -1129,23 +1130,23 @@
1129 assert(0);
1130 }
1131 }
1132
1133 /*
1134 ** Call this routine if the user lacks okHistory permission. If
1135 ** the anonymous user has okHistory permission, then paint a mesage
1136 ** to inform the user that much more information is available by
1137 ** logging in as anonymous.
1138 */
1139 void login_anonymous_available(void){
1140 if( !g.perm.History &&
1141 db_exists("SELECT 1 FROM user"
1142 " WHERE login='anonymous'"
1143 " AND cap LIKE '%%h%%'") ){
1144 const char *zUrl = PD("REQUEST_URI", "index");
1145 @ <p>Many <span class="disabled">hyperlinks are disabled.</span><br />
1146 @ Use <a href="%s(g.zTop)/login?anon=1&amp;g=%T(zUrl)">anonymous login</a>
1147 @ to enable hyperlinks.</p>
1148 }
1149 }
1150
1151 /*
1152
--- src/login.c
+++ src/login.c
@@ -562,11 +562,11 @@
562 redirect_to_g();
563 }
564 }
565 style_header("Login/Logout");
566 @ %s(zErrMsg)
567 if( zGoto && P("anon")==0 ){
568 @ <p>A login is required for <a href="%h(zGoto)">%h(zGoto)</a>.</p>
569 }
570 @ <form action="login" method="post">
571 if( zGoto ){
572 @ <input type="hidden" name="g" value="%h(zGoto)" />
@@ -911,13 +911,15 @@
911 }
912
913 /* Set the capabilities */
914 login_replace_capabilities(zCap, 0);
915 login_set_anon_nobody_capabilities();
916 if( zCap[0] && !g.perm.Hyperlink
917 && db_get_boolean("auto-enable-hyperlinks",1)
918 && isHuman(P("HTTP_USER_AGENT")) ){
919 g.perm.Hyperlink = 1;
920 g.javascriptHyperlink = 1;
921 }
922
923 /* If the public-pages glob pattern is defined and REQUEST_URI matches
924 ** one of the globs in public-pages, then also add in all default-perms
925 ** permissions.
@@ -973,21 +975,21 @@
975 }
976 for(i=0; zCap[i]; i++){
977 switch( zCap[i] ){
978 case 's': g.perm.Setup = 1; /* Fall thru into Admin */
979 case 'a': g.perm.Admin = g.perm.RdTkt = g.perm.WrTkt = g.perm.Zip =
980 g.perm.RdWiki = g.perm.WrWiki = g.perm.NewWiki =
981 g.perm.ApndWiki = g.perm.Hyperlink = g.perm.Clone =
982 g.perm.NewTkt = g.perm.Password = g.perm.RdAddr =
983 g.perm.TktFmt = g.perm.Attach = g.perm.ApndTkt = 1;
984 /* Fall thru into Read/Write */
985 case 'i': g.perm.Read = g.perm.Write = 1; break;
986 case 'o': g.perm.Read = 1; break;
987 case 'z': g.perm.Zip = 1; break;
988
989 case 'd': g.perm.Delete = 1; break;
990 case 'h': g.perm.Hyperlink = 1; break;
991 case 'g': g.perm.Clone = 1; break;
992 case 'p': g.perm.Password = 1; break;
993
994 case 'j': g.perm.RdWiki = 1; break;
995 case 'k': g.perm.WrWiki = g.perm.RdWiki = g.perm.ApndWiki =1; break;
@@ -1053,15 +1055,14 @@
1055 case 'c': rc = g.perm.ApndTkt; break;
1056 case 'd': rc = g.perm.Delete; break;
1057 case 'e': rc = g.perm.RdAddr; break;
1058 case 'f': rc = g.perm.NewWiki; break;
1059 case 'g': rc = g.perm.Clone; break;
1060 case 'h': rc = g.perm.Hyperlink; break;
1061 case 'i': rc = g.perm.Write; break;
1062 case 'j': rc = g.perm.RdWiki; break;
1063 case 'k': rc = g.perm.WrWiki; break;
 
1064 case 'm': rc = g.perm.ApndWiki; break;
1065 case 'n': rc = g.perm.NewTkt; break;
1066 case 'o': rc = g.perm.Read; break;
1067 case 'p': rc = g.perm.Password; break;
1068 /* case 'q': */
@@ -1129,23 +1130,23 @@
1130 assert(0);
1131 }
1132 }
1133
1134 /*
1135 ** Call this routine if the user lacks g.perm.Hyperlink permission. If
1136 ** the anonymous user has Hyperlink permission, then paint a mesage
1137 ** to inform the user that much more information is available by
1138 ** logging in as anonymous.
1139 */
1140 void login_anonymous_available(void){
1141 if( !g.perm.Hyperlink &&
1142 db_exists("SELECT 1 FROM user"
1143 " WHERE login='anonymous'"
1144 " AND cap LIKE '%%h%%'") ){
1145 const char *zUrl = PD("REQUEST_URI", "index");
1146 @ <p>Many <span class="disabled">hyperlinks are disabled.</span><br />
1147 @ Use <a href="%s(g.zTop)/login?anon=1&g=%T(zUrl)">anonymous login</a>
1148 @ to enable hyperlinks.</p>
1149 }
1150 }
1151
1152 /*
1153
+3 -2
--- src/main.c
+++ src/main.c
@@ -60,11 +60,11 @@
6060
char Delete; /* d: delete wiki or tickets */
6161
char Password; /* p: change password */
6262
char Query; /* q: create new reports */
6363
char Write; /* i: xfer inbound. checkin */
6464
char Read; /* o: xfer outbound. checkout */
65
- char History; /* h: access historical information. */
65
+ char Hyperlink; /* h: enable the display of hyperlinks */
6666
char Clone; /* g: clone */
6767
char RdWiki; /* j: view wiki via web */
6868
char NewWiki; /* f: create new wiki via web */
6969
char ApndWiki; /* m: append to wiki via web */
7070
char WrWiki; /* k: edit wiki via web */
@@ -135,11 +135,12 @@
135135
int xlinkClusterOnly; /* Set when cloning. Only process clusters */
136136
int fTimeFormat; /* 1 for UTC. 2 for localtime. 0 not yet selected */
137137
int *aCommitFile; /* Array of files to be committed */
138138
int markPrivate; /* All new artifacts are private if true */
139139
int clockSkewSeen; /* True if clocks on client and server out of sync */
140
- int isHTTP; /* True if running in server/CGI modes, else assume CLI. */
140
+ char isHTTP; /* True if erver/CGI modes, else assume CLI. */
141
+ char javascriptHyperlink; /* If true, set href= using script, not HTML */
141142
142143
int urlIsFile; /* True if a "file:" url */
143144
int urlIsHttps; /* True if a "https:" url */
144145
int urlIsSsh; /* True if an "ssh:" url */
145146
char *urlName; /* Hostname for http: or filename for file: */
146147
--- src/main.c
+++ src/main.c
@@ -60,11 +60,11 @@
60 char Delete; /* d: delete wiki or tickets */
61 char Password; /* p: change password */
62 char Query; /* q: create new reports */
63 char Write; /* i: xfer inbound. checkin */
64 char Read; /* o: xfer outbound. checkout */
65 char History; /* h: access historical information. */
66 char Clone; /* g: clone */
67 char RdWiki; /* j: view wiki via web */
68 char NewWiki; /* f: create new wiki via web */
69 char ApndWiki; /* m: append to wiki via web */
70 char WrWiki; /* k: edit wiki via web */
@@ -135,11 +135,12 @@
135 int xlinkClusterOnly; /* Set when cloning. Only process clusters */
136 int fTimeFormat; /* 1 for UTC. 2 for localtime. 0 not yet selected */
137 int *aCommitFile; /* Array of files to be committed */
138 int markPrivate; /* All new artifacts are private if true */
139 int clockSkewSeen; /* True if clocks on client and server out of sync */
140 int isHTTP; /* True if running in server/CGI modes, else assume CLI. */
 
141
142 int urlIsFile; /* True if a "file:" url */
143 int urlIsHttps; /* True if a "https:" url */
144 int urlIsSsh; /* True if an "ssh:" url */
145 char *urlName; /* Hostname for http: or filename for file: */
146
--- src/main.c
+++ src/main.c
@@ -60,11 +60,11 @@
60 char Delete; /* d: delete wiki or tickets */
61 char Password; /* p: change password */
62 char Query; /* q: create new reports */
63 char Write; /* i: xfer inbound. checkin */
64 char Read; /* o: xfer outbound. checkout */
65 char Hyperlink; /* h: enable the display of hyperlinks */
66 char Clone; /* g: clone */
67 char RdWiki; /* j: view wiki via web */
68 char NewWiki; /* f: create new wiki via web */
69 char ApndWiki; /* m: append to wiki via web */
70 char WrWiki; /* k: edit wiki via web */
@@ -135,11 +135,12 @@
135 int xlinkClusterOnly; /* Set when cloning. Only process clusters */
136 int fTimeFormat; /* 1 for UTC. 2 for localtime. 0 not yet selected */
137 int *aCommitFile; /* Array of files to be committed */
138 int markPrivate; /* All new artifacts are private if true */
139 int clockSkewSeen; /* True if clocks on client and server out of sync */
140 char isHTTP; /* True if erver/CGI modes, else assume CLI. */
141 char javascriptHyperlink; /* If true, set href= using script, not HTML */
142
143 int urlIsFile; /* True if a "file:" url */
144 int urlIsHttps; /* True if a "https:" url */
145 int urlIsSsh; /* True if an "ssh:" url */
146 char *urlName; /* Hostname for http: or filename for file: */
147
--- src/printf.c
+++ src/printf.c
@@ -47,10 +47,11 @@
4747
#define etFOSSILIZE 19 /* The fossil header encoding format. */
4848
#define etPATH 20 /* Path type */
4949
#define etWIKISTR 21 /* Wiki text rendered from a char*: %w */
5050
#define etWIKIBLOB 22 /* Wiki text rendered from a Blob*: %W */
5151
#define etSTRINGID 23 /* String with length limit for a UUID prefix: %S */
52
+#define etROOT 24 /* String value of g.zTop: % */
5253
5354
5455
/*
5556
** An "etByte" is an 8-bit unsigned value.
5657
*/
@@ -93,10 +94,11 @@
9394
{ 'b', 0, 2, etBLOB, 0, 0 },
9495
{ 'B', 0, 2, etBLOBSQL, 0, 0 },
9596
{ 'w', 0, 2, etWIKISTR, 0, 0 },
9697
{ 'W', 0, 2, etWIKIBLOB, 0, 0 },
9798
{ 'h', 0, 4, etHTMLIZE, 0, 0 },
99
+ { 'R', 0, 0, etROOT, 0, 0 },
98100
{ 't', 0, 4, etHTTPIZE, 0, 0 }, /* "/" -> "%2F" */
99101
{ 'T', 0, 4, etURLIZE, 0, 0 }, /* "/" unchanged */
100102
{ 'F', 0, 4, etFOSSILIZE, 0, 0 },
101103
{ 'S', 0, 4, etSTRINGID, 0, 0 },
102104
{ 'c', 0, 0, etCHARX, 0, 0 },
@@ -570,10 +572,15 @@
570572
bufpt[i]=e[i];
571573
}
572574
}
573575
bufpt[length]='\0';
574576
break;
577
+ }
578
+ case etROOT: {
579
+ bufpt = g.zTop;
580
+ length = (int)strlen(bufpt);
581
+ break;
575582
}
576583
case etSTRINGID: {
577584
precision = 16;
578585
/* Fall through */
579586
}
580587
--- src/printf.c
+++ src/printf.c
@@ -47,10 +47,11 @@
47 #define etFOSSILIZE 19 /* The fossil header encoding format. */
48 #define etPATH 20 /* Path type */
49 #define etWIKISTR 21 /* Wiki text rendered from a char*: %w */
50 #define etWIKIBLOB 22 /* Wiki text rendered from a Blob*: %W */
51 #define etSTRINGID 23 /* String with length limit for a UUID prefix: %S */
 
52
53
54 /*
55 ** An "etByte" is an 8-bit unsigned value.
56 */
@@ -93,10 +94,11 @@
93 { 'b', 0, 2, etBLOB, 0, 0 },
94 { 'B', 0, 2, etBLOBSQL, 0, 0 },
95 { 'w', 0, 2, etWIKISTR, 0, 0 },
96 { 'W', 0, 2, etWIKIBLOB, 0, 0 },
97 { 'h', 0, 4, etHTMLIZE, 0, 0 },
 
98 { 't', 0, 4, etHTTPIZE, 0, 0 }, /* "/" -> "%2F" */
99 { 'T', 0, 4, etURLIZE, 0, 0 }, /* "/" unchanged */
100 { 'F', 0, 4, etFOSSILIZE, 0, 0 },
101 { 'S', 0, 4, etSTRINGID, 0, 0 },
102 { 'c', 0, 0, etCHARX, 0, 0 },
@@ -570,10 +572,15 @@
570 bufpt[i]=e[i];
571 }
572 }
573 bufpt[length]='\0';
574 break;
 
 
 
 
 
575 }
576 case etSTRINGID: {
577 precision = 16;
578 /* Fall through */
579 }
580
--- src/printf.c
+++ src/printf.c
@@ -47,10 +47,11 @@
47 #define etFOSSILIZE 19 /* The fossil header encoding format. */
48 #define etPATH 20 /* Path type */
49 #define etWIKISTR 21 /* Wiki text rendered from a char*: %w */
50 #define etWIKIBLOB 22 /* Wiki text rendered from a Blob*: %W */
51 #define etSTRINGID 23 /* String with length limit for a UUID prefix: %S */
52 #define etROOT 24 /* String value of g.zTop: % */
53
54
55 /*
56 ** An "etByte" is an 8-bit unsigned value.
57 */
@@ -93,10 +94,11 @@
94 { 'b', 0, 2, etBLOB, 0, 0 },
95 { 'B', 0, 2, etBLOBSQL, 0, 0 },
96 { 'w', 0, 2, etWIKISTR, 0, 0 },
97 { 'W', 0, 2, etWIKIBLOB, 0, 0 },
98 { 'h', 0, 4, etHTMLIZE, 0, 0 },
99 { 'R', 0, 0, etROOT, 0, 0 },
100 { 't', 0, 4, etHTTPIZE, 0, 0 }, /* "/" -> "%2F" */
101 { 'T', 0, 4, etURLIZE, 0, 0 }, /* "/" unchanged */
102 { 'F', 0, 4, etFOSSILIZE, 0, 0 },
103 { 'S', 0, 4, etSTRINGID, 0, 0 },
104 { 'c', 0, 0, etCHARX, 0, 0 },
@@ -570,10 +572,15 @@
572 bufpt[i]=e[i];
573 }
574 }
575 bufpt[length]='\0';
576 break;
577 }
578 case etROOT: {
579 bufpt = g.zTop;
580 length = (int)strlen(bufpt);
581 break;
582 }
583 case etSTRINGID: {
584 precision = 16;
585 /* Fall through */
586 }
587
+12 -13
--- src/report.c
+++ src/report.c
@@ -56,26 +56,29 @@
5656
cnt++;
5757
blob_appendf(&ril, "<li>");
5858
if( zTitle[0] == '_' ){
5959
blob_appendf(&ril, "%s", zTitle);
6060
} else {
61
- blob_appendf(&ril, "<a href=\"rptview?rn=%d\" rel=\"nofollow\">%h</a>", rn, zTitle);
61
+ blob_appendf(&ril, "%z%h</a>", href("%R/rptview?rn=%d", rn), zTitle);
6262
}
6363
blob_appendf(&ril, "&nbsp;&nbsp;&nbsp;");
6464
if( g.perm.Write && zOwner && zOwner[0] ){
6565
blob_appendf(&ril, "(by <i>%h</i></i>) ", zOwner);
6666
}
6767
if( g.perm.TktFmt ){
68
- blob_appendf(&ril, "[<a href=\"rptedit?rn=%d&amp;copy=1\" rel=\"nofollow\">copy</a>] ", rn);
68
+ blob_appendf(&ril, "[%zcopy</a>] ",
69
+ href("%R/rptedit?rn=%d&copy=1", rn));
6970
}
7071
if( g.perm.Admin
7172
|| (g.perm.WrTkt && zOwner && fossil_strcmp(g.zLogin,zOwner)==0)
7273
){
73
- blob_appendf(&ril, "[<a href=\"rptedit?rn=%d\" rel=\"nofollow\">edit</a>] ", rn);
74
+ blob_appendf(&ril, "[%zedit</a>]",
75
+ href("%R/rptedit?rn=%d", rn));
7476
}
7577
if( g.perm.TktFmt ){
76
- blob_appendf(&ril, "[<a href=\"rptsql?rn=%d\" rel=\"nofollow\">sql</a>] ", rn);
78
+ blob_appendf(&ril, "[%zsql</a>]",
79
+ href("%R/rptsql?rn=%d", rn));
7780
}
7881
blob_appendf(&ril, "</li>\n");
7982
}
8083
8184
Th_Store("report_items", blob_str(&ril));
@@ -416,11 +419,11 @@
416419
}
417420
}
418421
if( zOwner==0 ) zOwner = g.zLogin;
419422
style_submenu_element("Cancel", "Cancel", "reportlist");
420423
if( rn>0 ){
421
- style_submenu_element("Delete", "Delete", "rptedit?rn=%d&amp;del1=1", rn);
424
+ style_submenu_element("Delete", "Delete", "rptedit?rn=%d&del1=1", rn);
422425
}
423426
style_header(rn>0 ? "Edit Report Format":"Create New Report Format");
424427
if( zErr ){
425428
@ <blockquote class="reportError">%h(zErr)</blockquote>
426429
}
@@ -720,11 +723,11 @@
720723
if( i==pState->iBg ) continue;
721724
zData = azArg[i];
722725
if( zData==0 ) zData = "";
723726
if( pState->iNewRow>=0 && i>=pState->iNewRow ){
724727
if( zTid && g.perm.Write ){
725
- @ <td valign="top"><a href="tktedit/%h(zTid)">edit</a></td>
728
+ @ <td valign="top">%z(href("%R/tktedit/%h",zTid))edit</a></td>
726729
zTid = 0;
727730
}
728731
if( zData[0] ){
729732
Blob content;
730733
@ </tr><tr style="background-color:%h(zBg)"><td colspan=%d(pState->nCol)>
@@ -732,25 +735,21 @@
732735
wiki_convert(&content, 0, 0);
733736
blob_reset(&content);
734737
}
735738
}else if( azName[i][0]=='#' ){
736739
zTid = zData;
737
- if( g.perm.History ){
738
- @ <td valign="top"><a href="tktview?name=%h(zData)">%h(zData)</a></td>
739
- }else{
740
- @ <td valign="top">%h(zData)</td>
741
- }
740
+ @ <td valign="top">%z(href("%R/tktview?name=%h",zData))%h(zData)</a></td>
742741
}else if( zData[0]==0 ){
743742
@ <td valign="top">&nbsp;</td>
744743
}else{
745744
@ <td valign="top">
746745
@ %h(zData)
747746
@ </td>
748747
}
749748
}
750749
if( zTid && g.perm.Write ){
751
- @ <td valign="top"><a href="tktedit/%h(zTid)">edit</a></td>
750
+ @ <td valign="top">%z(href("%R/tktedit/%h",zTid))edit</a></td>
752751
}
753752
@ </tr>
754753
return 0;
755754
}
756755
@@ -949,11 +948,11 @@
949948
if( !tabs ){
950949
struct GenerateHTML sState;
951950
952951
db_multi_exec("PRAGMA empty_result_callbacks=ON");
953952
style_submenu_element("Raw", "Raw",
954
- "rptview?tablist=1&amp;%h", PD("QUERY_STRING",""));
953
+ "rptview?tablist=1&%h", PD("QUERY_STRING",""));
955954
if( g.perm.Admin
956955
|| (g.perm.TktFmt && g.zLogin && fossil_strcmp(g.zLogin,zOwner)==0) ){
957956
style_submenu_element("Edit", "Edit", "rptedit?rn=%d", rn);
958957
}
959958
if( g.perm.TktFmt ){
960959
--- src/report.c
+++ src/report.c
@@ -56,26 +56,29 @@
56 cnt++;
57 blob_appendf(&ril, "<li>");
58 if( zTitle[0] == '_' ){
59 blob_appendf(&ril, "%s", zTitle);
60 } else {
61 blob_appendf(&ril, "<a href=\"rptview?rn=%d\" rel=\"nofollow\">%h</a>", rn, zTitle);
62 }
63 blob_appendf(&ril, "&nbsp;&nbsp;&nbsp;");
64 if( g.perm.Write && zOwner && zOwner[0] ){
65 blob_appendf(&ril, "(by <i>%h</i></i>) ", zOwner);
66 }
67 if( g.perm.TktFmt ){
68 blob_appendf(&ril, "[<a href=\"rptedit?rn=%d&amp;copy=1\" rel=\"nofollow\">copy</a>] ", rn);
 
69 }
70 if( g.perm.Admin
71 || (g.perm.WrTkt && zOwner && fossil_strcmp(g.zLogin,zOwner)==0)
72 ){
73 blob_appendf(&ril, "[<a href=\"rptedit?rn=%d\" rel=\"nofollow\">edit</a>] ", rn);
 
74 }
75 if( g.perm.TktFmt ){
76 blob_appendf(&ril, "[<a href=\"rptsql?rn=%d\" rel=\"nofollow\">sql</a>] ", rn);
 
77 }
78 blob_appendf(&ril, "</li>\n");
79 }
80
81 Th_Store("report_items", blob_str(&ril));
@@ -416,11 +419,11 @@
416 }
417 }
418 if( zOwner==0 ) zOwner = g.zLogin;
419 style_submenu_element("Cancel", "Cancel", "reportlist");
420 if( rn>0 ){
421 style_submenu_element("Delete", "Delete", "rptedit?rn=%d&amp;del1=1", rn);
422 }
423 style_header(rn>0 ? "Edit Report Format":"Create New Report Format");
424 if( zErr ){
425 @ <blockquote class="reportError">%h(zErr)</blockquote>
426 }
@@ -720,11 +723,11 @@
720 if( i==pState->iBg ) continue;
721 zData = azArg[i];
722 if( zData==0 ) zData = "";
723 if( pState->iNewRow>=0 && i>=pState->iNewRow ){
724 if( zTid && g.perm.Write ){
725 @ <td valign="top"><a href="tktedit/%h(zTid)">edit</a></td>
726 zTid = 0;
727 }
728 if( zData[0] ){
729 Blob content;
730 @ </tr><tr style="background-color:%h(zBg)"><td colspan=%d(pState->nCol)>
@@ -732,25 +735,21 @@
732 wiki_convert(&content, 0, 0);
733 blob_reset(&content);
734 }
735 }else if( azName[i][0]=='#' ){
736 zTid = zData;
737 if( g.perm.History ){
738 @ <td valign="top"><a href="tktview?name=%h(zData)">%h(zData)</a></td>
739 }else{
740 @ <td valign="top">%h(zData)</td>
741 }
742 }else if( zData[0]==0 ){
743 @ <td valign="top">&nbsp;</td>
744 }else{
745 @ <td valign="top">
746 @ %h(zData)
747 @ </td>
748 }
749 }
750 if( zTid && g.perm.Write ){
751 @ <td valign="top"><a href="tktedit/%h(zTid)">edit</a></td>
752 }
753 @ </tr>
754 return 0;
755 }
756
@@ -949,11 +948,11 @@
949 if( !tabs ){
950 struct GenerateHTML sState;
951
952 db_multi_exec("PRAGMA empty_result_callbacks=ON");
953 style_submenu_element("Raw", "Raw",
954 "rptview?tablist=1&amp;%h", PD("QUERY_STRING",""));
955 if( g.perm.Admin
956 || (g.perm.TktFmt && g.zLogin && fossil_strcmp(g.zLogin,zOwner)==0) ){
957 style_submenu_element("Edit", "Edit", "rptedit?rn=%d", rn);
958 }
959 if( g.perm.TktFmt ){
960
--- src/report.c
+++ src/report.c
@@ -56,26 +56,29 @@
56 cnt++;
57 blob_appendf(&ril, "<li>");
58 if( zTitle[0] == '_' ){
59 blob_appendf(&ril, "%s", zTitle);
60 } else {
61 blob_appendf(&ril, "%z%h</a>", href("%R/rptview?rn=%d", rn), zTitle);
62 }
63 blob_appendf(&ril, "&nbsp;&nbsp;&nbsp;");
64 if( g.perm.Write && zOwner && zOwner[0] ){
65 blob_appendf(&ril, "(by <i>%h</i></i>) ", zOwner);
66 }
67 if( g.perm.TktFmt ){
68 blob_appendf(&ril, "[%zcopy</a>] ",
69 href("%R/rptedit?rn=%d&copy=1", rn));
70 }
71 if( g.perm.Admin
72 || (g.perm.WrTkt && zOwner && fossil_strcmp(g.zLogin,zOwner)==0)
73 ){
74 blob_appendf(&ril, "[%zedit</a>]",
75 href("%R/rptedit?rn=%d", rn));
76 }
77 if( g.perm.TktFmt ){
78 blob_appendf(&ril, "[%zsql</a>]",
79 href("%R/rptsql?rn=%d", rn));
80 }
81 blob_appendf(&ril, "</li>\n");
82 }
83
84 Th_Store("report_items", blob_str(&ril));
@@ -416,11 +419,11 @@
419 }
420 }
421 if( zOwner==0 ) zOwner = g.zLogin;
422 style_submenu_element("Cancel", "Cancel", "reportlist");
423 if( rn>0 ){
424 style_submenu_element("Delete", "Delete", "rptedit?rn=%d&del1=1", rn);
425 }
426 style_header(rn>0 ? "Edit Report Format":"Create New Report Format");
427 if( zErr ){
428 @ <blockquote class="reportError">%h(zErr)</blockquote>
429 }
@@ -720,11 +723,11 @@
723 if( i==pState->iBg ) continue;
724 zData = azArg[i];
725 if( zData==0 ) zData = "";
726 if( pState->iNewRow>=0 && i>=pState->iNewRow ){
727 if( zTid && g.perm.Write ){
728 @ <td valign="top">%z(href("%R/tktedit/%h",zTid))edit</a></td>
729 zTid = 0;
730 }
731 if( zData[0] ){
732 Blob content;
733 @ </tr><tr style="background-color:%h(zBg)"><td colspan=%d(pState->nCol)>
@@ -732,25 +735,21 @@
735 wiki_convert(&content, 0, 0);
736 blob_reset(&content);
737 }
738 }else if( azName[i][0]=='#' ){
739 zTid = zData;
740 @ <td valign="top">%z(href("%R/tktview?name=%h",zData))%h(zData)</a></td>
 
 
 
 
741 }else if( zData[0]==0 ){
742 @ <td valign="top">&nbsp;</td>
743 }else{
744 @ <td valign="top">
745 @ %h(zData)
746 @ </td>
747 }
748 }
749 if( zTid && g.perm.Write ){
750 @ <td valign="top">%z(href("%R/tktedit/%h",zTid))edit</a></td>
751 }
752 @ </tr>
753 return 0;
754 }
755
@@ -949,11 +948,11 @@
948 if( !tabs ){
949 struct GenerateHTML sState;
950
951 db_multi_exec("PRAGMA empty_result_callbacks=ON");
952 style_submenu_element("Raw", "Raw",
953 "rptview?tablist=1&%h", PD("QUERY_STRING",""));
954 if( g.perm.Admin
955 || (g.perm.TktFmt && g.zLogin && fossil_strcmp(g.zLogin,zOwner)==0) ){
956 style_submenu_element("Edit", "Edit", "rptedit?rn=%d", rn);
957 }
958 if( g.perm.TktFmt ){
959
+23 -15
--- src/setup.c
+++ src/setup.c
@@ -524,11 +524,11 @@
524524
@ <input type="checkbox" name="ad"%s(oad) />%s(B('d'))Delete<br />
525525
@ <input type="checkbox" name="ae"%s(oae) />%s(B('e'))Email<br />
526526
@ <input type="checkbox" name="ap"%s(oap) />%s(B('p'))Password<br />
527527
@ <input type="checkbox" name="ai"%s(oai) />%s(B('i'))Check-In<br />
528528
@ <input type="checkbox" name="ao"%s(oao) />%s(B('o'))Check-Out<br />
529
- @ <input type="checkbox" name="ah"%s(oah) />%s(B('h'))History<br />
529
+ @ <input type="checkbox" name="ah"%s(oah) />%s(B('h'))Hyperlinks<br />
530530
@ <input type="checkbox" name="au"%s(oau) />%s(B('u'))Reader<br />
531531
@ <input type="checkbox" name="av"%s(oav) />%s(B('v'))Developer<br />
532532
@ <input type="checkbox" name="ag"%s(oag) />%s(B('g'))Clone<br />
533533
@ <input type="checkbox" name="aj"%s(oaj) />%s(B('j'))Read Wiki<br />
534534
@ <input type="checkbox" name="af"%s(oaf) />%s(B('f'))New Wiki<br />
@@ -625,24 +625,24 @@
625625
@ is first posted. The <span class="usertype">Setup</span> user can
626626
@ delete anything at any time.
627627
@ </p></li>
628628
@
629629
@ <li><p>
630
- @ The <span class="capability">History</span> privilege allows a user
630
+ @ The <span class="capability">Hyperlinks</span> privilege allows a user
631631
@ to see most hyperlinks. This is recommended ON for most logged-in users
632632
@ but OFF for user "nobody" to avoid problems with spiders trying to walk
633
- @ every historical version of every baseline and file.
633
+ @ every diff and annotation of every historical check-in and file.
634634
@ </p></li>
635635
@
636636
@ <li><p>
637637
@ The <span class="capability">Zip</span> privilege allows a user to
638638
@ see the "download as ZIP"
639639
@ hyperlink and permits access to the <tt>/zip</tt> page. This allows
640640
@ users to download ZIP archives without granting other rights like
641641
@ <span class="capability">Read</span> or
642
- @ <span class="capability">History</span>. This privilege is recommended for
643
- @ user <span class="usertype">nobody</span> so that automatic package
642
+ @ <span class="capability">Hyperlink</span>. The "z" privilege is recommended
643
+ @ for user <span class="usertype">nobody</span> so that automatic package
644644
@ downloaders can obtain the sources without going through the login
645645
@ procedure.
646646
@ </p></li>
647647
@
648648
@ <li><p>
@@ -704,12 +704,12 @@
704704
@ To disable universal access to the repository, make sure no user named
705705
@ <span class="usertype">nobody</span> exists or that the
706706
@ <span class="usertype">nobody</span> user has no capabilities
707707
@ enabled. The password for <span class="usertype">nobody</span> is ignore.
708708
@ To avoid problems with spiders overloading the server, it is recommended
709
- @ that the <span class="capability">h</span> (History) capability be turned
710
- @ off for the <span class="usertype">nobody</span> user.
709
+ @ that the <span class="capability">h</span> (Hyperlinks) capability be
710
+ @ turned off for the <span class="usertype">nobody</span> user.
711711
@ </p></li>
712712
@
713713
@ <li><p>
714714
@ Login is required for user <span class="usertype">anonymous</span> but the
715715
@ password is displayed on the login screen beside the password entry box
@@ -891,19 +891,27 @@
891891
@ than this, then the client will issue multiple HTTP requests.
892892
@ Values below 1 million are not recommended. 5 million is a
893893
@ reasonable number.</p>
894894
895895
@ <hr />
896
- onoff_attribute("Enable hyperlinks for \"nobody\" based on User-Agent",
897
- "auto-enable-hyperlinks", "autohyperlink", 1);
896
+ onoff_attribute(
897
+ "Enable hyperlinks for \"nobody\" based on User-Agent and Javascript",
898
+ "auto-enable-hyperlinks", "autohyperlink", 1);
898899
@ <p>Enable hyperlinks (the equivalent of the "h" permission) for all users
899
- @ including user "nobody", as long as the User-Agent string in the HTTP header
900
- @ indicates that the request is coming from an actual human being and not a
901
- @ a robot or script. Note: Bots can specify whatever User-Agent string they
902
- @ that want. So a bot that wants to impersonate a human can easily do so.
903
- @ Hence, this technique does not necessarily exclude malicious bots.
904
- @ </p>
900
+ @ including user "nobody", as long as (1) the User-Agent string in the
901
+ @ HTTP header indicates that the request is coming from an actual human
902
+ @ being and not a a robot or spider and (2) the user agent is able to
903
+ @ run Javascript in order to set the href= attribute of hyperlinks. Bots
904
+ @ and spiders can specify whatever User-Agent string they that want and
905
+ @ they can run javascript just like browsers. But most bots don't go to
906
+ @ that much trouble so this is normally an effective defense.</p>
907
+ @
908
+ @ <p>You do not normally want a bot to walk your entire repository because
909
+ @ if it does, your server will end up computing diffs and annotations for
910
+ @ every historical version of every file and creating ZIPs and tarballs of
911
+ @ every historical check-in, which can use a lot of CPU and bandwidth
912
+ @ even for relatively small projects.</p>
905913
906914
@ <hr />
907915
entry_attribute("Public pages", 30, "public-pages",
908916
"pubpage", "");
909917
@ <p>A comma-separated list of glob patterns for pages that are accessible
910918
--- src/setup.c
+++ src/setup.c
@@ -524,11 +524,11 @@
524 @ <input type="checkbox" name="ad"%s(oad) />%s(B('d'))Delete<br />
525 @ <input type="checkbox" name="ae"%s(oae) />%s(B('e'))Email<br />
526 @ <input type="checkbox" name="ap"%s(oap) />%s(B('p'))Password<br />
527 @ <input type="checkbox" name="ai"%s(oai) />%s(B('i'))Check-In<br />
528 @ <input type="checkbox" name="ao"%s(oao) />%s(B('o'))Check-Out<br />
529 @ <input type="checkbox" name="ah"%s(oah) />%s(B('h'))History<br />
530 @ <input type="checkbox" name="au"%s(oau) />%s(B('u'))Reader<br />
531 @ <input type="checkbox" name="av"%s(oav) />%s(B('v'))Developer<br />
532 @ <input type="checkbox" name="ag"%s(oag) />%s(B('g'))Clone<br />
533 @ <input type="checkbox" name="aj"%s(oaj) />%s(B('j'))Read Wiki<br />
534 @ <input type="checkbox" name="af"%s(oaf) />%s(B('f'))New Wiki<br />
@@ -625,24 +625,24 @@
625 @ is first posted. The <span class="usertype">Setup</span> user can
626 @ delete anything at any time.
627 @ </p></li>
628 @
629 @ <li><p>
630 @ The <span class="capability">History</span> privilege allows a user
631 @ to see most hyperlinks. This is recommended ON for most logged-in users
632 @ but OFF for user "nobody" to avoid problems with spiders trying to walk
633 @ every historical version of every baseline and file.
634 @ </p></li>
635 @
636 @ <li><p>
637 @ The <span class="capability">Zip</span> privilege allows a user to
638 @ see the "download as ZIP"
639 @ hyperlink and permits access to the <tt>/zip</tt> page. This allows
640 @ users to download ZIP archives without granting other rights like
641 @ <span class="capability">Read</span> or
642 @ <span class="capability">History</span>. This privilege is recommended for
643 @ user <span class="usertype">nobody</span> so that automatic package
644 @ downloaders can obtain the sources without going through the login
645 @ procedure.
646 @ </p></li>
647 @
648 @ <li><p>
@@ -704,12 +704,12 @@
704 @ To disable universal access to the repository, make sure no user named
705 @ <span class="usertype">nobody</span> exists or that the
706 @ <span class="usertype">nobody</span> user has no capabilities
707 @ enabled. The password for <span class="usertype">nobody</span> is ignore.
708 @ To avoid problems with spiders overloading the server, it is recommended
709 @ that the <span class="capability">h</span> (History) capability be turned
710 @ off for the <span class="usertype">nobody</span> user.
711 @ </p></li>
712 @
713 @ <li><p>
714 @ Login is required for user <span class="usertype">anonymous</span> but the
715 @ password is displayed on the login screen beside the password entry box
@@ -891,19 +891,27 @@
891 @ than this, then the client will issue multiple HTTP requests.
892 @ Values below 1 million are not recommended. 5 million is a
893 @ reasonable number.</p>
894
895 @ <hr />
896 onoff_attribute("Enable hyperlinks for \"nobody\" based on User-Agent",
897 "auto-enable-hyperlinks", "autohyperlink", 1);
 
898 @ <p>Enable hyperlinks (the equivalent of the "h" permission) for all users
899 @ including user "nobody", as long as the User-Agent string in the HTTP header
900 @ indicates that the request is coming from an actual human being and not a
901 @ a robot or script. Note: Bots can specify whatever User-Agent string they
902 @ that want. So a bot that wants to impersonate a human can easily do so.
903 @ Hence, this technique does not necessarily exclude malicious bots.
904 @ </p>
 
 
 
 
 
 
 
905
906 @ <hr />
907 entry_attribute("Public pages", 30, "public-pages",
908 "pubpage", "");
909 @ <p>A comma-separated list of glob patterns for pages that are accessible
910
--- src/setup.c
+++ src/setup.c
@@ -524,11 +524,11 @@
524 @ <input type="checkbox" name="ad"%s(oad) />%s(B('d'))Delete<br />
525 @ <input type="checkbox" name="ae"%s(oae) />%s(B('e'))Email<br />
526 @ <input type="checkbox" name="ap"%s(oap) />%s(B('p'))Password<br />
527 @ <input type="checkbox" name="ai"%s(oai) />%s(B('i'))Check-In<br />
528 @ <input type="checkbox" name="ao"%s(oao) />%s(B('o'))Check-Out<br />
529 @ <input type="checkbox" name="ah"%s(oah) />%s(B('h'))Hyperlinks<br />
530 @ <input type="checkbox" name="au"%s(oau) />%s(B('u'))Reader<br />
531 @ <input type="checkbox" name="av"%s(oav) />%s(B('v'))Developer<br />
532 @ <input type="checkbox" name="ag"%s(oag) />%s(B('g'))Clone<br />
533 @ <input type="checkbox" name="aj"%s(oaj) />%s(B('j'))Read Wiki<br />
534 @ <input type="checkbox" name="af"%s(oaf) />%s(B('f'))New Wiki<br />
@@ -625,24 +625,24 @@
625 @ is first posted. The <span class="usertype">Setup</span> user can
626 @ delete anything at any time.
627 @ </p></li>
628 @
629 @ <li><p>
630 @ The <span class="capability">Hyperlinks</span> privilege allows a user
631 @ to see most hyperlinks. This is recommended ON for most logged-in users
632 @ but OFF for user "nobody" to avoid problems with spiders trying to walk
633 @ every diff and annotation of every historical check-in and file.
634 @ </p></li>
635 @
636 @ <li><p>
637 @ The <span class="capability">Zip</span> privilege allows a user to
638 @ see the "download as ZIP"
639 @ hyperlink and permits access to the <tt>/zip</tt> page. This allows
640 @ users to download ZIP archives without granting other rights like
641 @ <span class="capability">Read</span> or
642 @ <span class="capability">Hyperlink</span>. The "z" privilege is recommended
643 @ for user <span class="usertype">nobody</span> so that automatic package
644 @ downloaders can obtain the sources without going through the login
645 @ procedure.
646 @ </p></li>
647 @
648 @ <li><p>
@@ -704,12 +704,12 @@
704 @ To disable universal access to the repository, make sure no user named
705 @ <span class="usertype">nobody</span> exists or that the
706 @ <span class="usertype">nobody</span> user has no capabilities
707 @ enabled. The password for <span class="usertype">nobody</span> is ignore.
708 @ To avoid problems with spiders overloading the server, it is recommended
709 @ that the <span class="capability">h</span> (Hyperlinks) capability be
710 @ turned off for the <span class="usertype">nobody</span> user.
711 @ </p></li>
712 @
713 @ <li><p>
714 @ Login is required for user <span class="usertype">anonymous</span> but the
715 @ password is displayed on the login screen beside the password entry box
@@ -891,19 +891,27 @@
891 @ than this, then the client will issue multiple HTTP requests.
892 @ Values below 1 million are not recommended. 5 million is a
893 @ reasonable number.</p>
894
895 @ <hr />
896 onoff_attribute(
897 "Enable hyperlinks for \"nobody\" based on User-Agent and Javascript",
898 "auto-enable-hyperlinks", "autohyperlink", 1);
899 @ <p>Enable hyperlinks (the equivalent of the "h" permission) for all users
900 @ including user "nobody", as long as (1) the User-Agent string in the
901 @ HTTP header indicates that the request is coming from an actual human
902 @ being and not a a robot or spider and (2) the user agent is able to
903 @ run Javascript in order to set the href= attribute of hyperlinks. Bots
904 @ and spiders can specify whatever User-Agent string they that want and
905 @ they can run javascript just like browsers. But most bots don't go to
906 @ that much trouble so this is normally an effective defense.</p>
907 @
908 @ <p>You do not normally want a bot to walk your entire repository because
909 @ if it does, your server will end up computing diffs and annotations for
910 @ every historical version of every file and creating ZIPs and tarballs of
911 @ every historical check-in, which can use a lot of CPU and bandwidth
912 @ even for relatively small projects.</p>
913
914 @ <hr />
915 entry_attribute("Public pages", 30, "public-pages",
916 "pubpage", "");
917 @ <p>A comma-separated list of glob patterns for pages that are accessible
918
+87
--- src/style.c
+++ src/style.c
@@ -45,10 +45,94 @@
4545
/*
4646
** remember, if a sidebox was used
4747
*/
4848
static int sideboxUsed = 0;
4949
50
+
51
+/*
52
+** List of hyperlinks that need to be resolved by javascript in
53
+** the footer.
54
+*/
55
+char **aHref = 0;
56
+int nHref = 0;
57
+int nHrefAlloc = 0;
58
+
59
+/*
60
+** Generate and return a anchor tag like this:
61
+**
62
+** <a href="URL">
63
+** or <a id="ID">
64
+**
65
+** The form of the anchor tag is determined by the g.javascriptHyperlink
66
+** variable. The href="URL" form is used if g.javascriptHyperlink is false.
67
+** If g.javascriptHyperlink is true then the
68
+** id="ID" form is used and javascript is generated in the footer to cause
69
+** href values to be inserted after the page has loaded. If
70
+** g.perm.History is false, then the <a id="ID"> form is still
71
+** generated but the javascript is not generated so the links never
72
+** activate.
73
+**
74
+** Filling in the href="URL" using javascript is a defense against bots.
75
+**
76
+** The name of this routine is deliberately kept short so that can be
77
+** easily used within @-lines. Example:
78
+**
79
+** @ %z(href("%R/artifact/%s",zUuid))%h(zFN)</a>
80
+**
81
+** Note %z format. The string returned by this function is always
82
+** obtained from fossil_malloc() so rendering it with %z will reclaim
83
+** that memory space.
84
+**
85
+** There are two versions of this routine: href() does a plain hyperlink
86
+** and xhref() adds extra attribute text.
87
+*/
88
+char *xhref(const char *zExtra, const char *zFormat, ...){
89
+ char *zUrl;
90
+ va_list ap;
91
+ va_start(ap, zFormat);
92
+ zUrl = vmprintf(zFormat, ap);
93
+ va_end(ap);
94
+ if( g.perm.Hyperlink && !g.javascriptHyperlink ){
95
+ return mprintf("<a %s href=\"%z\">", zExtra, zUrl);
96
+ }
97
+ if( nHref>=nHrefAlloc ){
98
+ nHrefAlloc = nHrefAlloc*2 + 10;
99
+ aHref = fossil_realloc(aHref, nHrefAlloc*sizeof(aHref[0]));
100
+ }
101
+ aHref[nHref++] = zUrl;
102
+ return mprintf("<a %s id=%d>", zExtra, nHref);
103
+}
104
+char *href(const char *zFormat, ...){
105
+ char *zUrl;
106
+ va_list ap;
107
+ va_start(ap, zFormat);
108
+ zUrl = vmprintf(zFormat, ap);
109
+ va_end(ap);
110
+ if( g.perm.Hyperlink && !g.javascriptHyperlink ){
111
+ return mprintf("<a href=\"%z\">", zUrl);
112
+ }
113
+ if( nHref>=nHrefAlloc ){
114
+ nHrefAlloc = nHrefAlloc*2 + 10;
115
+ aHref = fossil_realloc(aHref, nHrefAlloc*sizeof(aHref[0]));
116
+ }
117
+ aHref[nHref++] = zUrl;
118
+ return mprintf("<a id=%d>", nHref);
119
+}
120
+
121
+/*
122
+** Generate javascript that will set the href= attribute on all anchors.
123
+*/
124
+void style_resolve_href(void){
125
+ int i;
126
+ if( !g.perm.Hyperlink || !g.javascriptHyperlink || nHref==0 ) return;
127
+ @ <script>
128
+ for(i=0; i<nHref; i++){
129
+ @ document.getElementById(%d(i+1)).href="%s(aHref[i])";
130
+ }
131
+ @ </script>
132
+}
133
+
50134
/*
51135
** Add a new element to the submenu
52136
*/
53137
void style_submenu_element(
54138
const char *zLabel,
@@ -164,10 +248,13 @@
164248
if( g.thTrace ){
165249
cgi_append_content("<span class=\"thTrace\"><hr />\n", -1);
166250
cgi_append_content(blob_str(&g.thLog), blob_size(&g.thLog));
167251
cgi_append_content("</span>\n", -1);
168252
}
253
+
254
+ /* Set the href= field on hyperlinks */
255
+ style_resolve_href();
169256
}
170257
171258
/*
172259
** Begin a side-box on the right-hand side of a page. The title and
173260
** the width of the box are given as arguments. The width is usually
174261
--- src/style.c
+++ src/style.c
@@ -45,10 +45,94 @@
45 /*
46 ** remember, if a sidebox was used
47 */
48 static int sideboxUsed = 0;
49
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
50 /*
51 ** Add a new element to the submenu
52 */
53 void style_submenu_element(
54 const char *zLabel,
@@ -164,10 +248,13 @@
164 if( g.thTrace ){
165 cgi_append_content("<span class=\"thTrace\"><hr />\n", -1);
166 cgi_append_content(blob_str(&g.thLog), blob_size(&g.thLog));
167 cgi_append_content("</span>\n", -1);
168 }
 
 
 
169 }
170
171 /*
172 ** Begin a side-box on the right-hand side of a page. The title and
173 ** the width of the box are given as arguments. The width is usually
174
--- src/style.c
+++ src/style.c
@@ -45,10 +45,94 @@
45 /*
46 ** remember, if a sidebox was used
47 */
48 static int sideboxUsed = 0;
49
50
51 /*
52 ** List of hyperlinks that need to be resolved by javascript in
53 ** the footer.
54 */
55 char **aHref = 0;
56 int nHref = 0;
57 int nHrefAlloc = 0;
58
59 /*
60 ** Generate and return a anchor tag like this:
61 **
62 ** <a href="URL">
63 ** or <a id="ID">
64 **
65 ** The form of the anchor tag is determined by the g.javascriptHyperlink
66 ** variable. The href="URL" form is used if g.javascriptHyperlink is false.
67 ** If g.javascriptHyperlink is true then the
68 ** id="ID" form is used and javascript is generated in the footer to cause
69 ** href values to be inserted after the page has loaded. If
70 ** g.perm.History is false, then the <a id="ID"> form is still
71 ** generated but the javascript is not generated so the links never
72 ** activate.
73 **
74 ** Filling in the href="URL" using javascript is a defense against bots.
75 **
76 ** The name of this routine is deliberately kept short so that can be
77 ** easily used within @-lines. Example:
78 **
79 ** @ %z(href("%R/artifact/%s",zUuid))%h(zFN)</a>
80 **
81 ** Note %z format. The string returned by this function is always
82 ** obtained from fossil_malloc() so rendering it with %z will reclaim
83 ** that memory space.
84 **
85 ** There are two versions of this routine: href() does a plain hyperlink
86 ** and xhref() adds extra attribute text.
87 */
88 char *xhref(const char *zExtra, const char *zFormat, ...){
89 char *zUrl;
90 va_list ap;
91 va_start(ap, zFormat);
92 zUrl = vmprintf(zFormat, ap);
93 va_end(ap);
94 if( g.perm.Hyperlink && !g.javascriptHyperlink ){
95 return mprintf("<a %s href=\"%z\">", zExtra, zUrl);
96 }
97 if( nHref>=nHrefAlloc ){
98 nHrefAlloc = nHrefAlloc*2 + 10;
99 aHref = fossil_realloc(aHref, nHrefAlloc*sizeof(aHref[0]));
100 }
101 aHref[nHref++] = zUrl;
102 return mprintf("<a %s id=%d>", zExtra, nHref);
103 }
104 char *href(const char *zFormat, ...){
105 char *zUrl;
106 va_list ap;
107 va_start(ap, zFormat);
108 zUrl = vmprintf(zFormat, ap);
109 va_end(ap);
110 if( g.perm.Hyperlink && !g.javascriptHyperlink ){
111 return mprintf("<a href=\"%z\">", zUrl);
112 }
113 if( nHref>=nHrefAlloc ){
114 nHrefAlloc = nHrefAlloc*2 + 10;
115 aHref = fossil_realloc(aHref, nHrefAlloc*sizeof(aHref[0]));
116 }
117 aHref[nHref++] = zUrl;
118 return mprintf("<a id=%d>", nHref);
119 }
120
121 /*
122 ** Generate javascript that will set the href= attribute on all anchors.
123 */
124 void style_resolve_href(void){
125 int i;
126 if( !g.perm.Hyperlink || !g.javascriptHyperlink || nHref==0 ) return;
127 @ <script>
128 for(i=0; i<nHref; i++){
129 @ document.getElementById(%d(i+1)).href="%s(aHref[i])";
130 }
131 @ </script>
132 }
133
134 /*
135 ** Add a new element to the submenu
136 */
137 void style_submenu_element(
138 const char *zLabel,
@@ -164,10 +248,13 @@
248 if( g.thTrace ){
249 cgi_append_content("<span class=\"thTrace\"><hr />\n", -1);
250 cgi_append_content(blob_str(&g.thLog), blob_size(&g.thLog));
251 cgi_append_content("</span>\n", -1);
252 }
253
254 /* Set the href= field on hyperlinks */
255 style_resolve_href();
256 }
257
258 /*
259 ** Begin a side-box on the right-hand side of a page. The title and
260 ** the width of the box are given as arguments. The width is usually
261
+2 -2
--- src/tag.c
+++ src/tag.c
@@ -548,12 +548,12 @@
548548
" ORDER BY tagname"
549549
);
550550
@ <ul>
551551
while( db_step(&q)==SQLITE_ROW ){
552552
const char *zName = db_column_text(&q, 0);
553
- if( g.perm.History ){
554
- @ <li><a class="tagLink" href="%s(g.zTop)/timeline?t=%T(zName)">
553
+ if( g.perm.Hyperlink ){
554
+ @ <li>%z(xhref("class='taglink'","%R/timeline?t=%T",zName))
555555
@ %h(zName)</a></li>
556556
}else{
557557
@ <li><span class="tagDsp">%h(zName)</span></li>
558558
}
559559
}
560560
--- src/tag.c
+++ src/tag.c
@@ -548,12 +548,12 @@
548 " ORDER BY tagname"
549 );
550 @ <ul>
551 while( db_step(&q)==SQLITE_ROW ){
552 const char *zName = db_column_text(&q, 0);
553 if( g.perm.History ){
554 @ <li><a class="tagLink" href="%s(g.zTop)/timeline?t=%T(zName)">
555 @ %h(zName)</a></li>
556 }else{
557 @ <li><span class="tagDsp">%h(zName)</span></li>
558 }
559 }
560
--- src/tag.c
+++ src/tag.c
@@ -548,12 +548,12 @@
548 " ORDER BY tagname"
549 );
550 @ <ul>
551 while( db_step(&q)==SQLITE_ROW ){
552 const char *zName = db_column_text(&q, 0);
553 if( g.perm.Hyperlink ){
554 @ <li>%z(xhref("class='taglink'","%R/timeline?t=%T",zName))
555 @ %h(zName)</a></li>
556 }else{
557 @ <li><span class="tagDsp">%h(zName)</span></li>
558 }
559 }
560
+33 -52
--- src/timeline.c
+++ src/timeline.c
@@ -47,37 +47,37 @@
4747
** Generate a hyperlink to a version.
4848
*/
4949
void hyperlink_to_uuid(const char *zUuid){
5050
char z[UUID_SIZE+1];
5151
shorten_uuid(z, zUuid);
52
- if( g.perm.History ){
53
- @ <a class="timelineHistLink" href="%s(g.zTop)/info/%s(z)">[%s(z)]</a>
52
+ if( g.perm.Hyperlink ){
53
+ @ %z(xhref("class='timelineHistLink'","%R/info/%s",z))[%s(z)]</a>
5454
}else{
5555
@ <span class="timelineHistDsp">[%s(z)]</span>
5656
}
5757
}
5858
5959
/*
6060
** Generate a hyperlink to a diff between two versions.
6161
*/
6262
void hyperlink_to_diff(const char *zV1, const char *zV2){
63
- if( g.perm.History ){
63
+ if( g.perm.Hyperlink ){
6464
if( zV2==0 ){
65
- @ <a href="%s(g.zTop)/diff?v2=%s(zV1)">[diff]</a>
65
+ @ %z(href("%R/diff?v2=%s",zV1))[diff]</a>
6666
}else{
67
- @ <a href="%s(g.zTop)/diff?v1=%s(zV1)&amp;v2=%s(zV2)">[diff]</a>
67
+ @ %z(href("%R/diff?v1=%s&v2=%s",zV1,zV2))[diff]</a>
6868
}
6969
}
7070
}
7171
7272
/*
7373
** Generate a hyperlink to a date & time.
7474
*/
7575
void hyperlink_to_date(const char *zDate, const char *zSuffix){
7676
if( zSuffix==0 ) zSuffix = "";
77
- if( g.perm.History ){
78
- @ <a href="%s(g.zTop)/timeline?c=%T(zDate)">%s(zDate)</a>%s(zSuffix)
77
+ if( g.perm.Hyperlink ){
78
+ @ %z(href("%R/timeline?c=%T",zDate))%s(zDate)</a>%s(zSuffix)
7979
}else{
8080
@ %s(zDate)%s(zSuffix)
8181
}
8282
}
8383
@@ -86,15 +86,15 @@
8686
** events by that user. If the date+time is specified, then the timeline
8787
** is centered on that date+time.
8888
*/
8989
void hyperlink_to_user(const char *zU, const char *zD, const char *zSuf){
9090
if( zSuf==0 ) zSuf = "";
91
- if( g.perm.History ){
91
+ if( g.perm.Hyperlink ){
9292
if( zD && zD[0] ){
93
- @ <a href="%s(g.zTop)/timeline?c=%T(zD)&amp;u=%T(zU)">%h(zU)</a>%s(zSuf)
93
+ @ %z(href("%R/timeline?c=%T&u=%T",zD,zU))%h(zU)</a>%s(zSuf)
9494
}else{
95
- @ <a href="%s(g.zTop)/timeline?u=%T(zU)">%h(zU)</a>%s(zSuf)
95
+ @ %z(href("%R/timeline?u=%T",zU))%h(zU)</a>%s(zSuf)
9696
}
9797
}else{
9898
@ %s(zU)
9999
}
100100
}
@@ -353,39 +353,37 @@
353353
354354
/* Generate the "user: USERNAME" at the end of the comment, together
355355
** with a hyperlink to another timeline for that user.
356356
*/
357357
if( zTagList && zTagList[0]==0 ) zTagList = 0;
358
- if( g.perm.History && fossil_strcmp(zUser, zThisUser)!=0 ){
359
- char *zLink = mprintf("%s/timeline?u=%h&c=%t&nd",
360
- g.zTop, zUser, zDate);
361
- @ (user: <a href="%s(zLink)">%h(zUser)</a>%s(zTagList?",":"\051")
362
- fossil_free(zLink);
358
+ if( g.perm.Hyperlink && fossil_strcmp(zUser, zThisUser)!=0 ){
359
+ char *zLink = mprintf("%R/timeline?u=%h&c=%t&nd", zUser, zDate);
360
+ @ (user: %z(href("%z",zLink))%h(zUser)</a>%s(zTagList?",":"\051")
363361
}else{
364362
@ (user: %h(zUser)%s(zTagList?",":"\051")
365363
}
366364
367365
/* Generate a "detail" link for tags. */
368
- if( zType[0]=='g' && g.perm.History ){
369
- @ [<a href="%s(g.zTop)/info/%S(zUuid)">details</a>]
366
+ if( zType[0]=='g' && g.perm.Hyperlink ){
367
+ @ [%z(href("%R/info/%S",zUuid))details</a>]
370368
}
371369
372370
/* Generate the "tags: TAGLIST" at the end of the comment, together
373371
** with hyperlinks to the tag list.
374372
*/
375373
if( zTagList ){
376
- if( g.perm.History ){
374
+ if( g.perm.Hyperlink ){
377375
int i;
378376
const char *z = zTagList;
379377
Blob links;
380378
blob_zero(&links);
381379
while( z && z[0] ){
382380
for(i=0; z[i] && (z[i]!=',' || z[i+1]!=' '); i++){}
383381
if( zThisTag==0 || memcmp(z, zThisTag, i)!=0 || zThisTag[i]!=0 ){
384382
blob_appendf(&links,
385
- "<a href=\"%s/timeline?r=%#t&nd&c=%s\">%#h</a>%.2s",
386
- g.zTop, i, z, zDate, i, z, &z[i]
383
+ "%z%#h</a>%.2s",
384
+ href("%R/timeline?r=%#t&nd&c=%s",i,z,zDate), i,z, &z[i]
387385
);
388386
}else{
389387
blob_appendf(&links, "%#h", i+2, z);
390388
}
391389
if( z[i]==0 ) break;
@@ -403,11 +401,11 @@
403401
if( xExtra ){
404402
xExtra(rid);
405403
}
406404
407405
/* Generate the file-change list if requested */
408
- if( (tmFlags & TIMELINE_FCHANGES)!=0 && zType[0]=='c' && g.perm.History ){
406
+ if( (tmFlags & TIMELINE_FCHANGES)!=0 && zType[0]=='c' && g.perm.Hyperlink ){
409407
int inUl = 0;
410408
if( !fchngQueryInit ){
411409
db_prepare(&fchngQuery,
412410
"SELECT (pid==0) AS isnew,"
413411
" (fid==0) AS isdel,"
@@ -433,26 +431,26 @@
433431
@ <ul class="filelist">
434432
inUl = 1;
435433
}
436434
if( isNew ){
437435
@ <li> %h(zFilename) (new file) &nbsp;
438
- @ <a href="%s(g.zTop)/artifact/%S(zNew)"
439
- @ target="diffwindow">[view]</a></li>
436
+ @ %z(xhref("target='diffwindow'","%R/artifact/%S",zNew))
437
+ @ [view]</a></li>
440438
}else if( isDel ){
441439
@ <li> %h(zFilename) (deleted)</li>
442440
}else if( fossil_strcmp(zOld,zNew)==0 && zOldName!=0 ){
443441
@ <li> %h(zOldName) &rarr; %h(zFilename)
444
- @ <a href="%s(g.zTop)/artifact/%S(zNew)"
445
- @ target="diffwindow">[view]</a></li>
442
+ @ %z(xhref("target='diffwindow'","%R/artifact/%S",zNew))
443
+ @ [view]</a></li>
446444
}else{
447445
if( zOldName!=0 ){
448446
@ <li> %h(zOldName) &rarr; %h(zFilename)
449447
}else{
450448
@ <li> %h(zFilename) &nbsp;
451449
}
452
- @ <a href="%s(g.zTop)/fdiff?v1=%S(zOld)&v2=%S(zNew)"
453
- @ target="diffwindow">[diff]</a></li>
450
+ @ %z(xhref("target='diffwindow'","%R/fdiff?v1=%S&v2=%S",zOld,zNew))
451
+ @ [diff]</a></li>
454452
}
455453
}
456454
db_reset(&fchngQuery);
457455
if( inUl ){
458456
@ </ul>
@@ -974,21 +972,13 @@
974972
p = p->u.pTo;
975973
}
976974
blob_append(&sql, ")", -1);
977975
path_reset();
978976
blob_append(&desc, "All nodes on the path from ", -1);
979
- if( g.perm.History ){
980
- blob_appendf(&desc, "<a href='%s/info/%h'>[%h]</a>", g.zTop,zFrom,zFrom);
981
- }else{
982
- blob_appendf(&desc, "[%h]", zFrom);
983
- }
977
+ blob_appendf(&desc, "%z%h</a>", href("%R/info/%h", zFrom), zFrom);
984978
blob_append(&desc, " and ", -1);
985
- if( g.perm.History ){
986
- blob_appendf(&desc, "<a href='%s/info/%h'>[%h]</a>.", g.zTop, zTo, zTo);
987
- }else{
988
- blob_appendf(&desc, "[%h].", zTo);
989
- }
979
+ blob_appendf(&desc, "%z[%h]</a>", href("%R/info/%h",zTo), zTo);
990980
tmFlags |= TIMELINE_DISJOINT;
991981
db_multi_exec("%s", blob_str(&sql));
992982
}else if( (p_rid || d_rid) && g.perm.Read ){
993983
/* If p= or d= is present, ignore all other parameters other than n= */
994984
char *zUuid;
@@ -1021,16 +1011,12 @@
10211011
blob_appendf(&desc, "%d ancestors", np);
10221012
db_multi_exec("%s", blob_str(&sql));
10231013
}
10241014
if( d_rid==0 && useDividers ) timeline_add_dividers(0, p_rid);
10251015
}
1026
- if( g.perm.History ){
1027
- blob_appendf(&desc, " of <a href='%s/info/%s'>[%.10s]</a>",
1028
- g.zTop, zUuid, zUuid);
1029
- }else{
1030
- blob_appendf(&desc, " of check-in [%.10s]", zUuid);
1031
- }
1016
+ blob_appendf(&desc, " of %z[%.10s]</a>",
1017
+ href("%R/info/%s", zUuid), zUuid);
10321018
}else if( f_rid && g.perm.Read ){
10331019
/* If f= is present, ignore all other parameters other than n= */
10341020
char *zUuid;
10351021
db_multi_exec(
10361022
"CREATE TEMP TABLE IF NOT EXISTS ok(rid INTEGER PRIMARY KEY);"
@@ -1042,16 +1028,11 @@
10421028
blob_appendf(&sql, " AND event.objid IN ok");
10431029
db_multi_exec("%s", blob_str(&sql));
10441030
if( useDividers ) timeline_add_dividers(0, f_rid);
10451031
blob_appendf(&desc, "Parents and children of check-in ");
10461032
zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d", f_rid);
1047
- if( g.perm.History ){
1048
- blob_appendf(&desc, "<a href='%s/info/%s'>[%.10s]</a>",
1049
- g.zTop, zUuid, zUuid);
1050
- }else{
1051
- blob_appendf(&desc, "[%.10s]", zUuid);
1052
- }
1033
+ blob_appendf(&desc, "%z[%.10s]</a>", href("%R/info/%s", zUuid), zUuid);
10531034
}else{
10541035
/* Otherwise, a timeline based on a span of time */
10551036
int n;
10561037
const char *zEType = "timeline item";
10571038
char *zDate;
@@ -1219,11 +1200,11 @@
12191200
blob_appendf(&desc, " occurring around %h.<br />", zCirca);
12201201
}
12211202
if( zSearch ){
12221203
blob_appendf(&desc, " matching \"%h\"", zSearch);
12231204
}
1224
- if( g.perm.History ){
1205
+ if( g.perm.Hyperlink ){
12251206
if( zAfter || n==nEntry ){
12261207
zDate = db_text(0, "SELECT min(timestamp) FROM timeline /*scan*/");
12271208
timeline_submenu(&url, "Older", "b", zDate, "a");
12281209
free(zDate);
12291210
}
@@ -1623,11 +1604,11 @@
16231604
*/
16241605
void test_timewarp_page(void){
16251606
Stmt q;
16261607
16271608
login_check_credentials();
1628
- if( !g.perm.Read || !g.perm.History ){ login_needed(); return; }
1609
+ if( !g.perm.Read || !g.perm.Hyperlink ){ login_needed(); return; }
16291610
style_header("Instances of timewarp");
16301611
@ <ul>
16311612
db_prepare(&q,
16321613
"SELECT blob.uuid "
16331614
" FROM plink p, plink c, blob"
@@ -1635,10 +1616,10 @@
16351616
" AND blob.rid=c.cid"
16361617
);
16371618
while( db_step(&q)==SQLITE_ROW ){
16381619
const char *zUuid = db_column_text(&q, 0);
16391620
@ <li>
1640
- @ <a href="%s(g.zTop)/timeline?p=%S(zUuid)&amp;d=%S(zUuid)">%S(zUuid)</a>
1621
+ @ <a href="%s(g.zTop)/timeline?p=%S(zUuid)&d=%S(zUuid)">%S(zUuid)</a>
16411622
}
16421623
db_finalize(&q);
16431624
style_footer();
16441625
}
16451626
--- src/timeline.c
+++ src/timeline.c
@@ -47,37 +47,37 @@
47 ** Generate a hyperlink to a version.
48 */
49 void hyperlink_to_uuid(const char *zUuid){
50 char z[UUID_SIZE+1];
51 shorten_uuid(z, zUuid);
52 if( g.perm.History ){
53 @ <a class="timelineHistLink" href="%s(g.zTop)/info/%s(z)">[%s(z)]</a>
54 }else{
55 @ <span class="timelineHistDsp">[%s(z)]</span>
56 }
57 }
58
59 /*
60 ** Generate a hyperlink to a diff between two versions.
61 */
62 void hyperlink_to_diff(const char *zV1, const char *zV2){
63 if( g.perm.History ){
64 if( zV2==0 ){
65 @ <a href="%s(g.zTop)/diff?v2=%s(zV1)">[diff]</a>
66 }else{
67 @ <a href="%s(g.zTop)/diff?v1=%s(zV1)&amp;v2=%s(zV2)">[diff]</a>
68 }
69 }
70 }
71
72 /*
73 ** Generate a hyperlink to a date & time.
74 */
75 void hyperlink_to_date(const char *zDate, const char *zSuffix){
76 if( zSuffix==0 ) zSuffix = "";
77 if( g.perm.History ){
78 @ <a href="%s(g.zTop)/timeline?c=%T(zDate)">%s(zDate)</a>%s(zSuffix)
79 }else{
80 @ %s(zDate)%s(zSuffix)
81 }
82 }
83
@@ -86,15 +86,15 @@
86 ** events by that user. If the date+time is specified, then the timeline
87 ** is centered on that date+time.
88 */
89 void hyperlink_to_user(const char *zU, const char *zD, const char *zSuf){
90 if( zSuf==0 ) zSuf = "";
91 if( g.perm.History ){
92 if( zD && zD[0] ){
93 @ <a href="%s(g.zTop)/timeline?c=%T(zD)&amp;u=%T(zU)">%h(zU)</a>%s(zSuf)
94 }else{
95 @ <a href="%s(g.zTop)/timeline?u=%T(zU)">%h(zU)</a>%s(zSuf)
96 }
97 }else{
98 @ %s(zU)
99 }
100 }
@@ -353,39 +353,37 @@
353
354 /* Generate the "user: USERNAME" at the end of the comment, together
355 ** with a hyperlink to another timeline for that user.
356 */
357 if( zTagList && zTagList[0]==0 ) zTagList = 0;
358 if( g.perm.History && fossil_strcmp(zUser, zThisUser)!=0 ){
359 char *zLink = mprintf("%s/timeline?u=%h&c=%t&nd",
360 g.zTop, zUser, zDate);
361 @ (user: <a href="%s(zLink)">%h(zUser)</a>%s(zTagList?",":"\051")
362 fossil_free(zLink);
363 }else{
364 @ (user: %h(zUser)%s(zTagList?",":"\051")
365 }
366
367 /* Generate a "detail" link for tags. */
368 if( zType[0]=='g' && g.perm.History ){
369 @ [<a href="%s(g.zTop)/info/%S(zUuid)">details</a>]
370 }
371
372 /* Generate the "tags: TAGLIST" at the end of the comment, together
373 ** with hyperlinks to the tag list.
374 */
375 if( zTagList ){
376 if( g.perm.History ){
377 int i;
378 const char *z = zTagList;
379 Blob links;
380 blob_zero(&links);
381 while( z && z[0] ){
382 for(i=0; z[i] && (z[i]!=',' || z[i+1]!=' '); i++){}
383 if( zThisTag==0 || memcmp(z, zThisTag, i)!=0 || zThisTag[i]!=0 ){
384 blob_appendf(&links,
385 "<a href=\"%s/timeline?r=%#t&nd&c=%s\">%#h</a>%.2s",
386 g.zTop, i, z, zDate, i, z, &z[i]
387 );
388 }else{
389 blob_appendf(&links, "%#h", i+2, z);
390 }
391 if( z[i]==0 ) break;
@@ -403,11 +401,11 @@
403 if( xExtra ){
404 xExtra(rid);
405 }
406
407 /* Generate the file-change list if requested */
408 if( (tmFlags & TIMELINE_FCHANGES)!=0 && zType[0]=='c' && g.perm.History ){
409 int inUl = 0;
410 if( !fchngQueryInit ){
411 db_prepare(&fchngQuery,
412 "SELECT (pid==0) AS isnew,"
413 " (fid==0) AS isdel,"
@@ -433,26 +431,26 @@
433 @ <ul class="filelist">
434 inUl = 1;
435 }
436 if( isNew ){
437 @ <li> %h(zFilename) (new file) &nbsp;
438 @ <a href="%s(g.zTop)/artifact/%S(zNew)"
439 @ target="diffwindow">[view]</a></li>
440 }else if( isDel ){
441 @ <li> %h(zFilename) (deleted)</li>
442 }else if( fossil_strcmp(zOld,zNew)==0 && zOldName!=0 ){
443 @ <li> %h(zOldName) &rarr; %h(zFilename)
444 @ <a href="%s(g.zTop)/artifact/%S(zNew)"
445 @ target="diffwindow">[view]</a></li>
446 }else{
447 if( zOldName!=0 ){
448 @ <li> %h(zOldName) &rarr; %h(zFilename)
449 }else{
450 @ <li> %h(zFilename) &nbsp;
451 }
452 @ <a href="%s(g.zTop)/fdiff?v1=%S(zOld)&v2=%S(zNew)"
453 @ target="diffwindow">[diff]</a></li>
454 }
455 }
456 db_reset(&fchngQuery);
457 if( inUl ){
458 @ </ul>
@@ -974,21 +972,13 @@
974 p = p->u.pTo;
975 }
976 blob_append(&sql, ")", -1);
977 path_reset();
978 blob_append(&desc, "All nodes on the path from ", -1);
979 if( g.perm.History ){
980 blob_appendf(&desc, "<a href='%s/info/%h'>[%h]</a>", g.zTop,zFrom,zFrom);
981 }else{
982 blob_appendf(&desc, "[%h]", zFrom);
983 }
984 blob_append(&desc, " and ", -1);
985 if( g.perm.History ){
986 blob_appendf(&desc, "<a href='%s/info/%h'>[%h]</a>.", g.zTop, zTo, zTo);
987 }else{
988 blob_appendf(&desc, "[%h].", zTo);
989 }
990 tmFlags |= TIMELINE_DISJOINT;
991 db_multi_exec("%s", blob_str(&sql));
992 }else if( (p_rid || d_rid) && g.perm.Read ){
993 /* If p= or d= is present, ignore all other parameters other than n= */
994 char *zUuid;
@@ -1021,16 +1011,12 @@
1021 blob_appendf(&desc, "%d ancestors", np);
1022 db_multi_exec("%s", blob_str(&sql));
1023 }
1024 if( d_rid==0 && useDividers ) timeline_add_dividers(0, p_rid);
1025 }
1026 if( g.perm.History ){
1027 blob_appendf(&desc, " of <a href='%s/info/%s'>[%.10s]</a>",
1028 g.zTop, zUuid, zUuid);
1029 }else{
1030 blob_appendf(&desc, " of check-in [%.10s]", zUuid);
1031 }
1032 }else if( f_rid && g.perm.Read ){
1033 /* If f= is present, ignore all other parameters other than n= */
1034 char *zUuid;
1035 db_multi_exec(
1036 "CREATE TEMP TABLE IF NOT EXISTS ok(rid INTEGER PRIMARY KEY);"
@@ -1042,16 +1028,11 @@
1042 blob_appendf(&sql, " AND event.objid IN ok");
1043 db_multi_exec("%s", blob_str(&sql));
1044 if( useDividers ) timeline_add_dividers(0, f_rid);
1045 blob_appendf(&desc, "Parents and children of check-in ");
1046 zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d", f_rid);
1047 if( g.perm.History ){
1048 blob_appendf(&desc, "<a href='%s/info/%s'>[%.10s]</a>",
1049 g.zTop, zUuid, zUuid);
1050 }else{
1051 blob_appendf(&desc, "[%.10s]", zUuid);
1052 }
1053 }else{
1054 /* Otherwise, a timeline based on a span of time */
1055 int n;
1056 const char *zEType = "timeline item";
1057 char *zDate;
@@ -1219,11 +1200,11 @@
1219 blob_appendf(&desc, " occurring around %h.<br />", zCirca);
1220 }
1221 if( zSearch ){
1222 blob_appendf(&desc, " matching \"%h\"", zSearch);
1223 }
1224 if( g.perm.History ){
1225 if( zAfter || n==nEntry ){
1226 zDate = db_text(0, "SELECT min(timestamp) FROM timeline /*scan*/");
1227 timeline_submenu(&url, "Older", "b", zDate, "a");
1228 free(zDate);
1229 }
@@ -1623,11 +1604,11 @@
1623 */
1624 void test_timewarp_page(void){
1625 Stmt q;
1626
1627 login_check_credentials();
1628 if( !g.perm.Read || !g.perm.History ){ login_needed(); return; }
1629 style_header("Instances of timewarp");
1630 @ <ul>
1631 db_prepare(&q,
1632 "SELECT blob.uuid "
1633 " FROM plink p, plink c, blob"
@@ -1635,10 +1616,10 @@
1635 " AND blob.rid=c.cid"
1636 );
1637 while( db_step(&q)==SQLITE_ROW ){
1638 const char *zUuid = db_column_text(&q, 0);
1639 @ <li>
1640 @ <a href="%s(g.zTop)/timeline?p=%S(zUuid)&amp;d=%S(zUuid)">%S(zUuid)</a>
1641 }
1642 db_finalize(&q);
1643 style_footer();
1644 }
1645
--- src/timeline.c
+++ src/timeline.c
@@ -47,37 +47,37 @@
47 ** Generate a hyperlink to a version.
48 */
49 void hyperlink_to_uuid(const char *zUuid){
50 char z[UUID_SIZE+1];
51 shorten_uuid(z, zUuid);
52 if( g.perm.Hyperlink ){
53 @ %z(xhref("class='timelineHistLink'","%R/info/%s",z))[%s(z)]</a>
54 }else{
55 @ <span class="timelineHistDsp">[%s(z)]</span>
56 }
57 }
58
59 /*
60 ** Generate a hyperlink to a diff between two versions.
61 */
62 void hyperlink_to_diff(const char *zV1, const char *zV2){
63 if( g.perm.Hyperlink ){
64 if( zV2==0 ){
65 @ %z(href("%R/diff?v2=%s",zV1))[diff]</a>
66 }else{
67 @ %z(href("%R/diff?v1=%s&v2=%s",zV1,zV2))[diff]</a>
68 }
69 }
70 }
71
72 /*
73 ** Generate a hyperlink to a date & time.
74 */
75 void hyperlink_to_date(const char *zDate, const char *zSuffix){
76 if( zSuffix==0 ) zSuffix = "";
77 if( g.perm.Hyperlink ){
78 @ %z(href("%R/timeline?c=%T",zDate))%s(zDate)</a>%s(zSuffix)
79 }else{
80 @ %s(zDate)%s(zSuffix)
81 }
82 }
83
@@ -86,15 +86,15 @@
86 ** events by that user. If the date+time is specified, then the timeline
87 ** is centered on that date+time.
88 */
89 void hyperlink_to_user(const char *zU, const char *zD, const char *zSuf){
90 if( zSuf==0 ) zSuf = "";
91 if( g.perm.Hyperlink ){
92 if( zD && zD[0] ){
93 @ %z(href("%R/timeline?c=%T&u=%T",zD,zU))%h(zU)</a>%s(zSuf)
94 }else{
95 @ %z(href("%R/timeline?u=%T",zU))%h(zU)</a>%s(zSuf)
96 }
97 }else{
98 @ %s(zU)
99 }
100 }
@@ -353,39 +353,37 @@
353
354 /* Generate the "user: USERNAME" at the end of the comment, together
355 ** with a hyperlink to another timeline for that user.
356 */
357 if( zTagList && zTagList[0]==0 ) zTagList = 0;
358 if( g.perm.Hyperlink && fossil_strcmp(zUser, zThisUser)!=0 ){
359 char *zLink = mprintf("%R/timeline?u=%h&c=%t&nd", zUser, zDate);
360 @ (user: %z(href("%z",zLink))%h(zUser)</a>%s(zTagList?",":"\051")
 
 
361 }else{
362 @ (user: %h(zUser)%s(zTagList?",":"\051")
363 }
364
365 /* Generate a "detail" link for tags. */
366 if( zType[0]=='g' && g.perm.Hyperlink ){
367 @ [%z(href("%R/info/%S",zUuid))details</a>]
368 }
369
370 /* Generate the "tags: TAGLIST" at the end of the comment, together
371 ** with hyperlinks to the tag list.
372 */
373 if( zTagList ){
374 if( g.perm.Hyperlink ){
375 int i;
376 const char *z = zTagList;
377 Blob links;
378 blob_zero(&links);
379 while( z && z[0] ){
380 for(i=0; z[i] && (z[i]!=',' || z[i+1]!=' '); i++){}
381 if( zThisTag==0 || memcmp(z, zThisTag, i)!=0 || zThisTag[i]!=0 ){
382 blob_appendf(&links,
383 "%z%#h</a>%.2s",
384 href("%R/timeline?r=%#t&nd&c=%s",i,z,zDate), i,z, &z[i]
385 );
386 }else{
387 blob_appendf(&links, "%#h", i+2, z);
388 }
389 if( z[i]==0 ) break;
@@ -403,11 +401,11 @@
401 if( xExtra ){
402 xExtra(rid);
403 }
404
405 /* Generate the file-change list if requested */
406 if( (tmFlags & TIMELINE_FCHANGES)!=0 && zType[0]=='c' && g.perm.Hyperlink ){
407 int inUl = 0;
408 if( !fchngQueryInit ){
409 db_prepare(&fchngQuery,
410 "SELECT (pid==0) AS isnew,"
411 " (fid==0) AS isdel,"
@@ -433,26 +431,26 @@
431 @ <ul class="filelist">
432 inUl = 1;
433 }
434 if( isNew ){
435 @ <li> %h(zFilename) (new file) &nbsp;
436 @ %z(xhref("target='diffwindow'","%R/artifact/%S",zNew))
437 @ [view]</a></li>
438 }else if( isDel ){
439 @ <li> %h(zFilename) (deleted)</li>
440 }else if( fossil_strcmp(zOld,zNew)==0 && zOldName!=0 ){
441 @ <li> %h(zOldName) &rarr; %h(zFilename)
442 @ %z(xhref("target='diffwindow'","%R/artifact/%S",zNew))
443 @ [view]</a></li>
444 }else{
445 if( zOldName!=0 ){
446 @ <li> %h(zOldName) &rarr; %h(zFilename)
447 }else{
448 @ <li> %h(zFilename) &nbsp;
449 }
450 @ %z(xhref("target='diffwindow'","%R/fdiff?v1=%S&v2=%S",zOld,zNew))
451 @ [diff]</a></li>
452 }
453 }
454 db_reset(&fchngQuery);
455 if( inUl ){
456 @ </ul>
@@ -974,21 +972,13 @@
972 p = p->u.pTo;
973 }
974 blob_append(&sql, ")", -1);
975 path_reset();
976 blob_append(&desc, "All nodes on the path from ", -1);
977 blob_appendf(&desc, "%z%h</a>", href("%R/info/%h", zFrom), zFrom);
 
 
 
 
978 blob_append(&desc, " and ", -1);
979 blob_appendf(&desc, "%z[%h]</a>", href("%R/info/%h",zTo), zTo);
 
 
 
 
980 tmFlags |= TIMELINE_DISJOINT;
981 db_multi_exec("%s", blob_str(&sql));
982 }else if( (p_rid || d_rid) && g.perm.Read ){
983 /* If p= or d= is present, ignore all other parameters other than n= */
984 char *zUuid;
@@ -1021,16 +1011,12 @@
1011 blob_appendf(&desc, "%d ancestors", np);
1012 db_multi_exec("%s", blob_str(&sql));
1013 }
1014 if( d_rid==0 && useDividers ) timeline_add_dividers(0, p_rid);
1015 }
1016 blob_appendf(&desc, " of %z[%.10s]</a>",
1017 href("%R/info/%s", zUuid), zUuid);
 
 
 
 
1018 }else if( f_rid && g.perm.Read ){
1019 /* If f= is present, ignore all other parameters other than n= */
1020 char *zUuid;
1021 db_multi_exec(
1022 "CREATE TEMP TABLE IF NOT EXISTS ok(rid INTEGER PRIMARY KEY);"
@@ -1042,16 +1028,11 @@
1028 blob_appendf(&sql, " AND event.objid IN ok");
1029 db_multi_exec("%s", blob_str(&sql));
1030 if( useDividers ) timeline_add_dividers(0, f_rid);
1031 blob_appendf(&desc, "Parents and children of check-in ");
1032 zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d", f_rid);
1033 blob_appendf(&desc, "%z[%.10s]</a>", href("%R/info/%s", zUuid), zUuid);
 
 
 
 
 
1034 }else{
1035 /* Otherwise, a timeline based on a span of time */
1036 int n;
1037 const char *zEType = "timeline item";
1038 char *zDate;
@@ -1219,11 +1200,11 @@
1200 blob_appendf(&desc, " occurring around %h.<br />", zCirca);
1201 }
1202 if( zSearch ){
1203 blob_appendf(&desc, " matching \"%h\"", zSearch);
1204 }
1205 if( g.perm.Hyperlink ){
1206 if( zAfter || n==nEntry ){
1207 zDate = db_text(0, "SELECT min(timestamp) FROM timeline /*scan*/");
1208 timeline_submenu(&url, "Older", "b", zDate, "a");
1209 free(zDate);
1210 }
@@ -1623,11 +1604,11 @@
1604 */
1605 void test_timewarp_page(void){
1606 Stmt q;
1607
1608 login_check_credentials();
1609 if( !g.perm.Read || !g.perm.Hyperlink ){ login_needed(); return; }
1610 style_header("Instances of timewarp");
1611 @ <ul>
1612 db_prepare(&q,
1613 "SELECT blob.uuid "
1614 " FROM plink p, plink c, blob"
@@ -1635,10 +1616,10 @@
1616 " AND blob.rid=c.cid"
1617 );
1618 while( db_step(&q)==SQLITE_ROW ){
1619 const char *zUuid = db_column_text(&q, 0);
1620 @ <li>
1621 @ <a href="%s(g.zTop)/timeline?p=%S(zUuid)&d=%S(zUuid)">%S(zUuid)</a>
1622 }
1623 db_finalize(&q);
1624 style_footer();
1625 }
1626
+12 -12
--- src/tkt.c
+++ src/tkt.c
@@ -305,11 +305,11 @@
305305
if( !g.perm.RdTkt ){ login_needed(); return; }
306306
if( g.perm.WrTkt || g.perm.ApndTkt ){
307307
style_submenu_element("Edit", "Edit The Ticket", "%s/tktedit?name=%T",
308308
g.zTop, PD("name",""));
309309
}
310
- if( g.perm.History ){
310
+ if( g.perm.Hyperlink ){
311311
style_submenu_element("History", "History Of This Ticket",
312312
"%s/tkthistory/%T", g.zTop, zUuid);
313313
style_submenu_element("Timeline", "Timeline Of This Ticket",
314314
"%s/tkttimeline/%T", g.zTop, zUuid);
315315
style_submenu_element("Check-ins", "Check-ins Of This Ticket",
@@ -319,11 +319,11 @@
319319
style_submenu_element("New Ticket", "Create a new ticket",
320320
"%s/tktnew", g.zTop);
321321
}
322322
if( g.perm.ApndTkt && g.perm.Attach ){
323323
style_submenu_element("Attach", "Add An Attachment",
324
- "%s/attachadd?tkt=%T&amp;from=%s/tktview/%t",
324
+ "%s/attachadd?tkt=%T&from=%s/tktview/%t",
325325
g.zTop, zUuid, g.zTop, zUuid);
326326
}
327327
style_header("View Ticket");
328328
if( g.thTrace ) Th_Trace("BEGIN_TKTVIEW<br />\n", -1);
329329
ticket_init();
@@ -353,20 +353,20 @@
353353
@ <hr /><h2>Attachments:</h2>
354354
@ <ul>
355355
}
356356
cnt++;
357357
@ <li>
358
- if( g.perm.Read && g.perm.History ){
359
- @ <a href="%s(g.zTop)/attachview?tkt=%s(zFullName)&amp;file=%t(zFile)">
358
+ if( g.perm.Read && g.perm.Hyperlink ){
359
+ @ %z(href("%R/attachview?tkt=%s&file=%t",zFullName,zFile))
360360
@ %h(zFile)</a>
361361
}else{
362362
@ %h(zFile)
363363
}
364364
@ added by %h(zUser) on
365365
hyperlink_to_date(zDate, ".");
366366
if( g.perm.WrTkt && g.perm.Attach ){
367
- @ [<a href="%s(g.zTop)/attachdelete?tkt=%s(zFullName)&amp;file=%t(zFile)&amp;from=%s(g.zTop)/tktview%%3fname=%s(zFullName)">delete</a>]
367
+ @ [%z(href("%R/attachdelete?tkt=%s&file=%t&from=%R/tktview%%3fname=%s",zFullName,zFile,zFullName))delete</a>]
368368
}
369369
@ </li>
370370
}
371371
if( cnt ){
372372
@ </ul>
@@ -647,11 +647,11 @@
647647
return 0;
648648
}
649649
650650
/*
651651
** WEBPAGE: tkttimeline
652
-** URL: /tkttimeline?name=TICKETUUID&amp;y=TYPE
652
+** URL: /tkttimeline?name=TICKETUUID&y=TYPE
653653
**
654654
** Show the change history for a single ticket in timeline format.
655655
*/
656656
void tkttimeline_page(void){
657657
Stmt q;
@@ -662,16 +662,16 @@
662662
int tagid;
663663
char zGlobPattern[50];
664664
const char *zType;
665665
666666
login_check_credentials();
667
- if( !g.perm.History || !g.perm.RdTkt ){ login_needed(); return; }
667
+ if( !g.perm.Hyperlink || !g.perm.RdTkt ){ login_needed(); return; }
668668
zUuid = PD("name","");
669669
zType = PD("y","a");
670670
if( zType[0]!='c' ){
671671
style_submenu_element("Check-ins", "Check-ins",
672
- "%s/tkttimeline?name=%T&amp;y=ci", g.zTop, zUuid);
672
+ "%s/tkttimeline?name=%T&y=ci", g.zTop, zUuid);
673673
}else{
674674
style_submenu_element("Timeline", "Timeline",
675675
"%s/tkttimeline?name=%T", g.zTop, zUuid);
676676
}
677677
style_submenu_element("History", "History",
@@ -736,17 +736,17 @@
736736
char *zTitle;
737737
const char *zUuid;
738738
int tagid;
739739
740740
login_check_credentials();
741
- if( !g.perm.History || !g.perm.RdTkt ){ login_needed(); return; }
741
+ if( !g.perm.Hyperlink || !g.perm.RdTkt ){ login_needed(); return; }
742742
zUuid = PD("name","");
743743
zTitle = mprintf("History Of Ticket %h", zUuid);
744744
style_submenu_element("Status", "Status",
745745
"%s/info/%s", g.zTop, zUuid);
746746
style_submenu_element("Check-ins", "Check-ins",
747
- "%s/tkttimeline?name=%s&amp;y=ci", g.zTop, zUuid);
747
+ "%s/tkttimeline?name=%s&y=ci", g.zTop, zUuid);
748748
style_submenu_element("Timeline", "Timeline",
749749
"%s/tkttimeline?name=%s", g.zTop, zUuid);
750750
style_header(zTitle);
751751
free(zTitle);
752752
@@ -786,20 +786,20 @@
786786
@ <p>Delete attachment "%h(zFile)"
787787
}else{
788788
@
789789
@ <p>Add attachment "%h(zFile)"
790790
}
791
- @ [<a href="%s(g.zTop)/artifact/%T(zChngUuid)">%s(zShort)</a>]
791
+ @ [%z(href("%R/artifact/%T",zChngUuid))%s(zShort)</a>]
792792
@ (rid %d(rid)) by
793793
hyperlink_to_user(zUser,zDate," on");
794794
hyperlink_to_date(zDate, ".</p>");
795795
}else{
796796
pTicket = manifest_get(rid, CFTYPE_TICKET);
797797
if( pTicket ){
798798
@
799799
@ <p>Ticket change
800
- @ [<a href="%s(g.zTop)/artifact/%T(zChngUuid)">%s(zShort)</a>]
800
+ @ [%z(href("%R/artifact/%T",zChngUuid))%s(zShort)</a>]
801801
@ (rid %d(rid)) by
802802
hyperlink_to_user(pTicket->zUser,zDate," on");
803803
hyperlink_to_date(zDate, ":");
804804
@ </p>
805805
ticket_output_change_artifact(pTicket);
806806
--- src/tkt.c
+++ src/tkt.c
@@ -305,11 +305,11 @@
305 if( !g.perm.RdTkt ){ login_needed(); return; }
306 if( g.perm.WrTkt || g.perm.ApndTkt ){
307 style_submenu_element("Edit", "Edit The Ticket", "%s/tktedit?name=%T",
308 g.zTop, PD("name",""));
309 }
310 if( g.perm.History ){
311 style_submenu_element("History", "History Of This Ticket",
312 "%s/tkthistory/%T", g.zTop, zUuid);
313 style_submenu_element("Timeline", "Timeline Of This Ticket",
314 "%s/tkttimeline/%T", g.zTop, zUuid);
315 style_submenu_element("Check-ins", "Check-ins Of This Ticket",
@@ -319,11 +319,11 @@
319 style_submenu_element("New Ticket", "Create a new ticket",
320 "%s/tktnew", g.zTop);
321 }
322 if( g.perm.ApndTkt && g.perm.Attach ){
323 style_submenu_element("Attach", "Add An Attachment",
324 "%s/attachadd?tkt=%T&amp;from=%s/tktview/%t",
325 g.zTop, zUuid, g.zTop, zUuid);
326 }
327 style_header("View Ticket");
328 if( g.thTrace ) Th_Trace("BEGIN_TKTVIEW<br />\n", -1);
329 ticket_init();
@@ -353,20 +353,20 @@
353 @ <hr /><h2>Attachments:</h2>
354 @ <ul>
355 }
356 cnt++;
357 @ <li>
358 if( g.perm.Read && g.perm.History ){
359 @ <a href="%s(g.zTop)/attachview?tkt=%s(zFullName)&amp;file=%t(zFile)">
360 @ %h(zFile)</a>
361 }else{
362 @ %h(zFile)
363 }
364 @ added by %h(zUser) on
365 hyperlink_to_date(zDate, ".");
366 if( g.perm.WrTkt && g.perm.Attach ){
367 @ [<a href="%s(g.zTop)/attachdelete?tkt=%s(zFullName)&amp;file=%t(zFile)&amp;from=%s(g.zTop)/tktview%%3fname=%s(zFullName)">delete</a>]
368 }
369 @ </li>
370 }
371 if( cnt ){
372 @ </ul>
@@ -647,11 +647,11 @@
647 return 0;
648 }
649
650 /*
651 ** WEBPAGE: tkttimeline
652 ** URL: /tkttimeline?name=TICKETUUID&amp;y=TYPE
653 **
654 ** Show the change history for a single ticket in timeline format.
655 */
656 void tkttimeline_page(void){
657 Stmt q;
@@ -662,16 +662,16 @@
662 int tagid;
663 char zGlobPattern[50];
664 const char *zType;
665
666 login_check_credentials();
667 if( !g.perm.History || !g.perm.RdTkt ){ login_needed(); return; }
668 zUuid = PD("name","");
669 zType = PD("y","a");
670 if( zType[0]!='c' ){
671 style_submenu_element("Check-ins", "Check-ins",
672 "%s/tkttimeline?name=%T&amp;y=ci", g.zTop, zUuid);
673 }else{
674 style_submenu_element("Timeline", "Timeline",
675 "%s/tkttimeline?name=%T", g.zTop, zUuid);
676 }
677 style_submenu_element("History", "History",
@@ -736,17 +736,17 @@
736 char *zTitle;
737 const char *zUuid;
738 int tagid;
739
740 login_check_credentials();
741 if( !g.perm.History || !g.perm.RdTkt ){ login_needed(); return; }
742 zUuid = PD("name","");
743 zTitle = mprintf("History Of Ticket %h", zUuid);
744 style_submenu_element("Status", "Status",
745 "%s/info/%s", g.zTop, zUuid);
746 style_submenu_element("Check-ins", "Check-ins",
747 "%s/tkttimeline?name=%s&amp;y=ci", g.zTop, zUuid);
748 style_submenu_element("Timeline", "Timeline",
749 "%s/tkttimeline?name=%s", g.zTop, zUuid);
750 style_header(zTitle);
751 free(zTitle);
752
@@ -786,20 +786,20 @@
786 @ <p>Delete attachment "%h(zFile)"
787 }else{
788 @
789 @ <p>Add attachment "%h(zFile)"
790 }
791 @ [<a href="%s(g.zTop)/artifact/%T(zChngUuid)">%s(zShort)</a>]
792 @ (rid %d(rid)) by
793 hyperlink_to_user(zUser,zDate," on");
794 hyperlink_to_date(zDate, ".</p>");
795 }else{
796 pTicket = manifest_get(rid, CFTYPE_TICKET);
797 if( pTicket ){
798 @
799 @ <p>Ticket change
800 @ [<a href="%s(g.zTop)/artifact/%T(zChngUuid)">%s(zShort)</a>]
801 @ (rid %d(rid)) by
802 hyperlink_to_user(pTicket->zUser,zDate," on");
803 hyperlink_to_date(zDate, ":");
804 @ </p>
805 ticket_output_change_artifact(pTicket);
806
--- src/tkt.c
+++ src/tkt.c
@@ -305,11 +305,11 @@
305 if( !g.perm.RdTkt ){ login_needed(); return; }
306 if( g.perm.WrTkt || g.perm.ApndTkt ){
307 style_submenu_element("Edit", "Edit The Ticket", "%s/tktedit?name=%T",
308 g.zTop, PD("name",""));
309 }
310 if( g.perm.Hyperlink ){
311 style_submenu_element("History", "History Of This Ticket",
312 "%s/tkthistory/%T", g.zTop, zUuid);
313 style_submenu_element("Timeline", "Timeline Of This Ticket",
314 "%s/tkttimeline/%T", g.zTop, zUuid);
315 style_submenu_element("Check-ins", "Check-ins Of This Ticket",
@@ -319,11 +319,11 @@
319 style_submenu_element("New Ticket", "Create a new ticket",
320 "%s/tktnew", g.zTop);
321 }
322 if( g.perm.ApndTkt && g.perm.Attach ){
323 style_submenu_element("Attach", "Add An Attachment",
324 "%s/attachadd?tkt=%T&from=%s/tktview/%t",
325 g.zTop, zUuid, g.zTop, zUuid);
326 }
327 style_header("View Ticket");
328 if( g.thTrace ) Th_Trace("BEGIN_TKTVIEW<br />\n", -1);
329 ticket_init();
@@ -353,20 +353,20 @@
353 @ <hr /><h2>Attachments:</h2>
354 @ <ul>
355 }
356 cnt++;
357 @ <li>
358 if( g.perm.Read && g.perm.Hyperlink ){
359 @ %z(href("%R/attachview?tkt=%s&file=%t",zFullName,zFile))
360 @ %h(zFile)</a>
361 }else{
362 @ %h(zFile)
363 }
364 @ added by %h(zUser) on
365 hyperlink_to_date(zDate, ".");
366 if( g.perm.WrTkt && g.perm.Attach ){
367 @ [%z(href("%R/attachdelete?tkt=%s&file=%t&from=%R/tktview%%3fname=%s",zFullName,zFile,zFullName))delete</a>]
368 }
369 @ </li>
370 }
371 if( cnt ){
372 @ </ul>
@@ -647,11 +647,11 @@
647 return 0;
648 }
649
650 /*
651 ** WEBPAGE: tkttimeline
652 ** URL: /tkttimeline?name=TICKETUUID&y=TYPE
653 **
654 ** Show the change history for a single ticket in timeline format.
655 */
656 void tkttimeline_page(void){
657 Stmt q;
@@ -662,16 +662,16 @@
662 int tagid;
663 char zGlobPattern[50];
664 const char *zType;
665
666 login_check_credentials();
667 if( !g.perm.Hyperlink || !g.perm.RdTkt ){ login_needed(); return; }
668 zUuid = PD("name","");
669 zType = PD("y","a");
670 if( zType[0]!='c' ){
671 style_submenu_element("Check-ins", "Check-ins",
672 "%s/tkttimeline?name=%T&y=ci", g.zTop, zUuid);
673 }else{
674 style_submenu_element("Timeline", "Timeline",
675 "%s/tkttimeline?name=%T", g.zTop, zUuid);
676 }
677 style_submenu_element("History", "History",
@@ -736,17 +736,17 @@
736 char *zTitle;
737 const char *zUuid;
738 int tagid;
739
740 login_check_credentials();
741 if( !g.perm.Hyperlink || !g.perm.RdTkt ){ login_needed(); return; }
742 zUuid = PD("name","");
743 zTitle = mprintf("History Of Ticket %h", zUuid);
744 style_submenu_element("Status", "Status",
745 "%s/info/%s", g.zTop, zUuid);
746 style_submenu_element("Check-ins", "Check-ins",
747 "%s/tkttimeline?name=%s&y=ci", g.zTop, zUuid);
748 style_submenu_element("Timeline", "Timeline",
749 "%s/tkttimeline?name=%s", g.zTop, zUuid);
750 style_header(zTitle);
751 free(zTitle);
752
@@ -786,20 +786,20 @@
786 @ <p>Delete attachment "%h(zFile)"
787 }else{
788 @
789 @ <p>Add attachment "%h(zFile)"
790 }
791 @ [%z(href("%R/artifact/%T",zChngUuid))%s(zShort)</a>]
792 @ (rid %d(rid)) by
793 hyperlink_to_user(zUser,zDate," on");
794 hyperlink_to_date(zDate, ".</p>");
795 }else{
796 pTicket = manifest_get(rid, CFTYPE_TICKET);
797 if( pTicket ){
798 @
799 @ <p>Ticket change
800 @ [%z(href("%R/artifact/%T",zChngUuid))%s(zShort)</a>]
801 @ (rid %d(rid)) by
802 hyperlink_to_user(pTicket->zUser,zDate," on");
803 hyperlink_to_date(zDate, ":");
804 @ </p>
805 ticket_output_change_artifact(pTicket);
806
+19 -21
--- src/wiki.c
+++ src/wiki.c
@@ -104,11 +104,11 @@
104104
return;
105105
}
106106
style_header("Home");
107107
@ <p>This is a stub home-page for the project.
108108
@ To fill in this page, first go to
109
- @ <a href="%s(g.zTop)/setup_config">setup/config</a>
109
+ @ %z(href("%R/setup_config"))setup/config</a>
110110
@ and establish a "Project Name". Then create a
111111
@ wiki page with that name. The content of that wiki page
112112
@ will be displayed in place of this message.</p>
113113
style_footer();
114114
}
@@ -142,27 +142,25 @@
142142
if( zPageName==0 ){
143143
style_header("Wiki");
144144
@ <ul>
145145
{ char *zHomePageName = db_get("project-name",0);
146146
if( zHomePageName ){
147
- @ <li> <a href="%s(g.zTop)/wiki?name=%t(zHomePageName)">
147
+ @ <li> %z(href("%R/wiki?name=%t",zHomePageName))
148148
@ %h(zHomePageName)</a> wiki home page.</li>
149149
}
150150
}
151
- @ <li> <a href="%s(g.zTop)/timeline?y=w">Recent changes</a> to wiki
152
- @ pages. </li>
153
- @ <li> <a href="%s(g.zTop)/wiki_rules">Formatting rules</a> for
154
- @ wiki.</li>
155
- @ <li> Use the <a href="%s(g.zTop)/wiki?name=Sandbox">Sandbox</a>
151
+ @ <li> %z(href("%R/timeline?y=w"))Recent changes</a> to wiki pages.</li>
152
+ @ <li> %z(href("%R/wiki_rules"))Formatting rules</a> for wiki.</li>
153
+ @ <li> Use the %z(href("%R/wiki?name=Sandbox"))Sandbox</a>
156154
@ to experiment.</li>
157155
if( g.perm.NewWiki ){
158
- @ <li> Create a <a href="%s(g.zTop)/wikinew">new wiki page</a>.</li>
156
+ @ <li> Create a %z(href("%R/wikinew"))new wiki page</a>.</li>
159157
if( g.perm.Write ){
160
- @ <li> Create a <a href="%s(g.zTop)/eventedit">new event</a>.</li>
158
+ @ <li> Create a %z(href("%R/eventedit"))new event</a>.</li>
161159
}
162160
}
163
- @ <li> <a href="%s(g.zTop)/wcontent">List of All Wiki Pages</a>
161
+ @ <li> %z(href("%R/wcontent"))List of All Wiki Pages</a>
164162
@ available on this server.</li>
165163
@ <li> <form method="get" action="%s(g.zTop)/wfind"><div>
166164
@ Search wiki titles: <input type="text" name="title"/>
167165
@ &nbsp; <input type="submit" /></div></form>
168166
@ </li>
@@ -192,18 +190,18 @@
192190
style_submenu_element("Edit", "Edit Wiki Page", "%s/wikiedit?name=%T",
193191
g.zTop, zPageName);
194192
}
195193
if( rid && g.perm.ApndWiki && g.perm.Attach ){
196194
style_submenu_element("Attach", "Add An Attachment",
197
- "%s/attachadd?page=%T&amp;from=%s/wiki%%3fname=%T",
195
+ "%s/attachadd?page=%T&from=%s/wiki%%3fname=%T",
198196
g.zTop, zPageName, g.zTop, zPageName);
199197
}
200198
if( rid && g.perm.ApndWiki ){
201199
style_submenu_element("Append", "Add A Comment", "%s/wikiappend?name=%T",
202200
g.zTop, zPageName);
203201
}
204
- if( g.perm.History ){
202
+ if( g.perm.Hyperlink ){
205203
style_submenu_element("History", "History", "%s/whistory?name=%T",
206204
g.zTop, zPageName);
207205
}
208206
}
209207
style_header(zPageName);
@@ -225,20 +223,20 @@
225223
@ <hr /><h2>Attachments:</h2>
226224
@ <ul>
227225
}
228226
cnt++;
229227
@ <li>
230
- if( g.perm.History && g.perm.Read ){
231
- @ <a href="%s(g.zTop)/attachview?page=%s(zPageName)&amp;file=%t(zFile)">
228
+ if( g.perm.Hyperlink && g.perm.Read ){
229
+ @ %z(href("%R/attachview?page=%T&file=%t",zPageName,zFile))
232230
@ %h(zFile)</a>
233231
}else{
234232
@ %h(zFile)
235233
}
236234
@ added by %h(zUser) on
237235
hyperlink_to_date(zDate, ".");
238236
if( g.perm.WrWiki && g.perm.Attach ){
239
- @ [<a href="%s(g.zTop)/attachdelete?page=%s(zPageName)&amp;file=%t(zFile)&amp;from=%s(g.zTop)/wiki%%3fname=%s(zPageName)">delete</a>]
237
+ @ [%z(href("%R/attachdelete?page=%t&file=%t&from=%R/wiki%%3fname=%f",zPageName,zFile,zPageName))delete</a>]
240238
}
241239
@ </li>
242240
}
243241
if( cnt ){
244242
@ </ul>
@@ -544,11 +542,11 @@
544542
** Function called to output extra text at the end of each line in
545543
** a wiki history listing.
546544
*/
547545
static void wiki_history_extra(int rid){
548546
if( db_exists("SELECT 1 FROM tagxref WHERE rid=%d", rid) ){
549
- @ <a href="%s(g.zTop)/wdiff?name=%t(zWikiPageName)&amp;a=%d(rid)">[diff]</a>
547
+ @ %z(href("%R/wdiff?name=%t&a=%d",zWikiPageName,rid))[diff]</a>
550548
}
551549
}
552550
553551
/*
554552
** WEBPAGE: whistory
@@ -560,11 +558,11 @@
560558
Stmt q;
561559
char *zTitle;
562560
char *zSQL;
563561
const char *zPageName;
564562
login_check_credentials();
565
- if( !g.perm.History ){ login_needed(); return; }
563
+ if( !g.perm.Hyperlink ){ login_needed(); return; }
566564
zPageName = PD("name","");
567565
zTitle = mprintf("History Of %s", zPageName);
568566
style_header(zTitle);
569567
free(zTitle);
570568
@@ -597,11 +595,11 @@
597595
Blob w1, w2, d;
598596
int diffFlags;
599597
600598
login_check_credentials();
601599
rid1 = atoi(PD("a","0"));
602
- if( !g.perm.History ){ login_needed(); return; }
600
+ if( !g.perm.Hyperlink ){ login_needed(); return; }
603601
if( rid1==0 ) fossil_redirect_home();
604602
rid2 = atoi(PD("b","0"));
605603
zPageName = PD("name","");
606604
zTitle = mprintf("Changes To %s", zPageName);
607605
style_header(zTitle);
@@ -674,13 +672,13 @@
674672
wiki_prepare_page_list(&q);
675673
while( db_step(&q)==SQLITE_ROW ){
676674
const char *zName = db_column_text(&q, 0);
677675
int size = db_column_int(&q, 1);
678676
if( size>0 ){
679
- @ <li><a href="%s(g.zTop)/wiki?name=%T(zName)">%h(zName)</a></li>
677
+ @ <li>%z(href("%R/wiki?name=%T",zName))%h(zName)</a></li>
680678
}else if( showAll ){
681
- @ <li><a href="%s(g.zTop)/wiki?name=%T(zName)"><s>%h(zName)</s></a></li>
679
+ @ <li>%z(href("%R/wiki?name=%T",zName))<s>%h(zName)</s></a></li>
682680
}
683681
}
684682
db_finalize(&q);
685683
@ </ul>
686684
style_footer();
@@ -704,11 +702,11 @@
704702
"SELECT substr(tagname, 6, 1000) FROM tag WHERE tagname like 'wiki-%%%q%%'"
705703
" ORDER BY lower(tagname) /*sort*/" ,
706704
zTitle);
707705
while( db_step(&q)==SQLITE_ROW ){
708706
const char *zName = db_column_text(&q, 0);
709
- @ <li><a href="%s(g.zTop)/wiki?name=%T(zName)">%h(zName)</a></li>
707
+ @ <li>%z(href("%R/wiki?name=%T",zName))%h(zName)</a></li>
710708
}
711709
db_finalize(&q);
712710
@ </ul>
713711
style_footer();
714712
}
715713
--- src/wiki.c
+++ src/wiki.c
@@ -104,11 +104,11 @@
104 return;
105 }
106 style_header("Home");
107 @ <p>This is a stub home-page for the project.
108 @ To fill in this page, first go to
109 @ <a href="%s(g.zTop)/setup_config">setup/config</a>
110 @ and establish a "Project Name". Then create a
111 @ wiki page with that name. The content of that wiki page
112 @ will be displayed in place of this message.</p>
113 style_footer();
114 }
@@ -142,27 +142,25 @@
142 if( zPageName==0 ){
143 style_header("Wiki");
144 @ <ul>
145 { char *zHomePageName = db_get("project-name",0);
146 if( zHomePageName ){
147 @ <li> <a href="%s(g.zTop)/wiki?name=%t(zHomePageName)">
148 @ %h(zHomePageName)</a> wiki home page.</li>
149 }
150 }
151 @ <li> <a href="%s(g.zTop)/timeline?y=w">Recent changes</a> to wiki
152 @ pages. </li>
153 @ <li> <a href="%s(g.zTop)/wiki_rules">Formatting rules</a> for
154 @ wiki.</li>
155 @ <li> Use the <a href="%s(g.zTop)/wiki?name=Sandbox">Sandbox</a>
156 @ to experiment.</li>
157 if( g.perm.NewWiki ){
158 @ <li> Create a <a href="%s(g.zTop)/wikinew">new wiki page</a>.</li>
159 if( g.perm.Write ){
160 @ <li> Create a <a href="%s(g.zTop)/eventedit">new event</a>.</li>
161 }
162 }
163 @ <li> <a href="%s(g.zTop)/wcontent">List of All Wiki Pages</a>
164 @ available on this server.</li>
165 @ <li> <form method="get" action="%s(g.zTop)/wfind"><div>
166 @ Search wiki titles: <input type="text" name="title"/>
167 @ &nbsp; <input type="submit" /></div></form>
168 @ </li>
@@ -192,18 +190,18 @@
192 style_submenu_element("Edit", "Edit Wiki Page", "%s/wikiedit?name=%T",
193 g.zTop, zPageName);
194 }
195 if( rid && g.perm.ApndWiki && g.perm.Attach ){
196 style_submenu_element("Attach", "Add An Attachment",
197 "%s/attachadd?page=%T&amp;from=%s/wiki%%3fname=%T",
198 g.zTop, zPageName, g.zTop, zPageName);
199 }
200 if( rid && g.perm.ApndWiki ){
201 style_submenu_element("Append", "Add A Comment", "%s/wikiappend?name=%T",
202 g.zTop, zPageName);
203 }
204 if( g.perm.History ){
205 style_submenu_element("History", "History", "%s/whistory?name=%T",
206 g.zTop, zPageName);
207 }
208 }
209 style_header(zPageName);
@@ -225,20 +223,20 @@
225 @ <hr /><h2>Attachments:</h2>
226 @ <ul>
227 }
228 cnt++;
229 @ <li>
230 if( g.perm.History && g.perm.Read ){
231 @ <a href="%s(g.zTop)/attachview?page=%s(zPageName)&amp;file=%t(zFile)">
232 @ %h(zFile)</a>
233 }else{
234 @ %h(zFile)
235 }
236 @ added by %h(zUser) on
237 hyperlink_to_date(zDate, ".");
238 if( g.perm.WrWiki && g.perm.Attach ){
239 @ [<a href="%s(g.zTop)/attachdelete?page=%s(zPageName)&amp;file=%t(zFile)&amp;from=%s(g.zTop)/wiki%%3fname=%s(zPageName)">delete</a>]
240 }
241 @ </li>
242 }
243 if( cnt ){
244 @ </ul>
@@ -544,11 +542,11 @@
544 ** Function called to output extra text at the end of each line in
545 ** a wiki history listing.
546 */
547 static void wiki_history_extra(int rid){
548 if( db_exists("SELECT 1 FROM tagxref WHERE rid=%d", rid) ){
549 @ <a href="%s(g.zTop)/wdiff?name=%t(zWikiPageName)&amp;a=%d(rid)">[diff]</a>
550 }
551 }
552
553 /*
554 ** WEBPAGE: whistory
@@ -560,11 +558,11 @@
560 Stmt q;
561 char *zTitle;
562 char *zSQL;
563 const char *zPageName;
564 login_check_credentials();
565 if( !g.perm.History ){ login_needed(); return; }
566 zPageName = PD("name","");
567 zTitle = mprintf("History Of %s", zPageName);
568 style_header(zTitle);
569 free(zTitle);
570
@@ -597,11 +595,11 @@
597 Blob w1, w2, d;
598 int diffFlags;
599
600 login_check_credentials();
601 rid1 = atoi(PD("a","0"));
602 if( !g.perm.History ){ login_needed(); return; }
603 if( rid1==0 ) fossil_redirect_home();
604 rid2 = atoi(PD("b","0"));
605 zPageName = PD("name","");
606 zTitle = mprintf("Changes To %s", zPageName);
607 style_header(zTitle);
@@ -674,13 +672,13 @@
674 wiki_prepare_page_list(&q);
675 while( db_step(&q)==SQLITE_ROW ){
676 const char *zName = db_column_text(&q, 0);
677 int size = db_column_int(&q, 1);
678 if( size>0 ){
679 @ <li><a href="%s(g.zTop)/wiki?name=%T(zName)">%h(zName)</a></li>
680 }else if( showAll ){
681 @ <li><a href="%s(g.zTop)/wiki?name=%T(zName)"><s>%h(zName)</s></a></li>
682 }
683 }
684 db_finalize(&q);
685 @ </ul>
686 style_footer();
@@ -704,11 +702,11 @@
704 "SELECT substr(tagname, 6, 1000) FROM tag WHERE tagname like 'wiki-%%%q%%'"
705 " ORDER BY lower(tagname) /*sort*/" ,
706 zTitle);
707 while( db_step(&q)==SQLITE_ROW ){
708 const char *zName = db_column_text(&q, 0);
709 @ <li><a href="%s(g.zTop)/wiki?name=%T(zName)">%h(zName)</a></li>
710 }
711 db_finalize(&q);
712 @ </ul>
713 style_footer();
714 }
715
--- src/wiki.c
+++ src/wiki.c
@@ -104,11 +104,11 @@
104 return;
105 }
106 style_header("Home");
107 @ <p>This is a stub home-page for the project.
108 @ To fill in this page, first go to
109 @ %z(href("%R/setup_config"))setup/config</a>
110 @ and establish a "Project Name". Then create a
111 @ wiki page with that name. The content of that wiki page
112 @ will be displayed in place of this message.</p>
113 style_footer();
114 }
@@ -142,27 +142,25 @@
142 if( zPageName==0 ){
143 style_header("Wiki");
144 @ <ul>
145 { char *zHomePageName = db_get("project-name",0);
146 if( zHomePageName ){
147 @ <li> %z(href("%R/wiki?name=%t",zHomePageName))
148 @ %h(zHomePageName)</a> wiki home page.</li>
149 }
150 }
151 @ <li> %z(href("%R/timeline?y=w"))Recent changes</a> to wiki pages.</li>
152 @ <li> %z(href("%R/wiki_rules"))Formatting rules</a> for wiki.</li>
153 @ <li> Use the %z(href("%R/wiki?name=Sandbox"))Sandbox</a>
 
 
154 @ to experiment.</li>
155 if( g.perm.NewWiki ){
156 @ <li> Create a %z(href("%R/wikinew"))new wiki page</a>.</li>
157 if( g.perm.Write ){
158 @ <li> Create a %z(href("%R/eventedit"))new event</a>.</li>
159 }
160 }
161 @ <li> %z(href("%R/wcontent"))List of All Wiki Pages</a>
162 @ available on this server.</li>
163 @ <li> <form method="get" action="%s(g.zTop)/wfind"><div>
164 @ Search wiki titles: <input type="text" name="title"/>
165 @ &nbsp; <input type="submit" /></div></form>
166 @ </li>
@@ -192,18 +190,18 @@
190 style_submenu_element("Edit", "Edit Wiki Page", "%s/wikiedit?name=%T",
191 g.zTop, zPageName);
192 }
193 if( rid && g.perm.ApndWiki && g.perm.Attach ){
194 style_submenu_element("Attach", "Add An Attachment",
195 "%s/attachadd?page=%T&from=%s/wiki%%3fname=%T",
196 g.zTop, zPageName, g.zTop, zPageName);
197 }
198 if( rid && g.perm.ApndWiki ){
199 style_submenu_element("Append", "Add A Comment", "%s/wikiappend?name=%T",
200 g.zTop, zPageName);
201 }
202 if( g.perm.Hyperlink ){
203 style_submenu_element("History", "History", "%s/whistory?name=%T",
204 g.zTop, zPageName);
205 }
206 }
207 style_header(zPageName);
@@ -225,20 +223,20 @@
223 @ <hr /><h2>Attachments:</h2>
224 @ <ul>
225 }
226 cnt++;
227 @ <li>
228 if( g.perm.Hyperlink && g.perm.Read ){
229 @ %z(href("%R/attachview?page=%T&file=%t",zPageName,zFile))
230 @ %h(zFile)</a>
231 }else{
232 @ %h(zFile)
233 }
234 @ added by %h(zUser) on
235 hyperlink_to_date(zDate, ".");
236 if( g.perm.WrWiki && g.perm.Attach ){
237 @ [%z(href("%R/attachdelete?page=%t&file=%t&from=%R/wiki%%3fname=%f",zPageName,zFile,zPageName))delete</a>]
238 }
239 @ </li>
240 }
241 if( cnt ){
242 @ </ul>
@@ -544,11 +542,11 @@
542 ** Function called to output extra text at the end of each line in
543 ** a wiki history listing.
544 */
545 static void wiki_history_extra(int rid){
546 if( db_exists("SELECT 1 FROM tagxref WHERE rid=%d", rid) ){
547 @ %z(href("%R/wdiff?name=%t&a=%d",zWikiPageName,rid))[diff]</a>
548 }
549 }
550
551 /*
552 ** WEBPAGE: whistory
@@ -560,11 +558,11 @@
558 Stmt q;
559 char *zTitle;
560 char *zSQL;
561 const char *zPageName;
562 login_check_credentials();
563 if( !g.perm.Hyperlink ){ login_needed(); return; }
564 zPageName = PD("name","");
565 zTitle = mprintf("History Of %s", zPageName);
566 style_header(zTitle);
567 free(zTitle);
568
@@ -597,11 +595,11 @@
595 Blob w1, w2, d;
596 int diffFlags;
597
598 login_check_credentials();
599 rid1 = atoi(PD("a","0"));
600 if( !g.perm.Hyperlink ){ login_needed(); return; }
601 if( rid1==0 ) fossil_redirect_home();
602 rid2 = atoi(PD("b","0"));
603 zPageName = PD("name","");
604 zTitle = mprintf("Changes To %s", zPageName);
605 style_header(zTitle);
@@ -674,13 +672,13 @@
672 wiki_prepare_page_list(&q);
673 while( db_step(&q)==SQLITE_ROW ){
674 const char *zName = db_column_text(&q, 0);
675 int size = db_column_int(&q, 1);
676 if( size>0 ){
677 @ <li>%z(href("%R/wiki?name=%T",zName))%h(zName)</a></li>
678 }else if( showAll ){
679 @ <li>%z(href("%R/wiki?name=%T",zName))<s>%h(zName)</s></a></li>
680 }
681 }
682 db_finalize(&q);
683 @ </ul>
684 style_footer();
@@ -704,11 +702,11 @@
702 "SELECT substr(tagname, 6, 1000) FROM tag WHERE tagname like 'wiki-%%%q%%'"
703 " ORDER BY lower(tagname) /*sort*/" ,
704 zTitle);
705 while( db_step(&q)==SQLITE_ROW ){
706 const char *zName = db_column_text(&q, 0);
707 @ <li>%z(href("%R/wiki?name=%T",zName))%h(zName)</a></li>
708 }
709 db_finalize(&q);
710 @ </ul>
711 style_footer();
712 }
713
+9 -15
--- src/wikiformat.c
+++ src/wikiformat.c
@@ -1043,17 +1043,13 @@
10431043
|| strncmp(zTarget, "mailto:", 7)==0
10441044
){
10451045
blob_appendf(p->pOut, "<a href=\"%s\">", zTarget);
10461046
/* zTerm = "&#x27FE;</a>"; // doesn't work on windows */
10471047
}else if( zTarget[0]=='/' ){
1048
- if( 1 /* g.perm.History */ ){
1049
- blob_appendf(p->pOut, "<a href=\"%s%h\">", g.zTop, zTarget);
1050
- }else{
1051
- zTerm = "";
1052
- }
1048
+ blob_appendf(p->pOut, "<a href=\"%s%h\">", g.zTop, zTarget);
10531049
}else if( zTarget[0]=='.' || zTarget[0]=='#' ){
1054
- if( 1 /* g.perm.History */ ){
1050
+ if( 1 ){
10551051
blob_appendf(p->pOut, "<a href=\"%h\">", zTarget);
10561052
}else{
10571053
zTerm = "";
10581054
}
10591055
}else if( is_valid_uuid(zTarget) ){
@@ -1061,36 +1057,34 @@
10611057
if( is_ticket(zTarget, &isClosed) ){
10621058
/* Special display processing for tickets. Display the hyperlink
10631059
** as crossed out if the ticket is closed.
10641060
*/
10651061
if( isClosed ){
1066
- if( g.perm.History ){
1062
+ if( g.perm.Hyperlink ){
10671063
blob_appendf(p->pOut,
1068
- "<a href=\"%s/info/%s\"><span class=\"wikiTagCancelled\">[",
1069
- g.zTop, zTarget
1064
+ "%z<span class=\"wikiTagCancelled\">[",
1065
+ href("%R/info/%s",zTarget)
10701066
);
10711067
zTerm = "]</span></a>";
10721068
}else{
10731069
blob_appendf(p->pOut,"<span class=\"wikiTagCancelled\">[");
10741070
zTerm = "]</span>";
10751071
}
10761072
}else{
1077
- if( g.perm.History ){
1078
- blob_appendf(p->pOut,"<a href=\"%s/info/%s\">[",
1079
- g.zTop, zTarget
1080
- );
1073
+ if( g.perm.Hyperlink ){
1074
+ blob_appendf(p->pOut,"%z[", href("%R/info/%s", zTarget));
10811075
zTerm = "]</a>";
10821076
}else{
10831077
blob_appendf(p->pOut, "[");
10841078
zTerm = "]";
10851079
}
10861080
}
10871081
}else if( !in_this_repo(zTarget) ){
10881082
blob_appendf(p->pOut, "<span class=\"brokenlink\">[", zTarget);
10891083
zTerm = "]</span>";
1090
- }else if( g.perm.History ){
1091
- blob_appendf(p->pOut, "<a href=\"%s/info/%s\">[", g.zTop, zTarget);
1084
+ }else if( g.perm.Hyperlink ){
1085
+ blob_appendf(p->pOut, "%z[",href("%R/info/%s", zTarget));
10921086
zTerm = "]</a>";
10931087
}
10941088
}else if( strlen(zTarget)>=10 && fossil_isdigit(zTarget[0]) && zTarget[4]=='-'
10951089
&& db_int(0, "SELECT datetime(%Q) NOT NULL", zTarget) ){
10961090
blob_appendf(p->pOut, "<a href=\"%s/timeline?c=%T\">", g.zTop, zTarget);
10971091
--- src/wikiformat.c
+++ src/wikiformat.c
@@ -1043,17 +1043,13 @@
1043 || strncmp(zTarget, "mailto:", 7)==0
1044 ){
1045 blob_appendf(p->pOut, "<a href=\"%s\">", zTarget);
1046 /* zTerm = "&#x27FE;</a>"; // doesn't work on windows */
1047 }else if( zTarget[0]=='/' ){
1048 if( 1 /* g.perm.History */ ){
1049 blob_appendf(p->pOut, "<a href=\"%s%h\">", g.zTop, zTarget);
1050 }else{
1051 zTerm = "";
1052 }
1053 }else if( zTarget[0]=='.' || zTarget[0]=='#' ){
1054 if( 1 /* g.perm.History */ ){
1055 blob_appendf(p->pOut, "<a href=\"%h\">", zTarget);
1056 }else{
1057 zTerm = "";
1058 }
1059 }else if( is_valid_uuid(zTarget) ){
@@ -1061,36 +1057,34 @@
1061 if( is_ticket(zTarget, &isClosed) ){
1062 /* Special display processing for tickets. Display the hyperlink
1063 ** as crossed out if the ticket is closed.
1064 */
1065 if( isClosed ){
1066 if( g.perm.History ){
1067 blob_appendf(p->pOut,
1068 "<a href=\"%s/info/%s\"><span class=\"wikiTagCancelled\">[",
1069 g.zTop, zTarget
1070 );
1071 zTerm = "]</span></a>";
1072 }else{
1073 blob_appendf(p->pOut,"<span class=\"wikiTagCancelled\">[");
1074 zTerm = "]</span>";
1075 }
1076 }else{
1077 if( g.perm.History ){
1078 blob_appendf(p->pOut,"<a href=\"%s/info/%s\">[",
1079 g.zTop, zTarget
1080 );
1081 zTerm = "]</a>";
1082 }else{
1083 blob_appendf(p->pOut, "[");
1084 zTerm = "]";
1085 }
1086 }
1087 }else if( !in_this_repo(zTarget) ){
1088 blob_appendf(p->pOut, "<span class=\"brokenlink\">[", zTarget);
1089 zTerm = "]</span>";
1090 }else if( g.perm.History ){
1091 blob_appendf(p->pOut, "<a href=\"%s/info/%s\">[", g.zTop, zTarget);
1092 zTerm = "]</a>";
1093 }
1094 }else if( strlen(zTarget)>=10 && fossil_isdigit(zTarget[0]) && zTarget[4]=='-'
1095 && db_int(0, "SELECT datetime(%Q) NOT NULL", zTarget) ){
1096 blob_appendf(p->pOut, "<a href=\"%s/timeline?c=%T\">", g.zTop, zTarget);
1097
--- src/wikiformat.c
+++ src/wikiformat.c
@@ -1043,17 +1043,13 @@
1043 || strncmp(zTarget, "mailto:", 7)==0
1044 ){
1045 blob_appendf(p->pOut, "<a href=\"%s\">", zTarget);
1046 /* zTerm = "&#x27FE;</a>"; // doesn't work on windows */
1047 }else if( zTarget[0]=='/' ){
1048 blob_appendf(p->pOut, "<a href=\"%s%h\">", g.zTop, zTarget);
 
 
 
 
1049 }else if( zTarget[0]=='.' || zTarget[0]=='#' ){
1050 if( 1 ){
1051 blob_appendf(p->pOut, "<a href=\"%h\">", zTarget);
1052 }else{
1053 zTerm = "";
1054 }
1055 }else if( is_valid_uuid(zTarget) ){
@@ -1061,36 +1057,34 @@
1057 if( is_ticket(zTarget, &isClosed) ){
1058 /* Special display processing for tickets. Display the hyperlink
1059 ** as crossed out if the ticket is closed.
1060 */
1061 if( isClosed ){
1062 if( g.perm.Hyperlink ){
1063 blob_appendf(p->pOut,
1064 "%z<span class=\"wikiTagCancelled\">[",
1065 href("%R/info/%s",zTarget)
1066 );
1067 zTerm = "]</span></a>";
1068 }else{
1069 blob_appendf(p->pOut,"<span class=\"wikiTagCancelled\">[");
1070 zTerm = "]</span>";
1071 }
1072 }else{
1073 if( g.perm.Hyperlink ){
1074 blob_appendf(p->pOut,"%z[", href("%R/info/%s", zTarget));
 
 
1075 zTerm = "]</a>";
1076 }else{
1077 blob_appendf(p->pOut, "[");
1078 zTerm = "]";
1079 }
1080 }
1081 }else if( !in_this_repo(zTarget) ){
1082 blob_appendf(p->pOut, "<span class=\"brokenlink\">[", zTarget);
1083 zTerm = "]</span>";
1084 }else if( g.perm.Hyperlink ){
1085 blob_appendf(p->pOut, "%z[",href("%R/info/%s", zTarget));
1086 zTerm = "]</a>";
1087 }
1088 }else if( strlen(zTarget)>=10 && fossil_isdigit(zTarget[0]) && zTarget[4]=='-'
1089 && db_int(0, "SELECT datetime(%Q) NOT NULL", zTarget) ){
1090 blob_appendf(p->pOut, "<a href=\"%s/timeline?c=%T\">", g.zTop, zTarget);
1091

Keyboard Shortcuts

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