Check-in [d9c8a7dd73]
Not logged in

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
SHA1 Hash:d9c8a7dd73a7718527a8b95eb6971b059ce99636
Date: 2012-04-28 08:03:56
User: drh
Comment:Refinements to the new hyperlink logic and spider defense.
Tags And Properties
Changes

Changes to src/attach.c

73 for(i=0; zFilename[i]; i++){ 73 for(i=0; zFilename[i]; i++){ 74 if( zFilename[i]=='/' && zFilename[i+1]!=0 ){ 74 if( zFilename[i]=='/' && zFilename[i+1]!=0 ){ 75 zFilename = &zFilename[i+1]; 75 zFilename = &zFilename[i+1]; 76 i = -1; 76 i = -1; 77 } 77 } 78 } 78 } 79 if( strlen(zTarget)==UUID_SIZE && validate16(zTarget,UUID_SIZE) ){ 79 if( strlen(zTarget)==UUID_SIZE && validate16(zTarget,UUID_SIZE) ){ 80 zUrlTail = mprintf("tkt=%s&amp;file=%t", zTarget, zFilename); | 80 zUrlTail = mprintf("tkt=%s&file=%t", zTarget, zFilename); 81 }else{ 81 }else{ 82 zUrlTail = mprintf("page=%t&amp;file=%t", zTarget, zFilename); | 82 zUrlTail = mprintf("page=%t&file=%t", zTarget, zFilename); 83 } 83 } 84 @ 84 @ 85 @ <p><a href="/attachview?%s(zUrlTail)">%h(zFilename)</a> 85 @ <p><a href="/attachview?%s(zUrlTail)">%h(zFilename)</a> 86 @ [<a href="/attachdownload/%t(zFilename)?%s(zUrlTail)">download</a>]<br /> 86 @ [<a href="/attachdownload/%t(zFilename)?%s(zUrlTail)">download</a>]<br /> 87 if( zComment ) while( fossil_isspace(zComment[0]) ) zComment++; 87 if( zComment ) while( fossil_isspace(zComment[0]) ) zComment++; 88 if( zComment && zComment[0] ){ 88 if( zComment && zComment[0] ){ 89 @ %w(zComment)<br /> 89 @ %w(zComment)<br />

Changes to src/browse.c

75 */ 75 */ 76 void hyperlinked_path(const char *zPath, Blob *pOut, const char *zCI){ 76 void hyperlinked_path(const char *zPath, Blob *pOut, const char *zCI){ 77 int i, j; 77 int i, j; 78 char *zSep = ""; 78 char *zSep = ""; 79 79 80 for(i=0; zPath[i]; i=j){ 80 for(i=0; zPath[i]; i=j){ 81 for(j=i; zPath[j] && zPath[j]!='/'; j++){} 81 for(j=i; zPath[j] && zPath[j]!='/'; j++){} 82 if( zPath[j] && g.perm.History ){ | 82 if( zPath[j] && g.perm.Hyperlink ){ 83 if( zCI ){ 83 if( zCI ){ 84 char *zLink = href("%R/dir?ci=%S&amp;name=%#T", zCI, j, zPath); | 84 char *zLink = href("%R/dir?ci=%S&name=%#T", zCI, j, zPath); 85 blob_appendf(pOut, "%s%z%#h</a>", 85 blob_appendf(pOut, "%s%z%#h</a>", 86 zSep, zLink, j-i, &zPath[i]); 86 zSep, zLink, j-i, &zPath[i]); 87 }else{ 87 }else{ 88 char *zLink = href("%R/dir?name=%#T", j, zPath); 88 char *zLink = href("%R/dir?name=%#T", j, zPath); 89 blob_appendf(pOut, "%s%z%#h</a>", 89 blob_appendf(pOut, "%s%z%#h</a>", 90 zSep, zLink, j-i, &zPath[i]); 90 zSep, zLink, j-i, &zPath[i]); 91 } 91 } ................................................................................................................................................................................ 118 int rid = 0; 118 int rid = 0; 119 char *zUuid = 0; 119 char *zUuid = 0; 120 Blob dirname; 120 Blob dirname; 121 Manifest *pM = 0; 121 Manifest *pM = 0; 122 const char *zSubdirLink; 122 const char *zSubdirLink; 123 123 124 login_check_credentials(); 124 login_check_credentials(); 125 if( !g.perm.History ){ login_needed(); return; } | 125 if( !g.perm.Hyperlink ){ login_needed(); return; } 126 while( nD>1 && zD[nD-2]=='/' ){ zD[(--nD)-1] = 0; } 126 while( nD>1 && zD[nD-2]=='/' ){ zD[(--nD)-1] = 0; } 127 style_header("File List"); 127 style_header("File List"); 128 sqlite3_create_function(g.db, "pathelement", 2, SQLITE_UTF8, 0, 128 sqlite3_create_function(g.db, "pathelement", 2, SQLITE_UTF8, 0, 129 pathelementFunc, 0, 0); 129 pathelementFunc, 0, 0); 130 130 131 /* If the name= parameter is an empty string, make it a NULL pointer */ 131 /* If the name= parameter is an empty string, make it a NULL pointer */ 132 if( zD && strlen(zD)==0 ){ zD = 0; } 132 if( zD && strlen(zD)==0 ){ zD = 0; } ................................................................................................................................................................................ 157 } 157 } 158 if( zCI ){ 158 if( zCI ){ 159 char zShort[20]; 159 char zShort[20]; 160 memcpy(zShort, zUuid, 10); 160 memcpy(zShort, zUuid, 10); 161 zShort[10] = 0; 161 zShort[10] = 0; 162 @ <h2>Files of check-in [%z(href("vinfo?name=%T",zUuid))%s(zShort)</a>] 162 @ <h2>Files of check-in [%z(href("vinfo?name=%T",zUuid))%s(zShort)</a>] 163 @ %s(blob_str(&dirname))</h2> 163 @ %s(blob_str(&dirname))</h2> 164 zSubdirLink = mprintf("%R/dir?ci=%S&amp;name=%T", zUuid, zPrefix); | 164 zSubdirLink = mprintf("%R/dir?ci=%S&name=%T", zUuid, zPrefix); 165 if( zD ){ 165 if( zD ){ 166 style_submenu_element("Top", "Top", "%R/dir?ci=%S", zUuid); 166 style_submenu_element("Top", "Top", "%R/dir?ci=%S", zUuid); 167 style_submenu_element("All", "All", "%R/dir?name=%t", zD); 167 style_submenu_element("All", "All", "%R/dir?name=%t", zD); 168 }else{ 168 }else{ 169 style_submenu_element("All", "All", "%R/dir"); 169 style_submenu_element("All", "All", "%R/dir"); 170 } 170 } 171 }else{ 171 }else{ ................................................................................................................................................................................ 174 @ %s(blob_str(&dirname))</h2> 174 @ %s(blob_str(&dirname))</h2> 175 hasTrunk = db_exists( 175 hasTrunk = db_exists( 176 "SELECT 1 FROM tagxref WHERE tagid=%d AND value='trunk'", 176 "SELECT 1 FROM tagxref WHERE tagid=%d AND value='trunk'", 177 TAG_BRANCH); 177 TAG_BRANCH); 178 zSubdirLink = mprintf("%R/dir?name=%T", zPrefix); 178 zSubdirLink = mprintf("%R/dir?name=%T", zPrefix); 179 if( zD ){ 179 if( zD ){ 180 style_submenu_element("Top", "Top", "%R/dir"); 180 style_submenu_element("Top", "Top", "%R/dir"); 181 style_submenu_element("Tip", "Tip", "%R/dir?name=%t&amp;ci=tip", zD); | 181 style_submenu_element("Tip", "Tip", "%R/dir?name=%t&ci=tip", zD); 182 if( hasTrunk ){ 182 if( hasTrunk ){ 183 style_submenu_element("Trunk", "Trunk", "%R/dir?name=%t&amp;ci=trunk", | 183 style_submenu_element("Trunk", "Trunk", "%R/dir?name=%t&ci=trunk", 184 zD); 184 zD); 185 } 185 } 186 }else{ 186 }else{ 187 style_submenu_element("Tip", "Tip", "%R/dir?ci=tip"); 187 style_submenu_element("Tip", "Tip", "%R/dir?ci=tip"); 188 if( hasTrunk ){ 188 if( hasTrunk ){ 189 style_submenu_element("Trunk", "Trunk", "%R/dir?ci=trunk"); 189 style_submenu_element("Trunk", "Trunk", "%R/dir?ci=trunk"); 190 } 190 }

Changes to src/diffcmd.c

539 diff_all_two_versions(zFrom, zTo, zDiffCmd, diffFlags); 539 diff_all_two_versions(zFrom, zTo, zDiffCmd, diffFlags); 540 } 540 } 541 } 541 } 542 } 542 } 543 543 544 /* 544 /* 545 ** WEBPAGE: vpatch 545 ** WEBPAGE: vpatch 546 ** URL vpatch?from=UUID&amp;to=UUID | 546 ** URL vpatch?from=UUID&to=UUID 547 */ 547 */ 548 void vpatch_page(void){ 548 void vpatch_page(void){ 549 const char *zFrom = P("from"); 549 const char *zFrom = P("from"); 550 const char *zTo = P("to"); 550 const char *zTo = P("to"); 551 login_check_credentials(); 551 login_check_credentials(); 552 if( !g.perm.Read ){ login_needed(); return; } 552 if( !g.perm.Read ){ login_needed(); return; } 553 if( zFrom==0 || zTo==0 ) fossil_redirect_home(); 553 if( zFrom==0 || zTo==0 ) fossil_redirect_home(); 554 554 555 cgi_set_content_type("text/plain"); 555 cgi_set_content_type("text/plain"); 556 diff_all_two_versions(zFrom, zTo, 0, DIFF_NEWFILE); 556 diff_all_two_versions(zFrom, zTo, 0, DIFF_NEWFILE); 557 } 557 }

Changes to src/event.c

123 g.zTop, zEventId); 123 g.zTop, zEventId); 124 } 124 } 125 zETime = db_text(0, "SELECT datetime(%.17g)", pEvent->rEventDate); 125 zETime = db_text(0, "SELECT datetime(%.17g)", pEvent->rEventDate); 126 style_submenu_element("Context", "Context", "%s/timeline?c=%T", 126 style_submenu_element("Context", "Context", "%s/timeline?c=%T", 127 g.zTop, zETime); 127 g.zTop, zETime); 128 if( g.perm.Hyperlink ){ 128 if( g.perm.Hyperlink ){ 129 if( showDetail ){ 129 if( showDetail ){ 130 style_submenu_element("Plain", "Plain", "%s/event?name=%s&amp;aid=%s", | 130 style_submenu_element("Plain", "Plain", "%s/event?name=%s&aid=%s", 131 g.zTop, zEventId, zUuid); 131 g.zTop, zEventId, zUuid); 132 if( nextRid ){ 132 if( nextRid ){ 133 char *zNext; 133 char *zNext; 134 zNext = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", nextRid); 134 zNext = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", nextRid); 135 style_submenu_element("Next", "Next", 135 style_submenu_element("Next", "Next", 136 "%s/event?name=%s&amp;aid=%s&amp;detail=1", | 136 "%s/event?name=%s&aid=%s&detail=1", 137 g.zTop, zEventId, zNext); 137 g.zTop, zEventId, zNext); 138 free(zNext); 138 free(zNext); 139 } 139 } 140 if( prevRid ){ 140 if( prevRid ){ 141 char *zPrev; 141 char *zPrev; 142 zPrev = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", prevRid); 142 zPrev = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", prevRid); 143 style_submenu_element("Prev", "Prev", 143 style_submenu_element("Prev", "Prev", 144 "%s/event?name=%s&amp;aid=%s&amp;detail=1", | 144 "%s/event?name=%s&aid=%s&detail=1", 145 g.zTop, zEventId, zPrev); 145 g.zTop, zEventId, zPrev); 146 free(zPrev); 146 free(zPrev); 147 } 147 } 148 }else{ 148 }else{ 149 style_submenu_element("Detail", "Detail", 149 style_submenu_element("Detail", "Detail", 150 "%s/event?name=%s&amp;aid=%s&amp;detail=1", | 150 "%s/event?name=%s&aid=%s&detail=1", 151 g.zTop, zEventId, zUuid); 151 g.zTop, zEventId, zUuid); 152 } 152 } 153 } 153 } 154 154 155 if( showDetail && g.perm.Hyperlink ){ 155 if( showDetail && g.perm.Hyperlink ){ 156 int i; 156 int i; 157 const char *zClr = 0; 157 const char *zClr = 0;

Changes to src/finfo.c

321 }else{ 321 }else{ 322 @ <b>Deleted</b> by check-in 322 @ <b>Deleted</b> by check-in 323 } 323 } 324 hyperlink_to_uuid(zShortCkin); 324 hyperlink_to_uuid(zShortCkin); 325 @ %h(zCom) (user: 325 @ %h(zCom) (user: 326 hyperlink_to_user(zUser, zDate, ""); 326 hyperlink_to_user(zUser, zDate, ""); 327 @ branch: %h(zBr)) 327 @ branch: %h(zBr)) 328 if( g.perm.History && zUuid ){ | 328 if( g.perm.Hyperlink && zUuid ){ 329 const char *z = zFilename; 329 const char *z = zFilename; 330 if( fpid ){ 330 if( fpid ){ 331 @ %z(href("%R/fdiff?v1=%s&amp;v2=%s",zPUuid,zUuid))[diff]</a> | 331 @ %z(href("%R/fdiff?v1=%s&v2=%s",zPUuid,zUuid))[diff]</a> 332 } 332 } 333 @ %z(href("%R/annotate?checkin=%S&amp;filename=%h",zCkin,z)) | 333 @ %z(href("%R/annotate?checkin=%S&filename=%h",zCkin,z)) 334 @ [annotate]</a> 334 @ [annotate]</a> 335 } 335 } 336 @ </td></tr> 336 @ </td></tr> 337 } 337 } 338 db_finalize(&q); 338 db_finalize(&q); 339 if( pGraph ){ 339 if( pGraph ){ 340 graph_finish(pGraph, 0); 340 graph_finish(pGraph, 0);

Changes to src/info.c

376 } 376 } 377 if( diffFlags ){ 377 if( diffFlags ){ 378 @ <pre style="white-space:pre;"> 378 @ <pre style="white-space:pre;"> 379 append_diff(zOld, zNew, diffFlags); 379 append_diff(zOld, zNew, diffFlags); 380 @ </pre> 380 @ </pre> 381 }else if( zOld && zNew && fossil_strcmp(zOld,zNew)!=0 ){ 381 }else if( zOld && zNew && fossil_strcmp(zOld,zNew)!=0 ){ 382 @ &nbsp;&nbsp; 382 @ &nbsp;&nbsp; 383 @ %z(href("%R/fdiff?v1=%S&amp;v2=%S",zOld,zNew))[diff]</a> | 383 @ %z(href("%R/fdiff?v1=%S&v2=%S",zOld,zNew))[diff]</a> 384 } 384 } 385 @ </p> 385 @ </p> 386 } 386 } 387 } 387 } 388 388 389 /* 389 /* 390 ** Construct an appropriate diffFlag for text_diff() based on query 390 ** Construct an appropriate diffFlag for text_diff() based on query ................................................................................................................................................................................ 620 }else{ 620 }else{ 621 @ %z(xhref("class='button'","%R/vinfo/%T?sbs=0",zName)) 621 @ %z(xhref("class='button'","%R/vinfo/%T?sbs=0",zName)) 622 @ show&nbsp;unified&nbsp;diffs</a> 622 @ show&nbsp;unified&nbsp;diffs</a> 623 @ %z(xhref("class='button'","%R/vinfo/%T?sbs=1",zName)) 623 @ %z(xhref("class='button'","%R/vinfo/%T?sbs=1",zName)) 624 @ show&nbsp;side-by-side&nbsp;diffs</a> 624 @ show&nbsp;side-by-side&nbsp;diffs</a> 625 } 625 } 626 } 626 } 627 @ %z(xhref("class='button'","%R/vpatch?from=%S&amp;to=%S",zParent,zUuid)) | 627 @ %z(xhref("class='button'","%R/vpatch?from=%S&to=%S",zParent,zUuid)) 628 @ patch</a></div> 628 @ patch</a></div> 629 db_prepare(&q, 629 db_prepare(&q, 630 "SELECT name," 630 "SELECT name," 631 " mperm," 631 " mperm," 632 " (SELECT uuid FROM blob WHERE rid=mlink.pid)," 632 " (SELECT uuid FROM blob WHERE rid=mlink.pid)," 633 " (SELECT uuid FROM blob WHERE rid=mlink.fid)," 633 " (SELECT uuid FROM blob WHERE rid=mlink.fid)," 634 " (SELECT name FROM filename WHERE filename.fnid=mlink.pfnid)" 634 " (SELECT name FROM filename WHERE filename.fnid=mlink.pfnid)" ................................................................................................................................................................................ 790 } 790 } 791 db_finalize(&q); 791 db_finalize(&q); 792 } 792 } 793 793 794 794 795 /* 795 /* 796 ** WEBPAGE: vdiff 796 ** 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 798 ** 798 ** 799 ** Show all differences between two checkins. 799 ** Show all differences between two checkins. 800 */ 800 */ 801 void vdiff_page(void){ 801 void vdiff_page(void){ 802 int ridFrom, ridTo; 802 int ridFrom, ridTo; 803 int showDetail = 0; 803 int showDetail = 0; 804 int sideBySide = 0; 804 int sideBySide = 0; ................................................................................................................................................................................ 1256 rid = name_to_rid_www("name"); 1256 rid = name_to_rid_www("name"); 1257 login_check_credentials(); 1257 login_check_credentials(); 1258 if( !g.perm.Read ){ login_needed(); return; } 1258 if( !g.perm.Read ){ login_needed(); return; } 1259 if( rid==0 ) fossil_redirect_home(); 1259 if( rid==0 ) fossil_redirect_home(); 1260 if( g.perm.Admin ){ 1260 if( g.perm.Admin ){ 1261 const char *zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d", rid); 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) ){ 1262 if( db_exists("SELECT 1 FROM shun WHERE uuid='%s'", zUuid) ){ 1263 style_submenu_element("Unshun","Unshun", "%s/shun?uuid=%s&amp;sub=1", | 1263 style_submenu_element("Unshun","Unshun", "%s/shun?uuid=%s&sub=1", 1264 g.zTop, zUuid); 1264 g.zTop, zUuid); 1265 }else{ 1265 }else{ 1266 style_submenu_element("Shun","Shun", "%s/shun?shun=%s#addshun", 1266 style_submenu_element("Shun","Shun", "%s/shun?shun=%s#addshun", 1267 g.zTop, zUuid); 1267 g.zTop, zUuid); 1268 } 1268 } 1269 } 1269 } 1270 style_header("Hex Artifact Content"); 1270 style_header("Hex Artifact Content"); ................................................................................................................................................................................ 1403 1403 1404 login_check_credentials(); 1404 login_check_credentials(); 1405 if( !g.perm.Read ){ login_needed(); return; } 1405 if( !g.perm.Read ){ login_needed(); return; } 1406 if( rid==0 ) fossil_redirect_home(); 1406 if( rid==0 ) fossil_redirect_home(); 1407 if( g.perm.Admin ){ 1407 if( g.perm.Admin ){ 1408 const char *zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d", rid); 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) ){ 1409 if( db_exists("SELECT 1 FROM shun WHERE uuid='%s'", zUuid) ){ 1410 style_submenu_element("Unshun","Unshun", "%s/shun?uuid=%s&amp;sub=1", | 1410 style_submenu_element("Unshun","Unshun", "%s/shun?uuid=%s&sub=1", 1411 g.zTop, zUuid); 1411 g.zTop, zUuid); 1412 }else{ 1412 }else{ 1413 style_submenu_element("Shun","Shun", "%s/shun?shun=%s#addshun", 1413 style_submenu_element("Shun","Shun", "%s/shun?shun=%s#addshun", 1414 g.zTop, zUuid); 1414 g.zTop, zUuid); 1415 } 1415 } 1416 } 1416 } 1417 style_header("Artifact Content"); 1417 style_header("Artifact Content"); ................................................................................................................................................................................ 1462 output_text_with_line_numbers(z, zLn); 1462 output_text_with_line_numbers(z, zLn); 1463 }else{ 1463 }else{ 1464 @ <pre> 1464 @ <pre> 1465 @ %h(z) 1465 @ %h(z) 1466 @ </pre> 1466 @ </pre> 1467 } 1467 } 1468 }else if( strncmp(zMime, "image/", 6)==0 ){ 1468 }else if( strncmp(zMime, "image/", 6)==0 ){ 1469 @ <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> 1470 }else{ 1470 }else{ 1471 @ <i>(file is %d(blob_size(&content)) bytes of binary data)</i> 1471 @ <i>(file is %d(blob_size(&content)) bytes of binary data)</i> 1472 } 1472 } 1473 @ </blockquote> 1473 @ </blockquote> 1474 } 1474 } 1475 style_footer(); 1475 style_footer(); 1476 } 1476 } ................................................................................................................................................................................ 1491 login_check_credentials(); 1491 login_check_credentials(); 1492 if( !g.perm.RdTkt ){ login_needed(); return; } 1492 if( !g.perm.RdTkt ){ login_needed(); return; } 1493 rid = name_to_rid_www("name"); 1493 rid = name_to_rid_www("name"); 1494 if( rid==0 ){ fossil_redirect_home(); } 1494 if( rid==0 ){ fossil_redirect_home(); } 1495 zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d", rid); 1495 zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d", rid); 1496 if( g.perm.Admin ){ 1496 if( g.perm.Admin ){ 1497 if( db_exists("SELECT 1 FROM shun WHERE uuid='%s'", zUuid) ){ 1497 if( db_exists("SELECT 1 FROM shun WHERE uuid='%s'", zUuid) ){ 1498 style_submenu_element("Unshun","Unshun", "%s/shun?uuid=%s&amp;sub=1", | 1498 style_submenu_element("Unshun","Unshun", "%s/shun?uuid=%s&sub=1", 1499 g.zTop, zUuid); 1499 g.zTop, zUuid); 1500 }else{ 1500 }else{ 1501 style_submenu_element("Shun","Shun", "%s/shun?shun=%s#addshun", 1501 style_submenu_element("Shun","Shun", "%s/shun?shun=%s#addshun", 1502 g.zTop, zUuid); 1502 g.zTop, zUuid); 1503 } 1503 } 1504 } 1504 } 1505 pTktChng = manifest_get(rid, CFTYPE_TICKET); 1505 pTktChng = manifest_get(rid, CFTYPE_TICKET);

Changes to src/json_dir.c

64 char const * zDX = NULL; 64 char const * zDX = NULL; 65 int nD; 65 int nD; 66 char * zUuid = NULL; 66 char * zUuid = NULL; 67 char const * zCI = NULL; 67 char const * zCI = NULL; 68 Manifest * pM = NULL; 68 Manifest * pM = NULL; 69 Stmt q = empty_Stmt; 69 Stmt q = empty_Stmt; 70 int rid = 0; 70 int rid = 0; 71 if( !g.perm.History ){ | 71 if( !g.perm.Hyperlink ){ 72 json_set_err(FSL_JSON_E_DENIED, "Requires 'h' permissions."); 72 json_set_err(FSL_JSON_E_DENIED, "Requires 'h' permissions."); 73 return NULL; 73 return NULL; 74 } 74 } 75 zCI = json_find_option_cstr("checkin",NULL,"ci" ); 75 zCI = json_find_option_cstr("checkin",NULL,"ci" ); 76 76 77 /* If a specific check-in is requested, fetch and parse it. If the 77 /* If a specific check-in is requested, fetch and parse it. If the 78 ** specific check-in does not exist, clear zCI. zCI==0 will cause all 78 ** specific check-in does not exist, clear zCI. zCI==0 will cause all

Changes to src/json_timeline.c

51 */ 51 */ 52 cson_value * json_page_timeline(){ 52 cson_value * json_page_timeline(){ 53 #if 0 53 #if 0 54 /* The original timeline code does not require 'h' access, 54 /* The original timeline code does not require 'h' access, 55 but it arguably should. For JSON mode i think one could argue 55 but it arguably should. For JSON mode i think one could argue 56 that History permissions are required. 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 json_set_err(FSL_JSON_E_DENIED, "Timeline requires 'h' or 'o' access."); 59 json_set_err(FSL_JSON_E_DENIED, "Timeline requires 'h' or 'o' access."); 60 return NULL; 60 return NULL; 61 } 61 } 62 #endif 62 #endif 63 return json_page_dispatch_helper(&JsonPageDefs_Timeline[0]); 63 return json_page_dispatch_helper(&JsonPageDefs_Timeline[0]); 64 } 64 } 65 65 ................................................................................................................................................................................ 424 cson_value * listV = NULL; 424 cson_value * listV = NULL; 425 cson_array * list = NULL; 425 cson_array * list = NULL; 426 int check = 0; 426 int check = 0; 427 char showFiles = -1/*magic number*/; 427 char showFiles = -1/*magic number*/; 428 Stmt q = empty_Stmt; 428 Stmt q = empty_Stmt; 429 char warnRowToJsonFailed = 0; 429 char warnRowToJsonFailed = 0; 430 Blob sql = empty_blob; 430 Blob sql = empty_blob; 431 if( !g.perm.History ){ | 431 if( !g.perm.Hyperlink ){ 432 /* Reminder to self: HTML impl requires 'o' (Read) 432 /* Reminder to self: HTML impl requires 'o' (Read) 433 rights. 433 rights. 434 */ 434 */ 435 json_set_err( FSL_JSON_E_DENIED, "Checkin timeline requires 'h' access." ); 435 json_set_err( FSL_JSON_E_DENIED, "Checkin timeline requires 'h' access." ); 436 return NULL; 436 return NULL; 437 } 437 } 438 showFiles = json_find_option_bool("files",NULL,"f",0); 438 showFiles = json_find_option_bool("files",NULL,"f",0);

Changes to src/json_wiki.c

490 int argPos = g.json.dispatchDepth; 490 int argPos = g.json.dispatchDepth; 491 int r1 = 0, r2 = 0; 491 int r1 = 0, r2 = 0; 492 Manifest * pW1 = NULL, *pW2 = NULL; 492 Manifest * pW1 = NULL, *pW2 = NULL; 493 Blob w1 = empty_blob, w2 = empty_blob, d = empty_blob; 493 Blob w1 = empty_blob, w2 = empty_blob, d = empty_blob; 494 char const * zErrTag = NULL; 494 char const * zErrTag = NULL; 495 int diffFlags; 495 int diffFlags; 496 char * zUuid = NULL; 496 char * zUuid = NULL; 497 if( !g.perm.History ){ | 497 if( !g.perm.Hyperlink ){ 498 json_set_err(FSL_JSON_E_DENIED, 498 json_set_err(FSL_JSON_E_DENIED, 499 "Requires 'h' permissions."); 499 "Requires 'h' permissions."); 500 return NULL; 500 return NULL; 501 } 501 } 502 502 503 503 504 zV1 = json_find_option_cstr2( "v1",NULL, NULL, ++argPos ); 504 zV1 = json_find_option_cstr2( "v1",NULL, NULL, ++argPos );

Changes to src/login.c

560 */ 560 */ 561 login_set_user_cookie(zUsername, uid, NULL); 561 login_set_user_cookie(zUsername, uid, NULL); 562 redirect_to_g(); 562 redirect_to_g(); 563 } 563 } 564 } 564 } 565 style_header("Login/Logout"); 565 style_header("Login/Logout"); 566 @ %s(zErrMsg) 566 @ %s(zErrMsg) 567 if( zGoto ){ | 567 if( zGoto && P("anon")==0 ){ 568 @ <p>A login is required for <a href="%h(zGoto)">%h(zGoto)</a>.</p> 568 @ <p>A login is required for <a href="%h(zGoto)">%h(zGoto)</a>.</p> 569 } 569 } 570 @ <form action="login" method="post"> 570 @ <form action="login" method="post"> 571 if( zGoto ){ 571 if( zGoto ){ 572 @ <input type="hidden" name="g" value="%h(zGoto)" /> 572 @ <input type="hidden" name="g" value="%h(zGoto)" /> 573 } 573 } 574 @ <table class="login_out"> 574 @ <table class="login_out"> ................................................................................................................................................................................ 909 if( fossil_strcmp(g.zLogin,"nobody")==0 ){ 909 if( fossil_strcmp(g.zLogin,"nobody")==0 ){ 910 g.zLogin = 0; 910 g.zLogin = 0; 911 } 911 } 912 912 913 /* Set the capabilities */ 913 /* Set the capabilities */ 914 login_replace_capabilities(zCap, 0); 914 login_replace_capabilities(zCap, 0); 915 login_set_anon_nobody_capabilities(); 915 login_set_anon_nobody_capabilities(); 916 if( zCap[0] && !g.perm.History && !g.perm.Link | 916 if( zCap[0] && !g.perm.Hyperlink 917 && db_get_boolean("auto-enable-hyperlinks",1) 917 && db_get_boolean("auto-enable-hyperlinks",1) 918 && isHuman(P("HTTP_USER_AGENT")) ){ 918 && isHuman(P("HTTP_USER_AGENT")) ){ 919 g.perm.History = 1; | 919 g.perm.Hyperlink = 1; > 920 g.javascriptHyperlink = 1; 920 } 921 } 921 922 922 /* If the public-pages glob pattern is defined and REQUEST_URI matches 923 /* If the public-pages glob pattern is defined and REQUEST_URI matches 923 ** one of the globs in public-pages, then also add in all default-perms 924 ** one of the globs in public-pages, then also add in all default-perms 924 ** permissions. 925 ** permissions. 925 */ 926 */ 926 zPublicPages = db_get("public-pages",0); 927 zPublicPages = db_get("public-pages",0); ................................................................................................................................................................................ 972 if(NULL==zCap){ 973 if(NULL==zCap){ 973 return; 974 return; 974 } 975 } 975 for(i=0; zCap[i]; i++){ 976 for(i=0; zCap[i]; i++){ 976 switch( zCap[i] ){ 977 switch( zCap[i] ){ 977 case 's': g.perm.Setup = 1; /* Fall thru into Admin */ 978 case 's': g.perm.Setup = 1; /* Fall thru into Admin */ 978 case 'a': g.perm.Admin = g.perm.RdTkt = g.perm.WrTkt = g.perm.Zip = 979 case 'a': g.perm.Admin = g.perm.RdTkt = g.perm.WrTkt = g.perm.Zip = 979 g.perm.RdWiki = g.perm.WrWiki = g.perm.NewWiki = | 980 g.perm.RdWiki = g.perm.WrWiki = g.perm.NewWiki = 980 g.perm.ApndWiki = g.perm.History = g.perm.Clone = | 981 g.perm.ApndWiki = g.perm.Hyperlink = g.perm.Clone = 981 g.perm.NewTkt = g.perm.Password = g.perm.RdAddr = | 982 g.perm.NewTkt = g.perm.Password = g.perm.RdAddr = 982 g.perm.TktFmt = g.perm.Attach = g.perm.ApndTkt = 1 | 983 g.perm.TktFmt = g.perm.Attach = g.perm.ApndTkt = 1; 983 /* Fall thru into Read/Write */ | 984 /* Fall thru into Read/Write */ 984 case 'i': g.perm.Read = g.perm.Write = 1; break; 985 case 'i': g.perm.Read = g.perm.Write = 1; break; 985 case 'o': g.perm.Read = 1; break; 986 case 'o': g.perm.Read = 1; break; 986 case 'z': g.perm.Zip = 1; break; 987 case 'z': g.perm.Zip = 1; break; 987 988 988 case 'd': g.perm.Delete = 1; break; 989 case 'd': g.perm.Delete = 1; break; 989 case 'h': g.perm.History = g.perm.Hyperlink = 1; break; < 990 case 'l': g.perm.Link = g.perm.Hyperlink = 1; break; | 990 case 'h': g.perm.Hyperlink = 1; break; 991 case 'g': g.perm.Clone = 1; break; 991 case 'g': g.perm.Clone = 1; break; 992 case 'p': g.perm.Password = 1; break; 992 case 'p': g.perm.Password = 1; break; 993 993 994 case 'j': g.perm.RdWiki = 1; break; 994 case 'j': g.perm.RdWiki = 1; break; 995 case 'k': g.perm.WrWiki = g.perm.RdWiki = g.perm.ApndWiki =1; break; 995 case 'k': g.perm.WrWiki = g.perm.RdWiki = g.perm.ApndWiki =1; break; 996 case 'm': g.perm.ApndWiki = 1; break; 996 case 'm': g.perm.ApndWiki = 1; break; 997 case 'f': g.perm.NewWiki = 1; break; 997 case 'f': g.perm.NewWiki = 1; break; ................................................................................................................................................................................ 1053 case 'a': rc = g.perm.Admin; break; 1053 case 'a': rc = g.perm.Admin; break; 1054 case 'b': rc = g.perm.Attach; break; 1054 case 'b': rc = g.perm.Attach; break; 1055 case 'c': rc = g.perm.ApndTkt; break; 1055 case 'c': rc = g.perm.ApndTkt; break; 1056 case 'd': rc = g.perm.Delete; break; 1056 case 'd': rc = g.perm.Delete; break; 1057 case 'e': rc = g.perm.RdAddr; break; 1057 case 'e': rc = g.perm.RdAddr; break; 1058 case 'f': rc = g.perm.NewWiki; break; 1058 case 'f': rc = g.perm.NewWiki; break; 1059 case 'g': rc = g.perm.Clone; break; 1059 case 'g': rc = g.perm.Clone; break; 1060 case 'h': rc = g.perm.History; break; | 1060 case 'h': rc = g.perm.Hyperlink; break; 1061 case 'i': rc = g.perm.Write; break; 1061 case 'i': rc = g.perm.Write; break; 1062 case 'j': rc = g.perm.RdWiki; break; 1062 case 'j': rc = g.perm.RdWiki; break; 1063 case 'k': rc = g.perm.WrWiki; break; 1063 case 'k': rc = g.perm.WrWiki; break; 1064 case 'l': rc = g.perm.Link; break; < 1065 case 'm': rc = g.perm.ApndWiki; break; 1064 case 'm': rc = g.perm.ApndWiki; break; 1066 case 'n': rc = g.perm.NewTkt; break; 1065 case 'n': rc = g.perm.NewTkt; break; 1067 case 'o': rc = g.perm.Read; break; 1066 case 'o': rc = g.perm.Read; break; 1068 case 'p': rc = g.perm.Password; break; 1067 case 'p': rc = g.perm.Password; break; 1069 /* case 'q': */ 1068 /* case 'q': */ 1070 case 'r': rc = g.perm.RdTkt; break; 1069 case 'r': rc = g.perm.RdTkt; break; 1071 case 's': rc = g.perm.Setup; break; 1070 case 's': rc = g.perm.Setup; break; ................................................................................................................................................................................ 1129 cgi_redirect(mprintf("login?g=%T", zUrl)); 1128 cgi_redirect(mprintf("login?g=%T", zUrl)); 1130 /* NOTREACHED */ 1129 /* NOTREACHED */ 1131 assert(0); 1130 assert(0); 1132 } 1131 } 1133 } 1132 } 1134 1133 1135 /* 1134 /* 1136 ** Call this routine if the user lacks okHistory permission. If | 1135 ** Call this routine if the user lacks g.perm.Hyperlink permission. If 1137 ** the anonymous user has okHistory permission, then paint a mesage | 1136 ** the anonymous user has Hyperlink permission, then paint a mesage 1138 ** to inform the user that much more information is available by 1137 ** to inform the user that much more information is available by 1139 ** logging in as anonymous. 1138 ** logging in as anonymous. 1140 */ 1139 */ 1141 void login_anonymous_available(void){ 1140 void login_anonymous_available(void){ 1142 if( !g.perm.History && !g.perm.Link && | 1141 if( !g.perm.Hyperlink && 1143 db_exists("SELECT 1 FROM user" 1142 db_exists("SELECT 1 FROM user" 1144 " WHERE login='anonymous'" 1143 " WHERE login='anonymous'" 1145 " AND cap LIKE '%%h%%'") ){ 1144 " AND cap LIKE '%%h%%'") ){ 1146 const char *zUrl = PD("REQUEST_URI", "index"); 1145 const char *zUrl = PD("REQUEST_URI", "index"); 1147 @ <p>Many <span class="disabled">hyperlinks are disabled.</span><br /> 1146 @ <p>Many <span class="disabled">hyperlinks are disabled.</span><br /> 1148 @ 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> 1149 @ to enable hyperlinks.</p> 1148 @ to enable hyperlinks.</p> 1150 } 1149 } 1151 } 1150 } 1152 1151 1153 /* 1152 /* 1154 ** While rendering a form, call this routine to add the Anti-CSRF token 1153 ** While rendering a form, call this routine to add the Anti-CSRF token 1155 ** as a hidden element of the form. 1154 ** as a hidden element of the form.

Changes to src/main.c

49 /* 49 /* 50 ** Maximum number of auxiliary parameters on reports 50 ** Maximum number of auxiliary parameters on reports 51 */ 51 */ 52 #define MX_AUX 5 52 #define MX_AUX 5 53 53 54 /* 54 /* 55 ** Holds flags for fossil user permissions. 55 ** Holds flags for fossil user permissions. 56 ** < 57 ** History enables various hyperlinks directly, with an href= attribute < 58 ** in the HTML. Link puts an id= attribute in HTML and then adds the < 59 ** href= attribute using javascript. The Link option is designed to make < 60 ** it harder for bots and spiders to follow hyperlinks, and yet give the < 61 ** same experience to users. the Hyperlink permission is a composite which < 62 ** is enabled if either History or Hyperlink is turned on. < 63 */ 56 */ 64 struct FossilUserPerms { 57 struct FossilUserPerms { 65 char Setup; /* s: use Setup screens on web interface */ 58 char Setup; /* s: use Setup screens on web interface */ 66 char Admin; /* a: administrative permission */ 59 char Admin; /* a: administrative permission */ 67 char Delete; /* d: delete wiki or tickets */ 60 char Delete; /* d: delete wiki or tickets */ 68 char Password; /* p: change password */ 61 char Password; /* p: change password */ 69 char Query; /* q: create new reports */ 62 char Query; /* q: create new reports */ 70 char Write; /* i: xfer inbound. checkin */ 63 char Write; /* i: xfer inbound. checkin */ 71 char Read; /* o: xfer outbound. checkout */ 64 char Read; /* o: xfer outbound. checkout */ 72 char History; /* h: access historical information. */ | 65 char Hyperlink; /* h: enable the display of hyperlinks */ 73 char Link; /* l: enable href= using javascript */ < 74 char Clone; /* g: clone */ 66 char Clone; /* g: clone */ 75 char RdWiki; /* j: view wiki via web */ 67 char RdWiki; /* j: view wiki via web */ 76 char NewWiki; /* f: create new wiki via web */ 68 char NewWiki; /* f: create new wiki via web */ 77 char ApndWiki; /* m: append to wiki via web */ 69 char ApndWiki; /* m: append to wiki via web */ 78 char WrWiki; /* k: edit wiki via web */ 70 char WrWiki; /* k: edit wiki via web */ 79 char RdTkt; /* r: view tickets via web */ 71 char RdTkt; /* r: view tickets via web */ 80 char NewTkt; /* n: create new tickets */ 72 char NewTkt; /* n: create new tickets */ ................................................................................................................................................................................ 81 char ApndTkt; /* c: append to tickets via the web */ 73 char ApndTkt; /* c: append to tickets via the web */ 82 char WrTkt; /* w: make changes to tickets via web */ 74 char WrTkt; /* w: make changes to tickets via web */ 83 char Attach; /* b: add attachments */ 75 char Attach; /* b: add attachments */ 84 char TktFmt; /* t: create new ticket report formats */ 76 char TktFmt; /* t: create new ticket report formats */ 85 char RdAddr; /* e: read email addresses or other private data */ 77 char RdAddr; /* e: read email addresses or other private data */ 86 char Zip; /* z: download zipped artifact via /zip URL */ 78 char Zip; /* z: download zipped artifact via /zip URL */ 87 char Private; /* x: can send and receive private content */ 79 char Private; /* x: can send and receive private content */ 88 char Hyperlink; /* "h" or "l" */ < 89 }; 80 }; 90 81 91 #ifdef FOSSIL_ENABLE_TCL 82 #ifdef FOSSIL_ENABLE_TCL 92 /* 83 /* 93 ** All Tcl related context information is in this structure. This structure 84 ** All Tcl related context information is in this structure. This structure 94 ** definition has been copied from and should be kept in sync with the one in 85 ** definition has been copied from and should be kept in sync with the one in 95 ** "th_tcl.c". 86 ** "th_tcl.c". ................................................................................................................................................................................ 142 FILE *httpIn; /* Accept HTTP input from here */ 133 FILE *httpIn; /* Accept HTTP input from here */ 143 FILE *httpOut; /* Send HTTP output here */ 134 FILE *httpOut; /* Send HTTP output here */ 144 int xlinkClusterOnly; /* Set when cloning. Only process clusters */ 135 int xlinkClusterOnly; /* Set when cloning. Only process clusters */ 145 int fTimeFormat; /* 1 for UTC. 2 for localtime. 0 not yet selected */ 136 int fTimeFormat; /* 1 for UTC. 2 for localtime. 0 not yet selected */ 146 int *aCommitFile; /* Array of files to be committed */ 137 int *aCommitFile; /* Array of files to be committed */ 147 int markPrivate; /* All new artifacts are private if true */ 138 int markPrivate; /* All new artifacts are private if true */ 148 int clockSkewSeen; /* True if clocks on client and server out of sync */ 139 int clockSkewSeen; /* True if clocks on client and server out of sync */ 149 int isHTTP; /* True if running in server/CGI modes, else assume CL | 140 char isHTTP; /* True if erver/CGI modes, else assume CLI. */ > 141 char javascriptHyperlink; /* If true, set href= using script, not HTML */ 150 142 151 int urlIsFile; /* True if a "file:" url */ 143 int urlIsFile; /* True if a "file:" url */ 152 int urlIsHttps; /* True if a "https:" url */ 144 int urlIsHttps; /* True if a "https:" url */ 153 int urlIsSsh; /* True if an "ssh:" url */ 145 int urlIsSsh; /* True if an "ssh:" url */ 154 char *urlName; /* Hostname for http: or filename for file: */ 146 char *urlName; /* Hostname for http: or filename for file: */ 155 char *urlHostname; /* The HOST: parameter on http headers */ 147 char *urlHostname; /* The HOST: parameter on http headers */ 156 char *urlProtocol; /* "http" or "https" */ 148 char *urlProtocol; /* "http" or "https" */

Changes to src/report.c

62 } 62 } 63 blob_appendf(&ril, "&nbsp;&nbsp;&nbsp;"); 63 blob_appendf(&ril, "&nbsp;&nbsp;&nbsp;"); 64 if( g.perm.Write && zOwner && zOwner[0] ){ 64 if( g.perm.Write && zOwner && zOwner[0] ){ 65 blob_appendf(&ril, "(by <i>%h</i></i>) ", zOwner); 65 blob_appendf(&ril, "(by <i>%h</i></i>) ", zOwner); 66 } 66 } 67 if( g.perm.TktFmt ){ 67 if( g.perm.TktFmt ){ 68 blob_appendf(&ril, "[%zcopy</a>] ", 68 blob_appendf(&ril, "[%zcopy</a>] ", 69 href("%R/rptedit?rn=%d&amp;copy=1", rn)); | 69 href("%R/rptedit?rn=%d&copy=1", rn)); 70 } 70 } 71 if( g.perm.Admin 71 if( g.perm.Admin 72 || (g.perm.WrTkt && zOwner && fossil_strcmp(g.zLogin,zOwner)==0) 72 || (g.perm.WrTkt && zOwner && fossil_strcmp(g.zLogin,zOwner)==0) 73 ){ 73 ){ 74 blob_appendf(&ril, "[%zedit</a>]", 74 blob_appendf(&ril, "[%zedit</a>]", 75 href("%R/rptedit?rn=%d", rn)); 75 href("%R/rptedit?rn=%d", rn)); 76 } 76 } ................................................................................................................................................................................ 417 zTitle = mprintf("Copy Of %s", zTitle); 417 zTitle = mprintf("Copy Of %s", zTitle); 418 zOwner = g.zLogin; 418 zOwner = g.zLogin; 419 } 419 } 420 } 420 } 421 if( zOwner==0 ) zOwner = g.zLogin; 421 if( zOwner==0 ) zOwner = g.zLogin; 422 style_submenu_element("Cancel", "Cancel", "reportlist"); 422 style_submenu_element("Cancel", "Cancel", "reportlist"); 423 if( rn>0 ){ 423 if( rn>0 ){ 424 style_submenu_element("Delete", "Delete", "rptedit?rn=%d&amp;del1=1", rn); | 424 style_submenu_element("Delete", "Delete", "rptedit?rn=%d&del1=1", rn); 425 } 425 } 426 style_header(rn>0 ? "Edit Report Format":"Create New Report Format"); 426 style_header(rn>0 ? "Edit Report Format":"Create New Report Format"); 427 if( zErr ){ 427 if( zErr ){ 428 @ <blockquote class="reportError">%h(zErr)</blockquote> 428 @ <blockquote class="reportError">%h(zErr)</blockquote> 429 } 429 } 430 @ <form action="rptedit" method="post"><div> 430 @ <form action="rptedit" method="post"><div> 431 @ <input type="hidden" name="rn" value="%d(rn)" /> 431 @ <input type="hidden" name="rn" value="%d(rn)" /> ................................................................................................................................................................................ 946 946 947 count = 0; 947 count = 0; 948 if( !tabs ){ 948 if( !tabs ){ 949 struct GenerateHTML sState; 949 struct GenerateHTML sState; 950 950 951 db_multi_exec("PRAGMA empty_result_callbacks=ON"); 951 db_multi_exec("PRAGMA empty_result_callbacks=ON"); 952 style_submenu_element("Raw", "Raw", 952 style_submenu_element("Raw", "Raw", 953 "rptview?tablist=1&amp;%h", PD("QUERY_STRING","")); | 953 "rptview?tablist=1&%h", PD("QUERY_STRING","")); 954 if( g.perm.Admin 954 if( g.perm.Admin 955 || (g.perm.TktFmt && g.zLogin && fossil_strcmp(g.zLogin,zOwner)==0) ){ 955 || (g.perm.TktFmt && g.zLogin && fossil_strcmp(g.zLogin,zOwner)==0) ){ 956 style_submenu_element("Edit", "Edit", "rptedit?rn=%d", rn); 956 style_submenu_element("Edit", "Edit", "rptedit?rn=%d", rn); 957 } 957 } 958 if( g.perm.TktFmt ){ 958 if( g.perm.TktFmt ){ 959 style_submenu_element("SQL", "SQL", "rptsql?rn=%d",rn); 959 style_submenu_element("SQL", "SQL", "rptsql?rn=%d",rn); 960 } 960 }

Changes to src/setup.c

168 @ repository history</td></tr> 168 @ repository history</td></tr> 169 @ <tr><td valign="top"><b>i</b></td> 169 @ <tr><td valign="top"><b>i</b></td> 170 @ <td><i>Check-In:</i> Commit new versions in the repository</td></tr> 170 @ <td><i>Check-In:</i> Commit new versions in the repository</td></tr> 171 @ <tr><td valign="top"><b>j</b></td> 171 @ <tr><td valign="top"><b>j</b></td> 172 @ <td><i>Read-Wiki:</i> View wiki pages</td></tr> 172 @ <td><i>Read-Wiki:</i> View wiki pages</td></tr> 173 @ <tr><td valign="top"><b>k</b></td> 173 @ <tr><td valign="top"><b>k</b></td> 174 @ <td><i>Write-Wiki:</i> Edit wiki pages</td></tr> 174 @ <td><i>Write-Wiki:</i> Edit wiki pages</td></tr> 175 @ <tr><td valign="top"><b>l</b></td> < 176 @ <td><i>Link-Late:</i> Use javascript for hyperlinks to < 177 @ discourage bots</td></tr> < 178 @ <tr><td valign="top"><b>m</b></td> 175 @ <tr><td valign="top"><b>m</b></td> 179 @ <td><i>Append-Wiki:</i> Append to wiki pages</td></tr> 176 @ <td><i>Append-Wiki:</i> Append to wiki pages</td></tr> 180 @ <tr><td valign="top"><b>n</b></td> 177 @ <tr><td valign="top"><b>n</b></td> 181 @ <td><i>New-Tkt:</i> Create new tickets</td></tr> 178 @ <td><i>New-Tkt:</i> Create new tickets</td></tr> 182 @ <tr><td valign="top"><b>o</b></td> 179 @ <tr><td valign="top"><b>o</b></td> 183 @ <td><i>Check-Out:</i> Check out versions</td></tr> 180 @ <td><i>Check-Out:</i> Check out versions</td></tr> 184 @ <tr><td valign="top"><b>p</b></td> 181 @ <tr><td valign="top"><b>p</b></td> ................................................................................................................................................................................ 249 246 250 /* 247 /* 251 ** WEBPAGE: /setup_uedit 248 ** WEBPAGE: /setup_uedit 252 */ 249 */ 253 void user_edit(void){ 250 void user_edit(void){ 254 const char *zId, *zLogin, *zInfo, *zCap, *zPw; 251 const char *zId, *zLogin, *zInfo, *zCap, *zPw; 255 char *oaa, *oas, *oar, *oaw, *oan, *oai, *oaj, *oao, *oap; 252 char *oaa, *oas, *oar, *oaw, *oan, *oai, *oaj, *oao, *oap; 256 char *oak, *oad, *oac, *oaf, *oam, *oah, *oal, *oag, *oae; | 253 char *oak, *oad, *oac, *oaf, *oam, *oah, *oag, *oae; 257 char *oat, *oau, *oav, *oab, *oax, *oaz; 254 char *oat, *oau, *oav, *oab, *oax, *oaz; 258 const char *zGroup; 255 const char *zGroup; 259 const char *zOldLogin; 256 const char *zOldLogin; 260 char *inherit[128]; 257 char *inherit[128]; 261 int doWrite; 258 int doWrite; 262 int uid; 259 int uid; 263 int higherUser = 0; /* True if user being edited is SETUP and the */ 260 int higherUser = 0; /* True if user being edited is SETUP and the */ ................................................................................................................................................................................ 305 int ar = P("ar")!=0; 302 int ar = P("ar")!=0; 306 int as = g.perm.Setup && P("as")!=0; 303 int as = g.perm.Setup && P("as")!=0; 307 int aw = P("aw")!=0; 304 int aw = P("aw")!=0; 308 int ac = P("ac")!=0; 305 int ac = P("ac")!=0; 309 int af = P("af")!=0; 306 int af = P("af")!=0; 310 int am = P("am")!=0; 307 int am = P("am")!=0; 311 int ah = P("ah")!=0; 308 int ah = P("ah")!=0; 312 int al = P("al")!=0; < 313 int ag = P("ag")!=0; 309 int ag = P("ag")!=0; 314 int at = P("at")!=0; 310 int at = P("at")!=0; 315 int au = P("au")!=0; 311 int au = P("au")!=0; 316 int av = P("av")!=0; 312 int av = P("av")!=0; 317 int ax = P("ax")!=0; 313 int ax = P("ax")!=0; 318 int az = P("az")!=0; 314 int az = P("az")!=0; 319 if( aa ){ zCap[i++] = 'a'; } 315 if( aa ){ zCap[i++] = 'a'; } ................................................................................................................................................................................ 323 if( ae ){ zCap[i++] = 'e'; } 319 if( ae ){ zCap[i++] = 'e'; } 324 if( af ){ zCap[i++] = 'f'; } 320 if( af ){ zCap[i++] = 'f'; } 325 if( ah ){ zCap[i++] = 'h'; } 321 if( ah ){ zCap[i++] = 'h'; } 326 if( ag ){ zCap[i++] = 'g'; } 322 if( ag ){ zCap[i++] = 'g'; } 327 if( ai ){ zCap[i++] = 'i'; } 323 if( ai ){ zCap[i++] = 'i'; } 328 if( aj ){ zCap[i++] = 'j'; } 324 if( aj ){ zCap[i++] = 'j'; } 329 if( ak ){ zCap[i++] = 'k'; } 325 if( ak ){ zCap[i++] = 'k'; } 330 if( al ){ zCap[i++] = 'l'; } < 331 if( am ){ zCap[i++] = 'm'; } 326 if( am ){ zCap[i++] = 'm'; } 332 if( an ){ zCap[i++] = 'n'; } 327 if( an ){ zCap[i++] = 'n'; } 333 if( ao ){ zCap[i++] = 'o'; } 328 if( ao ){ zCap[i++] = 'o'; } 334 if( ap ){ zCap[i++] = 'p'; } 329 if( ap ){ zCap[i++] = 'p'; } 335 if( ar ){ zCap[i++] = 'r'; } 330 if( ar ){ zCap[i++] = 'r'; } 336 if( as ){ zCap[i++] = 's'; } 331 if( as ){ zCap[i++] = 's'; } 337 if( at ){ zCap[i++] = 't'; } 332 if( at ){ zCap[i++] = 't'; } ................................................................................................................................................................................ 415 410 416 /* Load the existing information about the user, if any 411 /* Load the existing information about the user, if any 417 */ 412 */ 418 zLogin = ""; 413 zLogin = ""; 419 zInfo = ""; 414 zInfo = ""; 420 zCap = ""; 415 zCap = ""; 421 zPw = ""; 416 zPw = ""; 422 oaa = oab = oac = oad = oae = oaf = oag = oah = oai = oaj = oak = oal = oam = | 417 oaa = oab = oac = oad = oae = oaf = oag = oah = oai = oaj = oak = oam = 423 oan = oao = oap = oar = oas = oat = oau = oav = oaw = oax = oaz = ""; 418 oan = oao = oap = oar = oas = oat = oau = oav = oaw = oax = oaz = ""; 424 if( uid ){ 419 if( uid ){ 425 zLogin = db_text("", "SELECT login FROM user WHERE uid=%d", uid); 420 zLogin = db_text("", "SELECT login FROM user WHERE uid=%d", uid); 426 zInfo = db_text("", "SELECT info FROM user WHERE uid=%d", uid); 421 zInfo = db_text("", "SELECT info FROM user WHERE uid=%d", uid); 427 zCap = db_text("", "SELECT cap FROM user WHERE uid=%d", uid); 422 zCap = db_text("", "SELECT cap FROM user WHERE uid=%d", uid); 428 zPw = db_text("", "SELECT pw FROM user WHERE uid=%d", uid); 423 zPw = db_text("", "SELECT pw FROM user WHERE uid=%d", uid); 429 if( strchr(zCap, 'a') ) oaa = " checked=\"checked\""; 424 if( strchr(zCap, 'a') ) oaa = " checked=\"checked\""; ................................................................................................................................................................................ 433 if( strchr(zCap, 'e') ) oae = " checked=\"checked\""; 428 if( strchr(zCap, 'e') ) oae = " checked=\"checked\""; 434 if( strchr(zCap, 'f') ) oaf = " checked=\"checked\""; 429 if( strchr(zCap, 'f') ) oaf = " checked=\"checked\""; 435 if( strchr(zCap, 'g') ) oag = " checked=\"checked\""; 430 if( strchr(zCap, 'g') ) oag = " checked=\"checked\""; 436 if( strchr(zCap, 'h') ) oah = " checked=\"checked\""; 431 if( strchr(zCap, 'h') ) oah = " checked=\"checked\""; 437 if( strchr(zCap, 'i') ) oai = " checked=\"checked\""; 432 if( strchr(zCap, 'i') ) oai = " checked=\"checked\""; 438 if( strchr(zCap, 'j') ) oaj = " checked=\"checked\""; 433 if( strchr(zCap, 'j') ) oaj = " checked=\"checked\""; 439 if( strchr(zCap, 'k') ) oak = " checked=\"checked\""; 434 if( strchr(zCap, 'k') ) oak = " checked=\"checked\""; 440 if( strchr(zCap, 'l') ) oal = " checked=\"checked\""; < 441 if( strchr(zCap, 'm') ) oam = " checked=\"checked\""; 435 if( strchr(zCap, 'm') ) oam = " checked=\"checked\""; 442 if( strchr(zCap, 'n') ) oan = " checked=\"checked\""; 436 if( strchr(zCap, 'n') ) oan = " checked=\"checked\""; 443 if( strchr(zCap, 'o') ) oao = " checked=\"checked\""; 437 if( strchr(zCap, 'o') ) oao = " checked=\"checked\""; 444 if( strchr(zCap, 'p') ) oap = " checked=\"checked\""; 438 if( strchr(zCap, 'p') ) oap = " checked=\"checked\""; 445 if( strchr(zCap, 'r') ) oar = " checked=\"checked\""; 439 if( strchr(zCap, 'r') ) oar = " checked=\"checked\""; 446 if( strchr(zCap, 's') ) oas = " checked=\"checked\""; 440 if( strchr(zCap, 's') ) oas = " checked=\"checked\""; 447 if( strchr(zCap, 't') ) oat = " checked=\"checked\""; 441 if( strchr(zCap, 't') ) oat = " checked=\"checked\""; ................................................................................................................................................................................ 529 @ <input type="checkbox" name="aa"%s(oaa) />%s(B('a'))Admin<br /> 523 @ <input type="checkbox" name="aa"%s(oaa) />%s(B('a'))Admin<br /> 530 @ <input type="checkbox" name="ad"%s(oad) />%s(B('d'))Delete<br /> 524 @ <input type="checkbox" name="ad"%s(oad) />%s(B('d'))Delete<br /> 531 @ <input type="checkbox" name="ae"%s(oae) />%s(B('e'))Email<br /> 525 @ <input type="checkbox" name="ae"%s(oae) />%s(B('e'))Email<br /> 532 @ <input type="checkbox" name="ap"%s(oap) />%s(B('p'))Password<br /> 526 @ <input type="checkbox" name="ap"%s(oap) />%s(B('p'))Password<br /> 533 @ <input type="checkbox" name="ai"%s(oai) />%s(B('i'))Check-In<br /> 527 @ <input type="checkbox" name="ai"%s(oai) />%s(B('i'))Check-In<br /> 534 @ <input type="checkbox" name="ao"%s(oao) />%s(B('o'))Check-Out<br /> 528 @ <input type="checkbox" name="ao"%s(oao) />%s(B('o'))Check-Out<br /> 535 @ <input type="checkbox" name="ah"%s(oah) />%s(B('h'))Hyperlinks<br /> 529 @ <input type="checkbox" name="ah"%s(oah) />%s(B('h'))Hyperlinks<br /> 536 @ <input type="checkbox" name="al"%s(oal) />%s(B('l'))Links-deferred<br /> < 537 @ <input type="checkbox" name="au"%s(oau) />%s(B('u'))Reader<br /> 530 @ <input type="checkbox" name="au"%s(oau) />%s(B('u'))Reader<br /> 538 @ <input type="checkbox" name="av"%s(oav) />%s(B('v'))Developer<br /> 531 @ <input type="checkbox" name="av"%s(oav) />%s(B('v'))Developer<br /> 539 @ <input type="checkbox" name="ag"%s(oag) />%s(B('g'))Clone<br /> 532 @ <input type="checkbox" name="ag"%s(oag) />%s(B('g'))Clone<br /> 540 @ <input type="checkbox" name="aj"%s(oaj) />%s(B('j'))Read Wiki<br /> 533 @ <input type="checkbox" name="aj"%s(oaj) />%s(B('j'))Read Wiki<br /> 541 @ <input type="checkbox" name="af"%s(oaf) />%s(B('f'))New Wiki<br /> 534 @ <input type="checkbox" name="af"%s(oaf) />%s(B('f'))New Wiki<br /> 542 @ <input type="checkbox" name="am"%s(oam) />%s(B('m'))Append Wiki<br /> 535 @ <input type="checkbox" name="am"%s(oam) />%s(B('m'))Append Wiki<br /> 543 @ <input type="checkbox" name="ak"%s(oak) />%s(B('k'))Write Wiki<br /> 536 @ <input type="checkbox" name="ak"%s(oak) />%s(B('k'))Write Wiki<br /> ................................................................................................................................................................................ 633 @ delete anything at any time. 626 @ delete anything at any time. 634 @ </p></li> 627 @ </p></li> 635 @ 628 @ 636 @ <li><p> 629 @ <li><p> 637 @ The <span class="capability">Hyperlinks</span> privilege allows a user 630 @ The <span class="capability">Hyperlinks</span> privilege allows a user 638 @ to see most hyperlinks. This is recommended ON for most logged-in users 631 @ to see most hyperlinks. This is recommended ON for most logged-in users 639 @ but OFF for user "nobody" to avoid problems with spiders trying to walk 632 @ but OFF for user "nobody" to avoid problems with spiders trying to walk 640 @ every historical version of every baseline and file. The | 633 @ every diff and annotation of every historical check-in and file. 641 @ <span class="capability">Link-deferred</span> privilege enables hyperlinks < 642 @ using javascript, which makes them harder for bots and spiders to find. < 643 @ </p></li> 634 @ </p></li> 644 @ 635 @ 645 @ <li><p> 636 @ <li><p> 646 @ The <span class="capability">Zip</span> privilege allows a user to 637 @ The <span class="capability">Zip</span> privilege allows a user to 647 @ see the "download as ZIP" 638 @ see the "download as ZIP" 648 @ hyperlink and permits access to the <tt>/zip</tt> page. This allows 639 @ hyperlink and permits access to the <tt>/zip</tt> page. This allows 649 @ users to download ZIP archives without granting other rights like 640 @ users to download ZIP archives without granting other rights like ................................................................................................................................................................................ 898 @ <p>Fossil tries to limit out-bound sync, clone, and pull packets 889 @ <p>Fossil tries to limit out-bound sync, clone, and pull packets 899 @ to this many bytes, uncompressed. If the client requires more data 890 @ to this many bytes, uncompressed. If the client requires more data 900 @ than this, then the client will issue multiple HTTP requests. 891 @ than this, then the client will issue multiple HTTP requests. 901 @ Values below 1 million are not recommended. 5 million is a 892 @ Values below 1 million are not recommended. 5 million is a 902 @ reasonable number.</p> 893 @ reasonable number.</p> 903 894 904 @ <hr /> 895 @ <hr /> > 896 onoff_attribute( 905 onoff_attribute("Enable hyperlinks for \"nobody\" based on User-Agent", | 897 "Enable hyperlinks for \"nobody\" based on User-Agent and Javascript", 906 "auto-enable-hyperlinks", "autohyperlink", 1); | 898 "auto-enable-hyperlinks", "autohyperlink", 1); 907 @ <p>Enable hyperlinks (the equivalent of the "h" permission) for all users 899 @ <p>Enable hyperlinks (the equivalent of the "h" permission) for all users 908 @ including user "nobody", as long as the User-Agent string in the HTTP header | 900 @ including user "nobody", as long as (1) the User-Agent string in the 909 @ indicates that the request is coming from an actual human being and not a | 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 910 @ a robot or script. Note: Bots can specify whatever User-Agent string they | 904 @ and spiders can specify whatever User-Agent string they that want and 911 @ that want. So a bot that wants to impersonate a human can easily do so. < 912 @ Hence, this technique does not necessarily exclude malicious bots. < 913 @ </p> < > 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> 914 913 915 @ <hr /> 914 @ <hr /> 916 entry_attribute("Public pages", 30, "public-pages", 915 entry_attribute("Public pages", 30, "public-pages", 917 "pubpage", ""); 916 "pubpage", ""); 918 @ <p>A comma-separated list of glob patterns for pages that are accessible 917 @ <p>A comma-separated list of glob patterns for pages that are accessible 919 @ without needing a login and using the privileges given by the 918 @ without needing a login and using the privileges given by the 920 @ "Default privileges" setting below. Example use case: Set this field 919 @ "Default privileges" setting below. Example use case: Set this field

Changes to src/style.c

58 58 59 /* 59 /* 60 ** Generate and return a anchor tag like this: 60 ** Generate and return a anchor tag like this: 61 ** 61 ** 62 ** <a href="URL"> 62 ** <a href="URL"> 63 ** or <a id="ID"> 63 ** or <a id="ID"> 64 ** 64 ** 65 ** The form of the anchor tag is determined by the g.perm.History | 65 ** The form of the anchor tag is determined by the g.javascriptHyperlink 66 ** variable. The href="URL" form is used if g.perm.History is true. | 66 ** variable. The href="URL" form is used if g.javascriptHyperlink is false. 67 ** If g.perm.History is false and g.perm.Link is true then the | 67 ** If g.javascriptHyperlink is true then the 68 ** id="ID" form is used and javascript is generated in the footer to cause 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 both | 69 ** href values to be inserted after the page has loaded. If 70 ** g.perm.History and g.perm.Link are false, then the <a id="ID"> form is | 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 71 ** generated but the javascript is not generated so the links never 72 ** activate. 72 ** activate. 73 ** 73 ** 74 ** Handling the href="URL" using javascript is a defense against bots. | 74 ** Filling in the href="URL" using javascript is a defense against bots. 75 ** 75 ** 76 ** The name of this routine is deliberately kept short so that can be 76 ** The name of this routine is deliberately kept short so that can be 77 ** easily used within @-lines. Example: 77 ** easily used within @-lines. Example: 78 ** 78 ** 79 ** @ %z(href("%s/artifact/%s",g.zTop,zUuid))%h(zFN)</a> | 79 ** @ %z(href("%R/artifact/%s",zUuid))%h(zFN)</a> 80 ** 80 ** 81 ** Note %z format. The string returned by this function is always 81 ** Note %z format. The string returned by this function is always 82 ** obtained from fossil_malloc(). | 82 ** obtained from fossil_malloc() so rendering it with %z will reclaim > 83 ** that memory space. 83 ** 84 ** 84 ** There are two versions of this routine href() does a plain hyperlink | 85 ** There are two versions of this routine: href() does a plain hyperlink 85 ** and xhref() adds extra attribute text. 86 ** and xhref() adds extra attribute text. 86 */ 87 */ 87 char *xhref(const char *zExtra, const char *zFormat, ...){ 88 char *xhref(const char *zExtra, const char *zFormat, ...){ 88 char *zUrl; 89 char *zUrl; 89 va_list ap; 90 va_list ap; 90 va_start(ap, zFormat); 91 va_start(ap, zFormat); 91 zUrl = vmprintf(zFormat, ap); 92 zUrl = vmprintf(zFormat, ap); 92 va_end(ap); 93 va_end(ap); 93 if( g.perm.History ){ | 94 if( g.perm.Hyperlink && !g.javascriptHyperlink ){ 94 return mprintf("<a %s href=\"%z\">", zExtra, zUrl); 95 return mprintf("<a %s href=\"%z\">", zExtra, zUrl); 95 } 96 } 96 if( nHref>=nHrefAlloc ){ 97 if( nHref>=nHrefAlloc ){ 97 nHrefAlloc = nHrefAlloc*2 + 10; 98 nHrefAlloc = nHrefAlloc*2 + 10; 98 aHref = fossil_realloc(aHref, nHrefAlloc*sizeof(aHref[0])); 99 aHref = fossil_realloc(aHref, nHrefAlloc*sizeof(aHref[0])); 99 } 100 } 100 aHref[nHref++] = zUrl; 101 aHref[nHref++] = zUrl; ................................................................................................................................................................................ 102 } 103 } 103 char *href(const char *zFormat, ...){ 104 char *href(const char *zFormat, ...){ 104 char *zUrl; 105 char *zUrl; 105 va_list ap; 106 va_list ap; 106 va_start(ap, zFormat); 107 va_start(ap, zFormat); 107 zUrl = vmprintf(zFormat, ap); 108 zUrl = vmprintf(zFormat, ap); 108 va_end(ap); 109 va_end(ap); 109 if( g.perm.History ){ | 110 if( g.perm.Hyperlink && !g.javascriptHyperlink ){ 110 return mprintf("<a href=\"%z\">", zUrl); 111 return mprintf("<a href=\"%z\">", zUrl); 111 } 112 } 112 if( nHref>=nHrefAlloc ){ 113 if( nHref>=nHrefAlloc ){ 113 nHrefAlloc = nHrefAlloc*2 + 10; 114 nHrefAlloc = nHrefAlloc*2 + 10; 114 aHref = fossil_realloc(aHref, nHrefAlloc*sizeof(aHref[0])); 115 aHref = fossil_realloc(aHref, nHrefAlloc*sizeof(aHref[0])); 115 } 116 } 116 aHref[nHref++] = zUrl; 117 aHref[nHref++] = zUrl; ................................................................................................................................................................................ 118 } 119 } 119 120 120 /* 121 /* 121 ** Generate javascript that will set the href= attribute on all anchors. 122 ** Generate javascript that will set the href= attribute on all anchors. 122 */ 123 */ 123 void style_resolve_href(void){ 124 void style_resolve_href(void){ 124 int i; 125 int i; 125 if( !g.perm.Link || nHref==0 ) return; | 126 if( !g.perm.Hyperlink || !g.javascriptHyperlink || nHref==0 ) return; 126 @ <script> 127 @ <script> 127 for(i=0; i<nHref; i++){ 128 for(i=0; i<nHref; i++){ 128 @ document.getElementById(%d(i+1)).href="%s(aHref[i])"; 129 @ document.getElementById(%d(i+1)).href="%s(aHref[i])"; 129 } 130 } 130 @ </script> 131 @ </script> 131 } 132 } 132 133

Changes to src/timeline.c

60 ** Generate a hyperlink to a diff between two versions. 60 ** Generate a hyperlink to a diff between two versions. 61 */ 61 */ 62 void hyperlink_to_diff(const char *zV1, const char *zV2){ 62 void hyperlink_to_diff(const char *zV1, const char *zV2){ 63 if( g.perm.Hyperlink ){ 63 if( g.perm.Hyperlink ){ 64 if( zV2==0 ){ 64 if( zV2==0 ){ 65 @ %z(href("%R/diff?v2=%s",zV1))[diff]</a> 65 @ %z(href("%R/diff?v2=%s",zV1))[diff]</a> 66 }else{ 66 }else{ 67 @ %z(href("%R/diff?v1=%s&amp;v2=%s",zV1,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 ** Generate a hyperlink to a date & time. 73 ** Generate a hyperlink to a date & time. 74 */ 74 */ ................................................................................................................................................................................ 86 ** events by that user. If the date+time is specified, then the timeline 86 ** events by that user. If the date+time is specified, then the timeline 87 ** is centered on that date+time. 87 ** is centered on that date+time. 88 */ 88 */ 89 void hyperlink_to_user(const char *zU, const char *zD, const char *zSuf){ 89 void hyperlink_to_user(const char *zU, const char *zD, const char *zSuf){ 90 if( zSuf==0 ) zSuf = ""; 90 if( zSuf==0 ) zSuf = ""; 91 if( g.perm.Hyperlink ){ 91 if( g.perm.Hyperlink ){ 92 if( zD && zD[0] ){ 92 if( zD && zD[0] ){ 93 @ %z(href("%R/timeline?c=%T&amp;u=%T",zD,zU))%h(zU)</a>%s(zSuf) | 93 @ %z(href("%R/timeline?c=%T&u=%T",zD,zU))%h(zU)</a>%s(zSuf) 94 }else{ 94 }else{ 95 @ %z(href("%R/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 }else{ 97 }else{ 98 @ %s(zU) 98 @ %s(zU) 99 } 99 } 100 } 100 } ................................................................................................................................................................................ 1614 " FROM plink p, plink c, blob" 1614 " FROM plink p, plink c, blob" 1615 " WHERE p.cid=c.pid AND p.mtime>c.mtime" 1615 " WHERE p.cid=c.pid AND p.mtime>c.mtime" 1616 " AND blob.rid=c.cid" 1616 " AND blob.rid=c.cid" 1617 ); 1617 ); 1618 while( db_step(&q)==SQLITE_ROW ){ 1618 while( db_step(&q)==SQLITE_ROW ){ 1619 const char *zUuid = db_column_text(&q, 0); 1619 const char *zUuid = db_column_text(&q, 0); 1620 @ <li> 1620 @ <li> 1621 @ <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> 1622 } 1622 } 1623 db_finalize(&q); 1623 db_finalize(&q); 1624 style_footer(); 1624 style_footer(); 1625 } 1625 }

Changes to src/tkt.c

317 } 317 } 318 if( g.perm.NewTkt ){ 318 if( g.perm.NewTkt ){ 319 style_submenu_element("New Ticket", "Create a new ticket", 319 style_submenu_element("New Ticket", "Create a new ticket", 320 "%s/tktnew", g.zTop); 320 "%s/tktnew", g.zTop); 321 } 321 } 322 if( g.perm.ApndTkt && g.perm.Attach ){ 322 if( g.perm.ApndTkt && g.perm.Attach ){ 323 style_submenu_element("Attach", "Add An Attachment", 323 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", 325 g.zTop, zUuid, g.zTop, zUuid); 325 g.zTop, zUuid, g.zTop, zUuid); 326 } 326 } 327 style_header("View Ticket"); 327 style_header("View Ticket"); 328 if( g.thTrace ) Th_Trace("BEGIN_TKTVIEW<br />\n", -1); 328 if( g.thTrace ) Th_Trace("BEGIN_TKTVIEW<br />\n", -1); 329 ticket_init(); 329 ticket_init(); 330 initializeVariablesFromDb(); 330 initializeVariablesFromDb(); 331 zScript = ticket_viewpage_code(); 331 zScript = ticket_viewpage_code(); ................................................................................................................................................................................ 352 if( cnt==0 ){ 352 if( cnt==0 ){ 353 @ <hr /><h2>Attachments:</h2> 353 @ <hr /><h2>Attachments:</h2> 354 @ <ul> 354 @ <ul> 355 } 355 } 356 cnt++; 356 cnt++; 357 @ <li> 357 @ <li> 358 if( g.perm.Read && g.perm.Hyperlink ){ 358 if( g.perm.Read && g.perm.Hyperlink ){ 359 @ %z(href("%R/attachview?tkt=%s&amp;file=%t",zFullName,zFile)) | 359 @ %z(href("%R/attachview?tkt=%s&file=%t",zFullName,zFile)) 360 @ %h(zFile)</a> 360 @ %h(zFile)</a> 361 }else{ 361 }else{ 362 @ %h(zFile) 362 @ %h(zFile) 363 } 363 } 364 @ added by %h(zUser) on 364 @ added by %h(zUser) on 365 hyperlink_to_date(zDate, "."); 365 hyperlink_to_date(zDate, "."); 366 if( g.perm.WrTkt && g.perm.Attach ){ 366 if( g.perm.WrTkt && g.perm.Attach ){ 367 @ [%z(href("%R/attachdelete?tkt=%s&amp;file=%t&amp;from=%R/tktview%%3fna | 367 @ [%z(href("%R/attachdelete?tkt=%s&file=%t&from=%R/tktview%%3fname=%s",z 368 } 368 } 369 @ </li> 369 @ </li> 370 } 370 } 371 if( cnt ){ 371 if( cnt ){ 372 @ </ul> 372 @ </ul> 373 } 373 } 374 db_finalize(&q); 374 db_finalize(&q); ................................................................................................................................................................................ 645 } 645 } 646 } 646 } 647 return 0; 647 return 0; 648 } 648 } 649 649 650 /* 650 /* 651 ** WEBPAGE: tkttimeline 651 ** WEBPAGE: tkttimeline 652 ** URL: /tkttimeline?name=TICKETUUID&amp;y=TYPE | 652 ** URL: /tkttimeline?name=TICKETUUID&y=TYPE 653 ** 653 ** 654 ** Show the change history for a single ticket in timeline format. 654 ** Show the change history for a single ticket in timeline format. 655 */ 655 */ 656 void tkttimeline_page(void){ 656 void tkttimeline_page(void){ 657 Stmt q; 657 Stmt q; 658 char *zTitle; 658 char *zTitle; 659 char *zSQL; 659 char *zSQL; ................................................................................................................................................................................ 665 665 666 login_check_credentials(); 666 login_check_credentials(); 667 if( !g.perm.Hyperlink || !g.perm.RdTkt ){ login_needed(); return; } 667 if( !g.perm.Hyperlink || !g.perm.RdTkt ){ login_needed(); return; } 668 zUuid = PD("name",""); 668 zUuid = PD("name",""); 669 zType = PD("y","a"); 669 zType = PD("y","a"); 670 if( zType[0]!='c' ){ 670 if( zType[0]!='c' ){ 671 style_submenu_element("Check-ins", "Check-ins", 671 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); 673 }else{ 673 }else{ 674 style_submenu_element("Timeline", "Timeline", 674 style_submenu_element("Timeline", "Timeline", 675 "%s/tkttimeline?name=%T", g.zTop, zUuid); 675 "%s/tkttimeline?name=%T", g.zTop, zUuid); 676 } 676 } 677 style_submenu_element("History", "History", 677 style_submenu_element("History", "History", 678 "%s/tkthistory/%s", g.zTop, zUuid); 678 "%s/tkthistory/%s", g.zTop, zUuid); 679 style_submenu_element("Status", "Status", 679 style_submenu_element("Status", "Status", ................................................................................................................................................................................ 740 login_check_credentials(); 740 login_check_credentials(); 741 if( !g.perm.Hyperlink || !g.perm.RdTkt ){ login_needed(); return; } 741 if( !g.perm.Hyperlink || !g.perm.RdTkt ){ login_needed(); return; } 742 zUuid = PD("name",""); 742 zUuid = PD("name",""); 743 zTitle = mprintf("History Of Ticket %h", zUuid); 743 zTitle = mprintf("History Of Ticket %h", zUuid); 744 style_submenu_element("Status", "Status", 744 style_submenu_element("Status", "Status", 745 "%s/info/%s", g.zTop, zUuid); 745 "%s/info/%s", g.zTop, zUuid); 746 style_submenu_element("Check-ins", "Check-ins", 746 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); 748 style_submenu_element("Timeline", "Timeline", 748 style_submenu_element("Timeline", "Timeline", 749 "%s/tkttimeline?name=%s", g.zTop, zUuid); 749 "%s/tkttimeline?name=%s", g.zTop, zUuid); 750 style_header(zTitle); 750 style_header(zTitle); 751 free(zTitle); 751 free(zTitle); 752 752 753 tagid = db_int(0, "SELECT tagid FROM tag WHERE tagname GLOB 'tkt-%q*'",zUuid); 753 tagid = db_int(0, "SELECT tagid FROM tag WHERE tagname GLOB 'tkt-%q*'",zUuid); 754 if( tagid==0 ){ 754 if( tagid==0 ){

Changes to src/wiki.c

188 if( !g.isHome ){ 188 if( !g.isHome ){ 189 if( (rid && g.perm.WrWiki) || (!rid && g.perm.NewWiki) ){ 189 if( (rid && g.perm.WrWiki) || (!rid && g.perm.NewWiki) ){ 190 style_submenu_element("Edit", "Edit Wiki Page", "%s/wikiedit?name=%T", 190 style_submenu_element("Edit", "Edit Wiki Page", "%s/wikiedit?name=%T", 191 g.zTop, zPageName); 191 g.zTop, zPageName); 192 } 192 } 193 if( rid && g.perm.ApndWiki && g.perm.Attach ){ 193 if( rid && g.perm.ApndWiki && g.perm.Attach ){ 194 style_submenu_element("Attach", "Add An Attachment", 194 style_submenu_element("Attach", "Add An Attachment", 195 "%s/attachadd?page=%T&amp;from=%s/wiki%%3fname=%T", | 195 "%s/attachadd?page=%T&from=%s/wiki%%3fname=%T", 196 g.zTop, zPageName, g.zTop, zPageName); 196 g.zTop, zPageName, g.zTop, zPageName); 197 } 197 } 198 if( rid && g.perm.ApndWiki ){ 198 if( rid && g.perm.ApndWiki ){ 199 style_submenu_element("Append", "Add A Comment", "%s/wikiappend?name=%T", 199 style_submenu_element("Append", "Add A Comment", "%s/wikiappend?name=%T", 200 g.zTop, zPageName); 200 g.zTop, zPageName); 201 } 201 } 202 if( g.perm.Hyperlink ){ 202 if( g.perm.Hyperlink ){ ................................................................................................................................................................................ 222 if( cnt==0 ){ 222 if( cnt==0 ){ 223 @ <hr /><h2>Attachments:</h2> 223 @ <hr /><h2>Attachments:</h2> 224 @ <ul> 224 @ <ul> 225 } 225 } 226 cnt++; 226 cnt++; 227 @ <li> 227 @ <li> 228 if( g.perm.Hyperlink && g.perm.Read ){ 228 if( g.perm.Hyperlink && g.perm.Read ){ 229 @ %z(href("%R/attachview?page=%T&amp;file=%t",zPageName,zFile)) | 229 @ %z(href("%R/attachview?page=%T&file=%t",zPageName,zFile)) 230 @ %h(zFile)</a> 230 @ %h(zFile)</a> 231 }else{ 231 }else{ 232 @ %h(zFile) 232 @ %h(zFile) 233 } 233 } 234 @ added by %h(zUser) on 234 @ added by %h(zUser) on 235 hyperlink_to_date(zDate, "."); 235 hyperlink_to_date(zDate, "."); 236 if( g.perm.WrWiki && g.perm.Attach ){ 236 if( g.perm.WrWiki && g.perm.Attach ){ 237 @ [%z(href("%R/attachdelete?page=%t&amp;file=%t&amp;from=%R/wiki%%3fname=% | 237 @ [%z(href("%R/attachdelete?page=%t&file=%t&from=%R/wiki%%3fname=%f",zPage 238 } 238 } 239 @ </li> 239 @ </li> 240 } 240 } 241 if( cnt ){ 241 if( cnt ){ 242 @ </ul> 242 @ </ul> 243 } 243 } 244 db_finalize(&q); 244 db_finalize(&q); ................................................................................................................................................................................ 540 540 541 /* 541 /* 542 ** Function called to output extra text at the end of each line in 542 ** Function called to output extra text at the end of each line in 543 ** a wiki history listing. 543 ** a wiki history listing. 544 */ 544 */ 545 static void wiki_history_extra(int rid){ 545 static void wiki_history_extra(int rid){ 546 if( db_exists("SELECT 1 FROM tagxref WHERE rid=%d", rid) ){ 546 if( db_exists("SELECT 1 FROM tagxref WHERE rid=%d", rid) ){ 547 @ %z(href("%R/wdiff?name=%t&amp;a=%d",zWikiPageName,rid))[diff]</a> | 547 @ %z(href("%R/wdiff?name=%t&a=%d",zWikiPageName,rid))[diff]</a> 548 } 548 } 549 } 549 } 550 550 551 /* 551 /* 552 ** WEBPAGE: whistory 552 ** WEBPAGE: whistory 553 ** URL: /whistory?name=PAGENAME 553 ** URL: /whistory?name=PAGENAME 554 ** 554 **

Changes to src/wikiformat.c

1041 || strncmp(zTarget, "https:", 6)==0 1041 || strncmp(zTarget, "https:", 6)==0 1042 || strncmp(zTarget, "ftp:", 4)==0 1042 || strncmp(zTarget, "ftp:", 4)==0 1043 || strncmp(zTarget, "mailto:", 7)==0 1043 || strncmp(zTarget, "mailto:", 7)==0 1044 ){ 1044 ){ 1045 blob_appendf(p->pOut, "<a href=\"%s\">", zTarget); 1045 blob_appendf(p->pOut, "<a href=\"%s\">", zTarget); 1046 /* zTerm = "&#x27FE;</a>"; // doesn't work on windows */ 1046 /* zTerm = "&#x27FE;</a>"; // doesn't work on windows */ 1047 }else if( zTarget[0]=='/' ){ 1047 }else if( zTarget[0]=='/' ){ 1048 if( 1 /* g.perm.History */ ){ < 1049 blob_appendf(p->pOut, "<a href=\"%s%h\">", g.zTop, zTarget); | 1048 blob_appendf(p->pOut, "<a href=\"%s%h\">", g.zTop, zTarget); 1050 }else{ < 1051 zTerm = ""; < 1052 } < 1053 }else if( zTarget[0]=='.' || zTarget[0]=='#' ){ 1049 }else if( zTarget[0]=='.' || zTarget[0]=='#' ){ 1054 if( 1 ){ 1050 if( 1 ){ 1055 blob_appendf(p->pOut, "<a href=\"%h\">", zTarget); 1051 blob_appendf(p->pOut, "<a href=\"%h\">", zTarget); 1056 }else{ 1052 }else{ 1057 zTerm = ""; 1053 zTerm = ""; 1058 } 1054 } 1059 }else if( is_valid_uuid(zTarget) ){ 1055 }else if( is_valid_uuid(zTarget) ){