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