Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Changes In Branch spider-defense Excluding Merge-Ins
This is equivalent to a diff from f9711803e2 to d9c8a7dd73
2012-04-28
| ||
08:05 | Move the enhanced spider-defense mechanism into the trunk. check-in: 433cde1ce8 user: drh tags: trunk | |
08:03 | Refinements to the new hyperlink logic and spider defense. Closed-Leaf check-in: d9c8a7dd73 user: drh tags: spider-defense | |
07:15 | Changes anchor tags (<a>) so that the href= attribute can be set by javascript rather than by HTML. This is to make it harder for spiders to follow the hyperlinks to every diff and annotation in the project history. It all seems to work, but it needs further testing and review before going live. check-in: 8ae52fc418 user: drh tags: spider-defense | |
03:32 | Enhance the "translate" utility so that formatting characters can occur in between the "%" and "C" of a printf-style conversion on @-lines. check-in: f9711803e2 user: drh tags: trunk | |
2012-04-27
| ||
15:56 | Always update the baseurl: entry in the config table if using a repository from a URL that has not previously been recorded. check-in: c7d6e334f8 user: drh tags: trunk | |
Changes to src/attach.c.
73 73 for(i=0; zFilename[i]; i++){ 74 74 if( zFilename[i]=='/' && zFilename[i+1]!=0 ){ 75 75 zFilename = &zFilename[i+1]; 76 76 i = -1; 77 77 } 78 78 } 79 79 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); 81 81 }else{ 82 - zUrlTail = mprintf("page=%t&file=%t", zTarget, zFilename); 82 + zUrlTail = mprintf("page=%t&file=%t", zTarget, zFilename); 83 83 } 84 84 @ 85 85 @ <p><a href="/attachview?%s(zUrlTail)">%h(zFilename)</a> 86 86 @ [<a href="/attachdownload/%t(zFilename)?%s(zUrlTail)">download</a>]<br /> 87 87 if( zComment ) while( fossil_isspace(zComment[0]) ) zComment++; 88 88 if( zComment && zComment[0] ){ 89 89 @ %w(zComment)<br />
Changes to src/branch.c.
319 319 style_submenu_element("Color-Test", "Color-Test", "brlist?colortest"); 320 320 }else{ 321 321 style_submenu_element("All", "All", "brlist?all"); 322 322 } 323 323 login_anonymous_available(); 324 324 style_sidebox_begin("Nomenclature:", "33%"); 325 325 @ <ol> 326 - @ <li> An <div class="sideboxDescribed"><a href="brlist"> 326 + @ <li> An <div class="sideboxDescribed">%z(href("brlist")) 327 327 @ 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> 329 329 @ The presence of open leaves presumably means 330 330 @ 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")) 332 332 @ 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")) 334 334 @ closed leaves</a></div>. 335 335 @ Closed branches are fixed and do not change (unless they are first 336 336 @ reopened)</li> 337 337 @ </ol> 338 338 style_sidebox_end(); 339 339 340 340 branch_prepare_list_query(&q, showAll?1:(showClosed?-1:0)); ................................................................................ 354 354 @ <ul> 355 355 cnt++; 356 356 } 357 357 if( colorTest ){ 358 358 const char *zColor = hash_color(zBr); 359 359 @ <li><span style="background-color: %s(zColor)"> 360 360 @ %h(zBr) → %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 361 }else{ 364 - @ <li><b>%h(zBr)</b></li> 362 + @ <li>%z(href("%R/timeline?r=%T",zBr))%h(zBr)</a></li> 365 363 } 366 364 } 367 365 if( cnt ){ 368 366 @ </ul> 369 367 } 370 368 db_finalize(&q); 371 369 @ <script type="text/JavaScript"> ................................................................................ 380 378 /* 381 379 ** This routine is called while for each check-in that is rendered by 382 380 ** the timeline of a "brlist" page. Add some additional hyperlinks 383 381 ** to the end of the line. 384 382 */ 385 383 static void brtimeline_extra(int rid){ 386 384 Stmt q; 387 - if( !g.perm.History ) return; 385 + if( !g.perm.Hyperlink ) return; 388 386 db_prepare(&q, 389 387 "SELECT substr(tagname,5) FROM tagxref, tag" 390 388 " WHERE tagxref.rid=%d" 391 389 " AND tagxref.tagid=tag.tagid" 392 390 " AND tagxref.tagtype>0" 393 391 " AND tag.tagname GLOB 'sym-*'", 394 392 rid 395 393 ); 396 394 while( db_step(&q)==SQLITE_ROW ){ 397 395 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> 399 397 } 400 398 db_finalize(&q); 401 399 } 402 400 403 401 /* 404 402 ** WEBPAGE: brtimeline 405 403 **
Changes to src/browse.c.
75 75 */ 76 76 void hyperlinked_path(const char *zPath, Blob *pOut, const char *zCI){ 77 77 int i, j; 78 78 char *zSep = ""; 79 79 80 80 for(i=0; zPath[i]; i=j){ 81 81 for(j=i; zPath[j] && zPath[j]!='/'; j++){} 82 - if( zPath[j] && g.perm.History ){ 82 + if( zPath[j] && g.perm.Hyperlink ){ 83 83 if( zCI ){ 84 - blob_appendf(pOut, "%s<a href=\"%s/dir?ci=%S&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]); 86 87 }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]); 89 91 } 90 92 }else{ 91 93 blob_appendf(pOut, "%s%#h", zSep, j-i, &zPath[i]); 92 94 } 93 95 zSep = "/"; 94 96 while( zPath[j]=='/' ){ j++; } 95 97 } ................................................................................ 116 118 int rid = 0; 117 119 char *zUuid = 0; 118 120 Blob dirname; 119 121 Manifest *pM = 0; 120 122 const char *zSubdirLink; 121 123 122 124 login_check_credentials(); 123 - if( !g.perm.History ){ login_needed(); return; } 125 + if( !g.perm.Hyperlink ){ login_needed(); return; } 124 126 while( nD>1 && zD[nD-2]=='/' ){ zD[(--nD)-1] = 0; } 125 127 style_header("File List"); 126 128 sqlite3_create_function(g.db, "pathelement", 2, SQLITE_UTF8, 0, 127 129 pathelementFunc, 0, 0); 128 130 129 131 /* If the name= parameter is an empty string, make it a NULL pointer */ 130 132 if( zD && strlen(zD)==0 ){ zD = 0; } ................................................................................ 153 155 blob_append(&dirname, "in the top-level directory", -1); 154 156 zPrefix = ""; 155 157 } 156 158 if( zCI ){ 157 159 char zShort[20]; 158 160 memcpy(zShort, zUuid, 10); 159 161 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>] 161 163 @ %s(blob_str(&dirname))</h2> 162 - zSubdirLink = mprintf("%s/dir?ci=%S&name=%T", g.zTop, zUuid, zPrefix); 164 + zSubdirLink = mprintf("%R/dir?ci=%S&name=%T", zUuid, zPrefix); 163 165 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); 166 168 }else{ 167 - style_submenu_element("All", "All", "%s/dir", g.zTop); 169 + style_submenu_element("All", "All", "%R/dir"); 168 170 } 169 171 }else{ 170 172 int hasTrunk; 171 173 @ <h2>The union of all files from all check-ins 172 174 @ %s(blob_str(&dirname))</h2> 173 175 hasTrunk = db_exists( 174 176 "SELECT 1 FROM tagxref WHERE tagid=%d AND value='trunk'", 175 177 TAG_BRANCH); 176 - zSubdirLink = mprintf("%s/dir?name=%T", g.zTop, zPrefix); 178 + zSubdirLink = mprintf("%R/dir?name=%T", zPrefix); 177 179 if( zD ){ 178 - style_submenu_element("Top", "Top", "%s/dir", g.zTop); 179 - style_submenu_element("Tip", "Tip", "%s/dir?name=%t&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); 181 182 if( hasTrunk ){ 182 - style_submenu_element("Trunk", "Trunk", "%s/dir?name=%t&ci=trunk", 183 - g.zTop,zD); 183 + style_submenu_element("Trunk", "Trunk", "%R/dir?name=%t&ci=trunk", 184 + zD); 184 185 } 185 186 }else{ 186 - style_submenu_element("Tip", "Tip", "%s/dir?ci=tip", g.zTop); 187 + style_submenu_element("Tip", "Tip", "%R/dir?ci=tip"); 187 188 if( hasTrunk ){ 188 - style_submenu_element("Trunk", "Trunk", "%s/dir?ci=trunk", g.zTop); 189 + style_submenu_element("Trunk", "Trunk", "%R/dir?ci=trunk"); 189 190 } 190 191 } 191 192 } 192 193 193 194 /* Compute the temporary table "localfiles" containing the names 194 195 ** of all files and subdirectories in the zD[] directory. 195 196 ** ................................................................................ 276 277 @ </ul></td><td class="browser"><ul class="browser"> 277 278 i = 0; 278 279 } 279 280 i++; 280 281 zFN = db_column_text(&q, 0); 281 282 if( zFN[0]=='/' ){ 282 283 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> 284 285 }else if( zCI ){ 285 286 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> 287 288 }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) 289 290 @ </a></li> 290 291 } 291 292 } 292 293 db_finalize(&q); 293 294 manifest_destroy(pM); 294 295 @ </ul></td></tr></table> 295 296 style_footer(); 296 297 }
Changes to src/diff.c.
1776 1776 while( db_step(&q)==SQLITE_ROW ){ 1777 1777 int pid = db_column_int(&q, 0); 1778 1778 const char *zUuid = db_column_text(&q, 1); 1779 1779 const char *zDate = db_column_text(&q, 2); 1780 1780 const char *zUser = db_column_text(&q, 3); 1781 1781 if( webLabel ){ 1782 1782 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 1785 1785 ); 1786 1786 }else{ 1787 1787 zLabel = mprintf("%.10s %s %13.13s", zUuid, zDate, zUser); 1788 1788 } 1789 1789 p->nVers++; 1790 1790 p->azVers = fossil_realloc(p->azVers, p->nVers*sizeof(p->azVers[0]) ); 1791 1791 p->azVers[p->nVers-1] = zLabel; ................................................................................ 1819 1819 if( mid==0 || fnid==0 ){ fossil_redirect_home(); } 1820 1820 iLimit = atoi(PD("limit","-1")); 1821 1821 if( !db_exists("SELECT 1 FROM mlink WHERE mid=%d AND fnid=%d",mid,fnid) ){ 1822 1822 fossil_redirect_home(); 1823 1823 } 1824 1824 style_header("File Annotation"); 1825 1825 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); 1827 1827 if( P("log") ){ 1828 1828 int i; 1829 1829 @ <h2>Versions analyzed:</h2> 1830 1830 @ <ol> 1831 1831 for(i=0; i<ann.nVers; i++){ 1832 1832 @ <li><tt>%s(ann.azVers[i])</tt></li> 1833 1833 }
Changes to src/diffcmd.c.
539 539 diff_all_two_versions(zFrom, zTo, zDiffCmd, diffFlags); 540 540 } 541 541 } 542 542 } 543 543 544 544 /* 545 545 ** WEBPAGE: vpatch 546 -** URL vpatch?from=UUID&to=UUID 546 +** URL vpatch?from=UUID&to=UUID 547 547 */ 548 548 void vpatch_page(void){ 549 549 const char *zFrom = P("from"); 550 550 const char *zTo = P("to"); 551 551 login_check_credentials(); 552 552 if( !g.perm.Read ){ login_needed(); return; } 553 553 if( zFrom==0 || zTo==0 ) fossil_redirect_home(); 554 554 555 555 cgi_set_content_type("text/plain"); 556 556 diff_all_two_versions(zFrom, zTo, 0, DIFF_NEWFILE); 557 557 }
Changes to src/event.c.
29 29 #include "event.h" 30 30 31 31 /* 32 32 ** Output a hyperlink to an event given its tagid. 33 33 */ 34 34 void hyperlink_to_event_tagid(int tagid){ 35 35 char *zEventId; 36 - char zShort[12]; 37 - 38 36 zEventId = db_text(0, "SELECT substr(tagname, 7) FROM tag WHERE tagid=%d", 39 37 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>] 46 39 free(zEventId); 47 40 } 48 41 49 42 /* 50 43 ** WEBPAGE: event 51 44 ** URL: /event 52 45 ** PARAMETERS: ................................................................................ 128 121 if( g.perm.WrWiki && g.perm.Write && nextRid==0 ){ 129 122 style_submenu_element("Edit", "Edit", "%s/eventedit?name=%s", 130 123 g.zTop, zEventId); 131 124 } 132 125 zETime = db_text(0, "SELECT datetime(%.17g)", pEvent->rEventDate); 133 126 style_submenu_element("Context", "Context", "%s/timeline?c=%T", 134 127 g.zTop, zETime); 135 - if( g.perm.History ){ 128 + if( g.perm.Hyperlink ){ 136 129 if( showDetail ){ 137 - style_submenu_element("Plain", "Plain", "%s/event?name=%s&aid=%s", 130 + style_submenu_element("Plain", "Plain", "%s/event?name=%s&aid=%s", 138 131 g.zTop, zEventId, zUuid); 139 132 if( nextRid ){ 140 133 char *zNext; 141 134 zNext = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", nextRid); 142 135 style_submenu_element("Next", "Next", 143 - "%s/event?name=%s&aid=%s&detail=1", 136 + "%s/event?name=%s&aid=%s&detail=1", 144 137 g.zTop, zEventId, zNext); 145 138 free(zNext); 146 139 } 147 140 if( prevRid ){ 148 141 char *zPrev; 149 142 zPrev = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", prevRid); 150 143 style_submenu_element("Prev", "Prev", 151 - "%s/event?name=%s&aid=%s&detail=1", 144 + "%s/event?name=%s&aid=%s&detail=1", 152 145 g.zTop, zEventId, zPrev); 153 146 free(zPrev); 154 147 } 155 148 }else{ 156 149 style_submenu_element("Detail", "Detail", 157 - "%s/event?name=%s&aid=%s&detail=1", 150 + "%s/event?name=%s&aid=%s&detail=1", 158 151 g.zTop, zEventId, zUuid); 159 152 } 160 153 } 161 154 162 - if( showDetail && g.perm.History ){ 155 + if( showDetail && g.perm.Hyperlink ){ 163 156 int i; 164 157 const char *zClr = 0; 165 158 Blob comment; 166 159 167 160 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>] 170 163 @ 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> 172 165 @ <blockquote> 173 166 for(i=0; i<pEvent->nTag; i++){ 174 167 if( fossil_strcmp(pEvent->aTag[i].zName,"+bgcolor")==0 ){ 175 168 zClr = pEvent->aTag[i].zValue; 176 169 } 177 170 } 178 171 if( zClr && zClr[0]==0 ) zClr = 0;
Changes to src/finfo.c.
303 303 @ <tr><td> 304 304 @ <div class="divider">%s(zPrevDate)</div> 305 305 @ </td></tr> 306 306 } 307 307 memcpy(zTime, &zDate[11], 5); 308 308 zTime[5] = 0; 309 309 @ <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> 311 311 @ <td class="timelineGraph"><div id="m%d(gidx)"></div></td> 312 312 if( zBgClr && zBgClr[0] ){ 313 313 @ <td class="timelineTableCell" style="background-color: %h(zBgClr);"> 314 314 }else{ 315 315 @ <td class="timelineTableCell"> 316 316 } 317 317 sqlite3_snprintf(sizeof(zShort), zShort, "%.10s", zUuid); 318 318 sqlite3_snprintf(sizeof(zShortCkin), zShortCkin, "%.10s", zCkin); 319 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 320 + @ %z(href("%R/artifact/%s",zUuid))[%S(zUuid)]</a> part of check-in 326 321 }else{ 327 322 @ <b>Deleted</b> by check-in 328 323 } 329 324 hyperlink_to_uuid(zShortCkin); 330 325 @ %h(zCom) (user: 331 326 hyperlink_to_user(zUser, zDate, ""); 332 327 @ branch: %h(zBr)) 333 - if( g.perm.History && zUuid ){ 328 + if( g.perm.Hyperlink && zUuid ){ 334 329 const char *z = zFilename; 335 330 if( fpid ){ 336 - @ <a href="%s(g.zTop)/fdiff?v1=%s(zPUuid)&v2=%s(zUuid)">[diff]</a> 331 + @ %z(href("%R/fdiff?v1=%s&v2=%s",zPUuid,zUuid))[diff]</a> 337 332 } 338 - @ <a href="%s(g.zTop)/annotate?checkin=%S(zCkin)&filename=%h(z)"> 333 + @ %z(href("%R/annotate?checkin=%S&filename=%h",zCkin,z)) 339 334 @ [annotate]</a> 340 335 } 341 336 @ </td></tr> 342 337 } 343 338 db_finalize(&q); 344 339 if( pGraph ){ 345 340 graph_finish(pGraph, 0);
Changes to src/info.c.
259 259 hyperlink_to_uuid(zOrigUuid); 260 260 }else{ 261 261 @ propagates to descendants 262 262 } 263 263 #if 0 264 264 if( zValue && fossil_strcmp(zTagname,"branch")==0 ){ 265 265 @ 266 - @ <a href="%s(g.zTop)/timeline?r=%T(zValue)">branch timeline</a> 266 + @ %z(href("%R/timeline?r=%T",zValue))branch timeline</a> 267 267 } 268 268 #endif 269 269 } 270 270 if( zSrcUuid && zSrcUuid[0] ){ 271 271 if( tagtype==0 ){ 272 272 @ by 273 273 }else{ ................................................................................ 331 331 const char *zName, /* Name of the file that has changed */ 332 332 const char *zOld, /* blob.uuid before change. NULL for added files */ 333 333 const char *zNew, /* blob.uuid after change. NULL for deletes */ 334 334 const char *zOldName, /* Prior name. NULL if no name change. */ 335 335 int diffFlags, /* Flags for text_diff(). Zero to omit diffs */ 336 336 int mperm /* executable or symlink permission for zNew */ 337 337 ){ 338 - if( !g.perm.History ){ 338 + if( !g.perm.Hyperlink ){ 339 339 if( zNew==0 ){ 340 340 @ <p>Deleted %h(zName)</p> 341 341 }else if( zOld==0 ){ 342 342 @ <p>Added %h(zName)</p> 343 343 }else if( zOldName!=0 && fossil_strcmp(zName,zOldName)!=0 ){ 344 344 @ <p>Name change from %h(zOldName) to %h(zName) 345 345 }else if( fossil_strcmp(zNew, zOld)==0 ){ ................................................................................ 352 352 @ <pre style="white-space:pre;"> 353 353 append_diff(zOld, zNew, diffFlags); 354 354 @ </pre> 355 355 } 356 356 }else{ 357 357 if( zOld && zNew ){ 358 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> 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 362 }else if( zOldName!=0 && fossil_strcmp(zName,zOldName)!=0 ){ 363 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>. 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 366 }else{ 367 367 @ <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> 369 369 } 370 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> 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 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> 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 376 } 377 377 if( diffFlags ){ 378 378 @ <pre style="white-space:pre;"> 379 379 append_diff(zOld, zNew, diffFlags); 380 380 @ </pre> 381 381 }else if( zOld && zNew && fossil_strcmp(zOld,zNew)!=0 ){ 382 382 @ 383 - @ <a href="%s(g.zTop)/fdiff?v1=%S(zOld)&v2=%S(zNew)">[diff]</a> 383 + @ %z(href("%R/fdiff?v1=%S&v2=%S",zOld,zNew))[diff]</a> 384 384 } 385 385 @ </p> 386 386 } 387 387 } 388 388 389 389 /* 390 390 ** Construct an appropriate diffFlag for text_diff() based on query ................................................................................ 533 533 const char *zDate = db_column_text(&q, 2); 534 534 if( zUser==0 || zUser[0]==0 ) zUser = "unknown"; 535 535 @ <tr><th>Received From:</th> 536 536 @ <td>%h(zUser) @ %h(zIpAddr) on %s(zDate)</td></tr> 537 537 } 538 538 db_finalize(&q); 539 539 } 540 - if( g.perm.History ){ 540 + if( g.perm.Hyperlink ){ 541 541 const char *zProjName = db_get("project-name", "unnamed"); 542 542 @ <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> 544 544 if( zParent ){ 545 - @ | <a href="%s(g.zTop)/timeline?p=%S(zUuid)">ancestors</a> 545 + @ | %z(href("%R/timeline?p=%S",zUuid))ancestors</a> 546 546 } 547 547 if( !isLeaf ){ 548 - @ | <a href="%s(g.zTop)/timeline?d=%S(zUuid)">descendants</a> 548 + @ | %z(href("%R/timeline?d=%S",zUuid))descendants</a> 549 549 } 550 550 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> 552 552 } 553 553 db_prepare(&q, "SELECT substr(tag.tagname,5) FROM tagxref, tag " 554 554 " WHERE rid=%d AND tagtype>0 " 555 555 " AND tag.tagid=tagxref.tagid " 556 556 " AND +tag.tagname GLOB 'sym-*'", rid); 557 557 while( db_step(&q)==SQLITE_ROW ){ 558 558 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> 560 560 } 561 561 db_finalize(&q); 562 562 @ </td></tr> 563 563 @ <tr><th>Other Links:</th> 564 564 @ <td> 565 - @ <a href="%s(g.zTop)/dir?ci=%S(zUuid)">files</a> 565 + @ %z(href("%R/dir?ci=%S",zUuid))files</a> 566 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)"> 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 571 @ ZIP archive</a> 572 572 fossil_free(zUrl); 573 573 } 574 - @ | <a href="%s(g.zTop)/artifact/%S(zUuid)">manifest</a> 574 + @ | %z(href("%R/artifact/%S",zUuid))manifest</a> 575 575 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> 577 577 } 578 578 @ </td> 579 579 @ </tr> 580 580 } 581 581 @ </table> 582 582 }else{ 583 583 style_header("Check-in Information"); ................................................................................ 588 588 if( zParent ){ 589 589 @ <div class="section">Changes</div> 590 590 @ <div class="sectionmenu"> 591 591 showDiff = g.zPath[0]!='c'; 592 592 if( db_get_boolean("show-version-diffs", 0)==0 ){ 593 593 showDiff = !showDiff; 594 594 if( showDiff ){ 595 - @ <a class="button" href="%s(g.zTop)/vinfo/%T(zName)"> 595 + @ %z(xhref("class='button'","%R/vinfo/%T",zName))) 596 596 @ hide diffs</a> 597 597 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)) 599 599 @ unified diffs</a> 600 600 }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)) 602 602 @ side-by-side diffs</a> 603 603 } 604 604 }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)) 606 606 @ show unified 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)) 608 608 @ show side-by-side diffs</a> 609 609 } 610 610 }else{ 611 611 if( showDiff ){ 612 - @ <a class="button" href="%s(g.zTop)/ci/%T(zName)">hide diffs</a> 612 + @ %z(xhref("class='button'","%R/ci/%T",zName))hide diffs</a> 613 613 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)) 615 615 @ unified diffs</a> 616 616 }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)) 618 618 @ side-by-side diffs</a> 619 619 } 620 620 }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)) 622 622 @ show unified 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)) 624 624 @ show side-by-side diffs</a> 625 625 } 626 626 } 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)) 628 628 @ patch</a></div> 629 629 db_prepare(&q, 630 630 "SELECT name," 631 631 " mperm," 632 632 " (SELECT uuid FROM blob WHERE rid=mlink.pid)," 633 633 " (SELECT uuid FROM blob WHERE rid=mlink.fid)," 634 634 " (SELECT name FROM filename WHERE filename.fnid=mlink.pfnid)" ................................................................................ 696 696 @ <tr><th>Date:</th><td> 697 697 hyperlink_to_date(zDate, "</td></tr>"); 698 698 if( g.perm.Setup ){ 699 699 @ <tr><th>Record ID:</th><td>%d(rid)</td></tr> 700 700 } 701 701 @ <tr><th>Original User:</th><td> 702 702 hyperlink_to_user(zUser, zDate, "</td></tr>"); 703 - if( g.perm.History ){ 703 + if( g.perm.Hyperlink ){ 704 704 @ <tr><th>Commands:</th> 705 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> 706 + @ &z(href("%R/whistory?name=%t",zName))history</a> 707 + @ | %z(href("%R/artifact/%S",zUuid))raw-text</a> 708 708 @ </td> 709 709 @ </tr> 710 710 } 711 711 @ </table></p> 712 712 }else{ 713 713 style_header("Wiki Information"); 714 714 rid = 0; ................................................................................ 790 790 } 791 791 db_finalize(&q); 792 792 } 793 793 794 794 795 795 /* 796 796 ** WEBPAGE: vdiff 797 -** URL: /vdiff?from=UUID&to=UUID&detail=BOOLEAN;sbs=BOOLEAN 797 +** URL: /vdiff?from=UUID&to=UUID&detail=BOOLEAN;sbs=BOOLEAN 798 798 ** 799 799 ** Show all differences between two checkins. 800 800 */ 801 801 void vdiff_page(void){ 802 802 int ridFrom, ridTo; 803 803 int showDetail = 0; 804 804 int sideBySide = 0; ................................................................................ 934 934 if( mPerm==PERM_LNK ){ 935 935 @ <li>Symbolic link 936 936 }else if( mPerm==PERM_EXE ){ 937 937 @ <li>Executable file 938 938 }else{ 939 939 @ <li>File 940 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 - } 941 + @ %z(href("%R/finfo?name=%T",zName))%h(zName)</a> 946 942 @ <ul> 947 943 prevName = fossil_strdup(zName); 948 944 } 949 945 @ <li> 950 946 hyperlink_to_date(zDate,""); 951 947 @ - part of checkin 952 948 hyperlink_to_uuid(zVers); 953 949 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> 959 951 } 960 952 @ - %w(zCom) (user: 961 953 hyperlink_to_user(zUser,zDate,""); 962 954 @ ) 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)) 965 957 @ [annotate]</a> 966 958 } 967 959 cnt++; 968 960 if( pDownloadName && blob_size(pDownloadName)==0 ){ 969 961 blob_append(pDownloadName, zName, -1); 970 962 } 971 963 } ................................................................................ 987 979 const char *zDate = db_column_text(&q, 1); 988 980 const char *zUser = db_column_text(&q, 2); 989 981 if( cnt>0 ){ 990 982 @ Also wiki page 991 983 }else{ 992 984 @ Wiki page 993 985 } 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 1000 987 hyperlink_to_user(zUser,zDate," on"); 1001 988 hyperlink_to_date(zDate,"."); 1002 989 nWiki++; 1003 990 cnt++; 1004 991 if( pDownloadName && blob_size(pDownloadName)==0 ){ 1005 992 blob_appendf(pDownloadName, "%s.wiki", zPagename); 1006 993 } ................................................................................ 1063 1050 /* const char *zSrc = db_column_text(&q, 4); */ 1064 1051 if( cnt>0 ){ 1065 1052 @ Also attachment "%h(zFilename)" to 1066 1053 }else{ 1067 1054 @ Attachment "%h(zFilename)" to 1068 1055 } 1069 1056 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>] 1072 1059 }else{ 1073 1060 @ ticket [%S(zTarget)] 1074 1061 } 1075 1062 }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>] 1078 1065 }else{ 1079 1066 @ wiki page [%h(zTarget)] 1080 1067 } 1081 1068 } 1082 1069 @ added by 1083 1070 hyperlink_to_user(zUser,zDate," on"); 1084 1071 hyperlink_to_date(zDate,"."); ................................................................................ 1089 1076 } 1090 1077 db_finalize(&q); 1091 1078 if( cnt==0 ){ 1092 1079 @ Control artifact. 1093 1080 if( pDownloadName && blob_size(pDownloadName)==0 ){ 1094 1081 blob_appendf(pDownloadName, "%.10s.txt", zUuid); 1095 1082 } 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> 1098 1085 } 1099 1086 } 1100 1087 1101 1088 1102 1089 /* 1103 1090 ** WEBPAGE: fdiff 1104 1091 ** URL: fdiff?v1=UUID&v2=UUID&patch&sbs=BOOLEAN ................................................................................ 1158 1145 style_submenu_element("Unified Diff", "udiff", 1159 1146 "%s/fdiff?v1=%T&v2=%T&sbs=0", 1160 1147 g.zTop, P("v1"), P("v2")); 1161 1148 } 1162 1149 1163 1150 if( P("smhdr")!=0 ){ 1164 1151 @ <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> 1167 1154 }else{ 1168 1155 @ <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> 1170 1157 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> 1173 1159 object_description(v2, 0, 0); 1174 1160 } 1175 1161 @ <hr /> 1176 1162 @ <div class="%s(zStyle)"> 1177 1163 @ %s(blob_str(&diff)) 1178 1164 @ </div> 1179 1165 blob_reset(&diff); ................................................................................ 1270 1256 rid = name_to_rid_www("name"); 1271 1257 login_check_credentials(); 1272 1258 if( !g.perm.Read ){ login_needed(); return; } 1273 1259 if( rid==0 ) fossil_redirect_home(); 1274 1260 if( g.perm.Admin ){ 1275 1261 const char *zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d", rid); 1276 1262 if( db_exists("SELECT 1 FROM shun WHERE uuid='%s'", zUuid) ){ 1277 - style_submenu_element("Unshun","Unshun", "%s/shun?uuid=%s&sub=1", 1263 + style_submenu_element("Unshun","Unshun", "%s/shun?uuid=%s&sub=1", 1278 1264 g.zTop, zUuid); 1279 1265 }else{ 1280 1266 style_submenu_element("Shun","Shun", "%s/shun?shun=%s#addshun", 1281 1267 g.zTop, zUuid); 1282 1268 } 1283 1269 } 1284 1270 style_header("Hex Artifact Content"); ................................................................................ 1417 1403 1418 1404 login_check_credentials(); 1419 1405 if( !g.perm.Read ){ login_needed(); return; } 1420 1406 if( rid==0 ) fossil_redirect_home(); 1421 1407 if( g.perm.Admin ){ 1422 1408 const char *zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d", rid); 1423 1409 if( db_exists("SELECT 1 FROM shun WHERE uuid='%s'", zUuid) ){ 1424 - style_submenu_element("Unshun","Unshun", "%s/shun?uuid=%s&sub=1", 1410 + style_submenu_element("Unshun","Unshun", "%s/shun?uuid=%s&sub=1", 1425 1411 g.zTop, zUuid); 1426 1412 }else{ 1427 1413 style_submenu_element("Shun","Shun", "%s/shun?shun=%s#addshun", 1428 1414 g.zTop, zUuid); 1429 1415 } 1430 1416 } 1431 1417 style_header("Artifact Content"); ................................................................................ 1476 1462 output_text_with_line_numbers(z, zLn); 1477 1463 }else{ 1478 1464 @ <pre> 1479 1465 @ %h(z) 1480 1466 @ </pre> 1481 1467 } 1482 1468 }else if( strncmp(zMime, "image/", 6)==0 ){ 1483 - @ <img src="%s(g.zTop)/raw?name=%s(zUuid)&m=%s(zMime)"></img> 1469 + @ <img src="%s(g.zTop)/raw?name=%s(zUuid)&m=%s(zMime)"></img> 1484 1470 }else{ 1485 1471 @ <i>(file is %d(blob_size(&content)) bytes of binary data)</i> 1486 1472 } 1487 1473 @ </blockquote> 1488 1474 } 1489 1475 style_footer(); 1490 1476 } ................................................................................ 1505 1491 login_check_credentials(); 1506 1492 if( !g.perm.RdTkt ){ login_needed(); return; } 1507 1493 rid = name_to_rid_www("name"); 1508 1494 if( rid==0 ){ fossil_redirect_home(); } 1509 1495 zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d", rid); 1510 1496 if( g.perm.Admin ){ 1511 1497 if( db_exists("SELECT 1 FROM shun WHERE uuid='%s'", zUuid) ){ 1512 - style_submenu_element("Unshun","Unshun", "%s/shun?uuid=%s&sub=1", 1498 + style_submenu_element("Unshun","Unshun", "%s/shun?uuid=%s&sub=1", 1513 1499 g.zTop, zUuid); 1514 1500 }else{ 1515 1501 style_submenu_element("Shun","Shun", "%s/shun?shun=%s#addshun", 1516 1502 g.zTop, zUuid); 1517 1503 } 1518 1504 } 1519 1505 pTktChng = manifest_get(rid, CFTYPE_TICKET); ................................................................................ 1520 1506 if( pTktChng==0 ){ 1521 1507 fossil_redirect_home(); 1522 1508 } 1523 1509 style_header("Ticket Change Details"); 1524 1510 zDate = db_text(0, "SELECT datetime(%.12f)", pTktChng->rDate); 1525 1511 memcpy(zTktName, pTktChng->zTicketUuid, 10); 1526 1512 zTktName[10] = 0; 1527 - if( g.perm.History ){ 1513 + if( g.perm.Hyperlink ){ 1528 1514 @ <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> 1530 1516 @ 1531 1517 @ <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> 1535 1520 }else{ 1536 1521 @ <h2>Changes to ticket %s(zTktName)</h2> 1537 1522 @ 1538 1523 @ <p>By %h(pTktChng->zUser) on %s(zDate). 1539 1524 @ </p> 1540 1525 } 1541 1526 @ ................................................................................ 1963 1948 @ %s(blob_str(&suffix)) 1964 1949 @ </td></tr></table> 1965 1950 @ </blockquote> 1966 1951 @ <hr /> 1967 1952 blob_reset(&suffix); 1968 1953 } 1969 1954 @ <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> 1971 1956 @ <form action="%s(g.zTop)/ci_edit" method="post"><div> 1972 1957 login_insert_csrf_secret(); 1973 1958 @ <input type="hidden" name="r" value="%S(zUuid)" /> 1974 1959 @ <table border="0" cellspacing="10"> 1975 1960 1976 1961 @ <tr><td align="right" valign="top"><b>User:</b></td> 1977 1962 @ <td valign="top">
Changes to src/json_dir.c.
64 64 char const * zDX = NULL; 65 65 int nD; 66 66 char * zUuid = NULL; 67 67 char const * zCI = NULL; 68 68 Manifest * pM = NULL; 69 69 Stmt q = empty_Stmt; 70 70 int rid = 0; 71 - if( !g.perm.History ){ 71 + if( !g.perm.Hyperlink ){ 72 72 json_set_err(FSL_JSON_E_DENIED, "Requires 'h' permissions."); 73 73 return NULL; 74 74 } 75 75 zCI = json_find_option_cstr("checkin",NULL,"ci" ); 76 76 77 77 /* If a specific check-in is requested, fetch and parse it. If the 78 78 ** specific check-in does not exist, clear zCI. zCI==0 will cause all
Changes to src/json_timeline.c.
51 51 */ 52 52 cson_value * json_page_timeline(){ 53 53 #if 0 54 54 /* The original timeline code does not require 'h' access, 55 55 but it arguably should. For JSON mode i think one could argue 56 56 that History permissions are required. 57 57 */ 58 - if(! g.perm.History && !g.perm.Read ){ 58 + if(! g.perm.Hyperlink && !g.perm.Read ){ 59 59 json_set_err(FSL_JSON_E_DENIED, "Timeline requires 'h' or 'o' access."); 60 60 return NULL; 61 61 } 62 62 #endif 63 63 return json_page_dispatch_helper(&JsonPageDefs_Timeline[0]); 64 64 } 65 65 ................................................................................ 424 424 cson_value * listV = NULL; 425 425 cson_array * list = NULL; 426 426 int check = 0; 427 427 char showFiles = -1/*magic number*/; 428 428 Stmt q = empty_Stmt; 429 429 char warnRowToJsonFailed = 0; 430 430 Blob sql = empty_blob; 431 - if( !g.perm.History ){ 431 + if( !g.perm.Hyperlink ){ 432 432 /* Reminder to self: HTML impl requires 'o' (Read) 433 433 rights. 434 434 */ 435 435 json_set_err( FSL_JSON_E_DENIED, "Checkin timeline requires 'h' access." ); 436 436 return NULL; 437 437 } 438 438 showFiles = json_find_option_bool("files",NULL,"f",0);
Changes to src/json_wiki.c.
490 490 int argPos = g.json.dispatchDepth; 491 491 int r1 = 0, r2 = 0; 492 492 Manifest * pW1 = NULL, *pW2 = NULL; 493 493 Blob w1 = empty_blob, w2 = empty_blob, d = empty_blob; 494 494 char const * zErrTag = NULL; 495 495 int diffFlags; 496 496 char * zUuid = NULL; 497 - if( !g.perm.History ){ 497 + if( !g.perm.Hyperlink ){ 498 498 json_set_err(FSL_JSON_E_DENIED, 499 499 "Requires 'h' permissions."); 500 500 return NULL; 501 501 } 502 502 503 503 504 504 zV1 = json_find_option_cstr2( "v1",NULL, NULL, ++argPos );
Changes to src/login.c.
560 560 */ 561 561 login_set_user_cookie(zUsername, uid, NULL); 562 562 redirect_to_g(); 563 563 } 564 564 } 565 565 style_header("Login/Logout"); 566 566 @ %s(zErrMsg) 567 - if( zGoto ){ 567 + if( zGoto && P("anon")==0 ){ 568 568 @ <p>A login is required for <a href="%h(zGoto)">%h(zGoto)</a>.</p> 569 569 } 570 570 @ <form action="login" method="post"> 571 571 if( zGoto ){ 572 572 @ <input type="hidden" name="g" value="%h(zGoto)" /> 573 573 } 574 574 @ <table class="login_out"> ................................................................................ 909 909 if( fossil_strcmp(g.zLogin,"nobody")==0 ){ 910 910 g.zLogin = 0; 911 911 } 912 912 913 913 /* Set the capabilities */ 914 914 login_replace_capabilities(zCap, 0); 915 915 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) 917 918 && isHuman(P("HTTP_USER_AGENT")) ){ 918 - g.perm.History = 1; 919 + g.perm.Hyperlink = 1; 920 + g.javascriptHyperlink = 1; 919 921 } 920 922 921 923 /* If the public-pages glob pattern is defined and REQUEST_URI matches 922 924 ** one of the globs in public-pages, then also add in all default-perms 923 925 ** permissions. 924 926 */ 925 927 zPublicPages = db_get("public-pages",0); ................................................................................ 971 973 if(NULL==zCap){ 972 974 return; 973 975 } 974 976 for(i=0; zCap[i]; i++){ 975 977 switch( zCap[i] ){ 976 978 case 's': g.perm.Setup = 1; /* Fall thru into Admin */ 977 979 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 */ 983 985 case 'i': g.perm.Read = g.perm.Write = 1; break; 984 986 case 'o': g.perm.Read = 1; break; 985 987 case 'z': g.perm.Zip = 1; break; 986 988 987 989 case 'd': g.perm.Delete = 1; break; 988 - case 'h': g.perm.History = 1; break; 990 + case 'h': g.perm.Hyperlink = 1; break; 989 991 case 'g': g.perm.Clone = 1; break; 990 992 case 'p': g.perm.Password = 1; break; 991 993 992 994 case 'j': g.perm.RdWiki = 1; break; 993 995 case 'k': g.perm.WrWiki = g.perm.RdWiki = g.perm.ApndWiki =1; break; 994 996 case 'm': g.perm.ApndWiki = 1; break; 995 997 case 'f': g.perm.NewWiki = 1; break; ................................................................................ 1051 1053 case 'a': rc = g.perm.Admin; break; 1052 1054 case 'b': rc = g.perm.Attach; break; 1053 1055 case 'c': rc = g.perm.ApndTkt; break; 1054 1056 case 'd': rc = g.perm.Delete; break; 1055 1057 case 'e': rc = g.perm.RdAddr; break; 1056 1058 case 'f': rc = g.perm.NewWiki; break; 1057 1059 case 'g': rc = g.perm.Clone; break; 1058 - case 'h': rc = g.perm.History; break; 1060 + case 'h': rc = g.perm.Hyperlink; break; 1059 1061 case 'i': rc = g.perm.Write; break; 1060 1062 case 'j': rc = g.perm.RdWiki; break; 1061 1063 case 'k': rc = g.perm.WrWiki; break; 1062 - /* case 'l': */ 1063 1064 case 'm': rc = g.perm.ApndWiki; break; 1064 1065 case 'n': rc = g.perm.NewTkt; break; 1065 1066 case 'o': rc = g.perm.Read; break; 1066 1067 case 'p': rc = g.perm.Password; break; 1067 1068 /* case 'q': */ 1068 1069 case 'r': rc = g.perm.RdTkt; break; 1069 1070 case 's': rc = g.perm.Setup; break; ................................................................................ 1127 1128 cgi_redirect(mprintf("login?g=%T", zUrl)); 1128 1129 /* NOTREACHED */ 1129 1130 assert(0); 1130 1131 } 1131 1132 } 1132 1133 1133 1134 /* 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 1136 1137 ** to inform the user that much more information is available by 1137 1138 ** logging in as anonymous. 1138 1139 */ 1139 1140 void login_anonymous_available(void){ 1140 - if( !g.perm.History && 1141 + if( !g.perm.Hyperlink && 1141 1142 db_exists("SELECT 1 FROM user" 1142 1143 " WHERE login='anonymous'" 1143 1144 " AND cap LIKE '%%h%%'") ){ 1144 1145 const char *zUrl = PD("REQUEST_URI", "index"); 1145 1146 @ <p>Many <span class="disabled">hyperlinks are disabled.</span><br /> 1146 - @ Use <a href="%s(g.zTop)/login?anon=1&g=%T(zUrl)">anonymous login</a> 1147 + @ Use <a href="%s(g.zTop)/login?anon=1&g=%T(zUrl)">anonymous login</a> 1147 1148 @ to enable hyperlinks.</p> 1148 1149 } 1149 1150 } 1150 1151 1151 1152 /* 1152 1153 ** While rendering a form, call this routine to add the Anti-CSRF token 1153 1154 ** as a hidden element of the form.
Changes to src/main.c.
58 58 char Setup; /* s: use Setup screens on web interface */ 59 59 char Admin; /* a: administrative permission */ 60 60 char Delete; /* d: delete wiki or tickets */ 61 61 char Password; /* p: change password */ 62 62 char Query; /* q: create new reports */ 63 63 char Write; /* i: xfer inbound. checkin */ 64 64 char Read; /* o: xfer outbound. checkout */ 65 - char History; /* h: access historical information. */ 65 + char Hyperlink; /* h: enable the display of hyperlinks */ 66 66 char Clone; /* g: clone */ 67 67 char RdWiki; /* j: view wiki via web */ 68 68 char NewWiki; /* f: create new wiki via web */ 69 69 char ApndWiki; /* m: append to wiki via web */ 70 70 char WrWiki; /* k: edit wiki via web */ 71 71 char RdTkt; /* r: view tickets via web */ 72 72 char NewTkt; /* n: create new tickets */ ................................................................................ 133 133 FILE *httpIn; /* Accept HTTP input from here */ 134 134 FILE *httpOut; /* Send HTTP output here */ 135 135 int xlinkClusterOnly; /* Set when cloning. Only process clusters */ 136 136 int fTimeFormat; /* 1 for UTC. 2 for localtime. 0 not yet selected */ 137 137 int *aCommitFile; /* Array of files to be committed */ 138 138 int markPrivate; /* All new artifacts are private if true */ 139 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. */ 140 + char isHTTP; /* True if erver/CGI modes, else assume CLI. */ 141 + char javascriptHyperlink; /* If true, set href= using script, not HTML */ 141 142 142 143 int urlIsFile; /* True if a "file:" url */ 143 144 int urlIsHttps; /* True if a "https:" url */ 144 145 int urlIsSsh; /* True if an "ssh:" url */ 145 146 char *urlName; /* Hostname for http: or filename for file: */ 146 147 char *urlHostname; /* The HOST: parameter on http headers */ 147 148 char *urlProtocol; /* "http" or "https" */
Changes to src/printf.c.
45 45 #define etHTTPIZE 17 /* Make text safe for HTTP. "/" encoded as %2f */ 46 46 #define etURLIZE 18 /* Make text safe for HTTP. "/" not encoded */ 47 47 #define etFOSSILIZE 19 /* The fossil header encoding format. */ 48 48 #define etPATH 20 /* Path type */ 49 49 #define etWIKISTR 21 /* Wiki text rendered from a char*: %w */ 50 50 #define etWIKIBLOB 22 /* Wiki text rendered from a Blob*: %W */ 51 51 #define etSTRINGID 23 /* String with length limit for a UUID prefix: %S */ 52 +#define etROOT 24 /* String value of g.zTop: % */ 52 53 53 54 54 55 /* 55 56 ** An "etByte" is an 8-bit unsigned value. 56 57 */ 57 58 typedef unsigned char etByte; 58 59 ................................................................................ 91 92 { 'q', 0, 4, etSQLESCAPE, 0, 0 }, 92 93 { 'Q', 0, 4, etSQLESCAPE2, 0, 0 }, 93 94 { 'b', 0, 2, etBLOB, 0, 0 }, 94 95 { 'B', 0, 2, etBLOBSQL, 0, 0 }, 95 96 { 'w', 0, 2, etWIKISTR, 0, 0 }, 96 97 { 'W', 0, 2, etWIKIBLOB, 0, 0 }, 97 98 { 'h', 0, 4, etHTMLIZE, 0, 0 }, 99 + { 'R', 0, 0, etROOT, 0, 0 }, 98 100 { 't', 0, 4, etHTTPIZE, 0, 0 }, /* "/" -> "%2F" */ 99 101 { 'T', 0, 4, etURLIZE, 0, 0 }, /* "/" unchanged */ 100 102 { 'F', 0, 4, etFOSSILIZE, 0, 0 }, 101 103 { 'S', 0, 4, etSTRINGID, 0, 0 }, 102 104 { 'c', 0, 0, etCHARX, 0, 0 }, 103 105 { 'o', 8, 0, etRADIX, 0, 2 }, 104 106 { 'u', 10, 0, etRADIX, 0, 0 }, ................................................................................ 568 570 bufpt[i]='/'; 569 571 }else{ 570 572 bufpt[i]=e[i]; 571 573 } 572 574 } 573 575 bufpt[length]='\0'; 574 576 break; 577 + } 578 + case etROOT: { 579 + bufpt = g.zTop; 580 + length = (int)strlen(bufpt); 581 + break; 575 582 } 576 583 case etSTRINGID: { 577 584 precision = 16; 578 585 /* Fall through */ 579 586 } 580 587 case etSTRING: 581 588 case etDYNSTRING: {
Changes to src/report.c.
54 54 } 55 55 rn = db_column_int(&q, 0); 56 56 cnt++; 57 57 blob_appendf(&ril, "<li>"); 58 58 if( zTitle[0] == '_' ){ 59 59 blob_appendf(&ril, "%s", zTitle); 60 60 } 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); 62 62 } 63 63 blob_appendf(&ril, " "); 64 64 if( g.perm.Write && zOwner && zOwner[0] ){ 65 65 blob_appendf(&ril, "(by <i>%h</i></i>) ", zOwner); 66 66 } 67 67 if( g.perm.TktFmt ){ 68 - blob_appendf(&ril, "[<a href=\"rptedit?rn=%d&copy=1\" rel=\"nofollow\">copy</a>] ", rn); 68 + blob_appendf(&ril, "[%zcopy</a>] ", 69 + href("%R/rptedit?rn=%d©=1", rn)); 69 70 } 70 71 if( g.perm.Admin 71 72 || (g.perm.WrTkt && zOwner && fossil_strcmp(g.zLogin,zOwner)==0) 72 73 ){ 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)); 74 76 } 75 77 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)); 77 80 } 78 81 blob_appendf(&ril, "</li>\n"); 79 82 } 80 83 81 84 Th_Store("report_items", blob_str(&ril)); 82 85 83 86 Th_Render(zScript); ................................................................................ 414 417 zTitle = mprintf("Copy Of %s", zTitle); 415 418 zOwner = g.zLogin; 416 419 } 417 420 } 418 421 if( zOwner==0 ) zOwner = g.zLogin; 419 422 style_submenu_element("Cancel", "Cancel", "reportlist"); 420 423 if( rn>0 ){ 421 - style_submenu_element("Delete", "Delete", "rptedit?rn=%d&del1=1", rn); 424 + style_submenu_element("Delete", "Delete", "rptedit?rn=%d&del1=1", rn); 422 425 } 423 426 style_header(rn>0 ? "Edit Report Format":"Create New Report Format"); 424 427 if( zErr ){ 425 428 @ <blockquote class="reportError">%h(zErr)</blockquote> 426 429 } 427 430 @ <form action="rptedit" method="post"><div> 428 431 @ <input type="hidden" name="rn" value="%d(rn)" /> ................................................................................ 718 721 for(i=0; i<nArg; i++){ 719 722 char *zData; 720 723 if( i==pState->iBg ) continue; 721 724 zData = azArg[i]; 722 725 if( zData==0 ) zData = ""; 723 726 if( pState->iNewRow>=0 && i>=pState->iNewRow ){ 724 727 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> 726 729 zTid = 0; 727 730 } 728 731 if( zData[0] ){ 729 732 Blob content; 730 733 @ </tr><tr style="background-color:%h(zBg)"><td colspan=%d(pState->nCol)> 731 734 blob_init(&content, zData, -1); 732 735 wiki_convert(&content, 0, 0); 733 736 blob_reset(&content); 734 737 } 735 738 }else if( azName[i][0]=='#' ){ 736 739 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> 742 741 }else if( zData[0]==0 ){ 743 742 @ <td valign="top"> </td> 744 743 }else{ 745 744 @ <td valign="top"> 746 745 @ %h(zData) 747 746 @ </td> 748 747 } 749 748 } 750 749 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> 752 751 } 753 752 @ </tr> 754 753 return 0; 755 754 } 756 755 757 756 /* 758 757 ** Output the text given in the argument. Convert tabs and newlines into ................................................................................ 947 946 948 947 count = 0; 949 948 if( !tabs ){ 950 949 struct GenerateHTML sState; 951 950 952 951 db_multi_exec("PRAGMA empty_result_callbacks=ON"); 953 952 style_submenu_element("Raw", "Raw", 954 - "rptview?tablist=1&%h", PD("QUERY_STRING","")); 953 + "rptview?tablist=1&%h", PD("QUERY_STRING","")); 955 954 if( g.perm.Admin 956 955 || (g.perm.TktFmt && g.zLogin && fossil_strcmp(g.zLogin,zOwner)==0) ){ 957 956 style_submenu_element("Edit", "Edit", "rptedit?rn=%d", rn); 958 957 } 959 958 if( g.perm.TktFmt ){ 960 959 style_submenu_element("SQL", "SQL", "rptsql?rn=%d",rn); 961 960 }
Changes to src/setup.c.
522 522 } 523 523 @ <input type="checkbox" name="aa"%s(oaa) />%s(B('a'))Admin<br /> 524 524 @ <input type="checkbox" name="ad"%s(oad) />%s(B('d'))Delete<br /> 525 525 @ <input type="checkbox" name="ae"%s(oae) />%s(B('e'))Email<br /> 526 526 @ <input type="checkbox" name="ap"%s(oap) />%s(B('p'))Password<br /> 527 527 @ <input type="checkbox" name="ai"%s(oai) />%s(B('i'))Check-In<br /> 528 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 /> 529 + @ <input type="checkbox" name="ah"%s(oah) />%s(B('h'))Hyperlinks<br /> 530 530 @ <input type="checkbox" name="au"%s(oau) />%s(B('u'))Reader<br /> 531 531 @ <input type="checkbox" name="av"%s(oav) />%s(B('v'))Developer<br /> 532 532 @ <input type="checkbox" name="ag"%s(oag) />%s(B('g'))Clone<br /> 533 533 @ <input type="checkbox" name="aj"%s(oaj) />%s(B('j'))Read Wiki<br /> 534 534 @ <input type="checkbox" name="af"%s(oaf) />%s(B('f'))New Wiki<br /> 535 535 @ <input type="checkbox" name="am"%s(oam) />%s(B('m'))Append Wiki<br /> 536 536 @ <input type="checkbox" name="ak"%s(oak) />%s(B('k'))Write Wiki<br /> ................................................................................ 623 623 @ by anonymous users. This capability is intended for deletion of spam. 624 624 @ The delete capability is only in effect for 24 hours after the item 625 625 @ is first posted. The <span class="usertype">Setup</span> user can 626 626 @ delete anything at any time. 627 627 @ </p></li> 628 628 @ 629 629 @ <li><p> 630 - @ The <span class="capability">History</span> privilege allows a user 630 + @ The <span class="capability">Hyperlinks</span> privilege allows a user 631 631 @ to see most hyperlinks. This is recommended ON for most logged-in users 632 632 @ 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. 634 634 @ </p></li> 635 635 @ 636 636 @ <li><p> 637 637 @ The <span class="capability">Zip</span> privilege allows a user to 638 638 @ see the "download as ZIP" 639 639 @ hyperlink and permits access to the <tt>/zip</tt> page. This allows 640 640 @ users to download ZIP archives without granting other rights like 641 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 642 + @ <span class="capability">Hyperlink</span>. The "z" privilege is recommended 643 + @ for user <span class="usertype">nobody</span> so that automatic package 644 644 @ downloaders can obtain the sources without going through the login 645 645 @ procedure. 646 646 @ </p></li> 647 647 @ 648 648 @ <li><p> 649 649 @ The <span class="capability">Check-in</span> privilege allows remote 650 650 @ users to "push". The <span class="capability">Check-out</span> privilege ................................................................................ 702 702 @ capabilities of the <span class="usertype">nobody</span> user are 703 703 @ inherited by all users, regardless of whether or not they are logged in. 704 704 @ To disable universal access to the repository, make sure no user named 705 705 @ <span class="usertype">nobody</span> exists or that the 706 706 @ <span class="usertype">nobody</span> user has no capabilities 707 707 @ enabled. The password for <span class="usertype">nobody</span> is ignore. 708 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. 709 + @ that the <span class="capability">h</span> (Hyperlinks) capability be 710 + @ turned off for the <span class="usertype">nobody</span> user. 711 711 @ </p></li> 712 712 @ 713 713 @ <li><p> 714 714 @ Login is required for user <span class="usertype">anonymous</span> but the 715 715 @ password is displayed on the login screen beside the password entry box 716 716 @ so anybody who can read should be able to login as anonymous. 717 717 @ On the other hand, spiders and web-crawlers will typically not ................................................................................ 889 889 @ <p>Fossil tries to limit out-bound sync, clone, and pull packets 890 890 @ to this many bytes, uncompressed. If the client requires more data 891 891 @ than this, then the client will issue multiple HTTP requests. 892 892 @ Values below 1 million are not recommended. 5 million is a 893 893 @ reasonable number.</p> 894 894 895 895 @ <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); 898 899 @ <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> 905 913 906 914 @ <hr /> 907 915 entry_attribute("Public pages", 30, "public-pages", 908 916 "pubpage", ""); 909 917 @ <p>A comma-separated list of glob patterns for pages that are accessible 910 918 @ without needing a login and using the privileges given by the 911 919 @ "Default privileges" setting below. Example use case: Set this field
Changes to src/style.c.
43 43 static int headerHasBeenGenerated = 0; 44 44 45 45 /* 46 46 ** remember, if a sidebox was used 47 47 */ 48 48 static int sideboxUsed = 0; 49 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 + 50 134 /* 51 135 ** Add a new element to the submenu 52 136 */ 53 137 void style_submenu_element( 54 138 const char *zLabel, 55 139 const char *zTitle, 56 140 const char *zLink, ................................................................................ 162 246 163 247 /* Render trace log if TH1 tracing is enabled. */ 164 248 if( g.thTrace ){ 165 249 cgi_append_content("<span class=\"thTrace\"><hr />\n", -1); 166 250 cgi_append_content(blob_str(&g.thLog), blob_size(&g.thLog)); 167 251 cgi_append_content("</span>\n", -1); 168 252 } 253 + 254 + /* Set the href= field on hyperlinks */ 255 + style_resolve_href(); 169 256 } 170 257 171 258 /* 172 259 ** Begin a side-box on the right-hand side of a page. The title and 173 260 ** the width of the box are given as arguments. The width is usually 174 261 ** a percentage of total screen width. 175 262 */
Changes to src/tag.c.
546 546 " AND tagtype=1)" 547 547 " AND tagname GLOB 'sym-*'" 548 548 " ORDER BY tagname" 549 549 ); 550 550 @ <ul> 551 551 while( db_step(&q)==SQLITE_ROW ){ 552 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)"> 553 + if( g.perm.Hyperlink ){ 554 + @ <li>%z(xhref("class='taglink'","%R/timeline?t=%T",zName)) 555 555 @ %h(zName)</a></li> 556 556 }else{ 557 557 @ <li><span class="tagDsp">%h(zName)</span></li> 558 558 } 559 559 } 560 560 @ </ul> 561 561 db_finalize(&q);
Changes to src/timeline.c.
45 45 46 46 /* 47 47 ** Generate a hyperlink to a version. 48 48 */ 49 49 void hyperlink_to_uuid(const char *zUuid){ 50 50 char z[UUID_SIZE+1]; 51 51 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> 54 54 }else{ 55 55 @ <span class="timelineHistDsp">[%s(z)]</span> 56 56 } 57 57 } 58 58 59 59 /* 60 60 ** Generate a hyperlink to a diff between two versions. 61 61 */ 62 62 void hyperlink_to_diff(const char *zV1, const char *zV2){ 63 - if( g.perm.History ){ 63 + if( g.perm.Hyperlink ){ 64 64 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> 66 66 }else{ 67 - @ <a href="%s(g.zTop)/diff?v1=%s(zV1)&v2=%s(zV2)">[diff]</a> 67 + @ %z(href("%R/diff?v1=%s&v2=%s",zV1,zV2))[diff]</a> 68 68 } 69 69 } 70 70 } 71 71 72 72 /* 73 73 ** Generate a hyperlink to a date & time. 74 74 */ 75 75 void hyperlink_to_date(const char *zDate, const char *zSuffix){ 76 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) 77 + if( g.perm.Hyperlink ){ 78 + @ %z(href("%R/timeline?c=%T",zDate))%s(zDate)</a>%s(zSuffix) 79 79 }else{ 80 80 @ %s(zDate)%s(zSuffix) 81 81 } 82 82 } 83 83 84 84 /* 85 85 ** Generate a hyperlink to a user. This will link to a timeline showing 86 86 ** events by that user. If the date+time is specified, then the timeline 87 87 ** is centered on that date+time. 88 88 */ 89 89 void hyperlink_to_user(const char *zU, const char *zD, const char *zSuf){ 90 90 if( zSuf==0 ) zSuf = ""; 91 - if( g.perm.History ){ 91 + if( g.perm.Hyperlink ){ 92 92 if( zD && zD[0] ){ 93 - @ <a href="%s(g.zTop)/timeline?c=%T(zD)&u=%T(zU)">%h(zU)</a>%s(zSuf) 93 + @ %z(href("%R/timeline?c=%T&u=%T",zD,zU))%h(zU)</a>%s(zSuf) 94 94 }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) 96 96 } 97 97 }else{ 98 98 @ %s(zU) 99 99 } 100 100 } 101 101 102 102 /* ................................................................................ 351 351 } 352 352 blob_reset(&comment); 353 353 354 354 /* Generate the "user: USERNAME" at the end of the comment, together 355 355 ** with a hyperlink to another timeline for that user. 356 356 */ 357 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); 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") 363 361 }else{ 364 362 @ (user: %h(zUser)%s(zTagList?",":"\051") 365 363 } 366 364 367 365 /* 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>] 370 368 } 371 369 372 370 /* Generate the "tags: TAGLIST" at the end of the comment, together 373 371 ** with hyperlinks to the tag list. 374 372 */ 375 373 if( zTagList ){ 376 - if( g.perm.History ){ 374 + if( g.perm.Hyperlink ){ 377 375 int i; 378 376 const char *z = zTagList; 379 377 Blob links; 380 378 blob_zero(&links); 381 379 while( z && z[0] ){ 382 380 for(i=0; z[i] && (z[i]!=',' || z[i+1]!=' '); i++){} 383 381 if( zThisTag==0 || memcmp(z, zThisTag, i)!=0 || zThisTag[i]!=0 ){ 384 382 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] 387 385 ); 388 386 }else{ 389 387 blob_appendf(&links, "%#h", i+2, z); 390 388 } 391 389 if( z[i]==0 ) break; 392 390 z += i+2; 393 391 } ................................................................................ 401 399 402 400 /* Generate extra hyperlinks at the end of the comment */ 403 401 if( xExtra ){ 404 402 xExtra(rid); 405 403 } 406 404 407 405 /* 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 ){ 409 407 int inUl = 0; 410 408 if( !fchngQueryInit ){ 411 409 db_prepare(&fchngQuery, 412 410 "SELECT (pid==0) AS isnew," 413 411 " (fid==0) AS isdel," 414 412 " (SELECT name FROM filename WHERE fnid=mlink.fnid) AS name," 415 413 " (SELECT uuid FROM blob WHERE rid=fid)," ................................................................................ 431 429 const char *zNew = db_column_text(&fchngQuery, 3); 432 430 if( !inUl ){ 433 431 @ <ul class="filelist"> 434 432 inUl = 1; 435 433 } 436 434 if( isNew ){ 437 435 @ <li> %h(zFilename) (new file) 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> 440 438 }else if( isDel ){ 441 439 @ <li> %h(zFilename) (deleted)</li> 442 440 }else if( fossil_strcmp(zOld,zNew)==0 && zOldName!=0 ){ 443 441 @ <li> %h(zOldName) → %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> 446 444 }else{ 447 445 if( zOldName!=0 ){ 448 446 @ <li> %h(zOldName) → %h(zFilename) 449 447 }else{ 450 448 @ <li> %h(zFilename) 451 449 } 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> 454 452 } 455 453 } 456 454 db_reset(&fchngQuery); 457 455 if( inUl ){ 458 456 @ </ul> 459 457 } 460 458 } ................................................................................ 972 970 while( p ){ 973 971 blob_appendf(&sql, ",%d", p->rid); 974 972 p = p->u.pTo; 975 973 } 976 974 blob_append(&sql, ")", -1); 977 975 path_reset(); 978 976 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); 984 978 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); 990 980 tmFlags |= TIMELINE_DISJOINT; 991 981 db_multi_exec("%s", blob_str(&sql)); 992 982 }else if( (p_rid || d_rid) && g.perm.Read ){ 993 983 /* If p= or d= is present, ignore all other parameters other than n= */ 994 984 char *zUuid; 995 985 int np, nd; 996 986 ................................................................................ 1019 1009 if( np>0 ){ 1020 1010 if( nd>0 ) blob_appendf(&desc, " and "); 1021 1011 blob_appendf(&desc, "%d ancestors", np); 1022 1012 db_multi_exec("%s", blob_str(&sql)); 1023 1013 } 1024 1014 if( d_rid==0 && useDividers ) timeline_add_dividers(0, p_rid); 1025 1015 } 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); 1032 1018 }else if( f_rid && g.perm.Read ){ 1033 1019 /* If f= is present, ignore all other parameters other than n= */ 1034 1020 char *zUuid; 1035 1021 db_multi_exec( 1036 1022 "CREATE TEMP TABLE IF NOT EXISTS ok(rid INTEGER PRIMARY KEY);" 1037 1023 "INSERT INTO ok VALUES(%d);" 1038 1024 "INSERT OR IGNORE INTO ok SELECT pid FROM plink WHERE cid=%d;" ................................................................................ 1040 1026 f_rid, f_rid, f_rid 1041 1027 ); 1042 1028 blob_appendf(&sql, " AND event.objid IN ok"); 1043 1029 db_multi_exec("%s", blob_str(&sql)); 1044 1030 if( useDividers ) timeline_add_dividers(0, f_rid); 1045 1031 blob_appendf(&desc, "Parents and children of check-in "); 1046 1032 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); 1053 1034 }else{ 1054 1035 /* Otherwise, a timeline based on a span of time */ 1055 1036 int n; 1056 1037 const char *zEType = "timeline item"; 1057 1038 char *zDate; 1058 1039 char *zNEntry = mprintf("%d", nEntry); 1059 1040 url_add_parameter(&url, "n", zNEntry); ................................................................................ 1217 1198 blob_appendf(&desc, " occurring on or before %h.<br />", zBefore); 1218 1199 }else if( zCirca ){ 1219 1200 blob_appendf(&desc, " occurring around %h.<br />", zCirca); 1220 1201 } 1221 1202 if( zSearch ){ 1222 1203 blob_appendf(&desc, " matching \"%h\"", zSearch); 1223 1204 } 1224 - if( g.perm.History ){ 1205 + if( g.perm.Hyperlink ){ 1225 1206 if( zAfter || n==nEntry ){ 1226 1207 zDate = db_text(0, "SELECT min(timestamp) FROM timeline /*scan*/"); 1227 1208 timeline_submenu(&url, "Older", "b", zDate, "a"); 1228 1209 free(zDate); 1229 1210 } 1230 1211 if( zBefore || (zAfter && n==nEntry) ){ 1231 1212 zDate = db_text(0, "SELECT max(timestamp) FROM timeline /*scan*/"); ................................................................................ 1621 1602 /* 1622 1603 ** WEBPAGE: test_timewarps 1623 1604 */ 1624 1605 void test_timewarp_page(void){ 1625 1606 Stmt q; 1626 1607 1627 1608 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; } 1629 1610 style_header("Instances of timewarp"); 1630 1611 @ <ul> 1631 1612 db_prepare(&q, 1632 1613 "SELECT blob.uuid " 1633 1614 " FROM plink p, plink c, blob" 1634 1615 " WHERE p.cid=c.pid AND p.mtime>c.mtime" 1635 1616 " AND blob.rid=c.cid" 1636 1617 ); 1637 1618 while( db_step(&q)==SQLITE_ROW ){ 1638 1619 const char *zUuid = db_column_text(&q, 0); 1639 1620 @ <li> 1640 - @ <a href="%s(g.zTop)/timeline?p=%S(zUuid)&d=%S(zUuid)">%S(zUuid)</a> 1621 + @ <a href="%s(g.zTop)/timeline?p=%S(zUuid)&d=%S(zUuid)">%S(zUuid)</a> 1641 1622 } 1642 1623 db_finalize(&q); 1643 1624 style_footer(); 1644 1625 }
Changes to src/tkt.c.
303 303 304 304 login_check_credentials(); 305 305 if( !g.perm.RdTkt ){ login_needed(); return; } 306 306 if( g.perm.WrTkt || g.perm.ApndTkt ){ 307 307 style_submenu_element("Edit", "Edit The Ticket", "%s/tktedit?name=%T", 308 308 g.zTop, PD("name","")); 309 309 } 310 - if( g.perm.History ){ 310 + if( g.perm.Hyperlink ){ 311 311 style_submenu_element("History", "History Of This Ticket", 312 312 "%s/tkthistory/%T", g.zTop, zUuid); 313 313 style_submenu_element("Timeline", "Timeline Of This Ticket", 314 314 "%s/tkttimeline/%T", g.zTop, zUuid); 315 315 style_submenu_element("Check-ins", "Check-ins Of This Ticket", 316 316 "%s/tkttimeline/%T?y=ci", g.zTop, zUuid); 317 317 } 318 318 if( g.perm.NewTkt ){ 319 319 style_submenu_element("New Ticket", "Create a new ticket", 320 320 "%s/tktnew", g.zTop); 321 321 } 322 322 if( g.perm.ApndTkt && g.perm.Attach ){ 323 323 style_submenu_element("Attach", "Add An Attachment", 324 - "%s/attachadd?tkt=%T&from=%s/tktview/%t", 324 + "%s/attachadd?tkt=%T&from=%s/tktview/%t", 325 325 g.zTop, zUuid, g.zTop, zUuid); 326 326 } 327 327 style_header("View Ticket"); 328 328 if( g.thTrace ) Th_Trace("BEGIN_TKTVIEW<br />\n", -1); 329 329 ticket_init(); 330 330 initializeVariablesFromDb(); 331 331 zScript = ticket_viewpage_code(); ................................................................................ 351 351 const char *zUser = db_column_text(&q, 2); 352 352 if( cnt==0 ){ 353 353 @ <hr /><h2>Attachments:</h2> 354 354 @ <ul> 355 355 } 356 356 cnt++; 357 357 @ <li> 358 - if( g.perm.Read && g.perm.History ){ 359 - @ <a href="%s(g.zTop)/attachview?tkt=%s(zFullName)&file=%t(zFile)"> 358 + if( g.perm.Read && g.perm.Hyperlink ){ 359 + @ %z(href("%R/attachview?tkt=%s&file=%t",zFullName,zFile)) 360 360 @ %h(zFile)</a> 361 361 }else{ 362 362 @ %h(zFile) 363 363 } 364 364 @ added by %h(zUser) on 365 365 hyperlink_to_date(zDate, "."); 366 366 if( g.perm.WrTkt && g.perm.Attach ){ 367 - @ [<a href="%s(g.zTop)/attachdelete?tkt=%s(zFullName)&file=%t(zFile)&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>] 368 368 } 369 369 @ </li> 370 370 } 371 371 if( cnt ){ 372 372 @ </ul> 373 373 } 374 374 db_finalize(&q); ................................................................................ 645 645 } 646 646 } 647 647 return 0; 648 648 } 649 649 650 650 /* 651 651 ** WEBPAGE: tkttimeline 652 -** URL: /tkttimeline?name=TICKETUUID&y=TYPE 652 +** URL: /tkttimeline?name=TICKETUUID&y=TYPE 653 653 ** 654 654 ** Show the change history for a single ticket in timeline format. 655 655 */ 656 656 void tkttimeline_page(void){ 657 657 Stmt q; 658 658 char *zTitle; 659 659 char *zSQL; ................................................................................ 660 660 const char *zUuid; 661 661 char *zFullUuid; 662 662 int tagid; 663 663 char zGlobPattern[50]; 664 664 const char *zType; 665 665 666 666 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; } 668 668 zUuid = PD("name",""); 669 669 zType = PD("y","a"); 670 670 if( zType[0]!='c' ){ 671 671 style_submenu_element("Check-ins", "Check-ins", 672 - "%s/tkttimeline?name=%T&y=ci", g.zTop, zUuid); 672 + "%s/tkttimeline?name=%T&y=ci", g.zTop, zUuid); 673 673 }else{ 674 674 style_submenu_element("Timeline", "Timeline", 675 675 "%s/tkttimeline?name=%T", g.zTop, zUuid); 676 676 } 677 677 style_submenu_element("History", "History", 678 678 "%s/tkthistory/%s", g.zTop, zUuid); 679 679 style_submenu_element("Status", "Status", ................................................................................ 734 734 void tkthistory_page(void){ 735 735 Stmt q; 736 736 char *zTitle; 737 737 const char *zUuid; 738 738 int tagid; 739 739 740 740 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; } 742 742 zUuid = PD("name",""); 743 743 zTitle = mprintf("History Of Ticket %h", zUuid); 744 744 style_submenu_element("Status", "Status", 745 745 "%s/info/%s", g.zTop, zUuid); 746 746 style_submenu_element("Check-ins", "Check-ins", 747 - "%s/tkttimeline?name=%s&y=ci", g.zTop, zUuid); 747 + "%s/tkttimeline?name=%s&y=ci", g.zTop, zUuid); 748 748 style_submenu_element("Timeline", "Timeline", 749 749 "%s/tkttimeline?name=%s", g.zTop, zUuid); 750 750 style_header(zTitle); 751 751 free(zTitle); 752 752 753 753 tagid = db_int(0, "SELECT tagid FROM tag WHERE tagname GLOB 'tkt-%q*'",zUuid); 754 754 if( tagid==0 ){ ................................................................................ 784 784 if( zSrc==0 || zSrc[0]==0 ){ 785 785 @ 786 786 @ <p>Delete attachment "%h(zFile)" 787 787 }else{ 788 788 @ 789 789 @ <p>Add attachment "%h(zFile)" 790 790 } 791 - @ [<a href="%s(g.zTop)/artifact/%T(zChngUuid)">%s(zShort)</a>] 791 + @ [%z(href("%R/artifact/%T",zChngUuid))%s(zShort)</a>] 792 792 @ (rid %d(rid)) by 793 793 hyperlink_to_user(zUser,zDate," on"); 794 794 hyperlink_to_date(zDate, ".</p>"); 795 795 }else{ 796 796 pTicket = manifest_get(rid, CFTYPE_TICKET); 797 797 if( pTicket ){ 798 798 @ 799 799 @ <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>] 801 801 @ (rid %d(rid)) by 802 802 hyperlink_to_user(pTicket->zUser,zDate," on"); 803 803 hyperlink_to_date(zDate, ":"); 804 804 @ </p> 805 805 ticket_output_change_artifact(pTicket); 806 806 } 807 807 manifest_destroy(pTicket);
Changes to src/wiki.c.
102 102 g.isHome = 1; 103 103 wiki_page(); 104 104 return; 105 105 } 106 106 style_header("Home"); 107 107 @ <p>This is a stub home-page for the project. 108 108 @ 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> 110 110 @ and establish a "Project Name". Then create a 111 111 @ wiki page with that name. The content of that wiki page 112 112 @ will be displayed in place of this message.</p> 113 113 style_footer(); 114 114 } 115 115 116 116 /* ................................................................................ 140 140 if( !g.perm.RdWiki ){ login_needed(); return; } 141 141 zPageName = P("name"); 142 142 if( zPageName==0 ){ 143 143 style_header("Wiki"); 144 144 @ <ul> 145 145 { char *zHomePageName = db_get("project-name",0); 146 146 if( zHomePageName ){ 147 - @ <li> <a href="%s(g.zTop)/wiki?name=%t(zHomePageName)"> 147 + @ <li> %z(href("%R/wiki?name=%t",zHomePageName)) 148 148 @ %h(zHomePageName)</a> wiki home page.</li> 149 149 } 150 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> 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> 156 154 @ to experiment.</li> 157 155 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> 159 157 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> 161 159 } 162 160 } 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> 164 162 @ available on this server.</li> 165 163 @ <li> <form method="get" action="%s(g.zTop)/wfind"><div> 166 164 @ Search wiki titles: <input type="text" name="title"/> 167 165 @ <input type="submit" /></div></form> 168 166 @ </li> 169 167 @ </ul> 170 168 style_footer(); ................................................................................ 190 188 if( !g.isHome ){ 191 189 if( (rid && g.perm.WrWiki) || (!rid && g.perm.NewWiki) ){ 192 190 style_submenu_element("Edit", "Edit Wiki Page", "%s/wikiedit?name=%T", 193 191 g.zTop, zPageName); 194 192 } 195 193 if( rid && g.perm.ApndWiki && g.perm.Attach ){ 196 194 style_submenu_element("Attach", "Add An Attachment", 197 - "%s/attachadd?page=%T&from=%s/wiki%%3fname=%T", 195 + "%s/attachadd?page=%T&from=%s/wiki%%3fname=%T", 198 196 g.zTop, zPageName, g.zTop, zPageName); 199 197 } 200 198 if( rid && g.perm.ApndWiki ){ 201 199 style_submenu_element("Append", "Add A Comment", "%s/wikiappend?name=%T", 202 200 g.zTop, zPageName); 203 201 } 204 - if( g.perm.History ){ 202 + if( g.perm.Hyperlink ){ 205 203 style_submenu_element("History", "History", "%s/whistory?name=%T", 206 204 g.zTop, zPageName); 207 205 } 208 206 } 209 207 style_header(zPageName); 210 208 blob_init(&wiki, zBody, -1); 211 209 wiki_convert(&wiki, 0, 0); ................................................................................ 223 221 const char *zUser = db_column_text(&q, 2); 224 222 if( cnt==0 ){ 225 223 @ <hr /><h2>Attachments:</h2> 226 224 @ <ul> 227 225 } 228 226 cnt++; 229 227 @ <li> 230 - if( g.perm.History && g.perm.Read ){ 231 - @ <a href="%s(g.zTop)/attachview?page=%s(zPageName)&file=%t(zFile)"> 228 + if( g.perm.Hyperlink && g.perm.Read ){ 229 + @ %z(href("%R/attachview?page=%T&file=%t",zPageName,zFile)) 232 230 @ %h(zFile)</a> 233 231 }else{ 234 232 @ %h(zFile) 235 233 } 236 234 @ added by %h(zUser) on 237 235 hyperlink_to_date(zDate, "."); 238 236 if( g.perm.WrWiki && g.perm.Attach ){ 239 - @ [<a href="%s(g.zTop)/attachdelete?page=%s(zPageName)&file=%t(zFile)&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>] 240 238 } 241 239 @ </li> 242 240 } 243 241 if( cnt ){ 244 242 @ </ul> 245 243 } 246 244 db_finalize(&q); ................................................................................ 542 540 543 541 /* 544 542 ** Function called to output extra text at the end of each line in 545 543 ** a wiki history listing. 546 544 */ 547 545 static void wiki_history_extra(int rid){ 548 546 if( db_exists("SELECT 1 FROM tagxref WHERE rid=%d", rid) ){ 549 - @ <a href="%s(g.zTop)/wdiff?name=%t(zWikiPageName)&a=%d(rid)">[diff]</a> 547 + @ %z(href("%R/wdiff?name=%t&a=%d",zWikiPageName,rid))[diff]</a> 550 548 } 551 549 } 552 550 553 551 /* 554 552 ** WEBPAGE: whistory 555 553 ** URL: /whistory?name=PAGENAME 556 554 ** ................................................................................ 558 556 */ 559 557 void whistory_page(void){ 560 558 Stmt q; 561 559 char *zTitle; 562 560 char *zSQL; 563 561 const char *zPageName; 564 562 login_check_credentials(); 565 - if( !g.perm.History ){ login_needed(); return; } 563 + if( !g.perm.Hyperlink ){ login_needed(); return; } 566 564 zPageName = PD("name",""); 567 565 zTitle = mprintf("History Of %s", zPageName); 568 566 style_header(zTitle); 569 567 free(zTitle); 570 568 571 569 zSQL = mprintf("%s AND event.objid IN " 572 570 " (SELECT rid FROM tagxref WHERE tagid=" ................................................................................ 595 593 const char *zPageName; 596 594 Manifest *pW1, *pW2 = 0; 597 595 Blob w1, w2, d; 598 596 int diffFlags; 599 597 600 598 login_check_credentials(); 601 599 rid1 = atoi(PD("a","0")); 602 - if( !g.perm.History ){ login_needed(); return; } 600 + if( !g.perm.Hyperlink ){ login_needed(); return; } 603 601 if( rid1==0 ) fossil_redirect_home(); 604 602 rid2 = atoi(PD("b","0")); 605 603 zPageName = PD("name",""); 606 604 zTitle = mprintf("Changes To %s", zPageName); 607 605 style_header(zTitle); 608 606 free(zTitle); 609 607 ................................................................................ 672 670 } 673 671 @ <ul> 674 672 wiki_prepare_page_list(&q); 675 673 while( db_step(&q)==SQLITE_ROW ){ 676 674 const char *zName = db_column_text(&q, 0); 677 675 int size = db_column_int(&q, 1); 678 676 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> 680 678 }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> 682 680 } 683 681 } 684 682 db_finalize(&q); 685 683 @ </ul> 686 684 style_footer(); 687 685 } 688 686 ................................................................................ 702 700 @ <ul> 703 701 db_prepare(&q, 704 702 "SELECT substr(tagname, 6, 1000) FROM tag WHERE tagname like 'wiki-%%%q%%'" 705 703 " ORDER BY lower(tagname) /*sort*/" , 706 704 zTitle); 707 705 while( db_step(&q)==SQLITE_ROW ){ 708 706 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> 710 708 } 711 709 db_finalize(&q); 712 710 @ </ul> 713 711 style_footer(); 714 712 } 715 713 716 714 /*
Changes to src/wikiformat.c.
1041 1041 || strncmp(zTarget, "https:", 6)==0 1042 1042 || strncmp(zTarget, "ftp:", 4)==0 1043 1043 || strncmp(zTarget, "mailto:", 7)==0 1044 1044 ){ 1045 1045 blob_appendf(p->pOut, "<a href=\"%s\">", zTarget); 1046 1046 /* zTerm = "⟾</a>"; // doesn't work on windows */ 1047 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 - } 1048 + blob_appendf(p->pOut, "<a href=\"%s%h\">", g.zTop, zTarget); 1053 1049 }else if( zTarget[0]=='.' || zTarget[0]=='#' ){ 1054 - if( 1 /* g.perm.History */ ){ 1050 + if( 1 ){ 1055 1051 blob_appendf(p->pOut, "<a href=\"%h\">", zTarget); 1056 1052 }else{ 1057 1053 zTerm = ""; 1058 1054 } 1059 1055 }else if( is_valid_uuid(zTarget) ){ 1060 1056 int isClosed = 0; 1061 1057 if( is_ticket(zTarget, &isClosed) ){ 1062 1058 /* Special display processing for tickets. Display the hyperlink 1063 1059 ** as crossed out if the ticket is closed. 1064 1060 */ 1065 1061 if( isClosed ){ 1066 - if( g.perm.History ){ 1062 + if( g.perm.Hyperlink ){ 1067 1063 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) 1070 1066 ); 1071 1067 zTerm = "]</span></a>"; 1072 1068 }else{ 1073 1069 blob_appendf(p->pOut,"<span class=\"wikiTagCancelled\">["); 1074 1070 zTerm = "]</span>"; 1075 1071 } 1076 1072 }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)); 1081 1075 zTerm = "]</a>"; 1082 1076 }else{ 1083 1077 blob_appendf(p->pOut, "["); 1084 1078 zTerm = "]"; 1085 1079 } 1086 1080 } 1087 1081 }else if( !in_this_repo(zTarget) ){ 1088 1082 blob_appendf(p->pOut, "<span class=\"brokenlink\">[", zTarget); 1089 1083 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)); 1092 1086 zTerm = "]</a>"; 1093 1087 } 1094 1088 }else if( strlen(zTarget)>=10 && fossil_isdigit(zTarget[0]) && zTarget[4]=='-' 1095 1089 && db_int(0, "SELECT datetime(%Q) NOT NULL", zTarget) ){ 1096 1090 blob_appendf(p->pOut, "<a href=\"%s/timeline?c=%T\">", g.zTop, zTarget); 1097 1091 }else if( strncmp(zTarget, "wiki:", 5)==0 1098 1092 && wiki_name_is_wellformed((const unsigned char*)zTarget) ){