Fossil SCM

Include non-sym- tags in tagview web page. Also merge mainline into tagview branch.

eric 2008-08-21 20:59 eric-tagview-rework merge
Commit 5fb14b9a0fa04a788de384897e65458a9d8f8eaa
+1 -1
--- src/admin.c
+++ src/admin.c
@@ -108,10 +108,10 @@
108108
}
109109
admin_prepare_submenu();
110110
style_header("Admin");
111111
@ <h2>Links:</h2>
112112
@ <ul>
113
- @ <li><a href='%s(g.zBaseURL)/admin/setup'>Fossil WWW Setup</a></li>
113
+ @ <li><a href='%s(g.zBaseURL)/setup'>Fossil WWW Setup</a></li>
114114
@ <li><a href='%s(g.zBaseURL)/admin/sql'>Run SQL queries</a></li>
115115
@ </ul>
116116
style_footer();
117117
}
118118
--- src/admin.c
+++ src/admin.c
@@ -108,10 +108,10 @@
108 }
109 admin_prepare_submenu();
110 style_header("Admin");
111 @ <h2>Links:</h2>
112 @ <ul>
113 @ <li><a href='%s(g.zBaseURL)/admin/setup'>Fossil WWW Setup</a></li>
114 @ <li><a href='%s(g.zBaseURL)/admin/sql'>Run SQL queries</a></li>
115 @ </ul>
116 style_footer();
117 }
118
--- src/admin.c
+++ src/admin.c
@@ -108,10 +108,10 @@
108 }
109 admin_prepare_submenu();
110 style_header("Admin");
111 @ <h2>Links:</h2>
112 @ <ul>
113 @ <li><a href='%s(g.zBaseURL)/setup'>Fossil WWW Setup</a></li>
114 @ <li><a href='%s(g.zBaseURL)/admin/sql'>Run SQL queries</a></li>
115 @ </ul>
116 style_footer();
117 }
118
+6 -2
--- src/checkin.c
+++ src/checkin.c
@@ -250,11 +250,15 @@
250250
}
251251
if( zEditor==0 ){
252252
zEditor = getenv("EDITOR");
253253
}
254254
if( zEditor==0 ){
255
+#ifdef __MINGW32__
256
+ zEditor = "notepad";
257
+#else
255258
zEditor = "ed";
259
+#endif
256260
}
257261
zFile = db_text(0, "SELECT '%qci-comment-' || hex(randomblob(6)) || '.txt'",
258262
g.zLocalRoot);
259263
#ifdef __MINGW32__
260264
blob_add_cr(&text);
@@ -329,11 +333,11 @@
329333
**
330334
** Usage: %fossil commit ?-m COMMENT? ?--nosign? ?FILE...?
331335
**
332336
** Create a new version containing all of the changes in the current
333337
** checkout. You will be prompted to enter a check-in comment unless
334
-** the "-m" option is used to specify a command line. You will be
338
+** the "-m" option is used to specify a comment line. You will be
335339
** prompted for your GPG passphrase in order to sign the new manifest
336340
** unless the "--nosign" options is used. All files that have
337341
** changed will be committed unless some subset of files is specified
338342
** on the command line.
339343
*/
@@ -593,11 +597,11 @@
593597
/*
594598
** COMMAND: test-import-manifest
595599
**
596600
** Usage: %fossil test-import-manifest DATE COMMENT ?-p PARENT_RECORDID?... ?-f (FILE_RECORDID PATH)?...
597601
**
598
-** Create a new version containing containing the specified file
602
+** Create a new version containing the specified file
599603
** revisions (if any), and child of the given PARENT version.
600604
*/
601605
void import_manifest_cmd(void){
602606
const char* zDate; /* argument - timestamp, as seconds since epoch (int) */
603607
const char* zComment; /* argument - manifest comment */
604608
--- src/checkin.c
+++ src/checkin.c
@@ -250,11 +250,15 @@
250 }
251 if( zEditor==0 ){
252 zEditor = getenv("EDITOR");
253 }
254 if( zEditor==0 ){
 
 
 
255 zEditor = "ed";
 
256 }
257 zFile = db_text(0, "SELECT '%qci-comment-' || hex(randomblob(6)) || '.txt'",
258 g.zLocalRoot);
259 #ifdef __MINGW32__
260 blob_add_cr(&text);
@@ -329,11 +333,11 @@
329 **
330 ** Usage: %fossil commit ?-m COMMENT? ?--nosign? ?FILE...?
331 **
332 ** Create a new version containing all of the changes in the current
333 ** checkout. You will be prompted to enter a check-in comment unless
334 ** the "-m" option is used to specify a command line. You will be
335 ** prompted for your GPG passphrase in order to sign the new manifest
336 ** unless the "--nosign" options is used. All files that have
337 ** changed will be committed unless some subset of files is specified
338 ** on the command line.
339 */
@@ -593,11 +597,11 @@
593 /*
594 ** COMMAND: test-import-manifest
595 **
596 ** Usage: %fossil test-import-manifest DATE COMMENT ?-p PARENT_RECORDID?... ?-f (FILE_RECORDID PATH)?...
597 **
598 ** Create a new version containing containing the specified file
599 ** revisions (if any), and child of the given PARENT version.
600 */
601 void import_manifest_cmd(void){
602 const char* zDate; /* argument - timestamp, as seconds since epoch (int) */
603 const char* zComment; /* argument - manifest comment */
604
--- src/checkin.c
+++ src/checkin.c
@@ -250,11 +250,15 @@
250 }
251 if( zEditor==0 ){
252 zEditor = getenv("EDITOR");
253 }
254 if( zEditor==0 ){
255 #ifdef __MINGW32__
256 zEditor = "notepad";
257 #else
258 zEditor = "ed";
259 #endif
260 }
261 zFile = db_text(0, "SELECT '%qci-comment-' || hex(randomblob(6)) || '.txt'",
262 g.zLocalRoot);
263 #ifdef __MINGW32__
264 blob_add_cr(&text);
@@ -329,11 +333,11 @@
333 **
334 ** Usage: %fossil commit ?-m COMMENT? ?--nosign? ?FILE...?
335 **
336 ** Create a new version containing all of the changes in the current
337 ** checkout. You will be prompted to enter a check-in comment unless
338 ** the "-m" option is used to specify a comment line. You will be
339 ** prompted for your GPG passphrase in order to sign the new manifest
340 ** unless the "--nosign" options is used. All files that have
341 ** changed will be committed unless some subset of files is specified
342 ** on the command line.
343 */
@@ -593,11 +597,11 @@
597 /*
598 ** COMMAND: test-import-manifest
599 **
600 ** Usage: %fossil test-import-manifest DATE COMMENT ?-p PARENT_RECORDID?... ?-f (FILE_RECORDID PATH)?...
601 **
602 ** Create a new version containing the specified file
603 ** revisions (if any), and child of the given PARENT version.
604 */
605 void import_manifest_cmd(void){
606 const char* zDate; /* argument - timestamp, as seconds since epoch (int) */
607 const char* zComment; /* argument - manifest comment */
608
+3 -1
--- src/db.c
+++ src/db.c
@@ -789,13 +789,15 @@
789789
"INSERT INTO user(login, pw, cap, info)"
790790
"VALUES(%Q,'','s','')", zUser
791791
);
792792
db_multi_exec(
793793
"INSERT INTO user(login,pw,cap,info)"
794
- " VALUES('anonymous','anonymous','hjkorw','Anon');"
794
+ " VALUES('anonymous','anonymous','aghknw','Anon');"
795795
"INSERT INTO user(login,pw,cap,info)"
796796
" VALUES('nobody','','jor','Nobody');"
797
+ "INSERT INTO user(login,pw,cap,info)"
798
+ " VALUES('developer','','deipt','Dev');"
797799
);
798800
user_select();
799801
800802
if (makeInitialVersion){
801803
blob_zero(&manifest);
802804
--- src/db.c
+++ src/db.c
@@ -789,13 +789,15 @@
789 "INSERT INTO user(login, pw, cap, info)"
790 "VALUES(%Q,'','s','')", zUser
791 );
792 db_multi_exec(
793 "INSERT INTO user(login,pw,cap,info)"
794 " VALUES('anonymous','anonymous','hjkorw','Anon');"
795 "INSERT INTO user(login,pw,cap,info)"
796 " VALUES('nobody','','jor','Nobody');"
 
 
797 );
798 user_select();
799
800 if (makeInitialVersion){
801 blob_zero(&manifest);
802
--- src/db.c
+++ src/db.c
@@ -789,13 +789,15 @@
789 "INSERT INTO user(login, pw, cap, info)"
790 "VALUES(%Q,'','s','')", zUser
791 );
792 db_multi_exec(
793 "INSERT INTO user(login,pw,cap,info)"
794 " VALUES('anonymous','anonymous','aghknw','Anon');"
795 "INSERT INTO user(login,pw,cap,info)"
796 " VALUES('nobody','','jor','Nobody');"
797 "INSERT INTO user(login,pw,cap,info)"
798 " VALUES('developer','','deipt','Dev');"
799 );
800 user_select();
801
802 if (makeInitialVersion){
803 blob_zero(&manifest);
804
+8 -4
--- src/info.c
+++ src/info.c
@@ -116,11 +116,11 @@
116116
Stmt q;
117117
int cnt = 0;
118118
db_prepare(&q,
119119
"SELECT plink.cid, blob.uuid, datetime(plink.mtime, 'localtime'),"
120120
" coalesce(event.euser,event.user),"
121
- " coalesce(event.comment,event.ecomment)"
121
+ " coalesce(event.ecomment,event.comment)"
122122
" FROM plink, blob, event"
123123
" WHERE plink.pid=%d"
124124
" AND blob.rid=plink.cid"
125125
" AND event.objid=plink.cid"
126126
" ORDER BY plink.mtime ASC",
@@ -168,11 +168,11 @@
168168
Stmt q;
169169
int cnt = 0;
170170
db_prepare(&q,
171171
"SELECT plink.pid, blob.uuid, datetime(event.mtime, 'localtime'),"
172172
" coalesce(event.euser,event.user),"
173
- " coalesce(event.comment,event.ecomment)"
173
+ " coalesce(event.ecomment,event.comment)"
174174
" FROM plink, blob, event"
175175
" WHERE plink.cid=%d"
176176
" AND blob.rid=plink.pid"
177177
" AND event.objid=plink.pid"
178178
" ORDER BY event.mtime DESC",
@@ -354,25 +354,29 @@
354354
}else{
355355
@ <tr><th>Comment:</th><td>%w(zComment)</td></tr>
356356
}
357357
@ </td></tr>
358358
if( g.okHistory ){
359
+ char *zShortUuid = mprintf("%.10s", zUuid);
360
+ const char *zProjName = db_get("project-name", "unnamed");
359361
@ <tr><th>Timelines:</th><td>
360362
@ <a href="%s(g.zBaseURL)/timeline?p=%d(rid)">ancestors</a>
361363
@ | <a href="%s(g.zBaseURL)/timeline?d=%d(rid)">descendants</a>
362364
@ | <a href="%s(g.zBaseURL)/timeline?d=%d(rid)&p=%d(rid)">both</a>
363365
@ </td></tr>
364366
@ <tr><th>Commands:</th>
365367
@ <td>
366368
@ <a href="%s(g.zBaseURL)/vdiff/%d(rid)">diff</a>
367
- @ | <a href="%s(g.zBaseURL)/zip/%s(zUuid).zip">ZIP archive</a>
369
+ @ | <a href="%s(g.zBaseURL)/zip/%s(zProjName)-%s(zShortUuid).zip?uuid=%s(zUuid)">
370
+ @ ZIP archive</a>
368371
@ | <a href="%s(g.zBaseURL)/artifact/%d(rid)">manifest</a>
369372
if( g.okWrite ){
370373
@ | <a href="%s(g.zBaseURL)/vedit?r=%d(rid)">edit</a>
371374
}
372375
@ </td>
373376
@ </tr>
377
+ free(zShortUuid);
374378
}
375379
@ </table></p>
376380
}else{
377381
style_header("Baseline Information");
378382
login_anonymous_available();
@@ -655,11 +659,11 @@
655659
Stmt q;
656660
int cnt = 0;
657661
int nWiki = 0;
658662
db_prepare(&q,
659663
"SELECT filename.name, datetime(event.mtime), substr(a.uuid,1,10),"
660
- " coalesce(event.comment,event.ecomment),"
664
+ " coalesce(event.ecomment,event.comment),"
661665
" coalesce(event.euser,event.user),"
662666
" b.uuid"
663667
" FROM mlink, filename, event, blob a, blob b"
664668
" WHERE filename.fnid=mlink.fnid"
665669
" AND event.objid=mlink.mid"
666670
--- src/info.c
+++ src/info.c
@@ -116,11 +116,11 @@
116 Stmt q;
117 int cnt = 0;
118 db_prepare(&q,
119 "SELECT plink.cid, blob.uuid, datetime(plink.mtime, 'localtime'),"
120 " coalesce(event.euser,event.user),"
121 " coalesce(event.comment,event.ecomment)"
122 " FROM plink, blob, event"
123 " WHERE plink.pid=%d"
124 " AND blob.rid=plink.cid"
125 " AND event.objid=plink.cid"
126 " ORDER BY plink.mtime ASC",
@@ -168,11 +168,11 @@
168 Stmt q;
169 int cnt = 0;
170 db_prepare(&q,
171 "SELECT plink.pid, blob.uuid, datetime(event.mtime, 'localtime'),"
172 " coalesce(event.euser,event.user),"
173 " coalesce(event.comment,event.ecomment)"
174 " FROM plink, blob, event"
175 " WHERE plink.cid=%d"
176 " AND blob.rid=plink.pid"
177 " AND event.objid=plink.pid"
178 " ORDER BY event.mtime DESC",
@@ -354,25 +354,29 @@
354 }else{
355 @ <tr><th>Comment:</th><td>%w(zComment)</td></tr>
356 }
357 @ </td></tr>
358 if( g.okHistory ){
 
 
359 @ <tr><th>Timelines:</th><td>
360 @ <a href="%s(g.zBaseURL)/timeline?p=%d(rid)">ancestors</a>
361 @ | <a href="%s(g.zBaseURL)/timeline?d=%d(rid)">descendants</a>
362 @ | <a href="%s(g.zBaseURL)/timeline?d=%d(rid)&p=%d(rid)">both</a>
363 @ </td></tr>
364 @ <tr><th>Commands:</th>
365 @ <td>
366 @ <a href="%s(g.zBaseURL)/vdiff/%d(rid)">diff</a>
367 @ | <a href="%s(g.zBaseURL)/zip/%s(zUuid).zip">ZIP archive</a>
 
368 @ | <a href="%s(g.zBaseURL)/artifact/%d(rid)">manifest</a>
369 if( g.okWrite ){
370 @ | <a href="%s(g.zBaseURL)/vedit?r=%d(rid)">edit</a>
371 }
372 @ </td>
373 @ </tr>
 
374 }
375 @ </table></p>
376 }else{
377 style_header("Baseline Information");
378 login_anonymous_available();
@@ -655,11 +659,11 @@
655 Stmt q;
656 int cnt = 0;
657 int nWiki = 0;
658 db_prepare(&q,
659 "SELECT filename.name, datetime(event.mtime), substr(a.uuid,1,10),"
660 " coalesce(event.comment,event.ecomment),"
661 " coalesce(event.euser,event.user),"
662 " b.uuid"
663 " FROM mlink, filename, event, blob a, blob b"
664 " WHERE filename.fnid=mlink.fnid"
665 " AND event.objid=mlink.mid"
666
--- src/info.c
+++ src/info.c
@@ -116,11 +116,11 @@
116 Stmt q;
117 int cnt = 0;
118 db_prepare(&q,
119 "SELECT plink.cid, blob.uuid, datetime(plink.mtime, 'localtime'),"
120 " coalesce(event.euser,event.user),"
121 " coalesce(event.ecomment,event.comment)"
122 " FROM plink, blob, event"
123 " WHERE plink.pid=%d"
124 " AND blob.rid=plink.cid"
125 " AND event.objid=plink.cid"
126 " ORDER BY plink.mtime ASC",
@@ -168,11 +168,11 @@
168 Stmt q;
169 int cnt = 0;
170 db_prepare(&q,
171 "SELECT plink.pid, blob.uuid, datetime(event.mtime, 'localtime'),"
172 " coalesce(event.euser,event.user),"
173 " coalesce(event.ecomment,event.comment)"
174 " FROM plink, blob, event"
175 " WHERE plink.cid=%d"
176 " AND blob.rid=plink.pid"
177 " AND event.objid=plink.pid"
178 " ORDER BY event.mtime DESC",
@@ -354,25 +354,29 @@
354 }else{
355 @ <tr><th>Comment:</th><td>%w(zComment)</td></tr>
356 }
357 @ </td></tr>
358 if( g.okHistory ){
359 char *zShortUuid = mprintf("%.10s", zUuid);
360 const char *zProjName = db_get("project-name", "unnamed");
361 @ <tr><th>Timelines:</th><td>
362 @ <a href="%s(g.zBaseURL)/timeline?p=%d(rid)">ancestors</a>
363 @ | <a href="%s(g.zBaseURL)/timeline?d=%d(rid)">descendants</a>
364 @ | <a href="%s(g.zBaseURL)/timeline?d=%d(rid)&p=%d(rid)">both</a>
365 @ </td></tr>
366 @ <tr><th>Commands:</th>
367 @ <td>
368 @ <a href="%s(g.zBaseURL)/vdiff/%d(rid)">diff</a>
369 @ | <a href="%s(g.zBaseURL)/zip/%s(zProjName)-%s(zShortUuid).zip?uuid=%s(zUuid)">
370 @ ZIP archive</a>
371 @ | <a href="%s(g.zBaseURL)/artifact/%d(rid)">manifest</a>
372 if( g.okWrite ){
373 @ | <a href="%s(g.zBaseURL)/vedit?r=%d(rid)">edit</a>
374 }
375 @ </td>
376 @ </tr>
377 free(zShortUuid);
378 }
379 @ </table></p>
380 }else{
381 style_header("Baseline Information");
382 login_anonymous_available();
@@ -655,11 +659,11 @@
659 Stmt q;
660 int cnt = 0;
661 int nWiki = 0;
662 db_prepare(&q,
663 "SELECT filename.name, datetime(event.mtime), substr(a.uuid,1,10),"
664 " coalesce(event.ecomment,event.comment),"
665 " coalesce(event.euser,event.user),"
666 " b.uuid"
667 " FROM mlink, filename, event, blob a, blob b"
668 " WHERE filename.fnid=mlink.fnid"
669 " AND event.objid=mlink.mid"
670
+8 -4
--- src/info.c
+++ src/info.c
@@ -116,11 +116,11 @@
116116
Stmt q;
117117
int cnt = 0;
118118
db_prepare(&q,
119119
"SELECT plink.cid, blob.uuid, datetime(plink.mtime, 'localtime'),"
120120
" coalesce(event.euser,event.user),"
121
- " coalesce(event.comment,event.ecomment)"
121
+ " coalesce(event.ecomment,event.comment)"
122122
" FROM plink, blob, event"
123123
" WHERE plink.pid=%d"
124124
" AND blob.rid=plink.cid"
125125
" AND event.objid=plink.cid"
126126
" ORDER BY plink.mtime ASC",
@@ -168,11 +168,11 @@
168168
Stmt q;
169169
int cnt = 0;
170170
db_prepare(&q,
171171
"SELECT plink.pid, blob.uuid, datetime(event.mtime, 'localtime'),"
172172
" coalesce(event.euser,event.user),"
173
- " coalesce(event.comment,event.ecomment)"
173
+ " coalesce(event.ecomment,event.comment)"
174174
" FROM plink, blob, event"
175175
" WHERE plink.cid=%d"
176176
" AND blob.rid=plink.pid"
177177
" AND event.objid=plink.pid"
178178
" ORDER BY event.mtime DESC",
@@ -354,25 +354,29 @@
354354
}else{
355355
@ <tr><th>Comment:</th><td>%w(zComment)</td></tr>
356356
}
357357
@ </td></tr>
358358
if( g.okHistory ){
359
+ char *zShortUuid = mprintf("%.10s", zUuid);
360
+ const char *zProjName = db_get("project-name", "unnamed");
359361
@ <tr><th>Timelines:</th><td>
360362
@ <a href="%s(g.zBaseURL)/timeline?p=%d(rid)">ancestors</a>
361363
@ | <a href="%s(g.zBaseURL)/timeline?d=%d(rid)">descendants</a>
362364
@ | <a href="%s(g.zBaseURL)/timeline?d=%d(rid)&p=%d(rid)">both</a>
363365
@ </td></tr>
364366
@ <tr><th>Commands:</th>
365367
@ <td>
366368
@ <a href="%s(g.zBaseURL)/vdiff/%d(rid)">diff</a>
367
- @ | <a href="%s(g.zBaseURL)/zip/%s(zUuid).zip">ZIP archive</a>
369
+ @ | <a href="%s(g.zBaseURL)/zip/%s(zProjName)-%s(zShortUuid).zip?uuid=%s(zUuid)">
370
+ @ ZIP archive</a>
368371
@ | <a href="%s(g.zBaseURL)/artifact/%d(rid)">manifest</a>
369372
if( g.okWrite ){
370373
@ | <a href="%s(g.zBaseURL)/vedit?r=%d(rid)">edit</a>
371374
}
372375
@ </td>
373376
@ </tr>
377
+ free(zShortUuid);
374378
}
375379
@ </table></p>
376380
}else{
377381
style_header("Baseline Information");
378382
login_anonymous_available();
@@ -655,11 +659,11 @@
655659
Stmt q;
656660
int cnt = 0;
657661
int nWiki = 0;
658662
db_prepare(&q,
659663
"SELECT filename.name, datetime(event.mtime), substr(a.uuid,1,10),"
660
- " coalesce(event.comment,event.ecomment),"
664
+ " coalesce(event.ecomment,event.comment),"
661665
" coalesce(event.euser,event.user),"
662666
" b.uuid"
663667
" FROM mlink, filename, event, blob a, blob b"
664668
" WHERE filename.fnid=mlink.fnid"
665669
" AND event.objid=mlink.mid"
666670
--- src/info.c
+++ src/info.c
@@ -116,11 +116,11 @@
116 Stmt q;
117 int cnt = 0;
118 db_prepare(&q,
119 "SELECT plink.cid, blob.uuid, datetime(plink.mtime, 'localtime'),"
120 " coalesce(event.euser,event.user),"
121 " coalesce(event.comment,event.ecomment)"
122 " FROM plink, blob, event"
123 " WHERE plink.pid=%d"
124 " AND blob.rid=plink.cid"
125 " AND event.objid=plink.cid"
126 " ORDER BY plink.mtime ASC",
@@ -168,11 +168,11 @@
168 Stmt q;
169 int cnt = 0;
170 db_prepare(&q,
171 "SELECT plink.pid, blob.uuid, datetime(event.mtime, 'localtime'),"
172 " coalesce(event.euser,event.user),"
173 " coalesce(event.comment,event.ecomment)"
174 " FROM plink, blob, event"
175 " WHERE plink.cid=%d"
176 " AND blob.rid=plink.pid"
177 " AND event.objid=plink.pid"
178 " ORDER BY event.mtime DESC",
@@ -354,25 +354,29 @@
354 }else{
355 @ <tr><th>Comment:</th><td>%w(zComment)</td></tr>
356 }
357 @ </td></tr>
358 if( g.okHistory ){
 
 
359 @ <tr><th>Timelines:</th><td>
360 @ <a href="%s(g.zBaseURL)/timeline?p=%d(rid)">ancestors</a>
361 @ | <a href="%s(g.zBaseURL)/timeline?d=%d(rid)">descendants</a>
362 @ | <a href="%s(g.zBaseURL)/timeline?d=%d(rid)&p=%d(rid)">both</a>
363 @ </td></tr>
364 @ <tr><th>Commands:</th>
365 @ <td>
366 @ <a href="%s(g.zBaseURL)/vdiff/%d(rid)">diff</a>
367 @ | <a href="%s(g.zBaseURL)/zip/%s(zUuid).zip">ZIP archive</a>
 
368 @ | <a href="%s(g.zBaseURL)/artifact/%d(rid)">manifest</a>
369 if( g.okWrite ){
370 @ | <a href="%s(g.zBaseURL)/vedit?r=%d(rid)">edit</a>
371 }
372 @ </td>
373 @ </tr>
 
374 }
375 @ </table></p>
376 }else{
377 style_header("Baseline Information");
378 login_anonymous_available();
@@ -655,11 +659,11 @@
655 Stmt q;
656 int cnt = 0;
657 int nWiki = 0;
658 db_prepare(&q,
659 "SELECT filename.name, datetime(event.mtime), substr(a.uuid,1,10),"
660 " coalesce(event.comment,event.ecomment),"
661 " coalesce(event.euser,event.user),"
662 " b.uuid"
663 " FROM mlink, filename, event, blob a, blob b"
664 " WHERE filename.fnid=mlink.fnid"
665 " AND event.objid=mlink.mid"
666
--- src/info.c
+++ src/info.c
@@ -116,11 +116,11 @@
116 Stmt q;
117 int cnt = 0;
118 db_prepare(&q,
119 "SELECT plink.cid, blob.uuid, datetime(plink.mtime, 'localtime'),"
120 " coalesce(event.euser,event.user),"
121 " coalesce(event.ecomment,event.comment)"
122 " FROM plink, blob, event"
123 " WHERE plink.pid=%d"
124 " AND blob.rid=plink.cid"
125 " AND event.objid=plink.cid"
126 " ORDER BY plink.mtime ASC",
@@ -168,11 +168,11 @@
168 Stmt q;
169 int cnt = 0;
170 db_prepare(&q,
171 "SELECT plink.pid, blob.uuid, datetime(event.mtime, 'localtime'),"
172 " coalesce(event.euser,event.user),"
173 " coalesce(event.ecomment,event.comment)"
174 " FROM plink, blob, event"
175 " WHERE plink.cid=%d"
176 " AND blob.rid=plink.pid"
177 " AND event.objid=plink.pid"
178 " ORDER BY event.mtime DESC",
@@ -354,25 +354,29 @@
354 }else{
355 @ <tr><th>Comment:</th><td>%w(zComment)</td></tr>
356 }
357 @ </td></tr>
358 if( g.okHistory ){
359 char *zShortUuid = mprintf("%.10s", zUuid);
360 const char *zProjName = db_get("project-name", "unnamed");
361 @ <tr><th>Timelines:</th><td>
362 @ <a href="%s(g.zBaseURL)/timeline?p=%d(rid)">ancestors</a>
363 @ | <a href="%s(g.zBaseURL)/timeline?d=%d(rid)">descendants</a>
364 @ | <a href="%s(g.zBaseURL)/timeline?d=%d(rid)&p=%d(rid)">both</a>
365 @ </td></tr>
366 @ <tr><th>Commands:</th>
367 @ <td>
368 @ <a href="%s(g.zBaseURL)/vdiff/%d(rid)">diff</a>
369 @ | <a href="%s(g.zBaseURL)/zip/%s(zProjName)-%s(zShortUuid).zip?uuid=%s(zUuid)">
370 @ ZIP archive</a>
371 @ | <a href="%s(g.zBaseURL)/artifact/%d(rid)">manifest</a>
372 if( g.okWrite ){
373 @ | <a href="%s(g.zBaseURL)/vedit?r=%d(rid)">edit</a>
374 }
375 @ </td>
376 @ </tr>
377 free(zShortUuid);
378 }
379 @ </table></p>
380 }else{
381 style_header("Baseline Information");
382 login_anonymous_available();
@@ -655,11 +659,11 @@
659 Stmt q;
660 int cnt = 0;
661 int nWiki = 0;
662 db_prepare(&q,
663 "SELECT filename.name, datetime(event.mtime), substr(a.uuid,1,10),"
664 " coalesce(event.ecomment,event.comment),"
665 " coalesce(event.euser,event.user),"
666 " b.uuid"
667 " FROM mlink, filename, event, blob a, blob b"
668 " WHERE filename.fnid=mlink.fnid"
669 " AND event.objid=mlink.mid"
670
+24 -2
--- src/login.c
+++ src/login.c
@@ -113,11 +113,11 @@
113113
);
114114
cgi_redirect(zGoto);
115115
return;
116116
}
117117
}
118
- if( zUsername!=0 && zPasswd!=0 ){
118
+ if( zUsername!=0 && zPasswd!=0 && zPasswd[0]!=0 ){
119119
int uid = db_int(0,
120120
"SELECT uid FROM user"
121121
" WHERE login=%Q AND pw=%Q", zUsername, zPasswd);
122122
if( uid<=0 || strcmp(zUsername,"nobody")==0 ){
123123
sleep(1);
@@ -300,13 +300,15 @@
300300
g.userUid = uid;
301301
if( g.zLogin && strcmp(g.zLogin,"nobody")==0 ){
302302
g.zLogin = 0;
303303
}
304304
if( uid && g.zLogin ){
305
+ /* All logged-in users inherit privileges from "nobody" */
305306
zNcap = db_text("", "SELECT cap FROM user WHERE login = 'nobody'");
306307
login_set_capabilities(zNcap);
307
- if( db_get_int("inherit-anon",0) ){
308
+ if( strcmp(g.zLogin, "anonymous")!=0 ){
309
+ /* All logged-in users inherit privileges from "anonymous" */
308310
zAcap = db_text("", "SELECT cap FROM user WHERE login = 'anonymous'");
309311
login_set_capabilities(zAcap);
310312
}
311313
}
312314
login_set_capabilities(zCap);
@@ -314,10 +316,11 @@
314316
315317
/*
316318
** Set the global capability flags based on a capability string.
317319
*/
318320
void login_set_capabilities(const char *zCap){
321
+ static char *zDev = 0;
319322
int i;
320323
for(i=0; zCap[i]; i++){
321324
switch( zCap[i] ){
322325
case 's': g.okSetup = 1;
323326
case 'a': g.okAdmin = g.okRdTkt = g.okWrTkt =
@@ -325,10 +328,11 @@
325328
g.okApndWiki = g.okHistory = g.okClone =
326329
g.okNewTkt = g.okPassword = g.okRdAddr =
327330
g.okTktFmt = 1;
328331
case 'i': g.okRead = g.okWrite = 1; break;
329332
case 'o': g.okRead = 1; break;
333
+ case 'z': g.okZip = 1; break;
330334
331335
case 'd': g.okDelete = 1; break;
332336
case 'h': g.okHistory = 1; break;
333337
case 'g': g.okClone = 1; break;
334338
case 'p': g.okPassword = 1; break;
@@ -343,10 +347,20 @@
343347
case 'n': g.okNewTkt = 1; break;
344348
case 'w': g.okWrTkt = g.okRdTkt = g.okNewTkt =
345349
g.okApndTkt = 1; break;
346350
case 'c': g.okApndTkt = 1; break;
347351
case 't': g.okTktFmt = 1; break;
352
+
353
+ /* The "v" privileges is a little different. It recursively
354
+ ** inherits all privileges of the user named "developer" */
355
+ case 'v': {
356
+ if( zDev==0 ){
357
+ zDev = db_text("", "SELECT cap FROM user WHERE login='developer'");
358
+ login_set_capabilities(zDev);
359
+ }
360
+ break;
361
+ }
348362
}
349363
}
350364
}
351365
352366
/*
@@ -359,27 +373,35 @@
359373
int rc = 1;
360374
if( nCap<0 ) nCap = strlen(zCap);
361375
for(i=0; i<nCap && rc && zCap[i]; i++){
362376
switch( zCap[i] ){
363377
case 'a': rc = g.okAdmin; break;
378
+ /* case 'b': */
364379
case 'c': rc = g.okApndTkt; break;
365380
case 'd': rc = g.okDelete; break;
366381
case 'e': rc = g.okRdAddr; break;
367382
case 'f': rc = g.okNewWiki; break;
368383
case 'g': rc = g.okClone; break;
369384
case 'h': rc = g.okHistory; break;
370385
case 'i': rc = g.okWrite; break;
371386
case 'j': rc = g.okRdWiki; break;
372387
case 'k': rc = g.okWrWiki; break;
388
+ /* case 'l': */
373389
case 'm': rc = g.okApndWiki; break;
374390
case 'n': rc = g.okNewTkt; break;
375391
case 'o': rc = g.okRead; break;
376392
case 'p': rc = g.okPassword; break;
393
+ /* case 'q': */
377394
case 'r': rc = g.okRdTkt; break;
378395
case 's': rc = g.okSetup; break;
379396
case 't': rc = g.okTktFmt; break;
397
+ /* case 'u': */
398
+ /* case 'v': */
380399
case 'w': rc = g.okWrTkt; break;
400
+ /* case 'x': */
401
+ /* case 'y': */
402
+ case 'z': rc = g.okZip; break;
381403
default: rc = 0; break;
382404
}
383405
}
384406
return rc;
385407
}
386408
--- src/login.c
+++ src/login.c
@@ -113,11 +113,11 @@
113 );
114 cgi_redirect(zGoto);
115 return;
116 }
117 }
118 if( zUsername!=0 && zPasswd!=0 ){
119 int uid = db_int(0,
120 "SELECT uid FROM user"
121 " WHERE login=%Q AND pw=%Q", zUsername, zPasswd);
122 if( uid<=0 || strcmp(zUsername,"nobody")==0 ){
123 sleep(1);
@@ -300,13 +300,15 @@
300 g.userUid = uid;
301 if( g.zLogin && strcmp(g.zLogin,"nobody")==0 ){
302 g.zLogin = 0;
303 }
304 if( uid && g.zLogin ){
 
305 zNcap = db_text("", "SELECT cap FROM user WHERE login = 'nobody'");
306 login_set_capabilities(zNcap);
307 if( db_get_int("inherit-anon",0) ){
 
308 zAcap = db_text("", "SELECT cap FROM user WHERE login = 'anonymous'");
309 login_set_capabilities(zAcap);
310 }
311 }
312 login_set_capabilities(zCap);
@@ -314,10 +316,11 @@
314
315 /*
316 ** Set the global capability flags based on a capability string.
317 */
318 void login_set_capabilities(const char *zCap){
 
319 int i;
320 for(i=0; zCap[i]; i++){
321 switch( zCap[i] ){
322 case 's': g.okSetup = 1;
323 case 'a': g.okAdmin = g.okRdTkt = g.okWrTkt =
@@ -325,10 +328,11 @@
325 g.okApndWiki = g.okHistory = g.okClone =
326 g.okNewTkt = g.okPassword = g.okRdAddr =
327 g.okTktFmt = 1;
328 case 'i': g.okRead = g.okWrite = 1; break;
329 case 'o': g.okRead = 1; break;
 
330
331 case 'd': g.okDelete = 1; break;
332 case 'h': g.okHistory = 1; break;
333 case 'g': g.okClone = 1; break;
334 case 'p': g.okPassword = 1; break;
@@ -343,10 +347,20 @@
343 case 'n': g.okNewTkt = 1; break;
344 case 'w': g.okWrTkt = g.okRdTkt = g.okNewTkt =
345 g.okApndTkt = 1; break;
346 case 'c': g.okApndTkt = 1; break;
347 case 't': g.okTktFmt = 1; break;
 
 
 
 
 
 
 
 
 
 
348 }
349 }
350 }
351
352 /*
@@ -359,27 +373,35 @@
359 int rc = 1;
360 if( nCap<0 ) nCap = strlen(zCap);
361 for(i=0; i<nCap && rc && zCap[i]; i++){
362 switch( zCap[i] ){
363 case 'a': rc = g.okAdmin; break;
 
364 case 'c': rc = g.okApndTkt; break;
365 case 'd': rc = g.okDelete; break;
366 case 'e': rc = g.okRdAddr; break;
367 case 'f': rc = g.okNewWiki; break;
368 case 'g': rc = g.okClone; break;
369 case 'h': rc = g.okHistory; break;
370 case 'i': rc = g.okWrite; break;
371 case 'j': rc = g.okRdWiki; break;
372 case 'k': rc = g.okWrWiki; break;
 
373 case 'm': rc = g.okApndWiki; break;
374 case 'n': rc = g.okNewTkt; break;
375 case 'o': rc = g.okRead; break;
376 case 'p': rc = g.okPassword; break;
 
377 case 'r': rc = g.okRdTkt; break;
378 case 's': rc = g.okSetup; break;
379 case 't': rc = g.okTktFmt; break;
 
 
380 case 'w': rc = g.okWrTkt; break;
 
 
 
381 default: rc = 0; break;
382 }
383 }
384 return rc;
385 }
386
--- src/login.c
+++ src/login.c
@@ -113,11 +113,11 @@
113 );
114 cgi_redirect(zGoto);
115 return;
116 }
117 }
118 if( zUsername!=0 && zPasswd!=0 && zPasswd[0]!=0 ){
119 int uid = db_int(0,
120 "SELECT uid FROM user"
121 " WHERE login=%Q AND pw=%Q", zUsername, zPasswd);
122 if( uid<=0 || strcmp(zUsername,"nobody")==0 ){
123 sleep(1);
@@ -300,13 +300,15 @@
300 g.userUid = uid;
301 if( g.zLogin && strcmp(g.zLogin,"nobody")==0 ){
302 g.zLogin = 0;
303 }
304 if( uid && g.zLogin ){
305 /* All logged-in users inherit privileges from "nobody" */
306 zNcap = db_text("", "SELECT cap FROM user WHERE login = 'nobody'");
307 login_set_capabilities(zNcap);
308 if( strcmp(g.zLogin, "anonymous")!=0 ){
309 /* All logged-in users inherit privileges from "anonymous" */
310 zAcap = db_text("", "SELECT cap FROM user WHERE login = 'anonymous'");
311 login_set_capabilities(zAcap);
312 }
313 }
314 login_set_capabilities(zCap);
@@ -314,10 +316,11 @@
316
317 /*
318 ** Set the global capability flags based on a capability string.
319 */
320 void login_set_capabilities(const char *zCap){
321 static char *zDev = 0;
322 int i;
323 for(i=0; zCap[i]; i++){
324 switch( zCap[i] ){
325 case 's': g.okSetup = 1;
326 case 'a': g.okAdmin = g.okRdTkt = g.okWrTkt =
@@ -325,10 +328,11 @@
328 g.okApndWiki = g.okHistory = g.okClone =
329 g.okNewTkt = g.okPassword = g.okRdAddr =
330 g.okTktFmt = 1;
331 case 'i': g.okRead = g.okWrite = 1; break;
332 case 'o': g.okRead = 1; break;
333 case 'z': g.okZip = 1; break;
334
335 case 'd': g.okDelete = 1; break;
336 case 'h': g.okHistory = 1; break;
337 case 'g': g.okClone = 1; break;
338 case 'p': g.okPassword = 1; break;
@@ -343,10 +347,20 @@
347 case 'n': g.okNewTkt = 1; break;
348 case 'w': g.okWrTkt = g.okRdTkt = g.okNewTkt =
349 g.okApndTkt = 1; break;
350 case 'c': g.okApndTkt = 1; break;
351 case 't': g.okTktFmt = 1; break;
352
353 /* The "v" privileges is a little different. It recursively
354 ** inherits all privileges of the user named "developer" */
355 case 'v': {
356 if( zDev==0 ){
357 zDev = db_text("", "SELECT cap FROM user WHERE login='developer'");
358 login_set_capabilities(zDev);
359 }
360 break;
361 }
362 }
363 }
364 }
365
366 /*
@@ -359,27 +373,35 @@
373 int rc = 1;
374 if( nCap<0 ) nCap = strlen(zCap);
375 for(i=0; i<nCap && rc && zCap[i]; i++){
376 switch( zCap[i] ){
377 case 'a': rc = g.okAdmin; break;
378 /* case 'b': */
379 case 'c': rc = g.okApndTkt; break;
380 case 'd': rc = g.okDelete; break;
381 case 'e': rc = g.okRdAddr; break;
382 case 'f': rc = g.okNewWiki; break;
383 case 'g': rc = g.okClone; break;
384 case 'h': rc = g.okHistory; break;
385 case 'i': rc = g.okWrite; break;
386 case 'j': rc = g.okRdWiki; break;
387 case 'k': rc = g.okWrWiki; break;
388 /* case 'l': */
389 case 'm': rc = g.okApndWiki; break;
390 case 'n': rc = g.okNewTkt; break;
391 case 'o': rc = g.okRead; break;
392 case 'p': rc = g.okPassword; break;
393 /* case 'q': */
394 case 'r': rc = g.okRdTkt; break;
395 case 's': rc = g.okSetup; break;
396 case 't': rc = g.okTktFmt; break;
397 /* case 'u': */
398 /* case 'v': */
399 case 'w': rc = g.okWrTkt; break;
400 /* case 'x': */
401 /* case 'y': */
402 case 'z': rc = g.okZip; break;
403 default: rc = 0; break;
404 }
405 }
406 return rc;
407 }
408
+24 -2
--- src/login.c
+++ src/login.c
@@ -113,11 +113,11 @@
113113
);
114114
cgi_redirect(zGoto);
115115
return;
116116
}
117117
}
118
- if( zUsername!=0 && zPasswd!=0 ){
118
+ if( zUsername!=0 && zPasswd!=0 && zPasswd[0]!=0 ){
119119
int uid = db_int(0,
120120
"SELECT uid FROM user"
121121
" WHERE login=%Q AND pw=%Q", zUsername, zPasswd);
122122
if( uid<=0 || strcmp(zUsername,"nobody")==0 ){
123123
sleep(1);
@@ -300,13 +300,15 @@
300300
g.userUid = uid;
301301
if( g.zLogin && strcmp(g.zLogin,"nobody")==0 ){
302302
g.zLogin = 0;
303303
}
304304
if( uid && g.zLogin ){
305
+ /* All logged-in users inherit privileges from "nobody" */
305306
zNcap = db_text("", "SELECT cap FROM user WHERE login = 'nobody'");
306307
login_set_capabilities(zNcap);
307
- if( db_get_int("inherit-anon",0) ){
308
+ if( strcmp(g.zLogin, "anonymous")!=0 ){
309
+ /* All logged-in users inherit privileges from "anonymous" */
308310
zAcap = db_text("", "SELECT cap FROM user WHERE login = 'anonymous'");
309311
login_set_capabilities(zAcap);
310312
}
311313
}
312314
login_set_capabilities(zCap);
@@ -314,10 +316,11 @@
314316
315317
/*
316318
** Set the global capability flags based on a capability string.
317319
*/
318320
void login_set_capabilities(const char *zCap){
321
+ static char *zDev = 0;
319322
int i;
320323
for(i=0; zCap[i]; i++){
321324
switch( zCap[i] ){
322325
case 's': g.okSetup = 1;
323326
case 'a': g.okAdmin = g.okRdTkt = g.okWrTkt =
@@ -325,10 +328,11 @@
325328
g.okApndWiki = g.okHistory = g.okClone =
326329
g.okNewTkt = g.okPassword = g.okRdAddr =
327330
g.okTktFmt = 1;
328331
case 'i': g.okRead = g.okWrite = 1; break;
329332
case 'o': g.okRead = 1; break;
333
+ case 'z': g.okZip = 1; break;
330334
331335
case 'd': g.okDelete = 1; break;
332336
case 'h': g.okHistory = 1; break;
333337
case 'g': g.okClone = 1; break;
334338
case 'p': g.okPassword = 1; break;
@@ -343,10 +347,20 @@
343347
case 'n': g.okNewTkt = 1; break;
344348
case 'w': g.okWrTkt = g.okRdTkt = g.okNewTkt =
345349
g.okApndTkt = 1; break;
346350
case 'c': g.okApndTkt = 1; break;
347351
case 't': g.okTktFmt = 1; break;
352
+
353
+ /* The "v" privileges is a little different. It recursively
354
+ ** inherits all privileges of the user named "developer" */
355
+ case 'v': {
356
+ if( zDev==0 ){
357
+ zDev = db_text("", "SELECT cap FROM user WHERE login='developer'");
358
+ login_set_capabilities(zDev);
359
+ }
360
+ break;
361
+ }
348362
}
349363
}
350364
}
351365
352366
/*
@@ -359,27 +373,35 @@
359373
int rc = 1;
360374
if( nCap<0 ) nCap = strlen(zCap);
361375
for(i=0; i<nCap && rc && zCap[i]; i++){
362376
switch( zCap[i] ){
363377
case 'a': rc = g.okAdmin; break;
378
+ /* case 'b': */
364379
case 'c': rc = g.okApndTkt; break;
365380
case 'd': rc = g.okDelete; break;
366381
case 'e': rc = g.okRdAddr; break;
367382
case 'f': rc = g.okNewWiki; break;
368383
case 'g': rc = g.okClone; break;
369384
case 'h': rc = g.okHistory; break;
370385
case 'i': rc = g.okWrite; break;
371386
case 'j': rc = g.okRdWiki; break;
372387
case 'k': rc = g.okWrWiki; break;
388
+ /* case 'l': */
373389
case 'm': rc = g.okApndWiki; break;
374390
case 'n': rc = g.okNewTkt; break;
375391
case 'o': rc = g.okRead; break;
376392
case 'p': rc = g.okPassword; break;
393
+ /* case 'q': */
377394
case 'r': rc = g.okRdTkt; break;
378395
case 's': rc = g.okSetup; break;
379396
case 't': rc = g.okTktFmt; break;
397
+ /* case 'u': */
398
+ /* case 'v': */
380399
case 'w': rc = g.okWrTkt; break;
400
+ /* case 'x': */
401
+ /* case 'y': */
402
+ case 'z': rc = g.okZip; break;
381403
default: rc = 0; break;
382404
}
383405
}
384406
return rc;
385407
}
386408
--- src/login.c
+++ src/login.c
@@ -113,11 +113,11 @@
113 );
114 cgi_redirect(zGoto);
115 return;
116 }
117 }
118 if( zUsername!=0 && zPasswd!=0 ){
119 int uid = db_int(0,
120 "SELECT uid FROM user"
121 " WHERE login=%Q AND pw=%Q", zUsername, zPasswd);
122 if( uid<=0 || strcmp(zUsername,"nobody")==0 ){
123 sleep(1);
@@ -300,13 +300,15 @@
300 g.userUid = uid;
301 if( g.zLogin && strcmp(g.zLogin,"nobody")==0 ){
302 g.zLogin = 0;
303 }
304 if( uid && g.zLogin ){
 
305 zNcap = db_text("", "SELECT cap FROM user WHERE login = 'nobody'");
306 login_set_capabilities(zNcap);
307 if( db_get_int("inherit-anon",0) ){
 
308 zAcap = db_text("", "SELECT cap FROM user WHERE login = 'anonymous'");
309 login_set_capabilities(zAcap);
310 }
311 }
312 login_set_capabilities(zCap);
@@ -314,10 +316,11 @@
314
315 /*
316 ** Set the global capability flags based on a capability string.
317 */
318 void login_set_capabilities(const char *zCap){
 
319 int i;
320 for(i=0; zCap[i]; i++){
321 switch( zCap[i] ){
322 case 's': g.okSetup = 1;
323 case 'a': g.okAdmin = g.okRdTkt = g.okWrTkt =
@@ -325,10 +328,11 @@
325 g.okApndWiki = g.okHistory = g.okClone =
326 g.okNewTkt = g.okPassword = g.okRdAddr =
327 g.okTktFmt = 1;
328 case 'i': g.okRead = g.okWrite = 1; break;
329 case 'o': g.okRead = 1; break;
 
330
331 case 'd': g.okDelete = 1; break;
332 case 'h': g.okHistory = 1; break;
333 case 'g': g.okClone = 1; break;
334 case 'p': g.okPassword = 1; break;
@@ -343,10 +347,20 @@
343 case 'n': g.okNewTkt = 1; break;
344 case 'w': g.okWrTkt = g.okRdTkt = g.okNewTkt =
345 g.okApndTkt = 1; break;
346 case 'c': g.okApndTkt = 1; break;
347 case 't': g.okTktFmt = 1; break;
 
 
 
 
 
 
 
 
 
 
348 }
349 }
350 }
351
352 /*
@@ -359,27 +373,35 @@
359 int rc = 1;
360 if( nCap<0 ) nCap = strlen(zCap);
361 for(i=0; i<nCap && rc && zCap[i]; i++){
362 switch( zCap[i] ){
363 case 'a': rc = g.okAdmin; break;
 
364 case 'c': rc = g.okApndTkt; break;
365 case 'd': rc = g.okDelete; break;
366 case 'e': rc = g.okRdAddr; break;
367 case 'f': rc = g.okNewWiki; break;
368 case 'g': rc = g.okClone; break;
369 case 'h': rc = g.okHistory; break;
370 case 'i': rc = g.okWrite; break;
371 case 'j': rc = g.okRdWiki; break;
372 case 'k': rc = g.okWrWiki; break;
 
373 case 'm': rc = g.okApndWiki; break;
374 case 'n': rc = g.okNewTkt; break;
375 case 'o': rc = g.okRead; break;
376 case 'p': rc = g.okPassword; break;
 
377 case 'r': rc = g.okRdTkt; break;
378 case 's': rc = g.okSetup; break;
379 case 't': rc = g.okTktFmt; break;
 
 
380 case 'w': rc = g.okWrTkt; break;
 
 
 
381 default: rc = 0; break;
382 }
383 }
384 return rc;
385 }
386
--- src/login.c
+++ src/login.c
@@ -113,11 +113,11 @@
113 );
114 cgi_redirect(zGoto);
115 return;
116 }
117 }
118 if( zUsername!=0 && zPasswd!=0 && zPasswd[0]!=0 ){
119 int uid = db_int(0,
120 "SELECT uid FROM user"
121 " WHERE login=%Q AND pw=%Q", zUsername, zPasswd);
122 if( uid<=0 || strcmp(zUsername,"nobody")==0 ){
123 sleep(1);
@@ -300,13 +300,15 @@
300 g.userUid = uid;
301 if( g.zLogin && strcmp(g.zLogin,"nobody")==0 ){
302 g.zLogin = 0;
303 }
304 if( uid && g.zLogin ){
305 /* All logged-in users inherit privileges from "nobody" */
306 zNcap = db_text("", "SELECT cap FROM user WHERE login = 'nobody'");
307 login_set_capabilities(zNcap);
308 if( strcmp(g.zLogin, "anonymous")!=0 ){
309 /* All logged-in users inherit privileges from "anonymous" */
310 zAcap = db_text("", "SELECT cap FROM user WHERE login = 'anonymous'");
311 login_set_capabilities(zAcap);
312 }
313 }
314 login_set_capabilities(zCap);
@@ -314,10 +316,11 @@
316
317 /*
318 ** Set the global capability flags based on a capability string.
319 */
320 void login_set_capabilities(const char *zCap){
321 static char *zDev = 0;
322 int i;
323 for(i=0; zCap[i]; i++){
324 switch( zCap[i] ){
325 case 's': g.okSetup = 1;
326 case 'a': g.okAdmin = g.okRdTkt = g.okWrTkt =
@@ -325,10 +328,11 @@
328 g.okApndWiki = g.okHistory = g.okClone =
329 g.okNewTkt = g.okPassword = g.okRdAddr =
330 g.okTktFmt = 1;
331 case 'i': g.okRead = g.okWrite = 1; break;
332 case 'o': g.okRead = 1; break;
333 case 'z': g.okZip = 1; break;
334
335 case 'd': g.okDelete = 1; break;
336 case 'h': g.okHistory = 1; break;
337 case 'g': g.okClone = 1; break;
338 case 'p': g.okPassword = 1; break;
@@ -343,10 +347,20 @@
347 case 'n': g.okNewTkt = 1; break;
348 case 'w': g.okWrTkt = g.okRdTkt = g.okNewTkt =
349 g.okApndTkt = 1; break;
350 case 'c': g.okApndTkt = 1; break;
351 case 't': g.okTktFmt = 1; break;
352
353 /* The "v" privileges is a little different. It recursively
354 ** inherits all privileges of the user named "developer" */
355 case 'v': {
356 if( zDev==0 ){
357 zDev = db_text("", "SELECT cap FROM user WHERE login='developer'");
358 login_set_capabilities(zDev);
359 }
360 break;
361 }
362 }
363 }
364 }
365
366 /*
@@ -359,27 +373,35 @@
373 int rc = 1;
374 if( nCap<0 ) nCap = strlen(zCap);
375 for(i=0; i<nCap && rc && zCap[i]; i++){
376 switch( zCap[i] ){
377 case 'a': rc = g.okAdmin; break;
378 /* case 'b': */
379 case 'c': rc = g.okApndTkt; break;
380 case 'd': rc = g.okDelete; break;
381 case 'e': rc = g.okRdAddr; break;
382 case 'f': rc = g.okNewWiki; break;
383 case 'g': rc = g.okClone; break;
384 case 'h': rc = g.okHistory; break;
385 case 'i': rc = g.okWrite; break;
386 case 'j': rc = g.okRdWiki; break;
387 case 'k': rc = g.okWrWiki; break;
388 /* case 'l': */
389 case 'm': rc = g.okApndWiki; break;
390 case 'n': rc = g.okNewTkt; break;
391 case 'o': rc = g.okRead; break;
392 case 'p': rc = g.okPassword; break;
393 /* case 'q': */
394 case 'r': rc = g.okRdTkt; break;
395 case 's': rc = g.okSetup; break;
396 case 't': rc = g.okTktFmt; break;
397 /* case 'u': */
398 /* case 'v': */
399 case 'w': rc = g.okWrTkt; break;
400 /* case 'x': */
401 /* case 'y': */
402 case 'z': rc = g.okZip; break;
403 default: rc = 0; break;
404 }
405 }
406 return rc;
407 }
408
+1
--- src/main.c
+++ src/main.c
@@ -117,10 +117,11 @@
117117
int okNewTkt; /* n: create new tickets */
118118
int okApndTkt; /* c: append to tickets via the web */
119119
int okWrTkt; /* w: make changes to tickets via web */
120120
int okTktFmt; /* t: create new ticket report formats */
121121
int okRdAddr; /* e: read email addresses or other private data */
122
+ int okZip; /* z: download zipped artifact via /zip URL */
122123
123124
FILE *fDebug; /* Write debug information here, if the file exists */
124125
125126
/* Storage for the aux() and/or option() SQL function arguments */
126127
int nAux; /* Number of distinct aux() or option() values */
127128
--- src/main.c
+++ src/main.c
@@ -117,10 +117,11 @@
117 int okNewTkt; /* n: create new tickets */
118 int okApndTkt; /* c: append to tickets via the web */
119 int okWrTkt; /* w: make changes to tickets via web */
120 int okTktFmt; /* t: create new ticket report formats */
121 int okRdAddr; /* e: read email addresses or other private data */
 
122
123 FILE *fDebug; /* Write debug information here, if the file exists */
124
125 /* Storage for the aux() and/or option() SQL function arguments */
126 int nAux; /* Number of distinct aux() or option() values */
127
--- src/main.c
+++ src/main.c
@@ -117,10 +117,11 @@
117 int okNewTkt; /* n: create new tickets */
118 int okApndTkt; /* c: append to tickets via the web */
119 int okWrTkt; /* w: make changes to tickets via web */
120 int okTktFmt; /* t: create new ticket report formats */
121 int okRdAddr; /* e: read email addresses or other private data */
122 int okZip; /* z: download zipped artifact via /zip URL */
123
124 FILE *fDebug; /* Write debug information here, if the file exists */
125
126 /* Storage for the aux() and/or option() SQL function arguments */
127 int nAux; /* Number of distinct aux() or option() values */
128
+6 -6
--- src/my_page.c
+++ src/my_page.c
@@ -27,12 +27,12 @@
2727
*/
2828
#include <assert.h>
2929
#include "config.h"
3030
#include "my_page.h"
3131
32
-/**
33
-Renders a logout button.
32
+/*
33
+** Renders a logout button.
3434
*/
3535
static void mypage_logout_button()
3636
{
3737
if( g.zLogin ){
3838
@ <br clear="both"/><hr/>
@@ -43,12 +43,12 @@
4343
@ <input type="submit" name="out" value="Logout"/></p>
4444
@ </form>
4545
}
4646
}
4747
48
-/**
49
-Renders a password changer.
48
+/*
49
+** Renders a password changer.
5050
*/
5151
static void mypage_password_changer()
5252
{
5353
if( g.okPassword ){
5454
@ <br clear="both"/><hr/>
@@ -71,12 +71,12 @@
7171
@ </form>
7272
}
7373
7474
}
7575
76
-/**
77
-Default page rendered for /my.
76
+/*
77
+** Default page rendered for /my.
7878
*/
7979
static void mypage_page_default()
8080
{
8181
int uid = g.userUid;
8282
char * sql = mprintf( "SELECT login,cap,info FROM user WHERE uid=%d",
8383
--- src/my_page.c
+++ src/my_page.c
@@ -27,12 +27,12 @@
27 */
28 #include <assert.h>
29 #include "config.h"
30 #include "my_page.h"
31
32 /**
33 Renders a logout button.
34 */
35 static void mypage_logout_button()
36 {
37 if( g.zLogin ){
38 @ <br clear="both"/><hr/>
@@ -43,12 +43,12 @@
43 @ <input type="submit" name="out" value="Logout"/></p>
44 @ </form>
45 }
46 }
47
48 /**
49 Renders a password changer.
50 */
51 static void mypage_password_changer()
52 {
53 if( g.okPassword ){
54 @ <br clear="both"/><hr/>
@@ -71,12 +71,12 @@
71 @ </form>
72 }
73
74 }
75
76 /**
77 Default page rendered for /my.
78 */
79 static void mypage_page_default()
80 {
81 int uid = g.userUid;
82 char * sql = mprintf( "SELECT login,cap,info FROM user WHERE uid=%d",
83
--- src/my_page.c
+++ src/my_page.c
@@ -27,12 +27,12 @@
27 */
28 #include <assert.h>
29 #include "config.h"
30 #include "my_page.h"
31
32 /*
33 ** Renders a logout button.
34 */
35 static void mypage_logout_button()
36 {
37 if( g.zLogin ){
38 @ <br clear="both"/><hr/>
@@ -43,12 +43,12 @@
43 @ <input type="submit" name="out" value="Logout"/></p>
44 @ </form>
45 }
46 }
47
48 /*
49 ** Renders a password changer.
50 */
51 static void mypage_password_changer()
52 {
53 if( g.okPassword ){
54 @ <br clear="both"/><hr/>
@@ -71,12 +71,12 @@
71 @ </form>
72 }
73
74 }
75
76 /*
77 ** Default page rendered for /my.
78 */
79 static void mypage_page_default()
80 {
81 int uid = g.userUid;
82 char * sql = mprintf( "SELECT login,cap,info FROM user WHERE uid=%d",
83
+6 -2
--- src/name.c
+++ src/name.c
@@ -110,20 +110,21 @@
110110
** 1 A single UUID was found
111111
** 2 More than one UUID was found, so this is presumably a
112112
** propagating tag. The return UUID is the most recent,
113113
** which is most likely to be the one wanted.
114114
*/
115
-int sym_tag_to_uuid(const char *pName, Blob *pUuid){
115
+int tag_to_uuid(const char *pName, Blob *pUuid,const char *pPrefix){
116116
Stmt q;
117117
int count = 0;
118118
db_prepare(&q,
119119
"SELECT (SELECT uuid FROM blob WHERE rid=objid)"
120120
" FROM tagxref JOIN event ON rid=objid"
121
- " WHERE tagid=(SELECT tagid FROM tag WHERE tagname='sym-'||%Q)"
121
+ " WHERE tagid=(SELECT tagid FROM tag WHERE tagname=%Q||%Q)"
122122
" AND tagtype>0"
123123
" AND value IS NULL"
124124
" ORDER BY event.mtime DESC",
125
+ pPrefix,
125126
pName
126127
);
127128
blob_zero(pUuid);
128129
while( db_step(&q)==SQLITE_ROW ){
129130
count++;
@@ -132,10 +133,13 @@
132133
}
133134
db_column_blob(&q, 0, pUuid);
134135
}
135136
db_finalize(&q);
136137
return count;
138
+}
139
+int sym_tag_to_uuid(const char *pName, Blob *pUuid){
140
+ return tag_to_uuid(pName,pUuid,"sym-");
137141
}
138142
139143
/*
140144
** COMMAND: test-name-to-uuid
141145
**
142146
--- src/name.c
+++ src/name.c
@@ -110,20 +110,21 @@
110 ** 1 A single UUID was found
111 ** 2 More than one UUID was found, so this is presumably a
112 ** propagating tag. The return UUID is the most recent,
113 ** which is most likely to be the one wanted.
114 */
115 int sym_tag_to_uuid(const char *pName, Blob *pUuid){
116 Stmt q;
117 int count = 0;
118 db_prepare(&q,
119 "SELECT (SELECT uuid FROM blob WHERE rid=objid)"
120 " FROM tagxref JOIN event ON rid=objid"
121 " WHERE tagid=(SELECT tagid FROM tag WHERE tagname='sym-'||%Q)"
122 " AND tagtype>0"
123 " AND value IS NULL"
124 " ORDER BY event.mtime DESC",
 
125 pName
126 );
127 blob_zero(pUuid);
128 while( db_step(&q)==SQLITE_ROW ){
129 count++;
@@ -132,10 +133,13 @@
132 }
133 db_column_blob(&q, 0, pUuid);
134 }
135 db_finalize(&q);
136 return count;
 
 
 
137 }
138
139 /*
140 ** COMMAND: test-name-to-uuid
141 **
142
--- src/name.c
+++ src/name.c
@@ -110,20 +110,21 @@
110 ** 1 A single UUID was found
111 ** 2 More than one UUID was found, so this is presumably a
112 ** propagating tag. The return UUID is the most recent,
113 ** which is most likely to be the one wanted.
114 */
115 int tag_to_uuid(const char *pName, Blob *pUuid,const char *pPrefix){
116 Stmt q;
117 int count = 0;
118 db_prepare(&q,
119 "SELECT (SELECT uuid FROM blob WHERE rid=objid)"
120 " FROM tagxref JOIN event ON rid=objid"
121 " WHERE tagid=(SELECT tagid FROM tag WHERE tagname=%Q||%Q)"
122 " AND tagtype>0"
123 " AND value IS NULL"
124 " ORDER BY event.mtime DESC",
125 pPrefix,
126 pName
127 );
128 blob_zero(pUuid);
129 while( db_step(&q)==SQLITE_ROW ){
130 count++;
@@ -132,10 +133,13 @@
133 }
134 db_column_blob(&q, 0, pUuid);
135 }
136 db_finalize(&q);
137 return count;
138 }
139 int sym_tag_to_uuid(const char *pName, Blob *pUuid){
140 return tag_to_uuid(pName,pUuid,"sym-");
141 }
142
143 /*
144 ** COMMAND: test-name-to-uuid
145 **
146
+6 -2
--- src/name.c
+++ src/name.c
@@ -110,20 +110,21 @@
110110
** 1 A single UUID was found
111111
** 2 More than one UUID was found, so this is presumably a
112112
** propagating tag. The return UUID is the most recent,
113113
** which is most likely to be the one wanted.
114114
*/
115
-int sym_tag_to_uuid(const char *pName, Blob *pUuid){
115
+int tag_to_uuid(const char *pName, Blob *pUuid,const char *pPrefix){
116116
Stmt q;
117117
int count = 0;
118118
db_prepare(&q,
119119
"SELECT (SELECT uuid FROM blob WHERE rid=objid)"
120120
" FROM tagxref JOIN event ON rid=objid"
121
- " WHERE tagid=(SELECT tagid FROM tag WHERE tagname='sym-'||%Q)"
121
+ " WHERE tagid=(SELECT tagid FROM tag WHERE tagname=%Q||%Q)"
122122
" AND tagtype>0"
123123
" AND value IS NULL"
124124
" ORDER BY event.mtime DESC",
125
+ pPrefix,
125126
pName
126127
);
127128
blob_zero(pUuid);
128129
while( db_step(&q)==SQLITE_ROW ){
129130
count++;
@@ -132,10 +133,13 @@
132133
}
133134
db_column_blob(&q, 0, pUuid);
134135
}
135136
db_finalize(&q);
136137
return count;
138
+}
139
+int sym_tag_to_uuid(const char *pName, Blob *pUuid){
140
+ return tag_to_uuid(pName,pUuid,"sym-");
137141
}
138142
139143
/*
140144
** COMMAND: test-name-to-uuid
141145
**
142146
--- src/name.c
+++ src/name.c
@@ -110,20 +110,21 @@
110 ** 1 A single UUID was found
111 ** 2 More than one UUID was found, so this is presumably a
112 ** propagating tag. The return UUID is the most recent,
113 ** which is most likely to be the one wanted.
114 */
115 int sym_tag_to_uuid(const char *pName, Blob *pUuid){
116 Stmt q;
117 int count = 0;
118 db_prepare(&q,
119 "SELECT (SELECT uuid FROM blob WHERE rid=objid)"
120 " FROM tagxref JOIN event ON rid=objid"
121 " WHERE tagid=(SELECT tagid FROM tag WHERE tagname='sym-'||%Q)"
122 " AND tagtype>0"
123 " AND value IS NULL"
124 " ORDER BY event.mtime DESC",
 
125 pName
126 );
127 blob_zero(pUuid);
128 while( db_step(&q)==SQLITE_ROW ){
129 count++;
@@ -132,10 +133,13 @@
132 }
133 db_column_blob(&q, 0, pUuid);
134 }
135 db_finalize(&q);
136 return count;
 
 
 
137 }
138
139 /*
140 ** COMMAND: test-name-to-uuid
141 **
142
--- src/name.c
+++ src/name.c
@@ -110,20 +110,21 @@
110 ** 1 A single UUID was found
111 ** 2 More than one UUID was found, so this is presumably a
112 ** propagating tag. The return UUID is the most recent,
113 ** which is most likely to be the one wanted.
114 */
115 int tag_to_uuid(const char *pName, Blob *pUuid,const char *pPrefix){
116 Stmt q;
117 int count = 0;
118 db_prepare(&q,
119 "SELECT (SELECT uuid FROM blob WHERE rid=objid)"
120 " FROM tagxref JOIN event ON rid=objid"
121 " WHERE tagid=(SELECT tagid FROM tag WHERE tagname=%Q||%Q)"
122 " AND tagtype>0"
123 " AND value IS NULL"
124 " ORDER BY event.mtime DESC",
125 pPrefix,
126 pName
127 );
128 blob_zero(pUuid);
129 while( db_step(&q)==SQLITE_ROW ){
130 count++;
@@ -132,10 +133,13 @@
133 }
134 db_column_blob(&q, 0, pUuid);
135 }
136 db_finalize(&q);
137 return count;
138 }
139 int sym_tag_to_uuid(const char *pName, Blob *pUuid){
140 return tag_to_uuid(pName,pUuid,"sym-");
141 }
142
143 /*
144 ** COMMAND: test-name-to-uuid
145 **
146
--- src/schema.c
+++ src/schema.c
@@ -297,10 +297,13 @@
297297
# define TAG_USER 3 /* User who made a checking */
298298
# define TAG_HIDDEN 4 /* Do not display or sync */
299299
# define TAG_PRIVATE 5 /* Display but do not sync */
300300
# define TAG_CLUSTER 6 /* A cluster */
301301
#endif
302
+#if EXPORT_INTERFACE
303
+# define MAX_INT_TAG 6 /* The largest pre-assigned tag id */
304
+#endif
302305
303306
/*
304307
** The schema for the locate FOSSIL database file found at the root
305308
** of very check-out. This database contains the complete state of
306309
** the checkout.
307310
--- src/schema.c
+++ src/schema.c
@@ -297,10 +297,13 @@
297 # define TAG_USER 3 /* User who made a checking */
298 # define TAG_HIDDEN 4 /* Do not display or sync */
299 # define TAG_PRIVATE 5 /* Display but do not sync */
300 # define TAG_CLUSTER 6 /* A cluster */
301 #endif
 
 
 
302
303 /*
304 ** The schema for the locate FOSSIL database file found at the root
305 ** of very check-out. This database contains the complete state of
306 ** the checkout.
307
--- src/schema.c
+++ src/schema.c
@@ -297,10 +297,13 @@
297 # define TAG_USER 3 /* User who made a checking */
298 # define TAG_HIDDEN 4 /* Do not display or sync */
299 # define TAG_PRIVATE 5 /* Display but do not sync */
300 # define TAG_CLUSTER 6 /* A cluster */
301 #endif
302 #if EXPORT_INTERFACE
303 # define MAX_INT_TAG 6 /* The largest pre-assigned tag id */
304 #endif
305
306 /*
307 ** The schema for the locate FOSSIL database file found at the root
308 ** of very check-out. This database contains the complete state of
309 ** the checkout.
310
--- src/schema.c
+++ src/schema.c
@@ -297,10 +297,13 @@
297297
# define TAG_USER 3 /* User who made a checking */
298298
# define TAG_HIDDEN 4 /* Do not display or sync */
299299
# define TAG_PRIVATE 5 /* Display but do not sync */
300300
# define TAG_CLUSTER 6 /* A cluster */
301301
#endif
302
+#if EXPORT_INTERFACE
303
+# define MAX_INT_TAG 6 /* The largest pre-assigned tag id */
304
+#endif
302305
303306
/*
304307
** The schema for the locate FOSSIL database file found at the root
305308
** of very check-out. This database contains the complete state of
306309
** the checkout.
307310
--- src/schema.c
+++ src/schema.c
@@ -297,10 +297,13 @@
297 # define TAG_USER 3 /* User who made a checking */
298 # define TAG_HIDDEN 4 /* Do not display or sync */
299 # define TAG_PRIVATE 5 /* Display but do not sync */
300 # define TAG_CLUSTER 6 /* A cluster */
301 #endif
 
 
 
302
303 /*
304 ** The schema for the locate FOSSIL database file found at the root
305 ** of very check-out. This database contains the complete state of
306 ** the checkout.
307
--- src/schema.c
+++ src/schema.c
@@ -297,10 +297,13 @@
297 # define TAG_USER 3 /* User who made a checking */
298 # define TAG_HIDDEN 4 /* Do not display or sync */
299 # define TAG_PRIVATE 5 /* Display but do not sync */
300 # define TAG_CLUSTER 6 /* A cluster */
301 #endif
302 #if EXPORT_INTERFACE
303 # define MAX_INT_TAG 6 /* The largest pre-assigned tag id */
304 #endif
305
306 /*
307 ** The schema for the locate FOSSIL database file found at the root
308 ** of very check-out. This database contains the complete state of
309 ** the checkout.
310
+109 -41
--- src/setup.c
+++ src/setup.c
@@ -134,52 +134,70 @@
134134
@ </table></td></tr></table>
135135
@ <td valign="top">
136136
@ <b>Notes:</b>
137137
@ <ol>
138138
@ <li><p>The permission flags are as follows:</p>
139
- @ <ol type="a">
140
- @ <li value="1"><b>Admin</b>: Create and delete users</li>
141
- @ <li value="3"><b>Append-Tkt</b>: Append to tickets</li>
142
- @ <li value="4"><b>Delete</b>: Delete wiki and tickets</li>
143
- @ <li value="5"><b>Email</b>: View sensitive data such as EMail addresses</li>
144
- @ <li value="6"><b>New-Wiki</b>: Create new wiki pages</li>
145
- @ <li value="7"><b>Clone</b>: Clone the repository</li>
146
- @ <li value="8"><b>History</b>: View detail repository history</li>
147
- @ <li value="9"><b>Check-In</b>: Commit new versions in the repository</li>
148
- @ <li value="10"><b>Read-Wiki</b>: View wiki pages</li>
149
- @ <li value="11"><b>Write-Wiki</b>: Edit wiki pages</li>
150
- @ <li value="13"><b>Append-Wiki</b>: Append to wiki pages</li>
151
- @ <li value="14"><b>New-Tkt</b>: Create new tickets</li>
152
- @ <li value="15"><b>Check-Out</b>: Check out versions</li>
153
- @ <li value="16"><b>Password</b>: Change your own password</li>
154
- @ <li value="18"><b>Read-Tkt</b>: View tickets</li>
155
- @ <li value="19"><b>Setup:</b> Setup and configure this website</li>
156
- @ <li value="20"><b>Tkt-Report:</b> Create new bug summary reports</li>
157
- @ <li value="23"><b>Write-Tkt</b>: Edit tickets</li>
158
- @ </ol>
159
- @ </p></li>
139
+ @ <table>
140
+ @ <tr><td><b>a</b></td><td><i>Admin:</i> Create and delete users</td></tr>
141
+ @ <tr><td><b>c</b></td><td><i>Append-Tkt:</i> Append to tickets</td></tr>
142
+ @ <tr><td><b>d</b></td><td><i>Delete:</i> Delete wiki and tickets</td></tr>
143
+ @ <tr><td><b>e</b></td><td><i>Email:</i> View sensitive data such as EMail addresses</td></tr>
144
+ @ <tr><td><b>f</b></td><td><i>New-Wiki:</i> Create new wiki pages</td></tr>
145
+ @ <tr><td><b>g</b></td><td><i>Clone:</i> Clone the repository</td></tr>
146
+ @ <tr><td><b>h</b></td><td><i>History:</i> View detail repository history</td></tr>
147
+ @ <tr><td><b>i</b></td><td><i>Check-In:</i> Commit new versions in the repository</td></tr>
148
+ @ <tr><td><b>j</b></td><td><i>Read-Wiki:</i> View wiki pages</td></tr>
149
+ @ <tr><td><b>k</b></td><td><i>Write-Wiki:</i> Edit wiki pages</td></tr>
150
+ @ <tr><td><b>m</b></td><td><i>Append-Wiki:</i> Append to wiki pages</td></tr>
151
+ @ <tr><td><b>n</b></td><td><i>New-Tkt:</i> Create new tickets</td></tr>
152
+ @ <tr><td><b>o</b></td><td><i>Check-Out:</i> Check out versions</td></tr>
153
+ @ <tr><td><b>p</b></td><td><i>Password:</i> Change your own password</td></tr>
154
+ @ <tr><td><b>r</b></td><td><i>Read-Tkt:</i> View tickets</td></tr>
155
+ @ <tr><td><b>s</b></td><td><i>Setup:</i> Setup and configure this website</td></tr>
156
+ @ <tr><td><b>t</b></td><td><i>Tkt-Report:</i> Create new bug summary reports</td></tr>
157
+ @ <tr><td><b>v</b></td><td><i>Developer:</i> Inherit privileges of user <tt>developer</tt></td></tr>
158
+ @ <tr><td><b>w</b></td><td><i>Write-Tkt:</i> Edit tickets</td></tr>
159
+ @ <tr><td><b>z</b></td><td><i>Zip download:</i> Download a baseline via the
160
+ @ <tt>/zip</tt> URL even without check<b>o</b>ut and <b>h</b>istory permissions</td></tr>
161
+ @ </table>
162
+ @ </li>
160163
@
161164
@ <li><p>
162
- @ Every user, logged in or not, has the privileges of <b>nobody</b>.
165
+ @ Every user, logged in or not, inherits the privileges of <b>nobody</b>.
163166
@ Any human can login as <b>anonymous</b> since the password is
164167
@ clearly displayed on the login page for them to type. The purpose
165168
@ of requiring anonymous to log in is to prevent access by spiders.
169
+ @ Every logged-in user inherits the privileges of <b>anonymous</b>.
166170
@ </p></li>
167171
@
168172
@ </ol>
169173
@ </td></tr></table>
170174
style_footer();
171175
}
176
+
177
+/*
178
+** Return true if zPw is a valid password string. A valid
179
+** password string is:
180
+**
181
+** (1) A zero-length string, or
182
+** (2) a string that contains a character other than '*'.
183
+*/
184
+static int isValidPwString(const char *zPw){
185
+ if( zPw==0 ) return 0;
186
+ if( zPw[0]==0 ) return 1;
187
+ while( zPw[0]=='*' ){ zPw++; }
188
+ return zPw[0]!=0;
189
+}
172190
173191
/*
174192
** WEBPAGE: /setup_uedit
175193
*/
176194
void user_edit(void){
177
- const char *zId, *zLogin, *zInfo, *zCap;
195
+ const char *zId, *zLogin, *zInfo, *zCap, *zPw;
178196
char *oaa, *oas, *oar, *oaw, *oan, *oai, *oaj, *oao, *oap;
179197
char *oak, *oad, *oac, *oaf, *oam, *oah, *oag, *oae;
180
- char *oat;
198
+ char *oat, *oav, *oaz;
181199
int doWrite;
182200
int uid;
183201
int higherUser = 0; /* True if user being edited is SETUP and the */
184202
/* user doing the editing is ADMIN. Disallow editing */
185203
@@ -208,12 +226,10 @@
208226
** modified user record. After writing the user record, redirect
209227
** to the page that displays a list of users.
210228
*/
211229
doWrite = cgi_all("login","info","pw") && !higherUser;
212230
if( doWrite ){
213
- const char *zPw;
214
- const char *zLogin;
215231
char zCap[50];
216232
int i = 0;
217233
int aa = P("aa")!=0;
218234
int ad = P("ad")!=0;
219235
int ae = P("ae")!=0;
@@ -230,10 +246,12 @@
230246
int af = P("af")!=0;
231247
int am = P("am")!=0;
232248
int ah = P("ah")!=0;
233249
int ag = P("ag")!=0;
234250
int at = P("at")!=0;
251
+ int av = P("av")!=0;
252
+ int az = P("az")!=0;
235253
if( aa ){ zCap[i++] = 'a'; }
236254
if( ac ){ zCap[i++] = 'c'; }
237255
if( ad ){ zCap[i++] = 'd'; }
238256
if( ae ){ zCap[i++] = 'e'; }
239257
if( af ){ zCap[i++] = 'f'; }
@@ -247,15 +265,17 @@
247265
if( ao ){ zCap[i++] = 'o'; }
248266
if( ap ){ zCap[i++] = 'p'; }
249267
if( ar ){ zCap[i++] = 'r'; }
250268
if( as ){ zCap[i++] = 's'; }
251269
if( at ){ zCap[i++] = 't'; }
270
+ if( av ){ zCap[i++] = 'v'; }
252271
if( aw ){ zCap[i++] = 'w'; }
272
+ if( az ){ zCap[i++] = 'z'; }
253273
254274
zCap[i] = 0;
255275
zPw = P("pw");
256
- if( zPw==0 || zPw[0]==0 ){
276
+ if( !isValidPwString(zPw) ){
257277
zPw = db_text(0, "SELECT pw FROM user WHERE uid=%d", uid);
258278
}
259279
zLogin = P("login");
260280
if( uid>0 &&
261281
db_exists("SELECT 1 FROM user WHERE login=%Q AND uid!=%d", zLogin, uid)
@@ -280,16 +300,18 @@
280300
/* Load the existing information about the user, if any
281301
*/
282302
zLogin = "";
283303
zInfo = "";
284304
zCap = "";
305
+ zPw = "";
285306
oaa = oac = oad = oae = oaf = oag = oah = oai = oaj = oak = oam =
286
- oan = oao = oap = oar = oas = oat = oaw = "";
307
+ oan = oao = oap = oar = oas = oat = oav = oaw = oaz = "";
287308
if( uid ){
288309
zLogin = db_text("", "SELECT login FROM user WHERE uid=%d", uid);
289310
zInfo = db_text("", "SELECT info FROM user WHERE uid=%d", uid);
290311
zCap = db_text("", "SELECT cap FROM user WHERE uid=%d", uid);
312
+ zPw = db_text("", "SELECT pw FROM user WHERE uid=%d", uid);
291313
if( strchr(zCap, 'a') ) oaa = " checked";
292314
if( strchr(zCap, 'c') ) oac = " checked";
293315
if( strchr(zCap, 'd') ) oad = " checked";
294316
if( strchr(zCap, 'e') ) oae = " checked";
295317
if( strchr(zCap, 'f') ) oaf = " checked";
@@ -303,11 +325,13 @@
303325
if( strchr(zCap, 'o') ) oao = " checked";
304326
if( strchr(zCap, 'p') ) oap = " checked";
305327
if( strchr(zCap, 'r') ) oar = " checked";
306328
if( strchr(zCap, 's') ) oas = " checked";
307329
if( strchr(zCap, 't') ) oat = " checked";
330
+ if( strchr(zCap, 'v') ) oav = " checked";
308331
if( strchr(zCap, 'w') ) oaw = " checked";
332
+ if( strchr(zCap, 'z') ) oaz = " checked";
309333
}
310334
311335
/* Begin generating the page
312336
*/
313337
style_submenu_element("Cancel", "Cancel", "setup_ulist");
@@ -346,35 +370,46 @@
346370
@ <input type="checkbox" name="ae"%s(oad)>Email</input><br>
347371
@ <input type="checkbox" name="ap"%s(oap)>Password</input><br>
348372
@ <input type="checkbox" name="ai"%s(oai)>Check-In</input><br>
349373
@ <input type="checkbox" name="ao"%s(oao)>Check-Out</input><br>
350374
@ <input type="checkbox" name="ah"%s(oah)>History</input><br>
375
+ @ <input type="checkbox" name="av"%s(oav)>Developer</input><br>
351376
@ <input type="checkbox" name="ag"%s(oag)>Clone</input><br>
352377
@ <input type="checkbox" name="aj"%s(oaj)>Read Wiki</input><br>
353378
@ <input type="checkbox" name="af"%s(oaf)>New Wiki</input><br>
354379
@ <input type="checkbox" name="am"%s(oam)>Append Wiki</input><br>
355380
@ <input type="checkbox" name="ak"%s(oak)>Write Wiki</input><br>
356381
@ <input type="checkbox" name="ar"%s(oar)>Read Tkt</input><br>
357382
@ <input type="checkbox" name="an"%s(oan)>New Tkt</input><br>
358383
@ <input type="checkbox" name="ac"%s(oac)>Append Tkt</input><br>
359384
@ <input type="checkbox" name="aw"%s(oaw)>Write Tkt</input><br>
360
- @ <input type="checkbox" name="at"%s(oat)>Tkt Report</input>
385
+ @ <input type="checkbox" name="at"%s(oat)>Tkt Report</input><br>
386
+ @ <input type="checkbox" name="az"%s(oaz)>Download Zip</input>
361387
@ </td>
362388
@ </tr>
363389
@ <tr>
364390
@ <td align="right">Password:</td>
365
- @ <td><input type="password" name="pw" value=""></td>
391
+ if( strcmp(zLogin, "anonymous")==0 ){
392
+ /* User the password for "anonymous" as cleartext */
393
+ @ <td><input type="text" name="pw" value="%h(zPw)"></td>
394
+ }else if( zPw[0] ){
395
+ /* Obscure the password for all other users */
396
+ @ <td><input type="password" name="pw" value="**********"></td>
397
+ }else{
398
+ /* Show an empty password as an empty input field */
399
+ @ <td><input type="password" name="pw" value=""></td>
400
+ }
366401
@ </tr>
367402
if( !higherUser ){
368403
@ <tr>
369404
@ <td>&nbsp</td>
370405
@ <td><input type="submit" name="submit" value="Apply Changes">
371406
@ </tr>
372407
}
373408
@ </table></td></tr></table>
374
- @ <p><b>Notes:</b></p>
375
- @ <ol>
409
+ @ <h2>Privileges And Capabilities:</h2>
410
+ @ <ul>
376411
if( higherUser ){
377412
@ <li><p><font color="blue"><b>
378413
@ User %h(zLogin) has Setup privileges and you only have Admin privileges
379414
@ so you are not permitted to make changes to %h(zLogin).
380415
@ </b></font></p></li>
@@ -401,10 +436,24 @@
401436
@ This is recommended ON for most logged-in users but OFF for
402437
@ user "nobody" to avoid problems with spiders trying to walk every
403438
@ historical version of every baseline and file.
404439
@ </p></li>
405440
@
441
+ @ <li><p>
442
+ @ The <b>Zip</b> privilege allows a user to see the download as zip hyperlink
443
+ @ as well as permit access to the <tt>/zip</tt> page. It can be allowed for
444
+ @ user "nobody" to grant him access to download artifacts he know from the
445
+ @ server without giving him other rights like <b>Read</b> or <b>History</b>.
446
+ @ So automatic package dowloaders could be able to obtain the sources without
447
+ @ going thru the login procedure.
448
+ @ </p></li>
449
+ @
450
+ @ <li><p>
451
+ @ The <b>Developer</b> privilege causes all privileges of the user
452
+ @ named "developer" to be inherited by this user.
453
+ @ </p></li>
454
+ @
406455
@ <li><p>
407456
@ The <b>Check-in</b> privilege allows remote users to "push".
408457
@ The <b>Check-out</b> privilege allows remote users to "pull".
409458
@ The <b>Clone</b> privilege allows remote users to "clone".
410459
@ </li><p>
@@ -418,39 +467,58 @@
418467
@ ticket report formats.
419468
@ </p></li>
420469
@
421470
@ <li><p>
422471
@ Users with the <b>Password</b> privilege are allowed to change their
423
- @ own password. Recommended ON for most users but OFF for "anonynmous"
424
- @ and "nobody".
472
+ @ own password. Recommended ON for most users but OFF for special
473
+ @ users "developer, "anonynmous", and "nobody".
425474
@ </p></li>
426475
@
427476
@ <li><p>
428477
@ The <b>EMail</b> privilege allows the display of sensitive information
429478
@ such as the email address of users and contact information on tickets.
430479
@ Recommended OFF for "anonymous" and for "nobody".
431480
@ </p></li>
432481
@
482
+ @ <li><p>
483
+ @ Login is prohibited if the password is an empty string.
484
+ @ </p></li>
485
+ @ </ul>
486
+ @
487
+ @ <h2>Special Logins</h2>
488
+ @
489
+ @ <ul>
433490
@ <li><p>
434491
@ No login is required for user "<b>nobody</b>". The capabilities
435
- @ of this user are available to anyone without supplying a username or
436
- @ password. To disable nobody access, make sure there is no user
437
- @ with an ID of <b>nobody</b> or that the nobody user has no
438
- @ capabilities enabled. The password for nobody is ignore. To
439
- @ avoid problems with spiders overloading the server, it is suggested
440
- @ that the 'h' (History) capability be turned off for user nobody.
492
+ @ of the <b>nobody</b> user are inherited by all users, regardless of
493
+ @ whether or not they are logged in. To disable universal access
494
+ @ to the repository, make sure no user named "<b>nobody</b>" exists or
495
+ @ that the <b>nobody</b> user has no capabilities enabled.
496
+ @ The password for <b>nobody</b> is ignore. To avoid problems with
497
+ @ spiders overloading the server, it is recommended
498
+ @ that the 'h' (History) capability be turned off for the <b>nobody</b>
499
+ @ user.
441500
@ </p></li>
442501
@
443502
@ <li><p>
444503
@ Login is required for user "<b>anonymous</b>" but the password
445504
@ is displayed on the login screen beside the password entry box
446505
@ so anybody who can read should be able to login as anonymous.
447506
@ On the other hand, spiders and web-crawlers will typically not
448507
@ be able to login. Set the capabilities of the anonymous user
449508
@ to things that you want any human to be able to do, but not any
450
- @ spider.
509
+ @ spider. Every other logged-in user inherits the privileges of
510
+ @ <b>anonymous</b>.
451511
@ </p></li>
512
+ @
513
+ @ <li><p>
514
+ @ The "<b>developer</b>" user is intended as a template for trusted users
515
+ @ with check-in privileges. When adding new trusted users, simply
516
+ @ select the <b>Developer</b> privilege to cause the new user to inherit
517
+ @ all privileges of the "developer" user.
518
+ @ </li></p>
519
+ @ </ul>
452520
@ </form>
453521
style_footer();
454522
}
455523
456524
457525
--- src/setup.c
+++ src/setup.c
@@ -134,52 +134,70 @@
134 @ </table></td></tr></table>
135 @ <td valign="top">
136 @ <b>Notes:</b>
137 @ <ol>
138 @ <li><p>The permission flags are as follows:</p>
139 @ <ol type="a">
140 @ <li value="1"><b>Admin</b>: Create and delete users</li>
141 @ <li value="3"><b>Append-Tkt</b>: Append to tickets</li>
142 @ <li value="4"><b>Delete</b>: Delete wiki and tickets</li>
143 @ <li value="5"><b>Email</b>: View sensitive data such as EMail addresses</li>
144 @ <li value="6"><b>New-Wiki</b>: Create new wiki pages</li>
145 @ <li value="7"><b>Clone</b>: Clone the repository</li>
146 @ <li value="8"><b>History</b>: View detail repository history</li>
147 @ <li value="9"><b>Check-In</b>: Commit new versions in the repository</li>
148 @ <li value="10"><b>Read-Wiki</b>: View wiki pages</li>
149 @ <li value="11"><b>Write-Wiki</b>: Edit wiki pages</li>
150 @ <li value="13"><b>Append-Wiki</b>: Append to wiki pages</li>
151 @ <li value="14"><b>New-Tkt</b>: Create new tickets</li>
152 @ <li value="15"><b>Check-Out</b>: Check out versions</li>
153 @ <li value="16"><b>Password</b>: Change your own password</li>
154 @ <li value="18"><b>Read-Tkt</b>: View tickets</li>
155 @ <li value="19"><b>Setup:</b> Setup and configure this website</li>
156 @ <li value="20"><b>Tkt-Report:</b> Create new bug summary reports</li>
157 @ <li value="23"><b>Write-Tkt</b>: Edit tickets</li>
158 @ </ol>
159 @ </p></li>
 
 
 
160 @
161 @ <li><p>
162 @ Every user, logged in or not, has the privileges of <b>nobody</b>.
163 @ Any human can login as <b>anonymous</b> since the password is
164 @ clearly displayed on the login page for them to type. The purpose
165 @ of requiring anonymous to log in is to prevent access by spiders.
 
166 @ </p></li>
167 @
168 @ </ol>
169 @ </td></tr></table>
170 style_footer();
171 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
172
173 /*
174 ** WEBPAGE: /setup_uedit
175 */
176 void user_edit(void){
177 const char *zId, *zLogin, *zInfo, *zCap;
178 char *oaa, *oas, *oar, *oaw, *oan, *oai, *oaj, *oao, *oap;
179 char *oak, *oad, *oac, *oaf, *oam, *oah, *oag, *oae;
180 char *oat;
181 int doWrite;
182 int uid;
183 int higherUser = 0; /* True if user being edited is SETUP and the */
184 /* user doing the editing is ADMIN. Disallow editing */
185
@@ -208,12 +226,10 @@
208 ** modified user record. After writing the user record, redirect
209 ** to the page that displays a list of users.
210 */
211 doWrite = cgi_all("login","info","pw") && !higherUser;
212 if( doWrite ){
213 const char *zPw;
214 const char *zLogin;
215 char zCap[50];
216 int i = 0;
217 int aa = P("aa")!=0;
218 int ad = P("ad")!=0;
219 int ae = P("ae")!=0;
@@ -230,10 +246,12 @@
230 int af = P("af")!=0;
231 int am = P("am")!=0;
232 int ah = P("ah")!=0;
233 int ag = P("ag")!=0;
234 int at = P("at")!=0;
 
 
235 if( aa ){ zCap[i++] = 'a'; }
236 if( ac ){ zCap[i++] = 'c'; }
237 if( ad ){ zCap[i++] = 'd'; }
238 if( ae ){ zCap[i++] = 'e'; }
239 if( af ){ zCap[i++] = 'f'; }
@@ -247,15 +265,17 @@
247 if( ao ){ zCap[i++] = 'o'; }
248 if( ap ){ zCap[i++] = 'p'; }
249 if( ar ){ zCap[i++] = 'r'; }
250 if( as ){ zCap[i++] = 's'; }
251 if( at ){ zCap[i++] = 't'; }
 
252 if( aw ){ zCap[i++] = 'w'; }
 
253
254 zCap[i] = 0;
255 zPw = P("pw");
256 if( zPw==0 || zPw[0]==0 ){
257 zPw = db_text(0, "SELECT pw FROM user WHERE uid=%d", uid);
258 }
259 zLogin = P("login");
260 if( uid>0 &&
261 db_exists("SELECT 1 FROM user WHERE login=%Q AND uid!=%d", zLogin, uid)
@@ -280,16 +300,18 @@
280 /* Load the existing information about the user, if any
281 */
282 zLogin = "";
283 zInfo = "";
284 zCap = "";
 
285 oaa = oac = oad = oae = oaf = oag = oah = oai = oaj = oak = oam =
286 oan = oao = oap = oar = oas = oat = oaw = "";
287 if( uid ){
288 zLogin = db_text("", "SELECT login FROM user WHERE uid=%d", uid);
289 zInfo = db_text("", "SELECT info FROM user WHERE uid=%d", uid);
290 zCap = db_text("", "SELECT cap FROM user WHERE uid=%d", uid);
 
291 if( strchr(zCap, 'a') ) oaa = " checked";
292 if( strchr(zCap, 'c') ) oac = " checked";
293 if( strchr(zCap, 'd') ) oad = " checked";
294 if( strchr(zCap, 'e') ) oae = " checked";
295 if( strchr(zCap, 'f') ) oaf = " checked";
@@ -303,11 +325,13 @@
303 if( strchr(zCap, 'o') ) oao = " checked";
304 if( strchr(zCap, 'p') ) oap = " checked";
305 if( strchr(zCap, 'r') ) oar = " checked";
306 if( strchr(zCap, 's') ) oas = " checked";
307 if( strchr(zCap, 't') ) oat = " checked";
 
308 if( strchr(zCap, 'w') ) oaw = " checked";
 
309 }
310
311 /* Begin generating the page
312 */
313 style_submenu_element("Cancel", "Cancel", "setup_ulist");
@@ -346,35 +370,46 @@
346 @ <input type="checkbox" name="ae"%s(oad)>Email</input><br>
347 @ <input type="checkbox" name="ap"%s(oap)>Password</input><br>
348 @ <input type="checkbox" name="ai"%s(oai)>Check-In</input><br>
349 @ <input type="checkbox" name="ao"%s(oao)>Check-Out</input><br>
350 @ <input type="checkbox" name="ah"%s(oah)>History</input><br>
 
351 @ <input type="checkbox" name="ag"%s(oag)>Clone</input><br>
352 @ <input type="checkbox" name="aj"%s(oaj)>Read Wiki</input><br>
353 @ <input type="checkbox" name="af"%s(oaf)>New Wiki</input><br>
354 @ <input type="checkbox" name="am"%s(oam)>Append Wiki</input><br>
355 @ <input type="checkbox" name="ak"%s(oak)>Write Wiki</input><br>
356 @ <input type="checkbox" name="ar"%s(oar)>Read Tkt</input><br>
357 @ <input type="checkbox" name="an"%s(oan)>New Tkt</input><br>
358 @ <input type="checkbox" name="ac"%s(oac)>Append Tkt</input><br>
359 @ <input type="checkbox" name="aw"%s(oaw)>Write Tkt</input><br>
360 @ <input type="checkbox" name="at"%s(oat)>Tkt Report</input>
 
361 @ </td>
362 @ </tr>
363 @ <tr>
364 @ <td align="right">Password:</td>
365 @ <td><input type="password" name="pw" value=""></td>
 
 
 
 
 
 
 
 
 
366 @ </tr>
367 if( !higherUser ){
368 @ <tr>
369 @ <td>&nbsp</td>
370 @ <td><input type="submit" name="submit" value="Apply Changes">
371 @ </tr>
372 }
373 @ </table></td></tr></table>
374 @ <p><b>Notes:</b></p>
375 @ <ol>
376 if( higherUser ){
377 @ <li><p><font color="blue"><b>
378 @ User %h(zLogin) has Setup privileges and you only have Admin privileges
379 @ so you are not permitted to make changes to %h(zLogin).
380 @ </b></font></p></li>
@@ -401,10 +436,24 @@
401 @ This is recommended ON for most logged-in users but OFF for
402 @ user "nobody" to avoid problems with spiders trying to walk every
403 @ historical version of every baseline and file.
404 @ </p></li>
405 @
 
 
 
 
 
 
 
 
 
 
 
 
 
 
406 @ <li><p>
407 @ The <b>Check-in</b> privilege allows remote users to "push".
408 @ The <b>Check-out</b> privilege allows remote users to "pull".
409 @ The <b>Clone</b> privilege allows remote users to "clone".
410 @ </li><p>
@@ -418,39 +467,58 @@
418 @ ticket report formats.
419 @ </p></li>
420 @
421 @ <li><p>
422 @ Users with the <b>Password</b> privilege are allowed to change their
423 @ own password. Recommended ON for most users but OFF for "anonynmous"
424 @ and "nobody".
425 @ </p></li>
426 @
427 @ <li><p>
428 @ The <b>EMail</b> privilege allows the display of sensitive information
429 @ such as the email address of users and contact information on tickets.
430 @ Recommended OFF for "anonymous" and for "nobody".
431 @ </p></li>
432 @
 
 
 
 
 
 
 
 
433 @ <li><p>
434 @ No login is required for user "<b>nobody</b>". The capabilities
435 @ of this user are available to anyone without supplying a username or
436 @ password. To disable nobody access, make sure there is no user
437 @ with an ID of <b>nobody</b> or that the nobody user has no
438 @ capabilities enabled. The password for nobody is ignore. To
439 @ avoid problems with spiders overloading the server, it is suggested
440 @ that the 'h' (History) capability be turned off for user nobody.
 
 
441 @ </p></li>
442 @
443 @ <li><p>
444 @ Login is required for user "<b>anonymous</b>" but the password
445 @ is displayed on the login screen beside the password entry box
446 @ so anybody who can read should be able to login as anonymous.
447 @ On the other hand, spiders and web-crawlers will typically not
448 @ be able to login. Set the capabilities of the anonymous user
449 @ to things that you want any human to be able to do, but not any
450 @ spider.
 
451 @ </p></li>
 
 
 
 
 
 
 
 
452 @ </form>
453 style_footer();
454 }
455
456
457
--- src/setup.c
+++ src/setup.c
@@ -134,52 +134,70 @@
134 @ </table></td></tr></table>
135 @ <td valign="top">
136 @ <b>Notes:</b>
137 @ <ol>
138 @ <li><p>The permission flags are as follows:</p>
139 @ <table>
140 @ <tr><td><b>a</b></td><td><i>Admin:</i> Create and delete users</td></tr>
141 @ <tr><td><b>c</b></td><td><i>Append-Tkt:</i> Append to tickets</td></tr>
142 @ <tr><td><b>d</b></td><td><i>Delete:</i> Delete wiki and tickets</td></tr>
143 @ <tr><td><b>e</b></td><td><i>Email:</i> View sensitive data such as EMail addresses</td></tr>
144 @ <tr><td><b>f</b></td><td><i>New-Wiki:</i> Create new wiki pages</td></tr>
145 @ <tr><td><b>g</b></td><td><i>Clone:</i> Clone the repository</td></tr>
146 @ <tr><td><b>h</b></td><td><i>History:</i> View detail repository history</td></tr>
147 @ <tr><td><b>i</b></td><td><i>Check-In:</i> Commit new versions in the repository</td></tr>
148 @ <tr><td><b>j</b></td><td><i>Read-Wiki:</i> View wiki pages</td></tr>
149 @ <tr><td><b>k</b></td><td><i>Write-Wiki:</i> Edit wiki pages</td></tr>
150 @ <tr><td><b>m</b></td><td><i>Append-Wiki:</i> Append to wiki pages</td></tr>
151 @ <tr><td><b>n</b></td><td><i>New-Tkt:</i> Create new tickets</td></tr>
152 @ <tr><td><b>o</b></td><td><i>Check-Out:</i> Check out versions</td></tr>
153 @ <tr><td><b>p</b></td><td><i>Password:</i> Change your own password</td></tr>
154 @ <tr><td><b>r</b></td><td><i>Read-Tkt:</i> View tickets</td></tr>
155 @ <tr><td><b>s</b></td><td><i>Setup:</i> Setup and configure this website</td></tr>
156 @ <tr><td><b>t</b></td><td><i>Tkt-Report:</i> Create new bug summary reports</td></tr>
157 @ <tr><td><b>v</b></td><td><i>Developer:</i> Inherit privileges of user <tt>developer</tt></td></tr>
158 @ <tr><td><b>w</b></td><td><i>Write-Tkt:</i> Edit tickets</td></tr>
159 @ <tr><td><b>z</b></td><td><i>Zip download:</i> Download a baseline via the
160 @ <tt>/zip</tt> URL even without check<b>o</b>ut and <b>h</b>istory permissions</td></tr>
161 @ </table>
162 @ </li>
163 @
164 @ <li><p>
165 @ Every user, logged in or not, inherits the privileges of <b>nobody</b>.
166 @ Any human can login as <b>anonymous</b> since the password is
167 @ clearly displayed on the login page for them to type. The purpose
168 @ of requiring anonymous to log in is to prevent access by spiders.
169 @ Every logged-in user inherits the privileges of <b>anonymous</b>.
170 @ </p></li>
171 @
172 @ </ol>
173 @ </td></tr></table>
174 style_footer();
175 }
176
177 /*
178 ** Return true if zPw is a valid password string. A valid
179 ** password string is:
180 **
181 ** (1) A zero-length string, or
182 ** (2) a string that contains a character other than '*'.
183 */
184 static int isValidPwString(const char *zPw){
185 if( zPw==0 ) return 0;
186 if( zPw[0]==0 ) return 1;
187 while( zPw[0]=='*' ){ zPw++; }
188 return zPw[0]!=0;
189 }
190
191 /*
192 ** WEBPAGE: /setup_uedit
193 */
194 void user_edit(void){
195 const char *zId, *zLogin, *zInfo, *zCap, *zPw;
196 char *oaa, *oas, *oar, *oaw, *oan, *oai, *oaj, *oao, *oap;
197 char *oak, *oad, *oac, *oaf, *oam, *oah, *oag, *oae;
198 char *oat, *oav, *oaz;
199 int doWrite;
200 int uid;
201 int higherUser = 0; /* True if user being edited is SETUP and the */
202 /* user doing the editing is ADMIN. Disallow editing */
203
@@ -208,12 +226,10 @@
226 ** modified user record. After writing the user record, redirect
227 ** to the page that displays a list of users.
228 */
229 doWrite = cgi_all("login","info","pw") && !higherUser;
230 if( doWrite ){
 
 
231 char zCap[50];
232 int i = 0;
233 int aa = P("aa")!=0;
234 int ad = P("ad")!=0;
235 int ae = P("ae")!=0;
@@ -230,10 +246,12 @@
246 int af = P("af")!=0;
247 int am = P("am")!=0;
248 int ah = P("ah")!=0;
249 int ag = P("ag")!=0;
250 int at = P("at")!=0;
251 int av = P("av")!=0;
252 int az = P("az")!=0;
253 if( aa ){ zCap[i++] = 'a'; }
254 if( ac ){ zCap[i++] = 'c'; }
255 if( ad ){ zCap[i++] = 'd'; }
256 if( ae ){ zCap[i++] = 'e'; }
257 if( af ){ zCap[i++] = 'f'; }
@@ -247,15 +265,17 @@
265 if( ao ){ zCap[i++] = 'o'; }
266 if( ap ){ zCap[i++] = 'p'; }
267 if( ar ){ zCap[i++] = 'r'; }
268 if( as ){ zCap[i++] = 's'; }
269 if( at ){ zCap[i++] = 't'; }
270 if( av ){ zCap[i++] = 'v'; }
271 if( aw ){ zCap[i++] = 'w'; }
272 if( az ){ zCap[i++] = 'z'; }
273
274 zCap[i] = 0;
275 zPw = P("pw");
276 if( !isValidPwString(zPw) ){
277 zPw = db_text(0, "SELECT pw FROM user WHERE uid=%d", uid);
278 }
279 zLogin = P("login");
280 if( uid>0 &&
281 db_exists("SELECT 1 FROM user WHERE login=%Q AND uid!=%d", zLogin, uid)
@@ -280,16 +300,18 @@
300 /* Load the existing information about the user, if any
301 */
302 zLogin = "";
303 zInfo = "";
304 zCap = "";
305 zPw = "";
306 oaa = oac = oad = oae = oaf = oag = oah = oai = oaj = oak = oam =
307 oan = oao = oap = oar = oas = oat = oav = oaw = oaz = "";
308 if( uid ){
309 zLogin = db_text("", "SELECT login FROM user WHERE uid=%d", uid);
310 zInfo = db_text("", "SELECT info FROM user WHERE uid=%d", uid);
311 zCap = db_text("", "SELECT cap FROM user WHERE uid=%d", uid);
312 zPw = db_text("", "SELECT pw FROM user WHERE uid=%d", uid);
313 if( strchr(zCap, 'a') ) oaa = " checked";
314 if( strchr(zCap, 'c') ) oac = " checked";
315 if( strchr(zCap, 'd') ) oad = " checked";
316 if( strchr(zCap, 'e') ) oae = " checked";
317 if( strchr(zCap, 'f') ) oaf = " checked";
@@ -303,11 +325,13 @@
325 if( strchr(zCap, 'o') ) oao = " checked";
326 if( strchr(zCap, 'p') ) oap = " checked";
327 if( strchr(zCap, 'r') ) oar = " checked";
328 if( strchr(zCap, 's') ) oas = " checked";
329 if( strchr(zCap, 't') ) oat = " checked";
330 if( strchr(zCap, 'v') ) oav = " checked";
331 if( strchr(zCap, 'w') ) oaw = " checked";
332 if( strchr(zCap, 'z') ) oaz = " checked";
333 }
334
335 /* Begin generating the page
336 */
337 style_submenu_element("Cancel", "Cancel", "setup_ulist");
@@ -346,35 +370,46 @@
370 @ <input type="checkbox" name="ae"%s(oad)>Email</input><br>
371 @ <input type="checkbox" name="ap"%s(oap)>Password</input><br>
372 @ <input type="checkbox" name="ai"%s(oai)>Check-In</input><br>
373 @ <input type="checkbox" name="ao"%s(oao)>Check-Out</input><br>
374 @ <input type="checkbox" name="ah"%s(oah)>History</input><br>
375 @ <input type="checkbox" name="av"%s(oav)>Developer</input><br>
376 @ <input type="checkbox" name="ag"%s(oag)>Clone</input><br>
377 @ <input type="checkbox" name="aj"%s(oaj)>Read Wiki</input><br>
378 @ <input type="checkbox" name="af"%s(oaf)>New Wiki</input><br>
379 @ <input type="checkbox" name="am"%s(oam)>Append Wiki</input><br>
380 @ <input type="checkbox" name="ak"%s(oak)>Write Wiki</input><br>
381 @ <input type="checkbox" name="ar"%s(oar)>Read Tkt</input><br>
382 @ <input type="checkbox" name="an"%s(oan)>New Tkt</input><br>
383 @ <input type="checkbox" name="ac"%s(oac)>Append Tkt</input><br>
384 @ <input type="checkbox" name="aw"%s(oaw)>Write Tkt</input><br>
385 @ <input type="checkbox" name="at"%s(oat)>Tkt Report</input><br>
386 @ <input type="checkbox" name="az"%s(oaz)>Download Zip</input>
387 @ </td>
388 @ </tr>
389 @ <tr>
390 @ <td align="right">Password:</td>
391 if( strcmp(zLogin, "anonymous")==0 ){
392 /* User the password for "anonymous" as cleartext */
393 @ <td><input type="text" name="pw" value="%h(zPw)"></td>
394 }else if( zPw[0] ){
395 /* Obscure the password for all other users */
396 @ <td><input type="password" name="pw" value="**********"></td>
397 }else{
398 /* Show an empty password as an empty input field */
399 @ <td><input type="password" name="pw" value=""></td>
400 }
401 @ </tr>
402 if( !higherUser ){
403 @ <tr>
404 @ <td>&nbsp</td>
405 @ <td><input type="submit" name="submit" value="Apply Changes">
406 @ </tr>
407 }
408 @ </table></td></tr></table>
409 @ <h2>Privileges And Capabilities:</h2>
410 @ <ul>
411 if( higherUser ){
412 @ <li><p><font color="blue"><b>
413 @ User %h(zLogin) has Setup privileges and you only have Admin privileges
414 @ so you are not permitted to make changes to %h(zLogin).
415 @ </b></font></p></li>
@@ -401,10 +436,24 @@
436 @ This is recommended ON for most logged-in users but OFF for
437 @ user "nobody" to avoid problems with spiders trying to walk every
438 @ historical version of every baseline and file.
439 @ </p></li>
440 @
441 @ <li><p>
442 @ The <b>Zip</b> privilege allows a user to see the download as zip hyperlink
443 @ as well as permit access to the <tt>/zip</tt> page. It can be allowed for
444 @ user "nobody" to grant him access to download artifacts he know from the
445 @ server without giving him other rights like <b>Read</b> or <b>History</b>.
446 @ So automatic package dowloaders could be able to obtain the sources without
447 @ going thru the login procedure.
448 @ </p></li>
449 @
450 @ <li><p>
451 @ The <b>Developer</b> privilege causes all privileges of the user
452 @ named "developer" to be inherited by this user.
453 @ </p></li>
454 @
455 @ <li><p>
456 @ The <b>Check-in</b> privilege allows remote users to "push".
457 @ The <b>Check-out</b> privilege allows remote users to "pull".
458 @ The <b>Clone</b> privilege allows remote users to "clone".
459 @ </li><p>
@@ -418,39 +467,58 @@
467 @ ticket report formats.
468 @ </p></li>
469 @
470 @ <li><p>
471 @ Users with the <b>Password</b> privilege are allowed to change their
472 @ own password. Recommended ON for most users but OFF for special
473 @ users "developer, "anonynmous", and "nobody".
474 @ </p></li>
475 @
476 @ <li><p>
477 @ The <b>EMail</b> privilege allows the display of sensitive information
478 @ such as the email address of users and contact information on tickets.
479 @ Recommended OFF for "anonymous" and for "nobody".
480 @ </p></li>
481 @
482 @ <li><p>
483 @ Login is prohibited if the password is an empty string.
484 @ </p></li>
485 @ </ul>
486 @
487 @ <h2>Special Logins</h2>
488 @
489 @ <ul>
490 @ <li><p>
491 @ No login is required for user "<b>nobody</b>". The capabilities
492 @ of the <b>nobody</b> user are inherited by all users, regardless of
493 @ whether or not they are logged in. To disable universal access
494 @ to the repository, make sure no user named "<b>nobody</b>" exists or
495 @ that the <b>nobody</b> user has no capabilities enabled.
496 @ The password for <b>nobody</b> is ignore. To avoid problems with
497 @ spiders overloading the server, it is recommended
498 @ that the 'h' (History) capability be turned off for the <b>nobody</b>
499 @ user.
500 @ </p></li>
501 @
502 @ <li><p>
503 @ Login is required for user "<b>anonymous</b>" but the password
504 @ is displayed on the login screen beside the password entry box
505 @ so anybody who can read should be able to login as anonymous.
506 @ On the other hand, spiders and web-crawlers will typically not
507 @ be able to login. Set the capabilities of the anonymous user
508 @ to things that you want any human to be able to do, but not any
509 @ spider. Every other logged-in user inherits the privileges of
510 @ <b>anonymous</b>.
511 @ </p></li>
512 @
513 @ <li><p>
514 @ The "<b>developer</b>" user is intended as a template for trusted users
515 @ with check-in privileges. When adding new trusted users, simply
516 @ select the <b>Developer</b> privilege to cause the new user to inherit
517 @ all privileges of the "developer" user.
518 @ </li></p>
519 @ </ul>
520 @ </form>
521 style_footer();
522 }
523
524
525
+3 -3
--- src/style.c
+++ src/style.c
@@ -82,11 +82,11 @@
8282
void style_header(const char *zTitleFormat, ...){
8383
va_list ap;
8484
char *zTitle;
8585
const char *zHeader = db_get("header", (char*)zDefaultHeader);
8686
login_check_credentials();
87
-
87
+
8888
va_start(ap, zTitleFormat);
8989
zTitle = vmprintf(zTitleFormat, ap);
9090
va_end(ap);
9191
9292
cgi_destination(CGI_HEADER);
@@ -112,13 +112,13 @@
112112
/*
113113
** Draw the footer at the bottom of the page.
114114
*/
115115
void style_footer(void){
116116
const char *zFooter;
117
-
117
+
118118
if( !headerHasBeenGenerated ) return;
119
-
119
+
120120
/* Go back and put the submenu at the top of the page. We delay the
121121
** creation of the submenu until the end so that we can add elements
122122
** to the submenu while generating page text.
123123
*/
124124
cgi_destination(CGI_HEADER);
125125
--- src/style.c
+++ src/style.c
@@ -82,11 +82,11 @@
82 void style_header(const char *zTitleFormat, ...){
83 va_list ap;
84 char *zTitle;
85 const char *zHeader = db_get("header", (char*)zDefaultHeader);
86 login_check_credentials();
87
88 va_start(ap, zTitleFormat);
89 zTitle = vmprintf(zTitleFormat, ap);
90 va_end(ap);
91
92 cgi_destination(CGI_HEADER);
@@ -112,13 +112,13 @@
112 /*
113 ** Draw the footer at the bottom of the page.
114 */
115 void style_footer(void){
116 const char *zFooter;
117
118 if( !headerHasBeenGenerated ) return;
119
120 /* Go back and put the submenu at the top of the page. We delay the
121 ** creation of the submenu until the end so that we can add elements
122 ** to the submenu while generating page text.
123 */
124 cgi_destination(CGI_HEADER);
125
--- src/style.c
+++ src/style.c
@@ -82,11 +82,11 @@
82 void style_header(const char *zTitleFormat, ...){
83 va_list ap;
84 char *zTitle;
85 const char *zHeader = db_get("header", (char*)zDefaultHeader);
86 login_check_credentials();
87
88 va_start(ap, zTitleFormat);
89 zTitle = vmprintf(zTitleFormat, ap);
90 va_end(ap);
91
92 cgi_destination(CGI_HEADER);
@@ -112,13 +112,13 @@
112 /*
113 ** Draw the footer at the bottom of the page.
114 */
115 void style_footer(void){
116 const char *zFooter;
117
118 if( !headerHasBeenGenerated ) return;
119
120 /* Go back and put the submenu at the top of the page. We delay the
121 ** creation of the submenu until the end so that we can add elements
122 ** to the submenu while generating page text.
123 */
124 cgi_destination(CGI_HEADER);
125
+3 -3
--- src/style.c
+++ src/style.c
@@ -82,11 +82,11 @@
8282
void style_header(const char *zTitleFormat, ...){
8383
va_list ap;
8484
char *zTitle;
8585
const char *zHeader = db_get("header", (char*)zDefaultHeader);
8686
login_check_credentials();
87
-
87
+
8888
va_start(ap, zTitleFormat);
8989
zTitle = vmprintf(zTitleFormat, ap);
9090
va_end(ap);
9191
9292
cgi_destination(CGI_HEADER);
@@ -112,13 +112,13 @@
112112
/*
113113
** Draw the footer at the bottom of the page.
114114
*/
115115
void style_footer(void){
116116
const char *zFooter;
117
-
117
+
118118
if( !headerHasBeenGenerated ) return;
119
-
119
+
120120
/* Go back and put the submenu at the top of the page. We delay the
121121
** creation of the submenu until the end so that we can add elements
122122
** to the submenu while generating page text.
123123
*/
124124
cgi_destination(CGI_HEADER);
125125
--- src/style.c
+++ src/style.c
@@ -82,11 +82,11 @@
82 void style_header(const char *zTitleFormat, ...){
83 va_list ap;
84 char *zTitle;
85 const char *zHeader = db_get("header", (char*)zDefaultHeader);
86 login_check_credentials();
87
88 va_start(ap, zTitleFormat);
89 zTitle = vmprintf(zTitleFormat, ap);
90 va_end(ap);
91
92 cgi_destination(CGI_HEADER);
@@ -112,13 +112,13 @@
112 /*
113 ** Draw the footer at the bottom of the page.
114 */
115 void style_footer(void){
116 const char *zFooter;
117
118 if( !headerHasBeenGenerated ) return;
119
120 /* Go back and put the submenu at the top of the page. We delay the
121 ** creation of the submenu until the end so that we can add elements
122 ** to the submenu while generating page text.
123 */
124 cgi_destination(CGI_HEADER);
125
--- src/style.c
+++ src/style.c
@@ -82,11 +82,11 @@
82 void style_header(const char *zTitleFormat, ...){
83 va_list ap;
84 char *zTitle;
85 const char *zHeader = db_get("header", (char*)zDefaultHeader);
86 login_check_credentials();
87
88 va_start(ap, zTitleFormat);
89 zTitle = vmprintf(zTitleFormat, ap);
90 va_end(ap);
91
92 cgi_destination(CGI_HEADER);
@@ -112,13 +112,13 @@
112 /*
113 ** Draw the footer at the bottom of the page.
114 */
115 void style_footer(void){
116 const char *zFooter;
117
118 if( !headerHasBeenGenerated ) return;
119
120 /* Go back and put the submenu at the top of the page. We delay the
121 ** creation of the submenu until the end so that we can add elements
122 ** to the submenu while generating page text.
123 */
124 cgi_destination(CGI_HEADER);
125
+95 -23
--- src/tag.c
+++ src/tag.c
@@ -245,20 +245,75 @@
245245
zValue = g.argc==5 ? g.argv[4] : 0;
246246
db_begin_transaction();
247247
tag_insert(zTag, tagtype, zValue, -1, 0.0, rid);
248248
db_end_transaction(0);
249249
}
250
+
251
+/*
252
+** Prepare an artifact that describes a fork from a certain UUID.
253
+** Furthermore a propagating symbolic tag will be inserted and
254
+** all other propagating symbolic tags will be cancelled.
255
+**
256
+** The changes are appended at the Blob pCtrl. However the manifest
257
+** is not complete at that stage.
258
+*/
259
+static void tag_prepare_fork(
260
+ Blob *pCtrl,
261
+ const char *zTagname,
262
+ int rid
263
+){
264
+ Stmt q;
265
+ Manifest origin;
266
+ Blob originContent;
267
+ char *zDate;
268
+ int i;
269
+
270
+ blob_appendf(pCtrl, "C Create\\snamed\\sfork\\s%s\n", zTagname+4);
271
+ content_get(rid, &originContent);
272
+ manifest_parse(&origin, &originContent);
273
+ zDate = db_text(0, "SELECT datetime('now')");
274
+ zDate[10] = 'T';
275
+ blob_appendf(pCtrl, "D %s\n", zDate);
276
+ for(i=0; i<origin.nFile; ++i){
277
+ blob_appendf(pCtrl, "F %s %s %s\n",
278
+ origin.aFile[i].zName,
279
+ origin.aFile[i].zUuid,
280
+ origin.aFile[i].zPerm);
281
+ }
282
+ if( origin.nParent>0 ){
283
+ blob_appendf(pCtrl, "P %s\n", origin.azParent[0]);
284
+ }
285
+ blob_appendf(pCtrl, "R %s\n", origin.zRepoCksum);
286
+ blob_appendf(pCtrl, "T *%F *", zTagname);
287
+
288
+ /* Cancel any sym- tags that propagate */
289
+ db_prepare(&q,
290
+ "SELECT tagname FROM tagxref, tag"
291
+ " WHERE tagxref.rid=%d AND tagxref.tagid=tag.tagid"
292
+ " AND tagtype>0 AND tagname LIKE 'sym-%%'"
293
+ " ORDER BY tagname",
294
+ rid);
295
+ while( db_step(&q)==SQLITE_ROW ){
296
+ const char *zTag = db_column_text(&q, 0);
297
+ blob_appendf(pCtrl, "\nT -%s *", zTag);
298
+ }
299
+ db_finalize(&q);
300
+
301
+ /* Cleanup */
302
+ manifest_clear(&origin);
303
+}
250304
251305
/*
252306
** Add a control record to the repository that either creates
253307
** or cancels a tag.
254308
*/
255309
static void tag_add_artifact(
256310
const char *zTagname, /* The tag to add or cancel */
257311
const char *zObjName, /* Name of object attached to */
258312
const char *zValue, /* Value for the tag. Might be NULL */
259
- int tagtype /* 0:cancel 1:singleton 2:propagated */
313
+ int tagtype, /* 0:cancel 1:singleton 2:propagated */
314
+ int fork /* Should a fork created from zObjName? */
260315
){
261316
int rid;
262317
int nrid;
263318
char *zDate;
264319
Blob uuid;
@@ -278,14 +333,18 @@
278333
279334
if( validate16(zTagname, strlen(zTagname)) ){
280335
fossil_fatal("invalid tag name \"%s\" - might be confused with a UUID",
281336
zTagname);
282337
}
283
- zDate = db_text(0, "SELECT datetime('now')");
284
- zDate[10] = 'T';
285
- blob_appendf(&ctrl, "D %s\n", zDate);
286
- blob_appendf(&ctrl, "T %c%F %b", zTagtype[tagtype], zTagname, &uuid);
338
+ if( fork ){
339
+ tag_prepare_fork(&ctrl, zTagname, rid);
340
+ }else{
341
+ zDate = db_text(0, "SELECT datetime('now')");
342
+ zDate[10] = 'T';
343
+ blob_appendf(&ctrl, "D %s\n", zDate);
344
+ blob_appendf(&ctrl, "T %c%F %b", zTagtype[tagtype], zTagname, &uuid);
345
+ }
287346
if( tagtype && zValue && zValue[0] ){
288347
blob_appendf(&ctrl, " %F\n", zValue);
289348
}else{
290349
blob_appendf(&ctrl, "\n");
291350
}
@@ -309,20 +368,31 @@
309368
**
310369
** %fossil tag add ?--raw? TAGNAME UUID ?VALUE?
311370
**
312371
** Add a new tag or property to UUID. The tag will
313372
** be usable instead of a UUID in commands like
314
-** update and the like.
373
+** update and such.
315374
**
316375
** %fossil tag branch ?--raw? TAGNAME UUID ?VALUE?
317376
**
318
-** Add a new tag or property to UUID and make that
319
-** tag propagate to all direct children.
377
+** A fork of UUID will be created. Then the new tag
378
+** or property will be added to the fork that
379
+** propagate to all direct children.
380
+**
381
+** Additionally all symbolic tags of that fork
382
+** inherited from UUID will be cancelled.
383
+**
384
+** However, if the option '--raw' was given, no
385
+** fork will be created but the tag/property will be
386
+** added to UUID directly and no tag will be
387
+** canceled.
388
+**
389
+** Please see the description of '--raw' below too.
320390
**
321
-** %fossil tag delete ?--raw? TAGNAME UUID
391
+** %fossil tag cancel ?--raw? TAGNAME UUID
322392
**
323
-** Delete the tag TAGNAME from UUID
393
+** Cancel the tag TAGNAME from UUID
324394
**
325395
** %fossil tag find ?--raw? TAGNAME
326396
**
327397
** List all baselines that use TAGNAME
328398
**
@@ -369,39 +439,43 @@
369439
blob_set(&tagname, prefix);
370440
371441
if( strncmp(g.argv[2],"add",n)==0 ){
372442
char *zValue;
373443
if( g.argc!=5 && g.argc!=6 ){
374
- usage("add TAGNAME UUID ?VALUE?");
444
+ usage("add ?--raw? TAGNAME UUID ?VALUE?");
375445
}
376446
blob_append(&tagname, g.argv[3], strlen(g.argv[3]));
377447
zValue = g.argc==6 ? g.argv[5] : 0;
378
- tag_add_artifact(blob_str(&tagname), g.argv[4], zValue, 1);
448
+ tag_add_artifact(blob_str(&tagname), g.argv[4], zValue, 1, 0);
379449
}else
380450
381451
if( strncmp(g.argv[2],"branch",n)==0 ){
382452
char *zValue;
383453
if( g.argc!=5 && g.argc!=6 ){
384
- usage("branch TAGNAME UUID ?VALUE?");
454
+ usage("branch ?--raw? TAGNAME UUID ?VALUE?");
385455
}
386456
blob_append(&tagname, g.argv[3], strlen(g.argv[3]));
387457
zValue = g.argc==6 ? g.argv[5] : 0;
388
- tag_add_artifact(blob_str(&tagname), g.argv[4], zValue, 2);
458
+ tag_add_artifact(blob_str(&tagname), g.argv[4], zValue, 2, raw==0);
459
+ if( !raw ){
460
+ const char *zUuid = db_text(0, "SELECT uuid, MAX(rowid) FROM blob");
461
+ printf("New_Fork \"%s\": %s\n", g.argv[3], zUuid);
462
+ }
389463
}else
390464
391
- if( strncmp(g.argv[2],"delete",n)==0 ){
465
+ if( strncmp(g.argv[2],"cancel",n)==0 ){
392466
if( g.argc!=5 ){
393
- usage("delete TAGNAME UUID");
467
+ usage("cancel ?--raw? TAGNAME UUID");
394468
}
395469
blob_append(&tagname, g.argv[3], strlen(g.argv[3]));
396
- tag_add_artifact(blob_str(&tagname), g.argv[4], 0, 0);
470
+ tag_add_artifact(blob_str(&tagname), g.argv[4], 0, 0, 0);
397471
}else
398472
399473
if( strncmp(g.argv[2],"find",n)==0 ){
400474
Stmt q;
401475
if( g.argc!=4 ){
402
- usage("find TAGNAME");
476
+ usage("find ?--raw? TAGNAME");
403477
}
404478
blob_append(&tagname, g.argv[3], strlen(g.argv[3]));
405479
db_prepare(&q,
406480
"SELECT blob.uuid FROM tagxref, blob"
407481
" WHERE tagid=(SELECT tagid FROM tag WHERE tagname=%B)"
@@ -415,12 +489,11 @@
415489
416490
if( strncmp(g.argv[2],"list",n)==0 ){
417491
Stmt q;
418492
if( g.argc==3 ){
419493
db_prepare(&q,
420
- "SELECT tagname"
421
- " FROM tag"
494
+ "SELECT tagname FROM tag"
422495
" WHERE EXISTS(SELECT 1 FROM tagxref"
423496
" WHERE tagid=tag.tagid"
424497
" AND tagtype>0)"
425498
" ORDER BY tagname"
426499
);
@@ -432,12 +505,11 @@
432505
}
433506
db_finalize(&q);
434507
}else if( g.argc==4 ){
435508
int rid = name_to_rid(g.argv[3]);
436509
db_prepare(&q,
437
- "SELECT tagname, value"
438
- " FROM tagxref, tag"
510
+ "SELECT tagname, value FROM tagxref, tag"
439511
" WHERE tagxref.rid=%d AND tagxref.tagid=tag.tagid"
440512
" AND tagtype>0"
441513
" ORDER BY tagname",
442514
rid
443515
);
@@ -466,7 +538,7 @@
466538
/* Cleanup */
467539
blob_reset(&tagname);
468540
return;
469541
470542
tag_cmd_usage:
471
- usage("add|branch|delete|find|list ...");
543
+ usage("add|branch|cancel|find|list ...");
472544
}
473545
--- src/tag.c
+++ src/tag.c
@@ -245,20 +245,75 @@
245 zValue = g.argc==5 ? g.argv[4] : 0;
246 db_begin_transaction();
247 tag_insert(zTag, tagtype, zValue, -1, 0.0, rid);
248 db_end_transaction(0);
249 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
250
251 /*
252 ** Add a control record to the repository that either creates
253 ** or cancels a tag.
254 */
255 static void tag_add_artifact(
256 const char *zTagname, /* The tag to add or cancel */
257 const char *zObjName, /* Name of object attached to */
258 const char *zValue, /* Value for the tag. Might be NULL */
259 int tagtype /* 0:cancel 1:singleton 2:propagated */
 
260 ){
261 int rid;
262 int nrid;
263 char *zDate;
264 Blob uuid;
@@ -278,14 +333,18 @@
278
279 if( validate16(zTagname, strlen(zTagname)) ){
280 fossil_fatal("invalid tag name \"%s\" - might be confused with a UUID",
281 zTagname);
282 }
283 zDate = db_text(0, "SELECT datetime('now')");
284 zDate[10] = 'T';
285 blob_appendf(&ctrl, "D %s\n", zDate);
286 blob_appendf(&ctrl, "T %c%F %b", zTagtype[tagtype], zTagname, &uuid);
 
 
 
 
287 if( tagtype && zValue && zValue[0] ){
288 blob_appendf(&ctrl, " %F\n", zValue);
289 }else{
290 blob_appendf(&ctrl, "\n");
291 }
@@ -309,20 +368,31 @@
309 **
310 ** %fossil tag add ?--raw? TAGNAME UUID ?VALUE?
311 **
312 ** Add a new tag or property to UUID. The tag will
313 ** be usable instead of a UUID in commands like
314 ** update and the like.
315 **
316 ** %fossil tag branch ?--raw? TAGNAME UUID ?VALUE?
317 **
318 ** Add a new tag or property to UUID and make that
319 ** tag propagate to all direct children.
 
 
 
 
 
 
 
 
 
 
 
320 **
321 ** %fossil tag delete ?--raw? TAGNAME UUID
322 **
323 ** Delete the tag TAGNAME from UUID
324 **
325 ** %fossil tag find ?--raw? TAGNAME
326 **
327 ** List all baselines that use TAGNAME
328 **
@@ -369,39 +439,43 @@
369 blob_set(&tagname, prefix);
370
371 if( strncmp(g.argv[2],"add",n)==0 ){
372 char *zValue;
373 if( g.argc!=5 && g.argc!=6 ){
374 usage("add TAGNAME UUID ?VALUE?");
375 }
376 blob_append(&tagname, g.argv[3], strlen(g.argv[3]));
377 zValue = g.argc==6 ? g.argv[5] : 0;
378 tag_add_artifact(blob_str(&tagname), g.argv[4], zValue, 1);
379 }else
380
381 if( strncmp(g.argv[2],"branch",n)==0 ){
382 char *zValue;
383 if( g.argc!=5 && g.argc!=6 ){
384 usage("branch TAGNAME UUID ?VALUE?");
385 }
386 blob_append(&tagname, g.argv[3], strlen(g.argv[3]));
387 zValue = g.argc==6 ? g.argv[5] : 0;
388 tag_add_artifact(blob_str(&tagname), g.argv[4], zValue, 2);
 
 
 
 
389 }else
390
391 if( strncmp(g.argv[2],"delete",n)==0 ){
392 if( g.argc!=5 ){
393 usage("delete TAGNAME UUID");
394 }
395 blob_append(&tagname, g.argv[3], strlen(g.argv[3]));
396 tag_add_artifact(blob_str(&tagname), g.argv[4], 0, 0);
397 }else
398
399 if( strncmp(g.argv[2],"find",n)==0 ){
400 Stmt q;
401 if( g.argc!=4 ){
402 usage("find TAGNAME");
403 }
404 blob_append(&tagname, g.argv[3], strlen(g.argv[3]));
405 db_prepare(&q,
406 "SELECT blob.uuid FROM tagxref, blob"
407 " WHERE tagid=(SELECT tagid FROM tag WHERE tagname=%B)"
@@ -415,12 +489,11 @@
415
416 if( strncmp(g.argv[2],"list",n)==0 ){
417 Stmt q;
418 if( g.argc==3 ){
419 db_prepare(&q,
420 "SELECT tagname"
421 " FROM tag"
422 " WHERE EXISTS(SELECT 1 FROM tagxref"
423 " WHERE tagid=tag.tagid"
424 " AND tagtype>0)"
425 " ORDER BY tagname"
426 );
@@ -432,12 +505,11 @@
432 }
433 db_finalize(&q);
434 }else if( g.argc==4 ){
435 int rid = name_to_rid(g.argv[3]);
436 db_prepare(&q,
437 "SELECT tagname, value"
438 " FROM tagxref, tag"
439 " WHERE tagxref.rid=%d AND tagxref.tagid=tag.tagid"
440 " AND tagtype>0"
441 " ORDER BY tagname",
442 rid
443 );
@@ -466,7 +538,7 @@
466 /* Cleanup */
467 blob_reset(&tagname);
468 return;
469
470 tag_cmd_usage:
471 usage("add|branch|delete|find|list ...");
472 }
473
--- src/tag.c
+++ src/tag.c
@@ -245,20 +245,75 @@
245 zValue = g.argc==5 ? g.argv[4] : 0;
246 db_begin_transaction();
247 tag_insert(zTag, tagtype, zValue, -1, 0.0, rid);
248 db_end_transaction(0);
249 }
250
251 /*
252 ** Prepare an artifact that describes a fork from a certain UUID.
253 ** Furthermore a propagating symbolic tag will be inserted and
254 ** all other propagating symbolic tags will be cancelled.
255 **
256 ** The changes are appended at the Blob pCtrl. However the manifest
257 ** is not complete at that stage.
258 */
259 static void tag_prepare_fork(
260 Blob *pCtrl,
261 const char *zTagname,
262 int rid
263 ){
264 Stmt q;
265 Manifest origin;
266 Blob originContent;
267 char *zDate;
268 int i;
269
270 blob_appendf(pCtrl, "C Create\\snamed\\sfork\\s%s\n", zTagname+4);
271 content_get(rid, &originContent);
272 manifest_parse(&origin, &originContent);
273 zDate = db_text(0, "SELECT datetime('now')");
274 zDate[10] = 'T';
275 blob_appendf(pCtrl, "D %s\n", zDate);
276 for(i=0; i<origin.nFile; ++i){
277 blob_appendf(pCtrl, "F %s %s %s\n",
278 origin.aFile[i].zName,
279 origin.aFile[i].zUuid,
280 origin.aFile[i].zPerm);
281 }
282 if( origin.nParent>0 ){
283 blob_appendf(pCtrl, "P %s\n", origin.azParent[0]);
284 }
285 blob_appendf(pCtrl, "R %s\n", origin.zRepoCksum);
286 blob_appendf(pCtrl, "T *%F *", zTagname);
287
288 /* Cancel any sym- tags that propagate */
289 db_prepare(&q,
290 "SELECT tagname FROM tagxref, tag"
291 " WHERE tagxref.rid=%d AND tagxref.tagid=tag.tagid"
292 " AND tagtype>0 AND tagname LIKE 'sym-%%'"
293 " ORDER BY tagname",
294 rid);
295 while( db_step(&q)==SQLITE_ROW ){
296 const char *zTag = db_column_text(&q, 0);
297 blob_appendf(pCtrl, "\nT -%s *", zTag);
298 }
299 db_finalize(&q);
300
301 /* Cleanup */
302 manifest_clear(&origin);
303 }
304
305 /*
306 ** Add a control record to the repository that either creates
307 ** or cancels a tag.
308 */
309 static void tag_add_artifact(
310 const char *zTagname, /* The tag to add or cancel */
311 const char *zObjName, /* Name of object attached to */
312 const char *zValue, /* Value for the tag. Might be NULL */
313 int tagtype, /* 0:cancel 1:singleton 2:propagated */
314 int fork /* Should a fork created from zObjName? */
315 ){
316 int rid;
317 int nrid;
318 char *zDate;
319 Blob uuid;
@@ -278,14 +333,18 @@
333
334 if( validate16(zTagname, strlen(zTagname)) ){
335 fossil_fatal("invalid tag name \"%s\" - might be confused with a UUID",
336 zTagname);
337 }
338 if( fork ){
339 tag_prepare_fork(&ctrl, zTagname, rid);
340 }else{
341 zDate = db_text(0, "SELECT datetime('now')");
342 zDate[10] = 'T';
343 blob_appendf(&ctrl, "D %s\n", zDate);
344 blob_appendf(&ctrl, "T %c%F %b", zTagtype[tagtype], zTagname, &uuid);
345 }
346 if( tagtype && zValue && zValue[0] ){
347 blob_appendf(&ctrl, " %F\n", zValue);
348 }else{
349 blob_appendf(&ctrl, "\n");
350 }
@@ -309,20 +368,31 @@
368 **
369 ** %fossil tag add ?--raw? TAGNAME UUID ?VALUE?
370 **
371 ** Add a new tag or property to UUID. The tag will
372 ** be usable instead of a UUID in commands like
373 ** update and such.
374 **
375 ** %fossil tag branch ?--raw? TAGNAME UUID ?VALUE?
376 **
377 ** A fork of UUID will be created. Then the new tag
378 ** or property will be added to the fork that
379 ** propagate to all direct children.
380 **
381 ** Additionally all symbolic tags of that fork
382 ** inherited from UUID will be cancelled.
383 **
384 ** However, if the option '--raw' was given, no
385 ** fork will be created but the tag/property will be
386 ** added to UUID directly and no tag will be
387 ** canceled.
388 **
389 ** Please see the description of '--raw' below too.
390 **
391 ** %fossil tag cancel ?--raw? TAGNAME UUID
392 **
393 ** Cancel the tag TAGNAME from UUID
394 **
395 ** %fossil tag find ?--raw? TAGNAME
396 **
397 ** List all baselines that use TAGNAME
398 **
@@ -369,39 +439,43 @@
439 blob_set(&tagname, prefix);
440
441 if( strncmp(g.argv[2],"add",n)==0 ){
442 char *zValue;
443 if( g.argc!=5 && g.argc!=6 ){
444 usage("add ?--raw? TAGNAME UUID ?VALUE?");
445 }
446 blob_append(&tagname, g.argv[3], strlen(g.argv[3]));
447 zValue = g.argc==6 ? g.argv[5] : 0;
448 tag_add_artifact(blob_str(&tagname), g.argv[4], zValue, 1, 0);
449 }else
450
451 if( strncmp(g.argv[2],"branch",n)==0 ){
452 char *zValue;
453 if( g.argc!=5 && g.argc!=6 ){
454 usage("branch ?--raw? TAGNAME UUID ?VALUE?");
455 }
456 blob_append(&tagname, g.argv[3], strlen(g.argv[3]));
457 zValue = g.argc==6 ? g.argv[5] : 0;
458 tag_add_artifact(blob_str(&tagname), g.argv[4], zValue, 2, raw==0);
459 if( !raw ){
460 const char *zUuid = db_text(0, "SELECT uuid, MAX(rowid) FROM blob");
461 printf("New_Fork \"%s\": %s\n", g.argv[3], zUuid);
462 }
463 }else
464
465 if( strncmp(g.argv[2],"cancel",n)==0 ){
466 if( g.argc!=5 ){
467 usage("cancel ?--raw? TAGNAME UUID");
468 }
469 blob_append(&tagname, g.argv[3], strlen(g.argv[3]));
470 tag_add_artifact(blob_str(&tagname), g.argv[4], 0, 0, 0);
471 }else
472
473 if( strncmp(g.argv[2],"find",n)==0 ){
474 Stmt q;
475 if( g.argc!=4 ){
476 usage("find ?--raw? TAGNAME");
477 }
478 blob_append(&tagname, g.argv[3], strlen(g.argv[3]));
479 db_prepare(&q,
480 "SELECT blob.uuid FROM tagxref, blob"
481 " WHERE tagid=(SELECT tagid FROM tag WHERE tagname=%B)"
@@ -415,12 +489,11 @@
489
490 if( strncmp(g.argv[2],"list",n)==0 ){
491 Stmt q;
492 if( g.argc==3 ){
493 db_prepare(&q,
494 "SELECT tagname FROM tag"
 
495 " WHERE EXISTS(SELECT 1 FROM tagxref"
496 " WHERE tagid=tag.tagid"
497 " AND tagtype>0)"
498 " ORDER BY tagname"
499 );
@@ -432,12 +505,11 @@
505 }
506 db_finalize(&q);
507 }else if( g.argc==4 ){
508 int rid = name_to_rid(g.argv[3]);
509 db_prepare(&q,
510 "SELECT tagname, value FROM tagxref, tag"
 
511 " WHERE tagxref.rid=%d AND tagxref.tagid=tag.tagid"
512 " AND tagtype>0"
513 " ORDER BY tagname",
514 rid
515 );
@@ -466,7 +538,7 @@
538 /* Cleanup */
539 blob_reset(&tagname);
540 return;
541
542 tag_cmd_usage:
543 usage("add|branch|cancel|find|list ...");
544 }
545
+31 -30
--- src/tagview.c
+++ src/tagview.c
@@ -134,36 +134,10 @@
134134
tagname);
135135
db_generic_query_view(zSql, 1);
136136
free(zSql);
137137
}
138138
139
-/*
140
-** Get the UUIDs for a tag
141
-*/
142
-char *tag_query_for_www(const char *pName){
143
- static const char zBaseSql[] =
144
- @ SELECT
145
- @ blob.rid,
146
- @ uuid,
147
- @ datetime(event.mtime,'localtime') AS timestamp,
148
- @ coalesce(ecomment, comment),
149
- @ coalesce(euser, user),
150
- @ (SELECT count(*) FROM plink WHERE pid=blob.rid AND isprim=1),
151
- @ (SELECT count(*) FROM plink WHERE cid=blob.rid),
152
- @ NOT EXISTS (SELECT 1 FROM plink WHERE pid=blob.rid),
153
- @ coalesce(bgcolor, brbgcolor),
154
- @ event.type
155
- @ FROM event JOIN blob JOIN tagxref
156
- @ WHERE blob.rid=event.objid
157
- @ AND tagxref.rid = event.objid
158
- @ AND tagxref.tagid = (SELECT tagid FROM tag
159
- @ WHERE tagname = 'sym-'||%Q)
160
- @ ORDER BY 3 desc
161
- ;
162
- return mprintf(zBaseSql,pName);
163
-}
164
-
165139
/*
166140
** WEBP AGE: /tagview
167141
*/
168142
void old_tagview_page(void){
169143
char const * check = 0;
@@ -202,11 +176,31 @@
202176
char *zSql;
203177
Stmt q;
204178
if( sym_tag_to_uuid(zName, &uuid) > 0){
205179
style_header("Tagged Baselines");
206180
@ <h2>%s(zName):</h2>
207
- zSql = tag_query_for_www(zName);
181
+ zSql = mprintf("%s AND EXISTS (SELECT 1"
182
+ " FROM tagxref"
183
+ " WHERE tagxref.rid = event.objid"
184
+ " AND tagxref.tagid = (SELECT tagid FROM tag"
185
+ " WHERE tagname = 'sym-'||%Q))"
186
+ " ORDER BY 3 desc",
187
+ timeline_query_for_www(), zName);
188
+ db_prepare(&q, zSql);
189
+ free(zSql);
190
+ www_print_timeline(&q);
191
+ db_finalize(&q);
192
+ }else if( tag_to_uuid(zName, &uuid, "") > 0){
193
+ style_header("Tagged Baselines");
194
+ @ <h2>%s(zName):</h2>
195
+ zSql = mprintf("%s AND EXISTS (SELECT 1"
196
+ " FROM tagxref"
197
+ " WHERE tagxref.rid = event.objid"
198
+ " AND tagxref.tagid = (SELECT tagid FROM tag"
199
+ " WHERE tagname = %Q))"
200
+ " ORDER BY 3 desc",
201
+ timeline_query_for_www(), zName);
208202
db_prepare(&q, zSql);
209203
free(zSql);
210204
www_print_timeline(&q);
211205
db_finalize(&q);
212206
}else{
@@ -217,28 +211,35 @@
217211
}else{
218212
Stmt q;
219213
const char *prefix = "sym-";
220214
int preflen = strlen(prefix);
221215
style_header("Tags");
222
- db_prepare(&q,
216
+ db_prepare(&q,
223217
"SELECT tagname"
224218
" FROM tag"
225219
" WHERE EXISTS(SELECT 1 FROM tagxref"
226220
" WHERE tagid=tag.tagid"
227221
" AND tagtype>0)"
228
- " ORDER BY tagname"
222
+ " AND tagid > %d"
223
+ " AND tagname NOT GLOB 'wiki-*'"
224
+ " AND tagname NOT GLOB 'tkt-*'"
225
+ " ORDER BY tagname",
226
+ MAX_INT_TAG
229227
);
230228
@ <ul>
231229
while( db_step(&q)==SQLITE_ROW ){
232230
const char *name = db_column_text(&q, 0);
233231
if( strncmp(name, prefix, preflen)==0 ){
234232
@ <li><a href=%s(g.zBaseURL)/tagview?name=%s(name+preflen)>
235
- @ %s(name+preflen)</a></li>
233
+ @ <strong>%s(name+preflen)</strong></a></li>
234
+ }else{
235
+ @ <li><a href=%s(g.zBaseURL)/tagview?name=%s(name)>
236
+ @ %s(name)</a></li>
236237
}
237238
}
238239
@ </ul>
239240
db_finalize(&q);
240241
}
241242
style_footer();
242243
}
243244
244245
#undef TAGVIEW_DEFAULT_FILTER
245246
--- src/tagview.c
+++ src/tagview.c
@@ -134,36 +134,10 @@
134 tagname);
135 db_generic_query_view(zSql, 1);
136 free(zSql);
137 }
138
139 /*
140 ** Get the UUIDs for a tag
141 */
142 char *tag_query_for_www(const char *pName){
143 static const char zBaseSql[] =
144 @ SELECT
145 @ blob.rid,
146 @ uuid,
147 @ datetime(event.mtime,'localtime') AS timestamp,
148 @ coalesce(ecomment, comment),
149 @ coalesce(euser, user),
150 @ (SELECT count(*) FROM plink WHERE pid=blob.rid AND isprim=1),
151 @ (SELECT count(*) FROM plink WHERE cid=blob.rid),
152 @ NOT EXISTS (SELECT 1 FROM plink WHERE pid=blob.rid),
153 @ coalesce(bgcolor, brbgcolor),
154 @ event.type
155 @ FROM event JOIN blob JOIN tagxref
156 @ WHERE blob.rid=event.objid
157 @ AND tagxref.rid = event.objid
158 @ AND tagxref.tagid = (SELECT tagid FROM tag
159 @ WHERE tagname = 'sym-'||%Q)
160 @ ORDER BY 3 desc
161 ;
162 return mprintf(zBaseSql,pName);
163 }
164
165 /*
166 ** WEBP AGE: /tagview
167 */
168 void old_tagview_page(void){
169 char const * check = 0;
@@ -202,11 +176,31 @@
202 char *zSql;
203 Stmt q;
204 if( sym_tag_to_uuid(zName, &uuid) > 0){
205 style_header("Tagged Baselines");
206 @ <h2>%s(zName):</h2>
207 zSql = tag_query_for_www(zName);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
208 db_prepare(&q, zSql);
209 free(zSql);
210 www_print_timeline(&q);
211 db_finalize(&q);
212 }else{
@@ -217,28 +211,35 @@
217 }else{
218 Stmt q;
219 const char *prefix = "sym-";
220 int preflen = strlen(prefix);
221 style_header("Tags");
222 db_prepare(&q,
223 "SELECT tagname"
224 " FROM tag"
225 " WHERE EXISTS(SELECT 1 FROM tagxref"
226 " WHERE tagid=tag.tagid"
227 " AND tagtype>0)"
228 " ORDER BY tagname"
 
 
 
 
229 );
230 @ <ul>
231 while( db_step(&q)==SQLITE_ROW ){
232 const char *name = db_column_text(&q, 0);
233 if( strncmp(name, prefix, preflen)==0 ){
234 @ <li><a href=%s(g.zBaseURL)/tagview?name=%s(name+preflen)>
235 @ %s(name+preflen)</a></li>
 
 
 
236 }
237 }
238 @ </ul>
239 db_finalize(&q);
240 }
241 style_footer();
242 }
243
244 #undef TAGVIEW_DEFAULT_FILTER
245
--- src/tagview.c
+++ src/tagview.c
@@ -134,36 +134,10 @@
134 tagname);
135 db_generic_query_view(zSql, 1);
136 free(zSql);
137 }
138
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
139 /*
140 ** WEBP AGE: /tagview
141 */
142 void old_tagview_page(void){
143 char const * check = 0;
@@ -202,11 +176,31 @@
176 char *zSql;
177 Stmt q;
178 if( sym_tag_to_uuid(zName, &uuid) > 0){
179 style_header("Tagged Baselines");
180 @ <h2>%s(zName):</h2>
181 zSql = mprintf("%s AND EXISTS (SELECT 1"
182 " FROM tagxref"
183 " WHERE tagxref.rid = event.objid"
184 " AND tagxref.tagid = (SELECT tagid FROM tag"
185 " WHERE tagname = 'sym-'||%Q))"
186 " ORDER BY 3 desc",
187 timeline_query_for_www(), zName);
188 db_prepare(&q, zSql);
189 free(zSql);
190 www_print_timeline(&q);
191 db_finalize(&q);
192 }else if( tag_to_uuid(zName, &uuid, "") > 0){
193 style_header("Tagged Baselines");
194 @ <h2>%s(zName):</h2>
195 zSql = mprintf("%s AND EXISTS (SELECT 1"
196 " FROM tagxref"
197 " WHERE tagxref.rid = event.objid"
198 " AND tagxref.tagid = (SELECT tagid FROM tag"
199 " WHERE tagname = %Q))"
200 " ORDER BY 3 desc",
201 timeline_query_for_www(), zName);
202 db_prepare(&q, zSql);
203 free(zSql);
204 www_print_timeline(&q);
205 db_finalize(&q);
206 }else{
@@ -217,28 +211,35 @@
211 }else{
212 Stmt q;
213 const char *prefix = "sym-";
214 int preflen = strlen(prefix);
215 style_header("Tags");
216 db_prepare(&q,
217 "SELECT tagname"
218 " FROM tag"
219 " WHERE EXISTS(SELECT 1 FROM tagxref"
220 " WHERE tagid=tag.tagid"
221 " AND tagtype>0)"
222 " AND tagid > %d"
223 " AND tagname NOT GLOB 'wiki-*'"
224 " AND tagname NOT GLOB 'tkt-*'"
225 " ORDER BY tagname",
226 MAX_INT_TAG
227 );
228 @ <ul>
229 while( db_step(&q)==SQLITE_ROW ){
230 const char *name = db_column_text(&q, 0);
231 if( strncmp(name, prefix, preflen)==0 ){
232 @ <li><a href=%s(g.zBaseURL)/tagview?name=%s(name+preflen)>
233 @ <strong>%s(name+preflen)</strong></a></li>
234 }else{
235 @ <li><a href=%s(g.zBaseURL)/tagview?name=%s(name)>
236 @ %s(name)</a></li>
237 }
238 }
239 @ </ul>
240 db_finalize(&q);
241 }
242 style_footer();
243 }
244
245 #undef TAGVIEW_DEFAULT_FILTER
246
+31 -30
--- src/tagview.c
+++ src/tagview.c
@@ -134,36 +134,10 @@
134134
tagname);
135135
db_generic_query_view(zSql, 1);
136136
free(zSql);
137137
}
138138
139
-/*
140
-** Get the UUIDs for a tag
141
-*/
142
-char *tag_query_for_www(const char *pName){
143
- static const char zBaseSql[] =
144
- @ SELECT
145
- @ blob.rid,
146
- @ uuid,
147
- @ datetime(event.mtime,'localtime') AS timestamp,
148
- @ coalesce(ecomment, comment),
149
- @ coalesce(euser, user),
150
- @ (SELECT count(*) FROM plink WHERE pid=blob.rid AND isprim=1),
151
- @ (SELECT count(*) FROM plink WHERE cid=blob.rid),
152
- @ NOT EXISTS (SELECT 1 FROM plink WHERE pid=blob.rid),
153
- @ coalesce(bgcolor, brbgcolor),
154
- @ event.type
155
- @ FROM event JOIN blob JOIN tagxref
156
- @ WHERE blob.rid=event.objid
157
- @ AND tagxref.rid = event.objid
158
- @ AND tagxref.tagid = (SELECT tagid FROM tag
159
- @ WHERE tagname = 'sym-'||%Q)
160
- @ ORDER BY 3 desc
161
- ;
162
- return mprintf(zBaseSql,pName);
163
-}
164
-
165139
/*
166140
** WEBP AGE: /tagview
167141
*/
168142
void old_tagview_page(void){
169143
char const * check = 0;
@@ -202,11 +176,31 @@
202176
char *zSql;
203177
Stmt q;
204178
if( sym_tag_to_uuid(zName, &uuid) > 0){
205179
style_header("Tagged Baselines");
206180
@ <h2>%s(zName):</h2>
207
- zSql = tag_query_for_www(zName);
181
+ zSql = mprintf("%s AND EXISTS (SELECT 1"
182
+ " FROM tagxref"
183
+ " WHERE tagxref.rid = event.objid"
184
+ " AND tagxref.tagid = (SELECT tagid FROM tag"
185
+ " WHERE tagname = 'sym-'||%Q))"
186
+ " ORDER BY 3 desc",
187
+ timeline_query_for_www(), zName);
188
+ db_prepare(&q, zSql);
189
+ free(zSql);
190
+ www_print_timeline(&q);
191
+ db_finalize(&q);
192
+ }else if( tag_to_uuid(zName, &uuid, "") > 0){
193
+ style_header("Tagged Baselines");
194
+ @ <h2>%s(zName):</h2>
195
+ zSql = mprintf("%s AND EXISTS (SELECT 1"
196
+ " FROM tagxref"
197
+ " WHERE tagxref.rid = event.objid"
198
+ " AND tagxref.tagid = (SELECT tagid FROM tag"
199
+ " WHERE tagname = %Q))"
200
+ " ORDER BY 3 desc",
201
+ timeline_query_for_www(), zName);
208202
db_prepare(&q, zSql);
209203
free(zSql);
210204
www_print_timeline(&q);
211205
db_finalize(&q);
212206
}else{
@@ -217,28 +211,35 @@
217211
}else{
218212
Stmt q;
219213
const char *prefix = "sym-";
220214
int preflen = strlen(prefix);
221215
style_header("Tags");
222
- db_prepare(&q,
216
+ db_prepare(&q,
223217
"SELECT tagname"
224218
" FROM tag"
225219
" WHERE EXISTS(SELECT 1 FROM tagxref"
226220
" WHERE tagid=tag.tagid"
227221
" AND tagtype>0)"
228
- " ORDER BY tagname"
222
+ " AND tagid > %d"
223
+ " AND tagname NOT GLOB 'wiki-*'"
224
+ " AND tagname NOT GLOB 'tkt-*'"
225
+ " ORDER BY tagname",
226
+ MAX_INT_TAG
229227
);
230228
@ <ul>
231229
while( db_step(&q)==SQLITE_ROW ){
232230
const char *name = db_column_text(&q, 0);
233231
if( strncmp(name, prefix, preflen)==0 ){
234232
@ <li><a href=%s(g.zBaseURL)/tagview?name=%s(name+preflen)>
235
- @ %s(name+preflen)</a></li>
233
+ @ <strong>%s(name+preflen)</strong></a></li>
234
+ }else{
235
+ @ <li><a href=%s(g.zBaseURL)/tagview?name=%s(name)>
236
+ @ %s(name)</a></li>
236237
}
237238
}
238239
@ </ul>
239240
db_finalize(&q);
240241
}
241242
style_footer();
242243
}
243244
244245
#undef TAGVIEW_DEFAULT_FILTER
245246
--- src/tagview.c
+++ src/tagview.c
@@ -134,36 +134,10 @@
134 tagname);
135 db_generic_query_view(zSql, 1);
136 free(zSql);
137 }
138
139 /*
140 ** Get the UUIDs for a tag
141 */
142 char *tag_query_for_www(const char *pName){
143 static const char zBaseSql[] =
144 @ SELECT
145 @ blob.rid,
146 @ uuid,
147 @ datetime(event.mtime,'localtime') AS timestamp,
148 @ coalesce(ecomment, comment),
149 @ coalesce(euser, user),
150 @ (SELECT count(*) FROM plink WHERE pid=blob.rid AND isprim=1),
151 @ (SELECT count(*) FROM plink WHERE cid=blob.rid),
152 @ NOT EXISTS (SELECT 1 FROM plink WHERE pid=blob.rid),
153 @ coalesce(bgcolor, brbgcolor),
154 @ event.type
155 @ FROM event JOIN blob JOIN tagxref
156 @ WHERE blob.rid=event.objid
157 @ AND tagxref.rid = event.objid
158 @ AND tagxref.tagid = (SELECT tagid FROM tag
159 @ WHERE tagname = 'sym-'||%Q)
160 @ ORDER BY 3 desc
161 ;
162 return mprintf(zBaseSql,pName);
163 }
164
165 /*
166 ** WEBP AGE: /tagview
167 */
168 void old_tagview_page(void){
169 char const * check = 0;
@@ -202,11 +176,31 @@
202 char *zSql;
203 Stmt q;
204 if( sym_tag_to_uuid(zName, &uuid) > 0){
205 style_header("Tagged Baselines");
206 @ <h2>%s(zName):</h2>
207 zSql = tag_query_for_www(zName);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
208 db_prepare(&q, zSql);
209 free(zSql);
210 www_print_timeline(&q);
211 db_finalize(&q);
212 }else{
@@ -217,28 +211,35 @@
217 }else{
218 Stmt q;
219 const char *prefix = "sym-";
220 int preflen = strlen(prefix);
221 style_header("Tags");
222 db_prepare(&q,
223 "SELECT tagname"
224 " FROM tag"
225 " WHERE EXISTS(SELECT 1 FROM tagxref"
226 " WHERE tagid=tag.tagid"
227 " AND tagtype>0)"
228 " ORDER BY tagname"
 
 
 
 
229 );
230 @ <ul>
231 while( db_step(&q)==SQLITE_ROW ){
232 const char *name = db_column_text(&q, 0);
233 if( strncmp(name, prefix, preflen)==0 ){
234 @ <li><a href=%s(g.zBaseURL)/tagview?name=%s(name+preflen)>
235 @ %s(name+preflen)</a></li>
 
 
 
236 }
237 }
238 @ </ul>
239 db_finalize(&q);
240 }
241 style_footer();
242 }
243
244 #undef TAGVIEW_DEFAULT_FILTER
245
--- src/tagview.c
+++ src/tagview.c
@@ -134,36 +134,10 @@
134 tagname);
135 db_generic_query_view(zSql, 1);
136 free(zSql);
137 }
138
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
139 /*
140 ** WEBP AGE: /tagview
141 */
142 void old_tagview_page(void){
143 char const * check = 0;
@@ -202,11 +176,31 @@
176 char *zSql;
177 Stmt q;
178 if( sym_tag_to_uuid(zName, &uuid) > 0){
179 style_header("Tagged Baselines");
180 @ <h2>%s(zName):</h2>
181 zSql = mprintf("%s AND EXISTS (SELECT 1"
182 " FROM tagxref"
183 " WHERE tagxref.rid = event.objid"
184 " AND tagxref.tagid = (SELECT tagid FROM tag"
185 " WHERE tagname = 'sym-'||%Q))"
186 " ORDER BY 3 desc",
187 timeline_query_for_www(), zName);
188 db_prepare(&q, zSql);
189 free(zSql);
190 www_print_timeline(&q);
191 db_finalize(&q);
192 }else if( tag_to_uuid(zName, &uuid, "") > 0){
193 style_header("Tagged Baselines");
194 @ <h2>%s(zName):</h2>
195 zSql = mprintf("%s AND EXISTS (SELECT 1"
196 " FROM tagxref"
197 " WHERE tagxref.rid = event.objid"
198 " AND tagxref.tagid = (SELECT tagid FROM tag"
199 " WHERE tagname = %Q))"
200 " ORDER BY 3 desc",
201 timeline_query_for_www(), zName);
202 db_prepare(&q, zSql);
203 free(zSql);
204 www_print_timeline(&q);
205 db_finalize(&q);
206 }else{
@@ -217,28 +211,35 @@
211 }else{
212 Stmt q;
213 const char *prefix = "sym-";
214 int preflen = strlen(prefix);
215 style_header("Tags");
216 db_prepare(&q,
217 "SELECT tagname"
218 " FROM tag"
219 " WHERE EXISTS(SELECT 1 FROM tagxref"
220 " WHERE tagid=tag.tagid"
221 " AND tagtype>0)"
222 " AND tagid > %d"
223 " AND tagname NOT GLOB 'wiki-*'"
224 " AND tagname NOT GLOB 'tkt-*'"
225 " ORDER BY tagname",
226 MAX_INT_TAG
227 );
228 @ <ul>
229 while( db_step(&q)==SQLITE_ROW ){
230 const char *name = db_column_text(&q, 0);
231 if( strncmp(name, prefix, preflen)==0 ){
232 @ <li><a href=%s(g.zBaseURL)/tagview?name=%s(name+preflen)>
233 @ <strong>%s(name+preflen)</strong></a></li>
234 }else{
235 @ <li><a href=%s(g.zBaseURL)/tagview?name=%s(name)>
236 @ %s(name)</a></li>
237 }
238 }
239 @ </ul>
240 db_finalize(&q);
241 }
242 style_footer();
243 }
244
245 #undef TAGVIEW_DEFAULT_FILTER
246
+8 -5
--- src/zip.c
+++ src/zip.c
@@ -351,31 +351,34 @@
351351
** Generate a ZIP archive for the baseline.
352352
** Return that ZIP archive as the HTTP reply content.
353353
*/
354354
void baseline_zip_page(void){
355355
int rid;
356
- char *zName;
357
- int nName;
356
+ char *zName, *zRid;
357
+ int nName, nRid;
358358
Blob zip;
359359
360360
login_check_credentials();
361
- if( !g.okRead || !g.okHistory ){ login_needed(); return; }
361
+ if( !g.okZip && (!g.okRead || !g.okHistory) ){ login_needed(); return; }
362362
zName = mprintf("%s", PD("name",""));
363363
nName = strlen(zName);
364
+ zRid = mprintf("%s", PD("uuid",""));
365
+ nRid = strlen(zRid);
364366
for(nName=strlen(zName)-1; nName>5; nName--){
365367
if( zName[nName]=='.' ){
366368
zName[nName] = 0;
367369
break;
368370
}
369371
}
370
- rid = name_to_rid(zName);
372
+ rid = name_to_rid(nRid?zRid:zName);
371373
if( rid==0 ){
372374
@ Not found
373375
return;
374376
}
375
- if( nName>10 ) zName[10] = 0;
377
+ if( nRid==0 && nName>10 ) zName[10] = 0;
376378
zip_of_baseline(rid, &zip, zName);
377379
free( zName );
380
+ free( zRid );
378381
cgi_set_content(&zip);
379382
cgi_set_content_type("application/zip");
380383
cgi_reply();
381384
}
382385
--- src/zip.c
+++ src/zip.c
@@ -351,31 +351,34 @@
351 ** Generate a ZIP archive for the baseline.
352 ** Return that ZIP archive as the HTTP reply content.
353 */
354 void baseline_zip_page(void){
355 int rid;
356 char *zName;
357 int nName;
358 Blob zip;
359
360 login_check_credentials();
361 if( !g.okRead || !g.okHistory ){ login_needed(); return; }
362 zName = mprintf("%s", PD("name",""));
363 nName = strlen(zName);
 
 
364 for(nName=strlen(zName)-1; nName>5; nName--){
365 if( zName[nName]=='.' ){
366 zName[nName] = 0;
367 break;
368 }
369 }
370 rid = name_to_rid(zName);
371 if( rid==0 ){
372 @ Not found
373 return;
374 }
375 if( nName>10 ) zName[10] = 0;
376 zip_of_baseline(rid, &zip, zName);
377 free( zName );
 
378 cgi_set_content(&zip);
379 cgi_set_content_type("application/zip");
380 cgi_reply();
381 }
382
--- src/zip.c
+++ src/zip.c
@@ -351,31 +351,34 @@
351 ** Generate a ZIP archive for the baseline.
352 ** Return that ZIP archive as the HTTP reply content.
353 */
354 void baseline_zip_page(void){
355 int rid;
356 char *zName, *zRid;
357 int nName, nRid;
358 Blob zip;
359
360 login_check_credentials();
361 if( !g.okZip && (!g.okRead || !g.okHistory) ){ login_needed(); return; }
362 zName = mprintf("%s", PD("name",""));
363 nName = strlen(zName);
364 zRid = mprintf("%s", PD("uuid",""));
365 nRid = strlen(zRid);
366 for(nName=strlen(zName)-1; nName>5; nName--){
367 if( zName[nName]=='.' ){
368 zName[nName] = 0;
369 break;
370 }
371 }
372 rid = name_to_rid(nRid?zRid:zName);
373 if( rid==0 ){
374 @ Not found
375 return;
376 }
377 if( nRid==0 && nName>10 ) zName[10] = 0;
378 zip_of_baseline(rid, &zip, zName);
379 free( zName );
380 free( zRid );
381 cgi_set_content(&zip);
382 cgi_set_content_type("application/zip");
383 cgi_reply();
384 }
385

Keyboard Shortcuts

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