Check-in [f4a25366a7]
Not logged in

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

Overview
SHA1 Hash:f4a25366a76d89dce3dc191246bbea3babb53505
Date: 2010-03-18 13:26:36
User: drh
Comment:Merge recent experimental changes (the attachment enhancement and the ability to delete wiki) into the trunk.
Tags And Properties
Changes

Added src/attach.c

> 1 /* > 2 ** Copyright (c) 2010 D. Richard Hipp > 3 ** > 4 ** This program is free software; you can redistribute it and/or > 5 ** modify it under the terms of the GNU General Public > 6 ** License version 2 as published by the Free Software Foundation. > 7 ** > 8 ** This program is distributed in the hope that it will be useful, > 9 ** but WITHOUT ANY WARRANTY; without even the implied warranty of > 10 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > 11 ** General Public License for more details. > 12 ** > 13 ** You should have received a copy of the GNU General Public > 14 ** License along with this library; if not, write to the > 15 ** Free Software Foundation, Inc., 59 Temple Place - Suite 330, > 16 ** Boston, MA 02111-1307, USA. > 17 ** > 18 ** Author contact information: > 19 ** drh@hwaci.com > 20 ** http://www.hwaci.com/drh/ > 21 ** > 22 ******************************************************************************* > 23 ** > 24 ** This file contains code for dealing with attachments. > 25 */ > 26 #include "config.h" > 27 #include "attach.h" > 28 #include <assert.h> > 29 > 30 /* > 31 ** WEBPAGE: attachlist > 32 ** > 33 ** tkt=TICKETUUID > 34 ** page=WIKIPAGE > 35 ** all > 36 ** > 37 ** List attachments. > 38 */ > 39 void attachlist_page(void){ > 40 const char *zPage = P("page"); > 41 const char *zTkt = P("tkt"); > 42 Blob sql; > 43 Stmt q; > 44 > 45 if( zPage && zTkt ) zTkt = 0; > 46 login_check_credentials(); > 47 blob_zero(&sql); > 48 blob_append(&sql, > 49 "SELECT datetime(mtime,'localtime'), src, target, filename, comment, user" > 50 " FROM attachment", > 51 -1 > 52 ); > 53 if( zPage ){ > 54 if( g.okRdWiki==0 ) login_needed(); > 55 style_header("Attachments To %h", zPage); > 56 blob_appendf(&sql, " WHERE target=%Q", zPage); > 57 }else if( zTkt ){ > 58 if( g.okRdTkt==0 ) login_needed(); > 59 style_header("Attachments To Ticket %.10s", zTkt); > 60 blob_appendf(&sql, " WHERE target GLOB '%q*'", zTkt); > 61 }else{ > 62 if( g.okRdTkt==0 && g.okRdWiki==0 ) login_needed(); > 63 style_header("All Attachments"); > 64 } > 65 blob_appendf(&sql, " ORDER BY mtime DESC"); > 66 db_prepare(&q, "%s", blob_str(&sql)); > 67 while( db_step(&q)==SQLITE_ROW ){ > 68 const char *zDate = db_column_text(&q, 0); > 69 const char *zSrc = db_column_text(&q, 1); > 70 const char *zTarget = db_column_text(&q, 2); > 71 const char *zFilename = db_column_text(&q, 3); > 72 const char *zComment = db_column_text(&q, 4); > 73 const char *zUser = db_column_text(&q, 5); > 74 int i; > 75 char *zUrlTail; > 76 for(i=0; zFilename[i]; i++){ > 77 if( zFilename[i]=='/' && zFilename[i+1]!=0 ){ > 78 zFilename = &zFilename[i+1]; > 79 i = -1; > 80 } > 81 } > 82 if( strlen(zTarget)==UUID_SIZE && validate16(zTarget,UUID_SIZE) ){ > 83 zUrlTail = mprintf("tkt=%s&file=%t", zTarget, zFilename); > 84 }else{ > 85 zUrlTail = mprintf("page=%t&file=%t", zTarget, zFilename); > 86 } > 87 @ > 88 @ <p><a href="/attachview?%s(zUrlTail)">%h(zFilename)</a> > 89 @ [<a href="/attachdownload/%t(zFilename)?%s(zUrlTail)">download</a>]<br> > 90 if( zComment ) while( isspace(zComment[0]) ) zComment++; > 91 if( zComment && zComment[0] ){ > 92 @ %w(zComment)<br> > 93 } > 94 if( zPage==0 && zTkt==0 ){ > 95 if( zSrc==0 || zSrc[0]==0 ){ > 96 zSrc = "Deleted from"; > 97 }else { > 98 zSrc = "Added to"; > 99 } > 100 if( strlen(zTarget)==UUID_SIZE && validate16(zTarget, UUID_SIZE) ){ > 101 char zShort[20]; > 102 memcpy(zShort, zTarget, 10); > 103 zShort[10] = 0; > 104 @ %s(zSrc) ticket <a href="%s(g.zTop)/tktview?name=%s(zTarget)"> > 105 @ %s(zShort)</a> > 106 }else{ > 107 @ %s(zSrc) wiki page <a href="%s(g.zTop)/wiki?name=%t(zTarget)"> > 108 @ %h(zTarget)</a> > 109 } > 110 }else{ > 111 if( zSrc==0 || zSrc[0]==0 ){ > 112 @ Deleted > 113 }else { > 114 @ Added > 115 } > 116 } > 117 @ by %h(zUser) on > 118 hyperlink_to_date(zDate, "."); > 119 free(zUrlTail); > 120 } > 121 db_finalize(&q); > 122 style_footer(); > 123 return; > 124 } > 125 > 126 /* > 127 ** WEBPAGE: attachdownload > 128 ** WEBPAGE: attachimage > 129 ** WEBPAGE: attachview > 130 ** > 131 ** tkt=TICKETUUID > 132 ** page=WIKIPAGE > 133 ** file=FILENAME > 134 ** attachid=ID > 135 ** > 136 ** List attachments. > 137 */ > 138 void attachview_page(void){ > 139 const char *zPage = P("page"); > 140 const char *zTkt = P("tkt"); > 141 const char *zFile = P("file"); > 142 const char *zTarget; > 143 int attachid = atoi(PD("attachid","0")); > 144 char *zUUID; > 145 > 146 if( zPage && zTkt ) zTkt = 0; > 147 if( zFile==0 ) fossil_redirect_home(); > 148 login_check_credentials(); > 149 if( zPage ){ > 150 if( g.okRdWiki==0 ) login_needed(); > 151 zTarget = zPage; > 152 }else if( zTkt ){ > 153 if( g.okRdTkt==0 ) login_needed(); > 154 zTarget = zTkt; > 155 }else{ > 156 fossil_redirect_home(); > 157 } > 158 if( attachid>0 ){ > 159 zUUID = db_text(0, > 160 "SELECT coalesce(src,'x') FROM attachment" > 161 " WHERE target=%Q AND attachid=%d", > 162 zTarget, attachid > 163 ); > 164 }else{ > 165 zUUID = db_text(0, > 166 "SELECT coalesce(src,'x') FROM attachment" > 167 " WHERE target=%Q AND filename=%Q" > 168 " ORDER BY mtime DESC LIMIT 1", > 169 zTarget, zFile > 170 ); > 171 } > 172 if( zUUID==0 || zUUID[0]==0 ){ > 173 style_header("No Such Attachment"); > 174 @ No such attachment.... > 175 style_footer(); > 176 return; > 177 }else if( zUUID[0]=='x' ){ > 178 style_header("Missing"); > 179 @ Attachment has been deleted > 180 style_footer(); > 181 return; > 182 } > 183 g.okRead = 1; > 184 cgi_replace_parameter("name",zUUID); > 185 if( strcmp(g.zPath,"attachview")==0 ){ > 186 artifact_page(); > 187 }else{ > 188 cgi_replace_parameter("m", mimetype_from_name(zFile)); > 189 rawartifact_page(); > 190 } > 191 } > 192 > 193 > 194 /* > 195 ** WEBPAGE: attachadd > 196 ** > 197 ** tkt=TICKETUUID > 198 ** page=WIKIPAGE > 199 ** from=URL > 200 ** > 201 ** Add a new attachment. > 202 */ > 203 void attachadd_page(void){ > 204 const char *zPage = P("page"); > 205 const char *zTkt = P("tkt"); > 206 const char *zFrom = P("from"); > 207 const char *aContent = P("f"); > 208 const char *zName = PD("f:filename","unknown"); > 209 const char *zTarget; > 210 const char *zTargetType; > 211 int szContent = atoi(PD("f:bytes","0")); > 212 > 213 if( P("cancel") ) cgi_redirect(zFrom); > 214 if( zPage && zTkt ) fossil_redirect_home(); > 215 if( zPage==0 && zTkt==0 ) fossil_redirect_home(); > 216 login_check_credentials(); > 217 if( zPage ){ > 218 if( g.okApndWiki==0 || g.okAttach==0 ) login_needed(); > 219 if( !db_exists("SELECT 1 FROM tag WHERE tagname='wiki-%q'", zPage) ){ > 220 fossil_redirect_home(); > 221 } > 222 zTarget = zPage; > 223 zTargetType = mprintf("Wiki Page <a href=\"%s/wiki?name=%h\">%h</a>", > 224 g.zTop, zPage, zPage); > 225 }else{ > 226 if( g.okApndTkt==0 || g.okAttach==0 ) login_needed(); > 227 if( !db_exists("SELECT 1 FROM tag WHERE tagname='tkt-%q'", zTkt) ){ > 228 fossil_redirect_home(); > 229 } > 230 zTarget = zTkt; > 231 zTargetType = mprintf("Ticket <a href=\"%s/tktview?name=%.10s\">%.10s</a>", > 232 g.zTop, zTkt, zTkt); > 233 } > 234 if( zFrom==0 ) zFrom = mprintf("%s/home", g.zTop); > 235 if( P("cancel") ){ > 236 cgi_redirect(zFrom); > 237 } > 238 if( P("ok") && szContent>0 ){ > 239 Blob content; > 240 Blob manifest; > 241 Blob cksum; > 242 char *zUUID; > 243 const char *zComment; > 244 char *zDate; > 245 int rid; > 246 int i, n; > 247 > 248 db_begin_transaction(); > 249 blob_init(&content, aContent, szContent); > 250 rid = content_put(&content, 0, 0); > 251 zUUID = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid); > 252 blob_zero(&manifest); > 253 for(i=n=0; zName[i]; i++){ > 254 if( zName[i]=='/' || zName[i]=='\\' ) n = i; > 255 } > 256 zName += n; > 257 if( zName[0]==0 ) zName = "unknown"; > 258 blob_appendf(&manifest, "A %F %F %s\n", zName, zTarget, zUUID); > 259 zComment = PD("comment", ""); > 260 while( isspace(zComment[0]) ) zComment++; > 261 n = strlen(zComment); > 262 while( n>0 && isspace(zComment[n-1]) ){ n--; } > 263 if( n>0 ){ > 264 blob_appendf(&manifest, "C %F\n", zComment); > 265 } > 266 zDate = db_text(0, "SELECT datetime('now')"); > 267 zDate[10] = 'T'; > 268 blob_appendf(&manifest, "D %s\n", zDate); > 269 blob_appendf(&manifest, "U %F\n", g.zLogin ? g.zLogin : "nobody"); > 270 md5sum_blob(&manifest, &cksum); > 271 blob_appendf(&manifest, "Z %b\n", &cksum); > 272 rid = content_put(&manifest, 0, 0); > 273 manifest_crosslink(rid, &manifest); > 274 db_end_transaction(0); > 275 cgi_redirect(zFrom); > 276 } > 277 style_header("Add Attachment"); > 278 @ <h2>Add Attachment To %s(zTargetType)</h2> > 279 @ <form action="%s(g.zBaseURL)/attachadd" method="POST" > 280 @ enctype="multipart/form-data"> > 281 @ File to Attach: > 282 @ <input type="file" name="f" size="60"><br> > 283 @ Description:<br> > 284 @ <textarea name="comment" cols=80 rows=5 wrap="virtual"></textarea><br> > 285 if( zTkt ){ > 286 @ <input type="hidden" name="tkt" value="%h(zTkt)"> > 287 }else{ > 288 @ <input type="hidden" name="page" value="%h(zPage)"> > 289 } > 290 @ <input type="hidden" name="from" value="%h(zFrom)"> > 291 @ <input type="submit" name="ok" value="Add Attachment"> > 292 @ <input type="submit" name="cancel" value="Cancel"> > 293 @ </form> > 294 style_footer(); > 295 } > 296 > 297 > 298 /* > 299 ** WEBPAGE: attachdelete > 300 ** > 301 ** tkt=TICKETUUID > 302 ** page=WIKIPAGE > 303 ** file=FILENAME > 304 ** > 305 ** "Delete" an attachment. Because objects in Fossil are immutable > 306 ** the attachment isn't really deleted. Instead, we change the content > 307 ** of the attachment to NULL, which the system understands as being > 308 ** deleted. Historical values of the attachment are preserved. > 309 */ > 310 void attachdel_page(void){ > 311 const char *zPage = P("page"); > 312 const char *zTkt = P("tkt"); > 313 const char *zFile = P("file"); > 314 const char *zFrom = P("from"); > 315 const char *zTarget; > 316 > 317 if( zPage && zTkt ) fossil_redirect_home(); > 318 if( zPage==0 && zTkt==0 ) fossil_redirect_home(); > 319 if( zFile==0 ) fossil_redirect_home(); > 320 login_check_credentials(); > 321 if( zPage ){ > 322 if( g.okWrWiki==0 || g.okAttach==0 ) login_needed(); > 323 zTarget = zPage; > 324 }else{ > 325 if( g.okWrTkt==0 || g.okAttach==0 ) login_needed(); > 326 zTarget = zTkt; > 327 } > 328 if( zFrom==0 ) zFrom = mprintf("%s/home", g.zTop); > 329 if( P("cancel") ){ > 330 cgi_redirect(zFrom); > 331 } > 332 if( P("confirm") ){ > 333 int i, n, rid; > 334 char *zDate; > 335 Blob manifest; > 336 Blob cksum; > 337 > 338 db_begin_transaction(); > 339 blob_zero(&manifest); > 340 for(i=n=0; zFile[i]; i++){ > 341 if( zFile[i]=='/' || zFile[i]=='\\' ) n = i; > 342 } > 343 zFile += n; > 344 if( zFile[0]==0 ) zFile = "unknown"; > 345 blob_appendf(&manifest, "A %F %F\n", zFile, zTarget); > 346 zDate = db_text(0, "SELECT datetime('now')"); > 347 zDate[10] = 'T'; > 348 blob_appendf(&manifest, "D %s\n", zDate); > 349 blob_appendf(&manifest, "U %F\n", g.zLogin ? g.zLogin : "nobody"); > 350 md5sum_blob(&manifest, &cksum); > 351 blob_appendf(&manifest, "Z %b\n", &cksum); > 352 rid = content_put(&manifest, 0, 0); > 353 manifest_crosslink(rid, &manifest); > 354 db_end_transaction(0); > 355 cgi_redirect(zFrom); > 356 } > 357 style_header("Delete Attachment"); > 358 @ <form action="%s(g.zBaseURL)/attachdelete" method="POST"> > 359 @ <p>Confirm that you want to delete the attachment named > 360 @ "%h(zFile)" on %s(zTkt?"ticket":"wiki page") %h(zTarget):<br> > 361 if( zTkt ){ > 362 @ <input type="hidden" name="tkt" value="%h(zTkt)"> > 363 }else{ > 364 @ <input type="hidden" name="page" value="%h(zPage)"> > 365 } > 366 @ <input type="hidden" name="file" value="%h(zFile)"> > 367 @ <input type="hidden" name="from" value="%h(zFrom)"> > 368 @ <input type="submit" name="confirm" value="Delete"> > 369 @ <input type="submit" name="cancel" value="Cancel"> > 370 @ </form> > 371 style_footer(); > 372 > 373 }

Changes to src/info.c

730 if( pDownloadName && blob_size(pDownloadName)==0 ){ 730 if( pDownloadName && blob_size(pDownloadName)==0 ){ 731 blob_append(pDownloadName, zUuid, -1); 731 blob_append(pDownloadName, zUuid, -1); 732 } 732 } 733 cnt++; 733 cnt++; 734 } 734 } 735 db_finalize(&q); 735 db_finalize(&q); 736 } 736 } > 737 db_prepare(&q, > 738 "SELECT target, filename, datetime(mtime), user, src" > 739 " FROM attachment" > 740 " WHERE src=(SELECT uuid FROM blob WHERE rid=%d)" > 741 " ORDER BY mtime DESC", > 742 rid > 743 ); > 744 while( db_step(&q)==SQLITE_ROW ){ > 745 const char *zTarget = db_column_text(&q, 0); > 746 const char *zFilename = db_column_text(&q, 1); > 747 const char *zDate = db_column_text(&q, 2); > 748 const char *zUser = db_column_text(&q, 3); > 749 const char *zSrc = db_column_text(&q, 4); > 750 if( cnt>0 ){ > 751 @ Also attachment "%h(zFilename)" to > 752 }else{ > 753 @ Attachment "%h(zFilename)" to > 754 } > 755 if( strlen(zTarget)==UUID_SIZE && validate16(zTarget,UUID_SIZE) ){ > 756 char zShort[20]; > 757 memcpy(zShort, zTarget, 10); > 758 if( g.okHistory && g.okRdTkt ){ > 759 @ ticket [<a href="%s(g.zTop)/tktview?name=%s(zShort)">%s(zShort)</a>] > 760 }else{ > 761 @ ticket [%s(zShort)] > 762 } > 763 }else{ > 764 if( g.okHistory && g.okRdWiki ){ > 765 @ wiki page [<a href="%s(g.zTop)/wiki?name=%t(zTarget)">%h(zTarget)</a>] > 766 }else{ > 767 @ wiki page [%h(zTarget)] > 768 } > 769 } > 770 @ added by > 771 hyperlink_to_user(zUser,zDate," on"); > 772 hyperlink_to_date(zDate,"."); > 773 cnt++; > 774 if( pDownloadName && blob_size(pDownloadName)==0 ){ > 775 blob_append(pDownloadName, zSrc, -1); > 776 } > 777 } > 778 db_finalize(&q); 737 if( cnt==0 ){ 779 if( cnt==0 ){ 738 char *zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid); 780 char *zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid); 739 @ Control artifact. 781 @ Control artifact. 740 if( pDownloadName && blob_size(pDownloadName)==0 ){ 782 if( pDownloadName && blob_size(pDownloadName)==0 ){ 741 blob_append(pDownloadName, zUuid, -1); 783 blob_append(pDownloadName, zUuid, -1); 742 } 784 } 743 }else if( linkToView && g.okHistory ){ 785 }else if( linkToView && g.okHistory ){

Changes to src/login.c

474 for(i=0; zCap[i]; i++){ 474 for(i=0; zCap[i]; i++){ 475 switch( zCap[i] ){ 475 switch( zCap[i] ){ 476 case 's': g.okSetup = 1; /* Fall thru into Admin */ 476 case 's': g.okSetup = 1; /* Fall thru into Admin */ 477 case 'a': g.okAdmin = g.okRdTkt = g.okWrTkt = g.okZip = 477 case 'a': g.okAdmin = g.okRdTkt = g.okWrTkt = g.okZip = 478 g.okRdWiki = g.okWrWiki = g.okNewWiki = 478 g.okRdWiki = g.okWrWiki = g.okNewWiki = 479 g.okApndWiki = g.okHistory = g.okClone = 479 g.okApndWiki = g.okHistory = g.okClone = 480 g.okNewTkt = g.okPassword = g.okRdAddr = 480 g.okNewTkt = g.okPassword = g.okRdAddr = > 481 g.okTktFmt = g.okAttach = 1; 481 g.okTktFmt = 1; /* Fall thru into Read/Write */ | 482 /* Fall thru into Read/Write */ 482 case 'i': g.okRead = g.okWrite = 1; break; 483 case 'i': g.okRead = g.okWrite = 1; break; 483 case 'o': g.okRead = 1; break; 484 case 'o': g.okRead = 1; break; 484 case 'z': g.okZip = 1; break; 485 case 'z': g.okZip = 1; break; 485 486 486 case 'd': g.okDelete = 1; break; 487 case 'd': g.okDelete = 1; break; 487 case 'h': g.okHistory = 1; break; 488 case 'h': g.okHistory = 1; break; 488 case 'g': g.okClone = 1; break; 489 case 'g': g.okClone = 1; break; ................................................................................................................................................................................ 496 case 'e': g.okRdAddr = 1; break; 497 case 'e': g.okRdAddr = 1; break; 497 case 'r': g.okRdTkt = 1; break; 498 case 'r': g.okRdTkt = 1; break; 498 case 'n': g.okNewTkt = 1; break; 499 case 'n': g.okNewTkt = 1; break; 499 case 'w': g.okWrTkt = g.okRdTkt = g.okNewTkt = 500 case 'w': g.okWrTkt = g.okRdTkt = g.okNewTkt = 500 g.okApndTkt = 1; break; 501 g.okApndTkt = 1; break; 501 case 'c': g.okApndTkt = 1; break; 502 case 'c': g.okApndTkt = 1; break; 502 case 't': g.okTktFmt = 1; break; 503 case 't': g.okTktFmt = 1; break; > 504 case 'b': g.okAttach = 1; break; 503 505 504 /* The "u" privileges is a little different. It recursively 506 /* The "u" privileges is a little different. It recursively 505 ** inherits all privileges of the user named "reader" */ 507 ** inherits all privileges of the user named "reader" */ 506 case 'u': { 508 case 'u': { 507 if( zUser==0 ){ 509 if( zUser==0 ){ 508 zUser = db_text("", "SELECT cap FROM user WHERE login='reader'"); 510 zUser = db_text("", "SELECT cap FROM user WHERE login='reader'"); 509 login_set_capabilities(zUser); 511 login_set_capabilities(zUser); ................................................................................................................................................................................ 532 int login_has_capability(const char *zCap, int nCap){ 534 int login_has_capability(const char *zCap, int nCap){ 533 int i; 535 int i; 534 int rc = 1; 536 int rc = 1; 535 if( nCap<0 ) nCap = strlen(zCap); 537 if( nCap<0 ) nCap = strlen(zCap); 536 for(i=0; i<nCap && rc && zCap[i]; i++){ 538 for(i=0; i<nCap && rc && zCap[i]; i++){ 537 switch( zCap[i] ){ 539 switch( zCap[i] ){ 538 case 'a': rc = g.okAdmin; break; 540 case 'a': rc = g.okAdmin; break; 539 /* case 'b': */ | 541 case 'b': rc = g.okAttach; break; 540 case 'c': rc = g.okApndTkt; break; 542 case 'c': rc = g.okApndTkt; break; 541 case 'd': rc = g.okDelete; break; 543 case 'd': rc = g.okDelete; break; 542 case 'e': rc = g.okRdAddr; break; 544 case 'e': rc = g.okRdAddr; break; 543 case 'f': rc = g.okNewWiki; break; 545 case 'f': rc = g.okNewWiki; break; 544 case 'g': rc = g.okClone; break; 546 case 'g': rc = g.okClone; break; 545 case 'h': rc = g.okHistory; break; 547 case 'h': rc = g.okHistory; break; 546 case 'i': rc = g.okWrite; break; 548 case 'i': rc = g.okWrite; break;

Changes to src/main.c

128 int okNewWiki; /* f: create new wiki via web */ 128 int okNewWiki; /* f: create new wiki via web */ 129 int okApndWiki; /* m: append to wiki via web */ 129 int okApndWiki; /* m: append to wiki via web */ 130 int okWrWiki; /* k: edit wiki via web */ 130 int okWrWiki; /* k: edit wiki via web */ 131 int okRdTkt; /* r: view tickets via web */ 131 int okRdTkt; /* r: view tickets via web */ 132 int okNewTkt; /* n: create new tickets */ 132 int okNewTkt; /* n: create new tickets */ 133 int okApndTkt; /* c: append to tickets via the web */ 133 int okApndTkt; /* c: append to tickets via the web */ 134 int okWrTkt; /* w: make changes to tickets via web */ 134 int okWrTkt; /* w: make changes to tickets via web */ > 135 int okAttach; /* b: add attachments */ 135 int okTktFmt; /* t: create new ticket report formats */ 136 int okTktFmt; /* t: create new ticket report formats */ 136 int okRdAddr; /* e: read email addresses or other private data */ 137 int okRdAddr; /* e: read email addresses or other private data */ 137 int okZip; /* z: download zipped artifact via /zip URL */ 138 int okZip; /* z: download zipped artifact via /zip URL */ 138 139 139 /* For defense against Cross-site Request Forgery attacks */ 140 /* For defense against Cross-site Request Forgery attacks */ 140 char zCsrfToken[12]; /* Value of the anti-CSRF token */ 141 char zCsrfToken[12]; /* Value of the anti-CSRF token */ 141 int okCsrf; /* Anti-CSRF token is present and valid */ 142 int okCsrf; /* Anti-CSRF token is present and valid */

Changes to src/main.mk

11 11 12 XTCC = $(TCC) $(CFLAGS) -I. -I$(SRCDIR) 12 XTCC = $(TCC) $(CFLAGS) -I. -I$(SRCDIR) 13 13 14 14 15 SRC = \ 15 SRC = \ 16 $(SRCDIR)/add.c \ 16 $(SRCDIR)/add.c \ 17 $(SRCDIR)/allrepo.c \ 17 $(SRCDIR)/allrepo.c \ > 18 $(SRCDIR)/attach.c \ 18 $(SRCDIR)/bag.c \ 19 $(SRCDIR)/bag.c \ 19 $(SRCDIR)/blob.c \ 20 $(SRCDIR)/blob.c \ 20 $(SRCDIR)/branch.c \ 21 $(SRCDIR)/branch.c \ 21 $(SRCDIR)/browse.c \ 22 $(SRCDIR)/browse.c \ 22 $(SRCDIR)/captcha.c \ 23 $(SRCDIR)/captcha.c \ 23 $(SRCDIR)/cgi.c \ 24 $(SRCDIR)/cgi.c \ 24 $(SRCDIR)/checkin.c \ 25 $(SRCDIR)/checkin.c \ ................................................................................................................................................................................ 84 $(SRCDIR)/winhttp.c \ 85 $(SRCDIR)/winhttp.c \ 85 $(SRCDIR)/xfer.c \ 86 $(SRCDIR)/xfer.c \ 86 $(SRCDIR)/zip.c 87 $(SRCDIR)/zip.c 87 88 88 TRANS_SRC = \ 89 TRANS_SRC = \ 89 add_.c \ 90 add_.c \ 90 allrepo_.c \ 91 allrepo_.c \ > 92 attach_.c \ 91 bag_.c \ 93 bag_.c \ 92 blob_.c \ 94 blob_.c \ 93 branch_.c \ 95 branch_.c \ 94 browse_.c \ 96 browse_.c \ 95 captcha_.c \ 97 captcha_.c \ 96 cgi_.c \ 98 cgi_.c \ 97 checkin_.c \ 99 checkin_.c \ ................................................................................................................................................................................ 157 winhttp_.c \ 159 winhttp_.c \ 158 xfer_.c \ 160 xfer_.c \ 159 zip_.c 161 zip_.c 160 162 161 OBJ = \ 163 OBJ = \ 162 $(OBJDIR)/add.o \ 164 $(OBJDIR)/add.o \ 163 $(OBJDIR)/allrepo.o \ 165 $(OBJDIR)/allrepo.o \ > 166 $(OBJDIR)/attach.o \ 164 $(OBJDIR)/bag.o \ 167 $(OBJDIR)/bag.o \ 165 $(OBJDIR)/blob.o \ 168 $(OBJDIR)/blob.o \ 166 $(OBJDIR)/branch.o \ 169 $(OBJDIR)/branch.o \ 167 $(OBJDIR)/browse.o \ 170 $(OBJDIR)/browse.o \ 168 $(OBJDIR)/captcha.o \ 171 $(OBJDIR)/captcha.o \ 169 $(OBJDIR)/cgi.o \ 172 $(OBJDIR)/cgi.o \ 170 $(OBJDIR)/checkin.o \ 173 $(OBJDIR)/checkin.o \ ................................................................................................................................................................................ 271 # 274 # 272 $(SRCDIR)/../manifest: 275 $(SRCDIR)/../manifest: 273 # noop 276 # noop 274 277 275 clean: 278 clean: 276 rm -f $(OBJDIR)/*.o *_.c $(APPNAME) VERSION.h 279 rm -f $(OBJDIR)/*.o *_.c $(APPNAME) VERSION.h 277 rm -f translate makeheaders mkindex page_index.h headers 280 rm -f translate makeheaders mkindex page_index.h headers 278 rm -f add.h allrepo.h bag.h blob.h branch.h browse.h captcha.h cgi.h che | 281 rm -f add.h allrepo.h attach.h bag.h blob.h branch.h browse.h captcha.h 279 282 280 page_index.h: $(TRANS_SRC) mkindex 283 page_index.h: $(TRANS_SRC) mkindex 281 ./mkindex $(TRANS_SRC) >$@ 284 ./mkindex $(TRANS_SRC) >$@ 282 headers: page_index.h makeheaders VERSION.h 285 headers: page_index.h makeheaders VERSION.h 283 ./makeheaders add_.c:add.h allrepo_.c:allrepo.h bag_.c:bag.h blob_.c:bl | 286 ./makeheaders add_.c:add.h allrepo_.c:allrepo.h attach_.c:attach.h bag_ 284 touch headers 287 touch headers 285 headers: Makefile 288 headers: Makefile 286 Makefile: 289 Makefile: 287 add_.c: $(SRCDIR)/add.c translate 290 add_.c: $(SRCDIR)/add.c translate 288 ./translate $(SRCDIR)/add.c >add_.c 291 ./translate $(SRCDIR)/add.c >add_.c 289 292 290 $(OBJDIR)/add.o: add_.c add.h $(SRCDIR)/config.h 293 $(OBJDIR)/add.o: add_.c add.h $(SRCDIR)/config.h ................................................................................................................................................................................ 294 allrepo_.c: $(SRCDIR)/allrepo.c translate 297 allrepo_.c: $(SRCDIR)/allrepo.c translate 295 ./translate $(SRCDIR)/allrepo.c >allrepo_.c 298 ./translate $(SRCDIR)/allrepo.c >allrepo_.c 296 299 297 $(OBJDIR)/allrepo.o: allrepo_.c allrepo.h $(SRCDIR)/config.h 300 $(OBJDIR)/allrepo.o: allrepo_.c allrepo.h $(SRCDIR)/config.h 298 $(XTCC) -o $(OBJDIR)/allrepo.o -c allrepo_.c 301 $(XTCC) -o $(OBJDIR)/allrepo.o -c allrepo_.c 299 302 300 allrepo.h: headers 303 allrepo.h: headers > 304 attach_.c: $(SRCDIR)/attach.c translate > 305 ./translate $(SRCDIR)/attach.c >attach_.c > 306 > 307 $(OBJDIR)/attach.o: attach_.c attach.h $(SRCDIR)/config.h > 308 $(XTCC) -o $(OBJDIR)/attach.o -c attach_.c > 309 > 310 attach.h: headers 301 bag_.c: $(SRCDIR)/bag.c translate 311 bag_.c: $(SRCDIR)/bag.c translate 302 ./translate $(SRCDIR)/bag.c >bag_.c 312 ./translate $(SRCDIR)/bag.c >bag_.c 303 313 304 $(OBJDIR)/bag.o: bag_.c bag.h $(SRCDIR)/config.h 314 $(OBJDIR)/bag.o: bag_.c bag.h $(SRCDIR)/config.h 305 $(XTCC) -o $(OBJDIR)/bag.o -c bag_.c 315 $(XTCC) -o $(OBJDIR)/bag.o -c bag_.c 306 316 307 bag.h: headers 317 bag.h: headers

Changes to src/makemake.tcl

5 5 6 # Basenames of all source files that get preprocessed using 6 # Basenames of all source files that get preprocessed using 7 # "translate" and "makeheaders" 7 # "translate" and "makeheaders" 8 # 8 # 9 set src { 9 set src { 10 add 10 add 11 allrepo 11 allrepo > 12 attach 12 bag 13 bag 13 blob 14 blob 14 branch 15 branch 15 browse 16 browse 16 captcha 17 captcha 17 cgi 18 cgi 18 checkin 19 checkin

Changes to src/manifest.c

194 && !wiki_name_is_wellformed((const unsigned char *)zTarget) ){ 194 && !wiki_name_is_wellformed((const unsigned char *)zTarget) ){ 195 goto manifest_syntax_error; 195 goto manifest_syntax_error; 196 } 196 } 197 if( blob_size(&a3)>0 197 if( blob_size(&a3)>0 198 && (blob_size(&a3)!=UUID_SIZE || !validate16(zSrc, UUID_SIZE)) ){ 198 && (blob_size(&a3)!=UUID_SIZE || !validate16(zSrc, UUID_SIZE)) ){ 199 goto manifest_syntax_error; 199 goto manifest_syntax_error; 200 } 200 } 201 p->zAttachName = zName; | 201 p->zAttachName = (char*)file_tail(zName); 202 p->zAttachSrc = zSrc; 202 p->zAttachSrc = zSrc; 203 p->zAttachTarget = zTarget; 203 p->zAttachTarget = zTarget; 204 break; 204 break; 205 } 205 } 206 206 207 /* 207 /* 208 ** C <comment> 208 ** C <comment> ................................................................................................................................................................................ 1078 } 1078 } 1079 } 1079 } 1080 if( m.type==CFTYPE_WIKI ){ 1080 if( m.type==CFTYPE_WIKI ){ 1081 char *zTag = mprintf("wiki-%s", m.zWikiTitle); 1081 char *zTag = mprintf("wiki-%s", m.zWikiTitle); 1082 int tagid = tag_findid(zTag, 1); 1082 int tagid = tag_findid(zTag, 1); 1083 int prior; 1083 int prior; 1084 char *zComment; 1084 char *zComment; > 1085 int nWiki; > 1086 char zLength[40]; > 1087 while( isspace(m.zWiki[0]) ) m.zWiki++; > 1088 nWiki = strlen(m.zWiki); > 1089 sqlite3_snprintf(sizeof(zLength), zLength, "%d", nWiki); 1085 tag_insert(zTag, 1, 0, rid, m.rDate, rid); | 1090 tag_insert(zTag, 1, zLength, rid, m.rDate, rid); 1086 free(zTag); 1091 free(zTag); 1087 prior = db_int(0, 1092 prior = db_int(0, 1088 "SELECT rid FROM tagxref" 1093 "SELECT rid FROM tagxref" 1089 " WHERE tagid=%d AND mtime<%.17g" 1094 " WHERE tagid=%d AND mtime<%.17g" 1090 " ORDER BY mtime DESC", 1095 " ORDER BY mtime DESC", 1091 tagid, m.rDate 1096 tagid, m.rDate 1092 ); 1097 ); 1093 if( prior ){ 1098 if( prior ){ 1094 content_deltify(prior, rid, 0); 1099 content_deltify(prior, rid, 0); 1095 } 1100 } > 1101 if( nWiki>0 ){ 1096 zComment = mprintf("Changes to wiki page [%h]", m.zWikiTitle); | 1102 zComment = mprintf("Changes to wiki page [%h]", m.zWikiTitle); > 1103 }else{ > 1104 zComment = mprintf("Deleted wiki page [%h]", m.zWikiTitle); > 1105 } 1097 db_multi_exec( 1106 db_multi_exec( 1098 "REPLACE INTO event(type,mtime,objid,user,comment," 1107 "REPLACE INTO event(type,mtime,objid,user,comment," 1099 " bgcolor,euser,ecomment)" 1108 " bgcolor,euser,ecomment)" 1100 "VALUES('w',%.17g,%d,%Q,%Q," 1109 "VALUES('w',%.17g,%d,%Q,%Q," 1101 " (SELECT value FROM tagxref WHERE tagid=%d AND rid=%d AND tagtype>1)," 1110 " (SELECT value FROM tagxref WHERE tagid=%d AND rid=%d AND tagtype>1)," 1102 " (SELECT value FROM tagxref WHERE tagid=%d AND rid=%d)," 1111 " (SELECT value FROM tagxref WHERE tagid=%d AND rid=%d)," 1103 " (SELECT value FROM tagxref WHERE tagid=%d AND rid=%d));", 1112 " (SELECT value FROM tagxref WHERE tagid=%d AND rid=%d));", ................................................................................................................................................................................ 1117 tag_insert(zTag, 1, 0, rid, m.rDate, rid); 1126 tag_insert(zTag, 1, 0, rid, m.rDate, rid); 1118 free(zTag); 1127 free(zTag); 1119 db_multi_exec("INSERT OR IGNORE INTO pending_tkt VALUES(%Q)", 1128 db_multi_exec("INSERT OR IGNORE INTO pending_tkt VALUES(%Q)", 1120 m.zTicketUuid); 1129 m.zTicketUuid); 1121 } 1130 } 1122 if( m.type==CFTYPE_ATTACHMENT ){ 1131 if( m.type==CFTYPE_ATTACHMENT ){ 1123 db_multi_exec( 1132 db_multi_exec( 1124 "INSERT OR IGNORE INTO attachment(mtime, target, filename)" | 1133 "INSERT INTO attachment(attachid, mtime, src, target," 1125 "VALUES(0.0,%Q,%Q)", | 1134 "filename, comment, user)" > 1135 "VALUES(%d,%.17g,%Q,%Q,%Q,%Q,%Q);", 1126 m.zAttachTarget, m.zAttachName | 1136 rid, m.rDate, m.zAttachSrc, m.zAttachTarget, m.zAttachName, > 1137 (m.zComment ? m.zComment : ""), m.zUser 1127 ); 1138 ); 1128 db_multi_exec( 1139 db_multi_exec( 1129 "UPDATE attachment SET mtime=%.17g, src=%Q, comment=%Q, user=%Q" | 1140 "UPDATE attachment SET isLatest = (mtime==" > 1141 "(SELECT max(mtime) FROM attachment" > 1142 " WHERE target=%Q AND filename=%Q))" 1130 " WHERE mtime<%.17g AND target=%Q AND filename=%Q", | 1143 " WHERE target=%Q AND filename=%Q", 1131 m.rDate, m.zAttachSrc, m.zComment, m.zUser, < > 1144 m.zAttachTarget, m.zAttachName, 1132 m.rDate, m.zAttachTarget, m.zAttachName | 1145 m.zAttachTarget, m.zAttachName 1133 ); 1146 ); > 1147 if( strlen(m.zAttachTarget)!=UUID_SIZE > 1148 || !validate16(m.zAttachTarget, UUID_SIZE) > 1149 ){ > 1150 char *zComment; > 1151 if( m.zAttachSrc && m.zAttachSrc[0] ){ > 1152 zComment = mprintf("Add attachment \"%h\" to wiki page [%h]", > 1153 m.zAttachName, m.zAttachTarget); > 1154 }else{ > 1155 zComment = mprintf("Delete attachment \"%h\" from wiki page [%h]", > 1156 m.zAttachName, m.zAttachTarget); > 1157 } > 1158 db_multi_exec( > 1159 "REPLACE INTO event(type,mtime,objid,user,comment)" > 1160 "VALUES('w',%.17g,%d,%Q,%Q)", > 1161 m.rDate, rid, m.zUser, zComment > 1162 ); > 1163 free(zComment); > 1164 }else{ > 1165 char *zComment; > 1166 if( m.zAttachSrc && m.zAttachSrc[0] ){ > 1167 zComment = mprintf("Add attachment \"%h\" to ticket [%.10s]", > 1168 m.zAttachName, m.zAttachTarget); > 1169 }else{ > 1170 zComment = mprintf("Delete attachment \"%h\" from ticket [%.10s]", > 1171 m.zAttachName, m.zAttachTarget); > 1172 } > 1173 db_multi_exec( > 1174 "REPLACE INTO event(type,mtime,objid,user,comment)" > 1175 "VALUES('t',%.17g,%d,%Q,%Q)", > 1176 m.rDate, rid, m.zUser, zComment > 1177 ); > 1178 free(zComment); > 1179 } 1134 } 1180 } 1135 db_end_transaction(0); 1181 db_end_transaction(0); 1136 manifest_clear(&m); 1182 manifest_clear(&m); 1137 return 1; 1183 return 1; 1138 } 1184 }

Changes to src/schema.c

325 @ ); 325 @ ); 326 @ CREATE INDEX backlink_src ON backlink(srcid, srctype); 326 @ CREATE INDEX backlink_src ON backlink(srcid, srctype); 327 @ 327 @ 328 @ -- Each attachment is an entry in the following table. Only 328 @ -- Each attachment is an entry in the following table. Only 329 @ -- the most recent attachment (identified by the D card) is saved. 329 @ -- the most recent attachment (identified by the D card) is saved. 330 @ -- 330 @ -- 331 @ CREATE TABLE attachment( 331 @ CREATE TABLE attachment( > 332 @ attachid INTEGER PRIMARY KEY, -- Local id for this attachment > 333 @ isLatest BOOLEAN DEFAULT 0, -- True if this is the one to use 332 @ mtime TIMESTAMP, -- Time when attachment last changed 334 @ mtime TIMESTAMP, -- Time when attachment last changed 333 @ src TEXT, -- UUID of the attachment. NULL to delete 335 @ src TEXT, -- UUID of the attachment. NULL to delete 334 @ target TEXT, -- Object attached to | 336 @ target TEXT, -- Object attached to. Wikiname or Tkt UUID 335 @ filename TEXT, -- Filename for the attachment 337 @ filename TEXT, -- Filename for the attachment 336 @ comment TEXT, -- Comment associated with this attachment 338 @ comment TEXT, -- Comment associated with this attachment 337 @ user TEXT, -- Name of user adding attachment | 339 @ user TEXT -- Name of user adding attachment 338 @ PRIMARY KEY(target, filename) < 339 @ ); 340 @ ); > 341 @ CREATE INDEX attachment_idx1 ON attachment(target, filename, mtime); > 342 @ CREATE INDEX attachment_idx2 ON attachment(src); 340 @ 343 @ 341 @ -- Template for the TICKET table 344 @ -- Template for the TICKET table 342 @ -- 345 @ -- 343 @ -- NB: when changing the schema of the TICKET table here, also make the 346 @ -- NB: when changing the schema of the TICKET table here, also make the 344 @ -- same change in tktsetup.c. 347 @ -- same change in tktsetup.c. 345 @ -- 348 @ -- 346 @ CREATE TABLE ticket( 349 @ CREATE TABLE ticket(

Changes to src/setup.c

145 @ <td valign="top"> 145 @ <td valign="top"> 146 @ <b>Notes:</b> 146 @ <b>Notes:</b> 147 @ <ol> 147 @ <ol> 148 @ <li><p>The permission flags are as follows:</p> 148 @ <li><p>The permission flags are as follows:</p> 149 @ <table> 149 @ <table> 150 @ <tr><td valign="top"><b>a</b></td> 150 @ <tr><td valign="top"><b>a</b></td> 151 @ <td><i>Admin:</i> Create and delete users</td></tr> 151 @ <td><i>Admin:</i> Create and delete users</td></tr> > 152 @ <tr><td valign="top"><b>b</b></td> > 153 @ <td><i>Attach:</i> Add attachments to wiki or tickets</td></tr> 152 @ <tr><td valign="top"><b>c</b></td> 154 @ <tr><td valign="top"><b>c</b></td> 153 @ <td><i>Append-Tkt:</i> Append to tickets</td></tr> 155 @ <td><i>Append-Tkt:</i> Append to tickets</td></tr> 154 @ <tr><td valign="top"><b>d</b></td> 156 @ <tr><td valign="top"><b>d</b></td> 155 @ <td><i>Delete:</i> Delete wiki and tickets</td></tr> 157 @ <td><i>Delete:</i> Delete wiki and tickets</td></tr> 156 @ <tr><td valign="top"><b>e</b></td> 158 @ <tr><td valign="top"><b>e</b></td> 157 @ <td><i>Email:</i> View sensitive data such as EMail addresses</td></tr> 159 @ <td><i>Email:</i> View sensitive data such as EMail addresses</td></tr> 158 @ <tr><td valign="top"><b>f</b></td> 160 @ <tr><td valign="top"><b>f</b></td> ................................................................................................................................................................................ 237 /* 239 /* 238 ** WEBPAGE: /setup_uedit 240 ** WEBPAGE: /setup_uedit 239 */ 241 */ 240 void user_edit(void){ 242 void user_edit(void){ 241 const char *zId, *zLogin, *zInfo, *zCap, *zPw; 243 const char *zId, *zLogin, *zInfo, *zCap, *zPw; 242 char *oaa, *oas, *oar, *oaw, *oan, *oai, *oaj, *oao, *oap; 244 char *oaa, *oas, *oar, *oaw, *oan, *oai, *oaj, *oao, *oap; 243 char *oak, *oad, *oac, *oaf, *oam, *oah, *oag, *oae; 245 char *oak, *oad, *oac, *oaf, *oam, *oah, *oag, *oae; 244 char *oat, *oau, *oav, *oaz; | 246 char *oat, *oau, *oav, *oab, *oaz; 245 const char *inherit[128]; 247 const char *inherit[128]; 246 int doWrite; 248 int doWrite; 247 int uid; 249 int uid; 248 int higherUser = 0; /* True if user being edited is SETUP and the */ 250 int higherUser = 0; /* True if user being edited is SETUP and the */ 249 /* user doing the editing is ADMIN. Disallow editing */ 251 /* user doing the editing is ADMIN. Disallow editing */ 250 252 251 /* Must have ADMIN privleges to access this page 253 /* Must have ADMIN privleges to access this page ................................................................................................................................................................................ 274 ** to the page that displays a list of users. 276 ** to the page that displays a list of users. 275 */ 277 */ 276 doWrite = cgi_all("login","info","pw") && !higherUser; 278 doWrite = cgi_all("login","info","pw") && !higherUser; 277 if( doWrite ){ 279 if( doWrite ){ 278 char zCap[50]; 280 char zCap[50]; 279 int i = 0; 281 int i = 0; 280 int aa = P("aa")!=0; 282 int aa = P("aa")!=0; > 283 int ab = P("ab")!=0; 281 int ad = P("ad")!=0; 284 int ad = P("ad")!=0; 282 int ae = P("ae")!=0; 285 int ae = P("ae")!=0; 283 int ai = P("ai")!=0; 286 int ai = P("ai")!=0; 284 int aj = P("aj")!=0; 287 int aj = P("aj")!=0; 285 int ak = P("ak")!=0; 288 int ak = P("ak")!=0; 286 int an = P("an")!=0; 289 int an = P("an")!=0; 287 int ao = P("ao")!=0; 290 int ao = P("ao")!=0; ................................................................................................................................................................................ 295 int ah = P("ah")!=0; 298 int ah = P("ah")!=0; 296 int ag = P("ag")!=0; 299 int ag = P("ag")!=0; 297 int at = P("at")!=0; 300 int at = P("at")!=0; 298 int au = P("au")!=0; 301 int au = P("au")!=0; 299 int av = P("av")!=0; 302 int av = P("av")!=0; 300 int az = P("az")!=0; 303 int az = P("az")!=0; 301 if( aa ){ zCap[i++] = 'a'; } 304 if( aa ){ zCap[i++] = 'a'; } > 305 if( ab ){ zCap[i++] = 'b'; } 302 if( ac ){ zCap[i++] = 'c'; } 306 if( ac ){ zCap[i++] = 'c'; } 303 if( ad ){ zCap[i++] = 'd'; } 307 if( ad ){ zCap[i++] = 'd'; } 304 if( ae ){ zCap[i++] = 'e'; } 308 if( ae ){ zCap[i++] = 'e'; } 305 if( af ){ zCap[i++] = 'f'; } 309 if( af ){ zCap[i++] = 'f'; } 306 if( ah ){ zCap[i++] = 'h'; } 310 if( ah ){ zCap[i++] = 'h'; } 307 if( ag ){ zCap[i++] = 'g'; } 311 if( ag ){ zCap[i++] = 'g'; } 308 if( ai ){ zCap[i++] = 'i'; } 312 if( ai ){ zCap[i++] = 'i'; } ................................................................................................................................................................................ 351 355 352 /* Load the existing information about the user, if any 356 /* Load the existing information about the user, if any 353 */ 357 */ 354 zLogin = ""; 358 zLogin = ""; 355 zInfo = ""; 359 zInfo = ""; 356 zCap = ""; 360 zCap = ""; 357 zPw = ""; 361 zPw = ""; 358 oaa = oac = oad = oae = oaf = oag = oah = oai = oaj = oak = oam = | 362 oaa = oab = oac = oad = oae = oaf = oag = oah = oai = oaj = oak = oam = 359 oan = oao = oap = oar = oas = oat = oau = oav = oaw = oaz = ""; 363 oan = oao = oap = oar = oas = oat = oau = oav = oaw = oaz = ""; 360 if( uid ){ 364 if( uid ){ 361 zLogin = db_text("", "SELECT login FROM user WHERE uid=%d", uid); 365 zLogin = db_text("", "SELECT login FROM user WHERE uid=%d", uid); 362 zInfo = db_text("", "SELECT info FROM user WHERE uid=%d", uid); 366 zInfo = db_text("", "SELECT info FROM user WHERE uid=%d", uid); 363 zCap = db_text("", "SELECT cap FROM user WHERE uid=%d", uid); 367 zCap = db_text("", "SELECT cap FROM user WHERE uid=%d", uid); 364 zPw = db_text("", "SELECT pw FROM user WHERE uid=%d", uid); 368 zPw = db_text("", "SELECT pw FROM user WHERE uid=%d", uid); 365 if( strchr(zCap, 'a') ) oaa = " checked"; 369 if( strchr(zCap, 'a') ) oaa = " checked"; > 370 if( strchr(zCap, 'b') ) oab = " checked"; 366 if( strchr(zCap, 'c') ) oac = " checked"; 371 if( strchr(zCap, 'c') ) oac = " checked"; 367 if( strchr(zCap, 'd') ) oad = " checked"; 372 if( strchr(zCap, 'd') ) oad = " checked"; 368 if( strchr(zCap, 'e') ) oae = " checked"; 373 if( strchr(zCap, 'e') ) oae = " checked"; 369 if( strchr(zCap, 'f') ) oaf = " checked"; 374 if( strchr(zCap, 'f') ) oaf = " checked"; 370 if( strchr(zCap, 'g') ) oag = " checked"; 375 if( strchr(zCap, 'g') ) oag = " checked"; 371 if( strchr(zCap, 'h') ) oah = " checked"; 376 if( strchr(zCap, 'h') ) oah = " checked"; 372 if( strchr(zCap, 'i') ) oai = " checked"; 377 if( strchr(zCap, 'i') ) oai = " checked"; ................................................................................................................................................................................ 465 @ <input type="checkbox" name="au"%s(oau)/>%s(B('u'))Reader<br> 470 @ <input type="checkbox" name="au"%s(oau)/>%s(B('u'))Reader<br> 466 @ <input type="checkbox" name="av"%s(oav)/>%s(B('v'))Developer<br> 471 @ <input type="checkbox" name="av"%s(oav)/>%s(B('v'))Developer<br> 467 @ <input type="checkbox" name="ag"%s(oag)/>%s(B('g'))Clone<br> 472 @ <input type="checkbox" name="ag"%s(oag)/>%s(B('g'))Clone<br> 468 @ <input type="checkbox" name="aj"%s(oaj)/>%s(B('j'))Read Wiki<br> 473 @ <input type="checkbox" name="aj"%s(oaj)/>%s(B('j'))Read Wiki<br> 469 @ <input type="checkbox" name="af"%s(oaf)/>%s(B('f'))New Wiki<br> 474 @ <input type="checkbox" name="af"%s(oaf)/>%s(B('f'))New Wiki<br> 470 @ <input type="checkbox" name="am"%s(oam)/>%s(B('m'))Append Wiki<br> 475 @ <input type="checkbox" name="am"%s(oam)/>%s(B('m'))Append Wiki<br> 471 @ <input type="checkbox" name="ak"%s(oak)/>%s(B('k'))Write Wiki<br> 476 @ <input type="checkbox" name="ak"%s(oak)/>%s(B('k'))Write Wiki<br> > 477 @ <input type="checkbox" name="ab"%s(oab)/>%s(B('b'))Attachments<br> 472 @ <input type="checkbox" name="ar"%s(oar)/>%s(B('r'))Read Tkt<br> | 478 @ <input type="checkbox" name="ar"%s(oar)/>%s(B('r'))Read Ticket<br> 473 @ <input type="checkbox" name="an"%s(oan)/>%s(B('n'))New Tkt<br> | 479 @ <input type="checkbox" name="an"%s(oan)/>%s(B('n'))New Ticket<br> 474 @ <input type="checkbox" name="ac"%s(oac)/>%s(B('c'))Append Tkt<br> | 480 @ <input type="checkbox" name="ac"%s(oac)/>%s(B('c'))Append Ticket<br> 475 @ <input type="checkbox" name="aw"%s(oaw)/>%s(B('w'))Write Tkt<br> | 481 @ <input type="checkbox" name="aw"%s(oaw)/>%s(B('w'))Write Ticket<br> 476 @ <input type="checkbox" name="at"%s(oat)/>%s(B('t'))Tkt Report<br> | 482 @ <input type="checkbox" name="at"%s(oat)/>%s(B('t'))Ticket Report<br> 477 @ <input type="checkbox" name="az"%s(oaz)/>%s(B('z'))Download Zip 483 @ <input type="checkbox" name="az"%s(oaz)/>%s(B('z'))Download Zip 478 @ </td> 484 @ </td> 479 @ </tr> 485 @ </tr> 480 @ <tr> 486 @ <tr> 481 @ <td align="right">Password:</td> 487 @ <td align="right">Password:</td> 482 if( zPw[0] ){ 488 if( zPw[0] ){ 483 /* Obscure the password for all users */ 489 /* Obscure the password for all users */ ................................................................................................................................................................................ 562 @ The <b>Check-out</b> privilege allows remote users to "pull". 568 @ The <b>Check-out</b> privilege allows remote users to "pull". 563 @ The <b>Clone</b> privilege allows remote users to "clone". 569 @ The <b>Clone</b> privilege allows remote users to "clone". 564 @ </li><p> 570 @ </li><p> 565 @ 571 @ 566 @ <li><p> 572 @ <li><p> 567 @ The <b>Read Wiki</b>, <b>New Wiki</b>, <b>Append Wiki</b>, and 573 @ The <b>Read Wiki</b>, <b>New Wiki</b>, <b>Append Wiki</b>, and 568 @ <b>Write Wiki</b> privileges control access to wiki pages. The 574 @ <b>Write Wiki</b> privileges control access to wiki pages. The 569 @ <b>Read Tkt</b>, <b>New Tkt</b>, <b>Append Tkt</b>, and | 575 @ <b>Read Ticket</b>, <b>New Ticket</b>, <b>Append Ticket</b>, and 570 @ <b>Write Tkt</b> privileges control access to trouble tickets. | 576 @ <b>Write Ticket</b> privileges control access to trouble tickets. 571 @ The <b>Tkt Report</b> privilege allows the user to create or edit | 577 @ The <b>Ticket Report</b> privilege allows the user to create or edit 572 @ ticket report formats. 578 @ ticket report formats. 573 @ </p></li> 579 @ </p></li> 574 @ 580 @ 575 @ <li><p> 581 @ <li><p> 576 @ Users with the <b>Password</b> privilege are allowed to change their 582 @ Users with the <b>Password</b> privilege are allowed to change their 577 @ own password. Recommended ON for most users but OFF for special 583 @ own password. Recommended ON for most users but OFF for special 578 @ users "developer", "anonymous", and "nobody". 584 @ users "developer", "anonymous", and "nobody". ................................................................................................................................................................................ 581 @ <li><p> 587 @ <li><p> 582 @ The <b>EMail</b> privilege allows the display of sensitive information 588 @ The <b>EMail</b> privilege allows the display of sensitive information 583 @ such as the email address of users and contact information on tickets. 589 @ such as the email address of users and contact information on tickets. 584 @ Recommended OFF for "anonymous" and for "nobody" but ON for 590 @ Recommended OFF for "anonymous" and for "nobody" but ON for 585 @ "developer". 591 @ "developer". 586 @ </p></li> 592 @ </p></li> 587 @ 593 @ > 594 @ <li><p> > 595 @ The <b>Attachment</b> privilege is needed in order to add attachments > 596 @ to tickets or wiki. Write privilege on the ticket or wiki is also > 597 @ required.</p></li> > 598 @ 588 @ <li><p> 599 @ <li><p> 589 @ Login is prohibited if the password is an empty string. 600 @ Login is prohibited if the password is an empty string. 590 @ </p></li> 601 @ </p></li> 591 @ </ul> 602 @ </ul> 592 @ 603 @ 593 @ <h2>Special Logins</h2> 604 @ <h2>Special Logins</h2> 594 @ 605 @

Changes to src/tkt.c

294 ** WEBPAGE: tktview 294 ** WEBPAGE: tktview 295 ** URL: tktview?name=UUID 295 ** URL: tktview?name=UUID 296 ** 296 ** 297 ** View a ticket. 297 ** View a ticket. 298 */ 298 */ 299 void tktview_page(void){ 299 void tktview_page(void){ 300 const char *zScript; 300 const char *zScript; > 301 char *zFullName; > 302 const char *zUuid = PD("name",""); > 303 301 login_check_credentials(); 304 login_check_credentials(); 302 if( !g.okRdTkt ){ login_needed(); return; } 305 if( !g.okRdTkt ){ login_needed(); return; } 303 if( g.okWrTkt || g.okApndTkt ){ 306 if( g.okWrTkt || g.okApndTkt ){ 304 style_submenu_element("Edit", "Edit The Ticket", "%s/tktedit?name=%T", 307 style_submenu_element("Edit", "Edit The Ticket", "%s/tktedit?name=%T", 305 g.zTop, PD("name","")); 308 g.zTop, PD("name","")); 306 } 309 } 307 if( g.okHistory ){ 310 if( g.okHistory ){ 308 const char *zUuid = PD("name",""); < 309 style_submenu_element("History", "History Of This Ticket", 311 style_submenu_element("History", "History Of This Ticket", 310 "%s/tkthistory/%T", g.zTop, zUuid); 312 "%s/tkthistory/%T", g.zTop, zUuid); 311 style_submenu_element("Timeline", "Timeline Of This Ticket", 313 style_submenu_element("Timeline", "Timeline Of This Ticket", 312 "%s/tkttimeline/%T", g.zTop, zUuid); 314 "%s/tkttimeline/%T", g.zTop, zUuid); 313 style_submenu_element("Check-ins", "Check-ins Of This Ticket", 315 style_submenu_element("Check-ins", "Check-ins Of This Ticket", 314 "%s/tkttimeline/%T?y=ci", g.zTop, zUuid); 316 "%s/tkttimeline/%T?y=ci", g.zTop, zUuid); 315 } 317 } 316 if( g.okNewTkt ){ 318 if( g.okNewTkt ){ 317 style_submenu_element("New Ticket", "Create a new ticket", 319 style_submenu_element("New Ticket", "Create a new ticket", 318 "%s/tktnew", g.zTop); 320 "%s/tktnew", g.zTop); 319 } 321 } > 322 if( g.okApndTkt && g.okAttach ){ > 323 style_submenu_element("Attach", "Add An Attachment", > 324 "%s/attachadd?tkt=%T&from=%s/tktview%%3fname=%t", > 325 g.zTop, zUuid, g.zTop, zUuid); > 326 } 320 style_header("View Ticket"); 327 style_header("View Ticket"); 321 if( g.thTrace ) Th_Trace("BEGIN_TKTVIEW<br />\n", -1); 328 if( g.thTrace ) Th_Trace("BEGIN_TKTVIEW<br />\n", -1); 322 ticket_init(); 329 ticket_init(); 323 initializeVariablesFromDb(); 330 initializeVariablesFromDb(); 324 zScript = ticket_viewpage_code(); 331 zScript = ticket_viewpage_code(); 325 if( g.thTrace ) Th_Trace("BEGIN_TKTVIEW_SCRIPT<br />\n", -1); 332 if( g.thTrace ) Th_Trace("BEGIN_TKTVIEW_SCRIPT<br />\n", -1); 326 Th_Render(zScript); 333 Th_Render(zScript); 327 if( g.thTrace ) Th_Trace("END_TKTVIEW<br />\n", -1); 334 if( g.thTrace ) Th_Trace("END_TKTVIEW<br />\n", -1); > 335 > 336 zFullName = db_text(0, > 337 "SELECT tkt_uuid FROM ticket" > 338 " WHERE tkt_uuid GLOB '%q*'", zUuid); > 339 if( zFullName ){ > 340 int cnt = 0; > 341 Stmt q; > 342 db_prepare(&q, > 343 "SELECT datetime(mtime,'localtime'), filename, user" > 344 " FROM attachment" > 345 " WHERE isLatest AND src!='' AND target=%Q" > 346 " ORDER BY mtime DESC", > 347 zFullName); > 348 while( db_step(&q)==SQLITE_ROW ){ > 349 const char *zDate = db_column_text(&q, 0); > 350 const char *zFile = db_column_text(&q, 1); > 351 const char *zUser = db_column_text(&q, 2); > 352 if( cnt==0 ){ > 353 @ <hr><h2>Attachments:</h2> > 354 @ <ul> > 355 } > 356 cnt++; > 357 @ <li><a href="%s(g.zTop)/attachview?tkt=%s(zFullName)&file=%t(zFile)"> > 358 @ %h(zFile)</a> add by %h(zUser) on > 359 hyperlink_to_date(zDate, "."); > 360 if( g.okWrTkt && g.okAttach ){ > 361 @ [<a href="%s(g.zTop)/attachdelete?tkt=%s(zFullName)&file=%t(zFile)&fro > 362 } > 363 } > 364 if( cnt ){ > 365 @ </ul> > 366 } > 367 db_finalize(&q); > 368 } > 369 328 style_footer(); 370 style_footer(); 329 } 371 } 330 372 331 /* 373 /* 332 ** TH command: append_field FIELD STRING 374 ** TH command: append_field FIELD STRING 333 ** 375 ** 334 ** FIELD is the name of a database column to which we might want 376 ** FIELD is the name of a database column to which we might want ................................................................................................................................................................................ 639 "AND '%s' GLOB (target||'*')) " 681 "AND '%s' GLOB (target||'*')) " 640 "ORDER BY mtime DESC", 682 "ORDER BY mtime DESC", 641 timeline_query_for_www(), zFullUuid, zFullUuid 683 timeline_query_for_www(), zFullUuid, zFullUuid 642 ); 684 ); 643 }else{ 685 }else{ 644 zSQL = mprintf( 686 zSQL = mprintf( 645 "%s AND event.objid IN " 687 "%s AND event.objid IN " 646 " (SELECT rid FROM tagxref WHERE tagid=%d UNION" | 688 " (SELECT rid FROM tagxref WHERE tagid=%d" > 689 " UNION SELECT srcid FROM backlink" 647 " SELECT srcid FROM backlink WHERE target GLOB '%.4s*' " | 690 " WHERE target GLOB '%.4s*'" 648 "AND '%s' GLOB (target||'*')) " | 691 " AND '%s' GLOB (target||'*')" > 692 " UNION SELECT attachid FROM attachment" > 693 " WHERE target=%Q) " 649 "ORDER BY mtime DESC", 694 "ORDER BY mtime DESC", 650 timeline_query_for_www(), tagid, zFullUuid, zFullUuid | 695 timeline_query_for_www(), tagid, zFullUuid, zFullUuid, zFullUuid 651 ); 696 ); 652 } 697 } 653 db_prepare(&q, zSQL); 698 db_prepare(&q, zSQL); 654 free(zSQL); 699 free(zSQL); 655 www_print_timeline(&q, TIMELINE_ARTID, 0); 700 www_print_timeline(&q, TIMELINE_ARTID, 0); 656 db_finalize(&q); 701 db_finalize(&q); 657 style_footer(); 702 style_footer(); ................................................................................................................................................................................ 685 tagid = db_int(0, "SELECT tagid FROM tag WHERE tagname GLOB 'tkt-%q*'",zUuid); 730 tagid = db_int(0, "SELECT tagid FROM tag WHERE tagname GLOB 'tkt-%q*'",zUuid); 686 if( tagid==0 ){ 731 if( tagid==0 ){ 687 @ No such ticket: %h(zUuid) 732 @ No such ticket: %h(zUuid) 688 style_footer(); 733 style_footer(); 689 return; 734 return; 690 } 735 } 691 db_prepare(&q, 736 db_prepare(&q, > 737 "SELECT datetime(mtime,'localtime'), objid, uuid, NULL, NULL, NULL" 692 "SELECT objid, uuid FROM event, blob" | 738 " FROM event, blob" 693 " WHERE objid IN (SELECT rid FROM tagxref WHERE tagid=%d)" 739 " WHERE objid IN (SELECT rid FROM tagxref WHERE tagid=%d)" 694 " AND blob.rid=event.objid" 740 " AND blob.rid=event.objid" > 741 " UNION " > 742 "SELECT datetime(mtime,'localtime'), attachid, uuid, src, filename, user" > 743 " FROM attachment, blob" > 744 " WHERE target=(SELECT substr(tagname,5) FROM tag WHERE tagid=%d)" > 745 " AND blob.rid=attachid" 695 " ORDER BY mtime DESC", | 746 " ORDER BY 1 DESC", 696 tagid | 747 tagid, tagid 697 ); 748 ); 698 while( db_step(&q)==SQLITE_ROW ){ 749 while( db_step(&q)==SQLITE_ROW ){ 699 Blob content; 750 Blob content; 700 Manifest m; 751 Manifest m; > 752 char zShort[12]; > 753 const char *zDate = db_column_text(&q, 0); 701 int rid = db_column_int(&q, 0); | 754 int rid = db_column_int(&q, 1); 702 const char *zChngUuid = db_column_text(&q, 1); | 755 const char *zChngUuid = db_column_text(&q, 2); 703 content_get(rid, &content); < 704 if( manifest_parse(&m, &content) && m.type==CFTYPE_TICKET ){ < 705 char *zDate = db_text(0, "SELECT datetime(%.12f)", m.rDate); | 756 const char *zFile = db_column_text(&q, 4); 706 char zUuid[12]; < 707 memcpy(zUuid, zChngUuid, 10); | 757 memcpy(zShort, zChngUuid, 10); 708 zUuid[10] = 0; | 758 zShort[10] = 0; 709 @ < > 759 if( zFile!=0 ){ > 760 const char *zSrc = db_column_text(&q, 3); 710 @ Ticket change | 761 const char *zUser = db_column_text(&q, 5); > 762 if( zSrc==0 || zSrc[0]==0 ){ > 763 @ > 764 @ <p>Delete attachment "%h(zFile)" > 765 }else{ > 766 @ > 767 @ <p>Add attachment "%h(zFile)" > 768 } 711 @ [<a href="%s(g.zTop)/artifact/%T(zChngUuid)">%s(zUuid)</a>]</a> | 769 @ [<a href="%s(g.zTop)/artifact/%T(zChngUuid)">%s(zShort)</a>] 712 @ (rid %d(rid)) by 770 @ (rid %d(rid)) by > 771 hyperlink_to_user(zUser,zDate," on"); > 772 hyperlink_to_date(zDate, ".</p>"); > 773 }else{ > 774 content_get(rid, &content); > 775 if( manifest_parse(&m, &content) && m.type==CFTYPE_TICKET ){ > 776 @ > 777 @ <p>Ticket change > 778 @ [<a href="%s(g.zTop)/artifact/%T(zChngUuid)">%s(zShort)</a>] > 779 @ (rid %d(rid)) by 713 hyperlink_to_user(m.zUser,zDate," on"); | 780 hyperlink_to_user(m.zUser,zDate," on"); 714 hyperlink_to_date(zDate, ":"); | 781 hyperlink_to_date(zDate, ":"); 715 free(zDate); < 716 ticket_output_change_artifact(&m); | 782 ticket_output_change_artifact(&m); > 783 @ </p> > 784 } > 785 manifest_clear(&m); 717 } 786 } 718 manifest_clear(&m); < 719 } 787 } 720 db_finalize(&q); 788 db_finalize(&q); 721 style_footer(); 789 style_footer(); 722 } 790 } 723 791 724 /* 792 /* 725 ** Return TRUE if the given BLOB contains a newline character. 793 ** Return TRUE if the given BLOB contains a newline character.

Changes to src/wiki.c

125 char *zTag; 125 char *zTag; 126 int rid = 0; 126 int rid = 0; 127 int isSandbox; 127 int isSandbox; 128 Blob wiki; 128 Blob wiki; 129 Manifest m; 129 Manifest m; 130 const char *zPageName; 130 const char *zPageName; 131 char *zBody = mprintf("%s","<i>Empty Page</i>"); 131 char *zBody = mprintf("%s","<i>Empty Page</i>"); > 132 Stmt q; > 133 int cnt = 0; 132 134 133 login_check_credentials(); 135 login_check_credentials(); 134 if( !g.okRdWiki ){ login_needed(); return; } 136 if( !g.okRdWiki ){ login_needed(); return; } 135 zPageName = P("name"); 137 zPageName = P("name"); 136 if( zPageName==0 ){ 138 if( zPageName==0 ){ 137 style_header("Wiki"); 139 style_header("Wiki"); 138 @ <ul> 140 @ <ul> ................................................................................................................................................................................ 150 @ to experiment.</li> 152 @ to experiment.</li> 151 if( g.okNewWiki ){ 153 if( g.okNewWiki ){ 152 @ <li> Create a <a href="%s(g.zBaseURL)/wikinew">new wiki page</a>.</li> 154 @ <li> Create a <a href="%s(g.zBaseURL)/wikinew">new wiki page</a>.</li> 153 } 155 } 154 @ <li> <a href="%s(g.zBaseURL)/wcontent">List of All Wiki Pages</a> 156 @ <li> <a href="%s(g.zBaseURL)/wcontent">List of All Wiki Pages</a> 155 @ available on this server.</li> 157 @ available on this server.</li> 156 @ <li> <form method="GET" action="%s(g.zBaseURL)/wfind"> 158 @ <li> <form method="GET" action="%s(g.zBaseURL)/wfind"> 157 @ Search wiki titles: <input type="text" name="title"/> &nbsp; <inpu | 159 @ Search wiki titles: <input type="text" name="title"/> > 160 @ &nbsp; <input type="submit" /> 158 @ </li> 161 @ </li> 159 @ </ul> 162 @ </ul> 160 style_footer(); 163 style_footer(); 161 return; 164 return; 162 } 165 } 163 if( check_name(zPageName) ) return; 166 if( check_name(zPageName) ) return; 164 isSandbox = is_sandbox(zPageName); 167 isSandbox = is_sandbox(zPageName); ................................................................................................................................................................................ 184 } 187 } 185 } 188 } 186 if( !g.isHome ){ 189 if( !g.isHome ){ 187 if( (rid && g.okWrWiki) || (!rid && g.okNewWiki) ){ 190 if( (rid && g.okWrWiki) || (!rid && g.okNewWiki) ){ 188 style_submenu_element("Edit", "Edit Wiki Page", "%s/wikiedit?name=%T", 191 style_submenu_element("Edit", "Edit Wiki Page", "%s/wikiedit?name=%T", 189 g.zTop, zPageName); 192 g.zTop, zPageName); 190 } 193 } > 194 if( rid && g.okWrWiki && g.okAttach ){ > 195 style_submenu_element("Attach", "Add An Attachment", > 196 "%s/attachadd?page=%T&from=%s/wiki%%3fname=%T", > 197 g.zTop, zPageName, g.zTop, zPageName); > 198 } 191 if( rid && g.okApndWiki ){ 199 if( rid && g.okApndWiki ){ 192 style_submenu_element("Append", "Add A Comment", "%s/wikiappend?name=%T", 200 style_submenu_element("Append", "Add A Comment", "%s/wikiappend?name=%T", 193 g.zTop, zPageName); 201 g.zTop, zPageName); 194 } 202 } 195 if( g.okHistory ){ 203 if( g.okHistory ){ 196 style_submenu_element("History", "History", "%s/whistory?name=%T", 204 style_submenu_element("History", "History", "%s/whistory?name=%T", 197 g.zTop, zPageName); 205 g.zTop, zPageName); 198 } 206 } 199 } 207 } 200 style_header(zPageName); 208 style_header(zPageName); 201 blob_init(&wiki, zBody, -1); 209 blob_init(&wiki, zBody, -1); 202 wiki_convert(&wiki, 0, 0); 210 wiki_convert(&wiki, 0, 0); 203 blob_reset(&wiki); 211 blob_reset(&wiki); > 212 > 213 db_prepare(&q, > 214 "SELECT datetime(mtime,'localtime'), filename, user" > 215 " FROM attachment" > 216 " WHERE isLatest AND src!='' AND target=%Q" > 217 " ORDER BY mtime DESC", > 218 zPageName); > 219 while( db_step(&q)==SQLITE_ROW ){ > 220 const char *zDate = db_column_text(&q, 0); > 221 const char *zFile = db_column_text(&q, 1); > 222 const char *zUser = db_column_text(&q, 2); > 223 if( cnt==0 ){ > 224 @ <hr><h2>Attachments:</h2> > 225 @ <ul> > 226 } > 227 cnt++; > 228 @ <li><a href="%s(g.zTop)/attachview?page=%s(zPageName)&file=%t(zFile)"> > 229 @ %h(zFile)</a> add by %h(zUser) on > 230 hyperlink_to_date(zDate, "."); > 231 if( g.okWrWiki && g.okAttach ){ > 232 @ [<a href="%s(g.zTop)/attachdelete?page=%s(zPageName)&file=%t(zFile)&from > 233 } > 234 } > 235 if( cnt ){ > 236 @ </ul> > 237 } > 238 db_finalize(&q); > 239 204 if( !isSandbox ){ 240 if( !isSandbox ){ 205 manifest_clear(&m); 241 manifest_clear(&m); 206 } 242 } 207 style_footer(); 243 style_footer(); 208 } 244 } 209 245 210 /* 246 /* ................................................................................................................................................................................ 513 static const char *zWikiPageName; 549 static const char *zWikiPageName; 514 550 515 /* 551 /* 516 ** Function called to output extra text at the end of each line in 552 ** Function called to output extra text at the end of each line in 517 ** a wiki history listing. 553 ** a wiki history listing. 518 */ 554 */ 519 static void wiki_history_extra(int rid){ 555 static void wiki_history_extra(int rid){ > 556 if( db_exists("SELECT 1 FROM tagxref WHERE rid=%d", rid) ){ 520 @ <a href="%s(g.zTop)/wdiff?name=%t(zWikiPageName)&a=%d(rid)">[diff]</a> | 557 @ <a href="%s(g.zTop)/wdiff?name=%t(zWikiPageName)&a=%d(rid)">[diff]</a> > 558 } 521 } 559 } 522 560 523 /* 561 /* 524 ** WEBPAGE: whistory 562 ** WEBPAGE: whistory 525 ** URL: /whistory?name=PAGENAME 563 ** URL: /whistory?name=PAGENAME 526 ** 564 ** 527 ** Show the complete change history for a single wiki page. 565 ** Show the complete change history for a single wiki page. ................................................................................................................................................................................ 536 zPageName = PD("name",""); 574 zPageName = PD("name",""); 537 zTitle = mprintf("History Of %s", zPageName); 575 zTitle = mprintf("History Of %s", zPageName); 538 style_header(zTitle); 576 style_header(zTitle); 539 free(zTitle); 577 free(zTitle); 540 578 541 zSQL = mprintf("%s AND event.objid IN " 579 zSQL = mprintf("%s AND event.objid IN " 542 " (SELECT rid FROM tagxref WHERE tagid=" 580 " (SELECT rid FROM tagxref WHERE tagid=" 543 "(SELECT tagid FROM tag WHERE tagname='wiki-%q'))" | 581 "(SELECT tagid FROM tag WHERE tagname='wiki-%q')" > 582 " UNION SELECT attachid FROM attachment" > 583 " WHERE target=%Q)" 544 "ORDER BY mtime DESC", 584 "ORDER BY mtime DESC", 545 timeline_query_for_www(), zPageName); | 585 timeline_query_for_www(), zPageName, zPageName); 546 db_prepare(&q, zSQL); 586 db_prepare(&q, zSQL); 547 free(zSQL); 587 free(zSQL); 548 zWikiPageName = zPageName; 588 zWikiPageName = zPageName; 549 www_print_timeline(&q, TIMELINE_ARTID, wiki_history_extra); 589 www_print_timeline(&q, TIMELINE_ARTID, wiki_history_extra); 550 db_finalize(&q); 590 db_finalize(&q); 551 style_footer(); 591 style_footer(); 552 } 592 } ................................................................................................................................................................................ 602 @ %h(blob_str(&d)) 642 @ %h(blob_str(&d)) 603 @ </pre> 643 @ </pre> 604 style_footer(); 644 style_footer(); 605 } 645 } 606 646 607 /* 647 /* 608 ** WEBPAGE: wcontent 648 ** WEBPAGE: wcontent > 649 ** > 650 ** all=1 Show deleted pages 609 ** 651 ** 610 ** List all available wiki pages with date created and last modified. 652 ** List all available wiki pages with date created and last modified. 611 */ 653 */ 612 void wcontent_page(void){ 654 void wcontent_page(void){ 613 Stmt q; 655 Stmt q; > 656 int showAll = P("all")!=0; > 657 614 login_check_credentials(); 658 login_check_credentials(); 615 if( !g.okRdWiki ){ login_needed(); return; } 659 if( !g.okRdWiki ){ login_needed(); return; } 616 style_header("Available Wiki Pages"); 660 style_header("Available Wiki Pages"); > 661 if( showAll ){ > 662 style_submenu_element("Active", "Only Active Pages", "%s/wcontent", g.zTop); > 663 }else{ > 664 style_submenu_element("All", "All", "%s/wcontent?all=1", g.zTop); > 665 } 617 @ <ul> 666 @ <ul> 618 db_prepare(&q, 667 db_prepare(&q, > 668 "SELECT" > 669 " substr(tagname, 6)," > 670 " (SELECT value FROM tagxref WHERE tagid=tag.tagid ORDER BY mtime DESC)" 619 "SELECT substr(tagname, 6, 1000) FROM tag WHERE tagname GLOB 'wiki-*'" | 671 " FROM tag WHERE tagname GLOB 'wiki-*'" 620 " ORDER BY lower(tagname)" 672 " ORDER BY lower(tagname)" 621 ); 673 ); 622 while( db_step(&q)==SQLITE_ROW ){ 674 while( db_step(&q)==SQLITE_ROW ){ 623 const char *zName = db_column_text(&q, 0); 675 const char *zName = db_column_text(&q, 0); > 676 int size = db_column_int(&q, 1); > 677 if( size>0 ){ 624 @ <li><a href="%s(g.zBaseURL)/wiki?name=%T(zName)">%h(zName)</a></li> | 678 @ <li><a href="%s(g.zTop)/wiki?name=%T(zName)">%h(zName)</a></li> > 679 }else if( showAll ){ > 680 @ <li><a href="%s(g.zTop)/wiki?name=%T(zName)"><s>%h(zName)</s></a></li> > 681 } 625 } 682 } 626 db_finalize(&q); 683 db_finalize(&q); 627 @ </ul> 684 @ </ul> 628 style_footer(); 685 style_footer(); 629 } 686 } 630 687 631 /* 688 /*