Fossil SCM
Include non-sym- tags in tagview web page. Also merge mainline into tagview branch.
Commit
5fb14b9a0fa04a788de384897e65458a9d8f8eaa
Parent
070e63db3362346…
20 files changed
+1
-1
+6
-2
+3
-1
+8
-4
+8
-4
+24
-2
+24
-2
+1
+6
-6
+6
-2
+6
-2
+3
+3
+109
-41
+3
-3
+3
-3
+95
-23
+31
-30
+31
-30
+8
-5
+1
-1
| --- src/admin.c | ||
| +++ src/admin.c | ||
| @@ -108,10 +108,10 @@ | ||
| 108 | 108 | } |
| 109 | 109 | admin_prepare_submenu(); |
| 110 | 110 | style_header("Admin"); |
| 111 | 111 | @ <h2>Links:</h2> |
| 112 | 112 | @ <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> | |
| 114 | 114 | @ <li><a href='%s(g.zBaseURL)/admin/sql'>Run SQL queries</a></li> |
| 115 | 115 | @ </ul> |
| 116 | 116 | style_footer(); |
| 117 | 117 | } |
| 118 | 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)/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 @@ | ||
| 250 | 250 | } |
| 251 | 251 | if( zEditor==0 ){ |
| 252 | 252 | zEditor = getenv("EDITOR"); |
| 253 | 253 | } |
| 254 | 254 | if( zEditor==0 ){ |
| 255 | +#ifdef __MINGW32__ | |
| 256 | + zEditor = "notepad"; | |
| 257 | +#else | |
| 255 | 258 | zEditor = "ed"; |
| 259 | +#endif | |
| 256 | 260 | } |
| 257 | 261 | zFile = db_text(0, "SELECT '%qci-comment-' || hex(randomblob(6)) || '.txt'", |
| 258 | 262 | g.zLocalRoot); |
| 259 | 263 | #ifdef __MINGW32__ |
| 260 | 264 | blob_add_cr(&text); |
| @@ -329,11 +333,11 @@ | ||
| 329 | 333 | ** |
| 330 | 334 | ** Usage: %fossil commit ?-m COMMENT? ?--nosign? ?FILE...? |
| 331 | 335 | ** |
| 332 | 336 | ** Create a new version containing all of the changes in the current |
| 333 | 337 | ** 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 | |
| 335 | 339 | ** prompted for your GPG passphrase in order to sign the new manifest |
| 336 | 340 | ** unless the "--nosign" options is used. All files that have |
| 337 | 341 | ** changed will be committed unless some subset of files is specified |
| 338 | 342 | ** on the command line. |
| 339 | 343 | */ |
| @@ -593,11 +597,11 @@ | ||
| 593 | 597 | /* |
| 594 | 598 | ** COMMAND: test-import-manifest |
| 595 | 599 | ** |
| 596 | 600 | ** Usage: %fossil test-import-manifest DATE COMMENT ?-p PARENT_RECORDID?... ?-f (FILE_RECORDID PATH)?... |
| 597 | 601 | ** |
| 598 | -** Create a new version containing containing the specified file | |
| 602 | +** Create a new version containing the specified file | |
| 599 | 603 | ** revisions (if any), and child of the given PARENT version. |
| 600 | 604 | */ |
| 601 | 605 | void import_manifest_cmd(void){ |
| 602 | 606 | const char* zDate; /* argument - timestamp, as seconds since epoch (int) */ |
| 603 | 607 | const char* zComment; /* argument - manifest comment */ |
| 604 | 608 |
| --- 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 |
M
src/db.c
+3
-1
| --- src/db.c | ||
| +++ src/db.c | ||
| @@ -789,13 +789,15 @@ | ||
| 789 | 789 | "INSERT INTO user(login, pw, cap, info)" |
| 790 | 790 | "VALUES(%Q,'','s','')", zUser |
| 791 | 791 | ); |
| 792 | 792 | db_multi_exec( |
| 793 | 793 | "INSERT INTO user(login,pw,cap,info)" |
| 794 | - " VALUES('anonymous','anonymous','hjkorw','Anon');" | |
| 794 | + " VALUES('anonymous','anonymous','aghknw','Anon');" | |
| 795 | 795 | "INSERT INTO user(login,pw,cap,info)" |
| 796 | 796 | " VALUES('nobody','','jor','Nobody');" |
| 797 | + "INSERT INTO user(login,pw,cap,info)" | |
| 798 | + " VALUES('developer','','deipt','Dev');" | |
| 797 | 799 | ); |
| 798 | 800 | user_select(); |
| 799 | 801 | |
| 800 | 802 | if (makeInitialVersion){ |
| 801 | 803 | blob_zero(&manifest); |
| 802 | 804 |
| --- 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 @@ | ||
| 116 | 116 | Stmt q; |
| 117 | 117 | int cnt = 0; |
| 118 | 118 | db_prepare(&q, |
| 119 | 119 | "SELECT plink.cid, blob.uuid, datetime(plink.mtime, 'localtime')," |
| 120 | 120 | " coalesce(event.euser,event.user)," |
| 121 | - " coalesce(event.comment,event.ecomment)" | |
| 121 | + " coalesce(event.ecomment,event.comment)" | |
| 122 | 122 | " FROM plink, blob, event" |
| 123 | 123 | " WHERE plink.pid=%d" |
| 124 | 124 | " AND blob.rid=plink.cid" |
| 125 | 125 | " AND event.objid=plink.cid" |
| 126 | 126 | " ORDER BY plink.mtime ASC", |
| @@ -168,11 +168,11 @@ | ||
| 168 | 168 | Stmt q; |
| 169 | 169 | int cnt = 0; |
| 170 | 170 | db_prepare(&q, |
| 171 | 171 | "SELECT plink.pid, blob.uuid, datetime(event.mtime, 'localtime')," |
| 172 | 172 | " coalesce(event.euser,event.user)," |
| 173 | - " coalesce(event.comment,event.ecomment)" | |
| 173 | + " coalesce(event.ecomment,event.comment)" | |
| 174 | 174 | " FROM plink, blob, event" |
| 175 | 175 | " WHERE plink.cid=%d" |
| 176 | 176 | " AND blob.rid=plink.pid" |
| 177 | 177 | " AND event.objid=plink.pid" |
| 178 | 178 | " ORDER BY event.mtime DESC", |
| @@ -354,25 +354,29 @@ | ||
| 354 | 354 | }else{ |
| 355 | 355 | @ <tr><th>Comment:</th><td>%w(zComment)</td></tr> |
| 356 | 356 | } |
| 357 | 357 | @ </td></tr> |
| 358 | 358 | if( g.okHistory ){ |
| 359 | + char *zShortUuid = mprintf("%.10s", zUuid); | |
| 360 | + const char *zProjName = db_get("project-name", "unnamed"); | |
| 359 | 361 | @ <tr><th>Timelines:</th><td> |
| 360 | 362 | @ <a href="%s(g.zBaseURL)/timeline?p=%d(rid)">ancestors</a> |
| 361 | 363 | @ | <a href="%s(g.zBaseURL)/timeline?d=%d(rid)">descendants</a> |
| 362 | 364 | @ | <a href="%s(g.zBaseURL)/timeline?d=%d(rid)&p=%d(rid)">both</a> |
| 363 | 365 | @ </td></tr> |
| 364 | 366 | @ <tr><th>Commands:</th> |
| 365 | 367 | @ <td> |
| 366 | 368 | @ <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> | |
| 368 | 371 | @ | <a href="%s(g.zBaseURL)/artifact/%d(rid)">manifest</a> |
| 369 | 372 | if( g.okWrite ){ |
| 370 | 373 | @ | <a href="%s(g.zBaseURL)/vedit?r=%d(rid)">edit</a> |
| 371 | 374 | } |
| 372 | 375 | @ </td> |
| 373 | 376 | @ </tr> |
| 377 | + free(zShortUuid); | |
| 374 | 378 | } |
| 375 | 379 | @ </table></p> |
| 376 | 380 | }else{ |
| 377 | 381 | style_header("Baseline Information"); |
| 378 | 382 | login_anonymous_available(); |
| @@ -655,11 +659,11 @@ | ||
| 655 | 659 | Stmt q; |
| 656 | 660 | int cnt = 0; |
| 657 | 661 | int nWiki = 0; |
| 658 | 662 | db_prepare(&q, |
| 659 | 663 | "SELECT filename.name, datetime(event.mtime), substr(a.uuid,1,10)," |
| 660 | - " coalesce(event.comment,event.ecomment)," | |
| 664 | + " coalesce(event.ecomment,event.comment)," | |
| 661 | 665 | " coalesce(event.euser,event.user)," |
| 662 | 666 | " b.uuid" |
| 663 | 667 | " FROM mlink, filename, event, blob a, blob b" |
| 664 | 668 | " WHERE filename.fnid=mlink.fnid" |
| 665 | 669 | " AND event.objid=mlink.mid" |
| 666 | 670 |
| --- 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 @@ | ||
| 116 | 116 | Stmt q; |
| 117 | 117 | int cnt = 0; |
| 118 | 118 | db_prepare(&q, |
| 119 | 119 | "SELECT plink.cid, blob.uuid, datetime(plink.mtime, 'localtime')," |
| 120 | 120 | " coalesce(event.euser,event.user)," |
| 121 | - " coalesce(event.comment,event.ecomment)" | |
| 121 | + " coalesce(event.ecomment,event.comment)" | |
| 122 | 122 | " FROM plink, blob, event" |
| 123 | 123 | " WHERE plink.pid=%d" |
| 124 | 124 | " AND blob.rid=plink.cid" |
| 125 | 125 | " AND event.objid=plink.cid" |
| 126 | 126 | " ORDER BY plink.mtime ASC", |
| @@ -168,11 +168,11 @@ | ||
| 168 | 168 | Stmt q; |
| 169 | 169 | int cnt = 0; |
| 170 | 170 | db_prepare(&q, |
| 171 | 171 | "SELECT plink.pid, blob.uuid, datetime(event.mtime, 'localtime')," |
| 172 | 172 | " coalesce(event.euser,event.user)," |
| 173 | - " coalesce(event.comment,event.ecomment)" | |
| 173 | + " coalesce(event.ecomment,event.comment)" | |
| 174 | 174 | " FROM plink, blob, event" |
| 175 | 175 | " WHERE plink.cid=%d" |
| 176 | 176 | " AND blob.rid=plink.pid" |
| 177 | 177 | " AND event.objid=plink.pid" |
| 178 | 178 | " ORDER BY event.mtime DESC", |
| @@ -354,25 +354,29 @@ | ||
| 354 | 354 | }else{ |
| 355 | 355 | @ <tr><th>Comment:</th><td>%w(zComment)</td></tr> |
| 356 | 356 | } |
| 357 | 357 | @ </td></tr> |
| 358 | 358 | if( g.okHistory ){ |
| 359 | + char *zShortUuid = mprintf("%.10s", zUuid); | |
| 360 | + const char *zProjName = db_get("project-name", "unnamed"); | |
| 359 | 361 | @ <tr><th>Timelines:</th><td> |
| 360 | 362 | @ <a href="%s(g.zBaseURL)/timeline?p=%d(rid)">ancestors</a> |
| 361 | 363 | @ | <a href="%s(g.zBaseURL)/timeline?d=%d(rid)">descendants</a> |
| 362 | 364 | @ | <a href="%s(g.zBaseURL)/timeline?d=%d(rid)&p=%d(rid)">both</a> |
| 363 | 365 | @ </td></tr> |
| 364 | 366 | @ <tr><th>Commands:</th> |
| 365 | 367 | @ <td> |
| 366 | 368 | @ <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> | |
| 368 | 371 | @ | <a href="%s(g.zBaseURL)/artifact/%d(rid)">manifest</a> |
| 369 | 372 | if( g.okWrite ){ |
| 370 | 373 | @ | <a href="%s(g.zBaseURL)/vedit?r=%d(rid)">edit</a> |
| 371 | 374 | } |
| 372 | 375 | @ </td> |
| 373 | 376 | @ </tr> |
| 377 | + free(zShortUuid); | |
| 374 | 378 | } |
| 375 | 379 | @ </table></p> |
| 376 | 380 | }else{ |
| 377 | 381 | style_header("Baseline Information"); |
| 378 | 382 | login_anonymous_available(); |
| @@ -655,11 +659,11 @@ | ||
| 655 | 659 | Stmt q; |
| 656 | 660 | int cnt = 0; |
| 657 | 661 | int nWiki = 0; |
| 658 | 662 | db_prepare(&q, |
| 659 | 663 | "SELECT filename.name, datetime(event.mtime), substr(a.uuid,1,10)," |
| 660 | - " coalesce(event.comment,event.ecomment)," | |
| 664 | + " coalesce(event.ecomment,event.comment)," | |
| 661 | 665 | " coalesce(event.euser,event.user)," |
| 662 | 666 | " b.uuid" |
| 663 | 667 | " FROM mlink, filename, event, blob a, blob b" |
| 664 | 668 | " WHERE filename.fnid=mlink.fnid" |
| 665 | 669 | " AND event.objid=mlink.mid" |
| 666 | 670 |
| --- 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 @@ | ||
| 113 | 113 | ); |
| 114 | 114 | cgi_redirect(zGoto); |
| 115 | 115 | return; |
| 116 | 116 | } |
| 117 | 117 | } |
| 118 | - if( zUsername!=0 && zPasswd!=0 ){ | |
| 118 | + if( zUsername!=0 && zPasswd!=0 && zPasswd[0]!=0 ){ | |
| 119 | 119 | int uid = db_int(0, |
| 120 | 120 | "SELECT uid FROM user" |
| 121 | 121 | " WHERE login=%Q AND pw=%Q", zUsername, zPasswd); |
| 122 | 122 | if( uid<=0 || strcmp(zUsername,"nobody")==0 ){ |
| 123 | 123 | sleep(1); |
| @@ -300,13 +300,15 @@ | ||
| 300 | 300 | g.userUid = uid; |
| 301 | 301 | if( g.zLogin && strcmp(g.zLogin,"nobody")==0 ){ |
| 302 | 302 | g.zLogin = 0; |
| 303 | 303 | } |
| 304 | 304 | if( uid && g.zLogin ){ |
| 305 | + /* All logged-in users inherit privileges from "nobody" */ | |
| 305 | 306 | zNcap = db_text("", "SELECT cap FROM user WHERE login = 'nobody'"); |
| 306 | 307 | 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" */ | |
| 308 | 310 | zAcap = db_text("", "SELECT cap FROM user WHERE login = 'anonymous'"); |
| 309 | 311 | login_set_capabilities(zAcap); |
| 310 | 312 | } |
| 311 | 313 | } |
| 312 | 314 | login_set_capabilities(zCap); |
| @@ -314,10 +316,11 @@ | ||
| 314 | 316 | |
| 315 | 317 | /* |
| 316 | 318 | ** Set the global capability flags based on a capability string. |
| 317 | 319 | */ |
| 318 | 320 | void login_set_capabilities(const char *zCap){ |
| 321 | + static char *zDev = 0; | |
| 319 | 322 | int i; |
| 320 | 323 | for(i=0; zCap[i]; i++){ |
| 321 | 324 | switch( zCap[i] ){ |
| 322 | 325 | case 's': g.okSetup = 1; |
| 323 | 326 | case 'a': g.okAdmin = g.okRdTkt = g.okWrTkt = |
| @@ -325,10 +328,11 @@ | ||
| 325 | 328 | g.okApndWiki = g.okHistory = g.okClone = |
| 326 | 329 | g.okNewTkt = g.okPassword = g.okRdAddr = |
| 327 | 330 | g.okTktFmt = 1; |
| 328 | 331 | case 'i': g.okRead = g.okWrite = 1; break; |
| 329 | 332 | case 'o': g.okRead = 1; break; |
| 333 | + case 'z': g.okZip = 1; break; | |
| 330 | 334 | |
| 331 | 335 | case 'd': g.okDelete = 1; break; |
| 332 | 336 | case 'h': g.okHistory = 1; break; |
| 333 | 337 | case 'g': g.okClone = 1; break; |
| 334 | 338 | case 'p': g.okPassword = 1; break; |
| @@ -343,10 +347,20 @@ | ||
| 343 | 347 | case 'n': g.okNewTkt = 1; break; |
| 344 | 348 | case 'w': g.okWrTkt = g.okRdTkt = g.okNewTkt = |
| 345 | 349 | g.okApndTkt = 1; break; |
| 346 | 350 | case 'c': g.okApndTkt = 1; break; |
| 347 | 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 | + } | |
| 348 | 362 | } |
| 349 | 363 | } |
| 350 | 364 | } |
| 351 | 365 | |
| 352 | 366 | /* |
| @@ -359,27 +373,35 @@ | ||
| 359 | 373 | int rc = 1; |
| 360 | 374 | if( nCap<0 ) nCap = strlen(zCap); |
| 361 | 375 | for(i=0; i<nCap && rc && zCap[i]; i++){ |
| 362 | 376 | switch( zCap[i] ){ |
| 363 | 377 | case 'a': rc = g.okAdmin; break; |
| 378 | + /* case 'b': */ | |
| 364 | 379 | case 'c': rc = g.okApndTkt; break; |
| 365 | 380 | case 'd': rc = g.okDelete; break; |
| 366 | 381 | case 'e': rc = g.okRdAddr; break; |
| 367 | 382 | case 'f': rc = g.okNewWiki; break; |
| 368 | 383 | case 'g': rc = g.okClone; break; |
| 369 | 384 | case 'h': rc = g.okHistory; break; |
| 370 | 385 | case 'i': rc = g.okWrite; break; |
| 371 | 386 | case 'j': rc = g.okRdWiki; break; |
| 372 | 387 | case 'k': rc = g.okWrWiki; break; |
| 388 | + /* case 'l': */ | |
| 373 | 389 | case 'm': rc = g.okApndWiki; break; |
| 374 | 390 | case 'n': rc = g.okNewTkt; break; |
| 375 | 391 | case 'o': rc = g.okRead; break; |
| 376 | 392 | case 'p': rc = g.okPassword; break; |
| 393 | + /* case 'q': */ | |
| 377 | 394 | case 'r': rc = g.okRdTkt; break; |
| 378 | 395 | case 's': rc = g.okSetup; break; |
| 379 | 396 | case 't': rc = g.okTktFmt; break; |
| 397 | + /* case 'u': */ | |
| 398 | + /* case 'v': */ | |
| 380 | 399 | case 'w': rc = g.okWrTkt; break; |
| 400 | + /* case 'x': */ | |
| 401 | + /* case 'y': */ | |
| 402 | + case 'z': rc = g.okZip; break; | |
| 381 | 403 | default: rc = 0; break; |
| 382 | 404 | } |
| 383 | 405 | } |
| 384 | 406 | return rc; |
| 385 | 407 | } |
| 386 | 408 |
| --- 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 @@ | ||
| 113 | 113 | ); |
| 114 | 114 | cgi_redirect(zGoto); |
| 115 | 115 | return; |
| 116 | 116 | } |
| 117 | 117 | } |
| 118 | - if( zUsername!=0 && zPasswd!=0 ){ | |
| 118 | + if( zUsername!=0 && zPasswd!=0 && zPasswd[0]!=0 ){ | |
| 119 | 119 | int uid = db_int(0, |
| 120 | 120 | "SELECT uid FROM user" |
| 121 | 121 | " WHERE login=%Q AND pw=%Q", zUsername, zPasswd); |
| 122 | 122 | if( uid<=0 || strcmp(zUsername,"nobody")==0 ){ |
| 123 | 123 | sleep(1); |
| @@ -300,13 +300,15 @@ | ||
| 300 | 300 | g.userUid = uid; |
| 301 | 301 | if( g.zLogin && strcmp(g.zLogin,"nobody")==0 ){ |
| 302 | 302 | g.zLogin = 0; |
| 303 | 303 | } |
| 304 | 304 | if( uid && g.zLogin ){ |
| 305 | + /* All logged-in users inherit privileges from "nobody" */ | |
| 305 | 306 | zNcap = db_text("", "SELECT cap FROM user WHERE login = 'nobody'"); |
| 306 | 307 | 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" */ | |
| 308 | 310 | zAcap = db_text("", "SELECT cap FROM user WHERE login = 'anonymous'"); |
| 309 | 311 | login_set_capabilities(zAcap); |
| 310 | 312 | } |
| 311 | 313 | } |
| 312 | 314 | login_set_capabilities(zCap); |
| @@ -314,10 +316,11 @@ | ||
| 314 | 316 | |
| 315 | 317 | /* |
| 316 | 318 | ** Set the global capability flags based on a capability string. |
| 317 | 319 | */ |
| 318 | 320 | void login_set_capabilities(const char *zCap){ |
| 321 | + static char *zDev = 0; | |
| 319 | 322 | int i; |
| 320 | 323 | for(i=0; zCap[i]; i++){ |
| 321 | 324 | switch( zCap[i] ){ |
| 322 | 325 | case 's': g.okSetup = 1; |
| 323 | 326 | case 'a': g.okAdmin = g.okRdTkt = g.okWrTkt = |
| @@ -325,10 +328,11 @@ | ||
| 325 | 328 | g.okApndWiki = g.okHistory = g.okClone = |
| 326 | 329 | g.okNewTkt = g.okPassword = g.okRdAddr = |
| 327 | 330 | g.okTktFmt = 1; |
| 328 | 331 | case 'i': g.okRead = g.okWrite = 1; break; |
| 329 | 332 | case 'o': g.okRead = 1; break; |
| 333 | + case 'z': g.okZip = 1; break; | |
| 330 | 334 | |
| 331 | 335 | case 'd': g.okDelete = 1; break; |
| 332 | 336 | case 'h': g.okHistory = 1; break; |
| 333 | 337 | case 'g': g.okClone = 1; break; |
| 334 | 338 | case 'p': g.okPassword = 1; break; |
| @@ -343,10 +347,20 @@ | ||
| 343 | 347 | case 'n': g.okNewTkt = 1; break; |
| 344 | 348 | case 'w': g.okWrTkt = g.okRdTkt = g.okNewTkt = |
| 345 | 349 | g.okApndTkt = 1; break; |
| 346 | 350 | case 'c': g.okApndTkt = 1; break; |
| 347 | 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 | + } | |
| 348 | 362 | } |
| 349 | 363 | } |
| 350 | 364 | } |
| 351 | 365 | |
| 352 | 366 | /* |
| @@ -359,27 +373,35 @@ | ||
| 359 | 373 | int rc = 1; |
| 360 | 374 | if( nCap<0 ) nCap = strlen(zCap); |
| 361 | 375 | for(i=0; i<nCap && rc && zCap[i]; i++){ |
| 362 | 376 | switch( zCap[i] ){ |
| 363 | 377 | case 'a': rc = g.okAdmin; break; |
| 378 | + /* case 'b': */ | |
| 364 | 379 | case 'c': rc = g.okApndTkt; break; |
| 365 | 380 | case 'd': rc = g.okDelete; break; |
| 366 | 381 | case 'e': rc = g.okRdAddr; break; |
| 367 | 382 | case 'f': rc = g.okNewWiki; break; |
| 368 | 383 | case 'g': rc = g.okClone; break; |
| 369 | 384 | case 'h': rc = g.okHistory; break; |
| 370 | 385 | case 'i': rc = g.okWrite; break; |
| 371 | 386 | case 'j': rc = g.okRdWiki; break; |
| 372 | 387 | case 'k': rc = g.okWrWiki; break; |
| 388 | + /* case 'l': */ | |
| 373 | 389 | case 'm': rc = g.okApndWiki; break; |
| 374 | 390 | case 'n': rc = g.okNewTkt; break; |
| 375 | 391 | case 'o': rc = g.okRead; break; |
| 376 | 392 | case 'p': rc = g.okPassword; break; |
| 393 | + /* case 'q': */ | |
| 377 | 394 | case 'r': rc = g.okRdTkt; break; |
| 378 | 395 | case 's': rc = g.okSetup; break; |
| 379 | 396 | case 't': rc = g.okTktFmt; break; |
| 397 | + /* case 'u': */ | |
| 398 | + /* case 'v': */ | |
| 380 | 399 | case 'w': rc = g.okWrTkt; break; |
| 400 | + /* case 'x': */ | |
| 401 | + /* case 'y': */ | |
| 402 | + case 'z': rc = g.okZip; break; | |
| 381 | 403 | default: rc = 0; break; |
| 382 | 404 | } |
| 383 | 405 | } |
| 384 | 406 | return rc; |
| 385 | 407 | } |
| 386 | 408 |
| --- 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 @@ | ||
| 117 | 117 | int okNewTkt; /* n: create new tickets */ |
| 118 | 118 | int okApndTkt; /* c: append to tickets via the web */ |
| 119 | 119 | int okWrTkt; /* w: make changes to tickets via web */ |
| 120 | 120 | int okTktFmt; /* t: create new ticket report formats */ |
| 121 | 121 | int okRdAddr; /* e: read email addresses or other private data */ |
| 122 | + int okZip; /* z: download zipped artifact via /zip URL */ | |
| 122 | 123 | |
| 123 | 124 | FILE *fDebug; /* Write debug information here, if the file exists */ |
| 124 | 125 | |
| 125 | 126 | /* Storage for the aux() and/or option() SQL function arguments */ |
| 126 | 127 | int nAux; /* Number of distinct aux() or option() values */ |
| 127 | 128 |
| --- 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 @@ | ||
| 27 | 27 | */ |
| 28 | 28 | #include <assert.h> |
| 29 | 29 | #include "config.h" |
| 30 | 30 | #include "my_page.h" |
| 31 | 31 | |
| 32 | -/** | |
| 33 | -Renders a logout button. | |
| 32 | +/* | |
| 33 | +** Renders a logout button. | |
| 34 | 34 | */ |
| 35 | 35 | static void mypage_logout_button() |
| 36 | 36 | { |
| 37 | 37 | if( g.zLogin ){ |
| 38 | 38 | @ <br clear="both"/><hr/> |
| @@ -43,12 +43,12 @@ | ||
| 43 | 43 | @ <input type="submit" name="out" value="Logout"/></p> |
| 44 | 44 | @ </form> |
| 45 | 45 | } |
| 46 | 46 | } |
| 47 | 47 | |
| 48 | -/** | |
| 49 | -Renders a password changer. | |
| 48 | +/* | |
| 49 | +** Renders a password changer. | |
| 50 | 50 | */ |
| 51 | 51 | static void mypage_password_changer() |
| 52 | 52 | { |
| 53 | 53 | if( g.okPassword ){ |
| 54 | 54 | @ <br clear="both"/><hr/> |
| @@ -71,12 +71,12 @@ | ||
| 71 | 71 | @ </form> |
| 72 | 72 | } |
| 73 | 73 | |
| 74 | 74 | } |
| 75 | 75 | |
| 76 | -/** | |
| 77 | -Default page rendered for /my. | |
| 76 | +/* | |
| 77 | +** Default page rendered for /my. | |
| 78 | 78 | */ |
| 79 | 79 | static void mypage_page_default() |
| 80 | 80 | { |
| 81 | 81 | int uid = g.userUid; |
| 82 | 82 | char * sql = mprintf( "SELECT login,cap,info FROM user WHERE uid=%d", |
| 83 | 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 |
| --- 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 @@ | ||
| 110 | 110 | ** 1 A single UUID was found |
| 111 | 111 | ** 2 More than one UUID was found, so this is presumably a |
| 112 | 112 | ** propagating tag. The return UUID is the most recent, |
| 113 | 113 | ** which is most likely to be the one wanted. |
| 114 | 114 | */ |
| 115 | -int sym_tag_to_uuid(const char *pName, Blob *pUuid){ | |
| 115 | +int tag_to_uuid(const char *pName, Blob *pUuid,const char *pPrefix){ | |
| 116 | 116 | Stmt q; |
| 117 | 117 | int count = 0; |
| 118 | 118 | db_prepare(&q, |
| 119 | 119 | "SELECT (SELECT uuid FROM blob WHERE rid=objid)" |
| 120 | 120 | " 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)" | |
| 122 | 122 | " AND tagtype>0" |
| 123 | 123 | " AND value IS NULL" |
| 124 | 124 | " ORDER BY event.mtime DESC", |
| 125 | + pPrefix, | |
| 125 | 126 | pName |
| 126 | 127 | ); |
| 127 | 128 | blob_zero(pUuid); |
| 128 | 129 | while( db_step(&q)==SQLITE_ROW ){ |
| 129 | 130 | count++; |
| @@ -132,10 +133,13 @@ | ||
| 132 | 133 | } |
| 133 | 134 | db_column_blob(&q, 0, pUuid); |
| 134 | 135 | } |
| 135 | 136 | db_finalize(&q); |
| 136 | 137 | return count; |
| 138 | +} | |
| 139 | +int sym_tag_to_uuid(const char *pName, Blob *pUuid){ | |
| 140 | + return tag_to_uuid(pName,pUuid,"sym-"); | |
| 137 | 141 | } |
| 138 | 142 | |
| 139 | 143 | /* |
| 140 | 144 | ** COMMAND: test-name-to-uuid |
| 141 | 145 | ** |
| 142 | 146 |
| --- 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 @@ | ||
| 110 | 110 | ** 1 A single UUID was found |
| 111 | 111 | ** 2 More than one UUID was found, so this is presumably a |
| 112 | 112 | ** propagating tag. The return UUID is the most recent, |
| 113 | 113 | ** which is most likely to be the one wanted. |
| 114 | 114 | */ |
| 115 | -int sym_tag_to_uuid(const char *pName, Blob *pUuid){ | |
| 115 | +int tag_to_uuid(const char *pName, Blob *pUuid,const char *pPrefix){ | |
| 116 | 116 | Stmt q; |
| 117 | 117 | int count = 0; |
| 118 | 118 | db_prepare(&q, |
| 119 | 119 | "SELECT (SELECT uuid FROM blob WHERE rid=objid)" |
| 120 | 120 | " 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)" | |
| 122 | 122 | " AND tagtype>0" |
| 123 | 123 | " AND value IS NULL" |
| 124 | 124 | " ORDER BY event.mtime DESC", |
| 125 | + pPrefix, | |
| 125 | 126 | pName |
| 126 | 127 | ); |
| 127 | 128 | blob_zero(pUuid); |
| 128 | 129 | while( db_step(&q)==SQLITE_ROW ){ |
| 129 | 130 | count++; |
| @@ -132,10 +133,13 @@ | ||
| 132 | 133 | } |
| 133 | 134 | db_column_blob(&q, 0, pUuid); |
| 134 | 135 | } |
| 135 | 136 | db_finalize(&q); |
| 136 | 137 | return count; |
| 138 | +} | |
| 139 | +int sym_tag_to_uuid(const char *pName, Blob *pUuid){ | |
| 140 | + return tag_to_uuid(pName,pUuid,"sym-"); | |
| 137 | 141 | } |
| 138 | 142 | |
| 139 | 143 | /* |
| 140 | 144 | ** COMMAND: test-name-to-uuid |
| 141 | 145 | ** |
| 142 | 146 |
| --- 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 |
+3
| --- src/schema.c | ||
| +++ src/schema.c | ||
| @@ -297,10 +297,13 @@ | ||
| 297 | 297 | # define TAG_USER 3 /* User who made a checking */ |
| 298 | 298 | # define TAG_HIDDEN 4 /* Do not display or sync */ |
| 299 | 299 | # define TAG_PRIVATE 5 /* Display but do not sync */ |
| 300 | 300 | # define TAG_CLUSTER 6 /* A cluster */ |
| 301 | 301 | #endif |
| 302 | +#if EXPORT_INTERFACE | |
| 303 | +# define MAX_INT_TAG 6 /* The largest pre-assigned tag id */ | |
| 304 | +#endif | |
| 302 | 305 | |
| 303 | 306 | /* |
| 304 | 307 | ** The schema for the locate FOSSIL database file found at the root |
| 305 | 308 | ** of very check-out. This database contains the complete state of |
| 306 | 309 | ** the checkout. |
| 307 | 310 |
| --- 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 |
+3
| --- src/schema.c | ||
| +++ src/schema.c | ||
| @@ -297,10 +297,13 @@ | ||
| 297 | 297 | # define TAG_USER 3 /* User who made a checking */ |
| 298 | 298 | # define TAG_HIDDEN 4 /* Do not display or sync */ |
| 299 | 299 | # define TAG_PRIVATE 5 /* Display but do not sync */ |
| 300 | 300 | # define TAG_CLUSTER 6 /* A cluster */ |
| 301 | 301 | #endif |
| 302 | +#if EXPORT_INTERFACE | |
| 303 | +# define MAX_INT_TAG 6 /* The largest pre-assigned tag id */ | |
| 304 | +#endif | |
| 302 | 305 | |
| 303 | 306 | /* |
| 304 | 307 | ** The schema for the locate FOSSIL database file found at the root |
| 305 | 308 | ** of very check-out. This database contains the complete state of |
| 306 | 309 | ** the checkout. |
| 307 | 310 |
| --- 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 @@ | ||
| 134 | 134 | @ </table></td></tr></table> |
| 135 | 135 | @ <td valign="top"> |
| 136 | 136 | @ <b>Notes:</b> |
| 137 | 137 | @ <ol> |
| 138 | 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> | |
| 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> | |
| 160 | 163 | @ |
| 161 | 164 | @ <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>. | |
| 163 | 166 | @ Any human can login as <b>anonymous</b> since the password is |
| 164 | 167 | @ clearly displayed on the login page for them to type. The purpose |
| 165 | 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>. | |
| 166 | 170 | @ </p></li> |
| 167 | 171 | @ |
| 168 | 172 | @ </ol> |
| 169 | 173 | @ </td></tr></table> |
| 170 | 174 | style_footer(); |
| 171 | 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 | +} | |
| 172 | 190 | |
| 173 | 191 | /* |
| 174 | 192 | ** WEBPAGE: /setup_uedit |
| 175 | 193 | */ |
| 176 | 194 | void user_edit(void){ |
| 177 | - const char *zId, *zLogin, *zInfo, *zCap; | |
| 195 | + const char *zId, *zLogin, *zInfo, *zCap, *zPw; | |
| 178 | 196 | char *oaa, *oas, *oar, *oaw, *oan, *oai, *oaj, *oao, *oap; |
| 179 | 197 | char *oak, *oad, *oac, *oaf, *oam, *oah, *oag, *oae; |
| 180 | - char *oat; | |
| 198 | + char *oat, *oav, *oaz; | |
| 181 | 199 | int doWrite; |
| 182 | 200 | int uid; |
| 183 | 201 | int higherUser = 0; /* True if user being edited is SETUP and the */ |
| 184 | 202 | /* user doing the editing is ADMIN. Disallow editing */ |
| 185 | 203 | |
| @@ -208,12 +226,10 @@ | ||
| 208 | 226 | ** modified user record. After writing the user record, redirect |
| 209 | 227 | ** to the page that displays a list of users. |
| 210 | 228 | */ |
| 211 | 229 | doWrite = cgi_all("login","info","pw") && !higherUser; |
| 212 | 230 | if( doWrite ){ |
| 213 | - const char *zPw; | |
| 214 | - const char *zLogin; | |
| 215 | 231 | char zCap[50]; |
| 216 | 232 | int i = 0; |
| 217 | 233 | int aa = P("aa")!=0; |
| 218 | 234 | int ad = P("ad")!=0; |
| 219 | 235 | int ae = P("ae")!=0; |
| @@ -230,10 +246,12 @@ | ||
| 230 | 246 | int af = P("af")!=0; |
| 231 | 247 | int am = P("am")!=0; |
| 232 | 248 | int ah = P("ah")!=0; |
| 233 | 249 | int ag = P("ag")!=0; |
| 234 | 250 | int at = P("at")!=0; |
| 251 | + int av = P("av")!=0; | |
| 252 | + int az = P("az")!=0; | |
| 235 | 253 | if( aa ){ zCap[i++] = 'a'; } |
| 236 | 254 | if( ac ){ zCap[i++] = 'c'; } |
| 237 | 255 | if( ad ){ zCap[i++] = 'd'; } |
| 238 | 256 | if( ae ){ zCap[i++] = 'e'; } |
| 239 | 257 | if( af ){ zCap[i++] = 'f'; } |
| @@ -247,15 +265,17 @@ | ||
| 247 | 265 | if( ao ){ zCap[i++] = 'o'; } |
| 248 | 266 | if( ap ){ zCap[i++] = 'p'; } |
| 249 | 267 | if( ar ){ zCap[i++] = 'r'; } |
| 250 | 268 | if( as ){ zCap[i++] = 's'; } |
| 251 | 269 | if( at ){ zCap[i++] = 't'; } |
| 270 | + if( av ){ zCap[i++] = 'v'; } | |
| 252 | 271 | if( aw ){ zCap[i++] = 'w'; } |
| 272 | + if( az ){ zCap[i++] = 'z'; } | |
| 253 | 273 | |
| 254 | 274 | zCap[i] = 0; |
| 255 | 275 | zPw = P("pw"); |
| 256 | - if( zPw==0 || zPw[0]==0 ){ | |
| 276 | + if( !isValidPwString(zPw) ){ | |
| 257 | 277 | zPw = db_text(0, "SELECT pw FROM user WHERE uid=%d", uid); |
| 258 | 278 | } |
| 259 | 279 | zLogin = P("login"); |
| 260 | 280 | if( uid>0 && |
| 261 | 281 | db_exists("SELECT 1 FROM user WHERE login=%Q AND uid!=%d", zLogin, uid) |
| @@ -280,16 +300,18 @@ | ||
| 280 | 300 | /* Load the existing information about the user, if any |
| 281 | 301 | */ |
| 282 | 302 | zLogin = ""; |
| 283 | 303 | zInfo = ""; |
| 284 | 304 | zCap = ""; |
| 305 | + zPw = ""; | |
| 285 | 306 | 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 = ""; | |
| 287 | 308 | if( uid ){ |
| 288 | 309 | zLogin = db_text("", "SELECT login FROM user WHERE uid=%d", uid); |
| 289 | 310 | zInfo = db_text("", "SELECT info FROM user WHERE uid=%d", uid); |
| 290 | 311 | zCap = db_text("", "SELECT cap FROM user WHERE uid=%d", uid); |
| 312 | + zPw = db_text("", "SELECT pw FROM user WHERE uid=%d", uid); | |
| 291 | 313 | if( strchr(zCap, 'a') ) oaa = " checked"; |
| 292 | 314 | if( strchr(zCap, 'c') ) oac = " checked"; |
| 293 | 315 | if( strchr(zCap, 'd') ) oad = " checked"; |
| 294 | 316 | if( strchr(zCap, 'e') ) oae = " checked"; |
| 295 | 317 | if( strchr(zCap, 'f') ) oaf = " checked"; |
| @@ -303,11 +325,13 @@ | ||
| 303 | 325 | if( strchr(zCap, 'o') ) oao = " checked"; |
| 304 | 326 | if( strchr(zCap, 'p') ) oap = " checked"; |
| 305 | 327 | if( strchr(zCap, 'r') ) oar = " checked"; |
| 306 | 328 | if( strchr(zCap, 's') ) oas = " checked"; |
| 307 | 329 | if( strchr(zCap, 't') ) oat = " checked"; |
| 330 | + if( strchr(zCap, 'v') ) oav = " checked"; | |
| 308 | 331 | if( strchr(zCap, 'w') ) oaw = " checked"; |
| 332 | + if( strchr(zCap, 'z') ) oaz = " checked"; | |
| 309 | 333 | } |
| 310 | 334 | |
| 311 | 335 | /* Begin generating the page |
| 312 | 336 | */ |
| 313 | 337 | style_submenu_element("Cancel", "Cancel", "setup_ulist"); |
| @@ -346,35 +370,46 @@ | ||
| 346 | 370 | @ <input type="checkbox" name="ae"%s(oad)>Email</input><br> |
| 347 | 371 | @ <input type="checkbox" name="ap"%s(oap)>Password</input><br> |
| 348 | 372 | @ <input type="checkbox" name="ai"%s(oai)>Check-In</input><br> |
| 349 | 373 | @ <input type="checkbox" name="ao"%s(oao)>Check-Out</input><br> |
| 350 | 374 | @ <input type="checkbox" name="ah"%s(oah)>History</input><br> |
| 375 | + @ <input type="checkbox" name="av"%s(oav)>Developer</input><br> | |
| 351 | 376 | @ <input type="checkbox" name="ag"%s(oag)>Clone</input><br> |
| 352 | 377 | @ <input type="checkbox" name="aj"%s(oaj)>Read Wiki</input><br> |
| 353 | 378 | @ <input type="checkbox" name="af"%s(oaf)>New Wiki</input><br> |
| 354 | 379 | @ <input type="checkbox" name="am"%s(oam)>Append Wiki</input><br> |
| 355 | 380 | @ <input type="checkbox" name="ak"%s(oak)>Write Wiki</input><br> |
| 356 | 381 | @ <input type="checkbox" name="ar"%s(oar)>Read Tkt</input><br> |
| 357 | 382 | @ <input type="checkbox" name="an"%s(oan)>New Tkt</input><br> |
| 358 | 383 | @ <input type="checkbox" name="ac"%s(oac)>Append Tkt</input><br> |
| 359 | 384 | @ <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> | |
| 361 | 387 | @ </td> |
| 362 | 388 | @ </tr> |
| 363 | 389 | @ <tr> |
| 364 | 390 | @ <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 | + } | |
| 366 | 401 | @ </tr> |
| 367 | 402 | if( !higherUser ){ |
| 368 | 403 | @ <tr> |
| 369 | 404 | @ <td> </td> |
| 370 | 405 | @ <td><input type="submit" name="submit" value="Apply Changes"> |
| 371 | 406 | @ </tr> |
| 372 | 407 | } |
| 373 | 408 | @ </table></td></tr></table> |
| 374 | - @ <p><b>Notes:</b></p> | |
| 375 | - @ <ol> | |
| 409 | + @ <h2>Privileges And Capabilities:</h2> | |
| 410 | + @ <ul> | |
| 376 | 411 | if( higherUser ){ |
| 377 | 412 | @ <li><p><font color="blue"><b> |
| 378 | 413 | @ User %h(zLogin) has Setup privileges and you only have Admin privileges |
| 379 | 414 | @ so you are not permitted to make changes to %h(zLogin). |
| 380 | 415 | @ </b></font></p></li> |
| @@ -401,10 +436,24 @@ | ||
| 401 | 436 | @ This is recommended ON for most logged-in users but OFF for |
| 402 | 437 | @ user "nobody" to avoid problems with spiders trying to walk every |
| 403 | 438 | @ historical version of every baseline and file. |
| 404 | 439 | @ </p></li> |
| 405 | 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 | + @ | |
| 406 | 455 | @ <li><p> |
| 407 | 456 | @ The <b>Check-in</b> privilege allows remote users to "push". |
| 408 | 457 | @ The <b>Check-out</b> privilege allows remote users to "pull". |
| 409 | 458 | @ The <b>Clone</b> privilege allows remote users to "clone". |
| 410 | 459 | @ </li><p> |
| @@ -418,39 +467,58 @@ | ||
| 418 | 467 | @ ticket report formats. |
| 419 | 468 | @ </p></li> |
| 420 | 469 | @ |
| 421 | 470 | @ <li><p> |
| 422 | 471 | @ 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". | |
| 425 | 474 | @ </p></li> |
| 426 | 475 | @ |
| 427 | 476 | @ <li><p> |
| 428 | 477 | @ The <b>EMail</b> privilege allows the display of sensitive information |
| 429 | 478 | @ such as the email address of users and contact information on tickets. |
| 430 | 479 | @ Recommended OFF for "anonymous" and for "nobody". |
| 431 | 480 | @ </p></li> |
| 432 | 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> | |
| 433 | 490 | @ <li><p> |
| 434 | 491 | @ 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. | |
| 441 | 500 | @ </p></li> |
| 442 | 501 | @ |
| 443 | 502 | @ <li><p> |
| 444 | 503 | @ Login is required for user "<b>anonymous</b>" but the password |
| 445 | 504 | @ is displayed on the login screen beside the password entry box |
| 446 | 505 | @ so anybody who can read should be able to login as anonymous. |
| 447 | 506 | @ On the other hand, spiders and web-crawlers will typically not |
| 448 | 507 | @ be able to login. Set the capabilities of the anonymous user |
| 449 | 508 | @ 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>. | |
| 451 | 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> | |
| 452 | 520 | @ </form> |
| 453 | 521 | style_footer(); |
| 454 | 522 | } |
| 455 | 523 | |
| 456 | 524 | |
| 457 | 525 |
| --- 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> </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> </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 @@ | ||
| 82 | 82 | void style_header(const char *zTitleFormat, ...){ |
| 83 | 83 | va_list ap; |
| 84 | 84 | char *zTitle; |
| 85 | 85 | const char *zHeader = db_get("header", (char*)zDefaultHeader); |
| 86 | 86 | login_check_credentials(); |
| 87 | - | |
| 87 | + | |
| 88 | 88 | va_start(ap, zTitleFormat); |
| 89 | 89 | zTitle = vmprintf(zTitleFormat, ap); |
| 90 | 90 | va_end(ap); |
| 91 | 91 | |
| 92 | 92 | cgi_destination(CGI_HEADER); |
| @@ -112,13 +112,13 @@ | ||
| 112 | 112 | /* |
| 113 | 113 | ** Draw the footer at the bottom of the page. |
| 114 | 114 | */ |
| 115 | 115 | void style_footer(void){ |
| 116 | 116 | const char *zFooter; |
| 117 | - | |
| 117 | + | |
| 118 | 118 | if( !headerHasBeenGenerated ) return; |
| 119 | - | |
| 119 | + | |
| 120 | 120 | /* Go back and put the submenu at the top of the page. We delay the |
| 121 | 121 | ** creation of the submenu until the end so that we can add elements |
| 122 | 122 | ** to the submenu while generating page text. |
| 123 | 123 | */ |
| 124 | 124 | cgi_destination(CGI_HEADER); |
| 125 | 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 |
| --- 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 @@ | ||
| 82 | 82 | void style_header(const char *zTitleFormat, ...){ |
| 83 | 83 | va_list ap; |
| 84 | 84 | char *zTitle; |
| 85 | 85 | const char *zHeader = db_get("header", (char*)zDefaultHeader); |
| 86 | 86 | login_check_credentials(); |
| 87 | - | |
| 87 | + | |
| 88 | 88 | va_start(ap, zTitleFormat); |
| 89 | 89 | zTitle = vmprintf(zTitleFormat, ap); |
| 90 | 90 | va_end(ap); |
| 91 | 91 | |
| 92 | 92 | cgi_destination(CGI_HEADER); |
| @@ -112,13 +112,13 @@ | ||
| 112 | 112 | /* |
| 113 | 113 | ** Draw the footer at the bottom of the page. |
| 114 | 114 | */ |
| 115 | 115 | void style_footer(void){ |
| 116 | 116 | const char *zFooter; |
| 117 | - | |
| 117 | + | |
| 118 | 118 | if( !headerHasBeenGenerated ) return; |
| 119 | - | |
| 119 | + | |
| 120 | 120 | /* Go back and put the submenu at the top of the page. We delay the |
| 121 | 121 | ** creation of the submenu until the end so that we can add elements |
| 122 | 122 | ** to the submenu while generating page text. |
| 123 | 123 | */ |
| 124 | 124 | cgi_destination(CGI_HEADER); |
| 125 | 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 |
| --- 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 @@ | ||
| 245 | 245 | zValue = g.argc==5 ? g.argv[4] : 0; |
| 246 | 246 | db_begin_transaction(); |
| 247 | 247 | tag_insert(zTag, tagtype, zValue, -1, 0.0, rid); |
| 248 | 248 | db_end_transaction(0); |
| 249 | 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 | +} | |
| 250 | 304 | |
| 251 | 305 | /* |
| 252 | 306 | ** Add a control record to the repository that either creates |
| 253 | 307 | ** or cancels a tag. |
| 254 | 308 | */ |
| 255 | 309 | static void tag_add_artifact( |
| 256 | 310 | const char *zTagname, /* The tag to add or cancel */ |
| 257 | 311 | const char *zObjName, /* Name of object attached to */ |
| 258 | 312 | 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? */ | |
| 260 | 315 | ){ |
| 261 | 316 | int rid; |
| 262 | 317 | int nrid; |
| 263 | 318 | char *zDate; |
| 264 | 319 | Blob uuid; |
| @@ -278,14 +333,18 @@ | ||
| 278 | 333 | |
| 279 | 334 | if( validate16(zTagname, strlen(zTagname)) ){ |
| 280 | 335 | fossil_fatal("invalid tag name \"%s\" - might be confused with a UUID", |
| 281 | 336 | zTagname); |
| 282 | 337 | } |
| 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 | + } | |
| 287 | 346 | if( tagtype && zValue && zValue[0] ){ |
| 288 | 347 | blob_appendf(&ctrl, " %F\n", zValue); |
| 289 | 348 | }else{ |
| 290 | 349 | blob_appendf(&ctrl, "\n"); |
| 291 | 350 | } |
| @@ -309,20 +368,31 @@ | ||
| 309 | 368 | ** |
| 310 | 369 | ** %fossil tag add ?--raw? TAGNAME UUID ?VALUE? |
| 311 | 370 | ** |
| 312 | 371 | ** Add a new tag or property to UUID. The tag will |
| 313 | 372 | ** be usable instead of a UUID in commands like |
| 314 | -** update and the like. | |
| 373 | +** update and such. | |
| 315 | 374 | ** |
| 316 | 375 | ** %fossil tag branch ?--raw? TAGNAME UUID ?VALUE? |
| 317 | 376 | ** |
| 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. | |
| 320 | 390 | ** |
| 321 | -** %fossil tag delete ?--raw? TAGNAME UUID | |
| 391 | +** %fossil tag cancel ?--raw? TAGNAME UUID | |
| 322 | 392 | ** |
| 323 | -** Delete the tag TAGNAME from UUID | |
| 393 | +** Cancel the tag TAGNAME from UUID | |
| 324 | 394 | ** |
| 325 | 395 | ** %fossil tag find ?--raw? TAGNAME |
| 326 | 396 | ** |
| 327 | 397 | ** List all baselines that use TAGNAME |
| 328 | 398 | ** |
| @@ -369,39 +439,43 @@ | ||
| 369 | 439 | blob_set(&tagname, prefix); |
| 370 | 440 | |
| 371 | 441 | if( strncmp(g.argv[2],"add",n)==0 ){ |
| 372 | 442 | char *zValue; |
| 373 | 443 | if( g.argc!=5 && g.argc!=6 ){ |
| 374 | - usage("add TAGNAME UUID ?VALUE?"); | |
| 444 | + usage("add ?--raw? TAGNAME UUID ?VALUE?"); | |
| 375 | 445 | } |
| 376 | 446 | blob_append(&tagname, g.argv[3], strlen(g.argv[3])); |
| 377 | 447 | 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); | |
| 379 | 449 | }else |
| 380 | 450 | |
| 381 | 451 | if( strncmp(g.argv[2],"branch",n)==0 ){ |
| 382 | 452 | char *zValue; |
| 383 | 453 | if( g.argc!=5 && g.argc!=6 ){ |
| 384 | - usage("branch TAGNAME UUID ?VALUE?"); | |
| 454 | + usage("branch ?--raw? TAGNAME UUID ?VALUE?"); | |
| 385 | 455 | } |
| 386 | 456 | blob_append(&tagname, g.argv[3], strlen(g.argv[3])); |
| 387 | 457 | 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 | + } | |
| 389 | 463 | }else |
| 390 | 464 | |
| 391 | - if( strncmp(g.argv[2],"delete",n)==0 ){ | |
| 465 | + if( strncmp(g.argv[2],"cancel",n)==0 ){ | |
| 392 | 466 | if( g.argc!=5 ){ |
| 393 | - usage("delete TAGNAME UUID"); | |
| 467 | + usage("cancel ?--raw? TAGNAME UUID"); | |
| 394 | 468 | } |
| 395 | 469 | 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); | |
| 397 | 471 | }else |
| 398 | 472 | |
| 399 | 473 | if( strncmp(g.argv[2],"find",n)==0 ){ |
| 400 | 474 | Stmt q; |
| 401 | 475 | if( g.argc!=4 ){ |
| 402 | - usage("find TAGNAME"); | |
| 476 | + usage("find ?--raw? TAGNAME"); | |
| 403 | 477 | } |
| 404 | 478 | blob_append(&tagname, g.argv[3], strlen(g.argv[3])); |
| 405 | 479 | db_prepare(&q, |
| 406 | 480 | "SELECT blob.uuid FROM tagxref, blob" |
| 407 | 481 | " WHERE tagid=(SELECT tagid FROM tag WHERE tagname=%B)" |
| @@ -415,12 +489,11 @@ | ||
| 415 | 489 | |
| 416 | 490 | if( strncmp(g.argv[2],"list",n)==0 ){ |
| 417 | 491 | Stmt q; |
| 418 | 492 | if( g.argc==3 ){ |
| 419 | 493 | db_prepare(&q, |
| 420 | - "SELECT tagname" | |
| 421 | - " FROM tag" | |
| 494 | + "SELECT tagname FROM tag" | |
| 422 | 495 | " WHERE EXISTS(SELECT 1 FROM tagxref" |
| 423 | 496 | " WHERE tagid=tag.tagid" |
| 424 | 497 | " AND tagtype>0)" |
| 425 | 498 | " ORDER BY tagname" |
| 426 | 499 | ); |
| @@ -432,12 +505,11 @@ | ||
| 432 | 505 | } |
| 433 | 506 | db_finalize(&q); |
| 434 | 507 | }else if( g.argc==4 ){ |
| 435 | 508 | int rid = name_to_rid(g.argv[3]); |
| 436 | 509 | db_prepare(&q, |
| 437 | - "SELECT tagname, value" | |
| 438 | - " FROM tagxref, tag" | |
| 510 | + "SELECT tagname, value FROM tagxref, tag" | |
| 439 | 511 | " WHERE tagxref.rid=%d AND tagxref.tagid=tag.tagid" |
| 440 | 512 | " AND tagtype>0" |
| 441 | 513 | " ORDER BY tagname", |
| 442 | 514 | rid |
| 443 | 515 | ); |
| @@ -466,7 +538,7 @@ | ||
| 466 | 538 | /* Cleanup */ |
| 467 | 539 | blob_reset(&tagname); |
| 468 | 540 | return; |
| 469 | 541 | |
| 470 | 542 | tag_cmd_usage: |
| 471 | - usage("add|branch|delete|find|list ..."); | |
| 543 | + usage("add|branch|cancel|find|list ..."); | |
| 472 | 544 | } |
| 473 | 545 |
| --- 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 @@ | ||
| 134 | 134 | tagname); |
| 135 | 135 | db_generic_query_view(zSql, 1); |
| 136 | 136 | free(zSql); |
| 137 | 137 | } |
| 138 | 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 | 139 | /* |
| 166 | 140 | ** WEBP AGE: /tagview |
| 167 | 141 | */ |
| 168 | 142 | void old_tagview_page(void){ |
| 169 | 143 | char const * check = 0; |
| @@ -202,11 +176,31 @@ | ||
| 202 | 176 | char *zSql; |
| 203 | 177 | Stmt q; |
| 204 | 178 | if( sym_tag_to_uuid(zName, &uuid) > 0){ |
| 205 | 179 | style_header("Tagged Baselines"); |
| 206 | 180 | @ <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); | |
| 208 | 202 | db_prepare(&q, zSql); |
| 209 | 203 | free(zSql); |
| 210 | 204 | www_print_timeline(&q); |
| 211 | 205 | db_finalize(&q); |
| 212 | 206 | }else{ |
| @@ -217,28 +211,35 @@ | ||
| 217 | 211 | }else{ |
| 218 | 212 | Stmt q; |
| 219 | 213 | const char *prefix = "sym-"; |
| 220 | 214 | int preflen = strlen(prefix); |
| 221 | 215 | style_header("Tags"); |
| 222 | - db_prepare(&q, | |
| 216 | + db_prepare(&q, | |
| 223 | 217 | "SELECT tagname" |
| 224 | 218 | " FROM tag" |
| 225 | 219 | " WHERE EXISTS(SELECT 1 FROM tagxref" |
| 226 | 220 | " WHERE tagid=tag.tagid" |
| 227 | 221 | " 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 | |
| 229 | 227 | ); |
| 230 | 228 | @ <ul> |
| 231 | 229 | while( db_step(&q)==SQLITE_ROW ){ |
| 232 | 230 | const char *name = db_column_text(&q, 0); |
| 233 | 231 | if( strncmp(name, prefix, preflen)==0 ){ |
| 234 | 232 | @ <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> | |
| 236 | 237 | } |
| 237 | 238 | } |
| 238 | 239 | @ </ul> |
| 239 | 240 | db_finalize(&q); |
| 240 | 241 | } |
| 241 | 242 | style_footer(); |
| 242 | 243 | } |
| 243 | 244 | |
| 244 | 245 | #undef TAGVIEW_DEFAULT_FILTER |
| 245 | 246 |
| --- 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 @@ | ||
| 134 | 134 | tagname); |
| 135 | 135 | db_generic_query_view(zSql, 1); |
| 136 | 136 | free(zSql); |
| 137 | 137 | } |
| 138 | 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 | 139 | /* |
| 166 | 140 | ** WEBP AGE: /tagview |
| 167 | 141 | */ |
| 168 | 142 | void old_tagview_page(void){ |
| 169 | 143 | char const * check = 0; |
| @@ -202,11 +176,31 @@ | ||
| 202 | 176 | char *zSql; |
| 203 | 177 | Stmt q; |
| 204 | 178 | if( sym_tag_to_uuid(zName, &uuid) > 0){ |
| 205 | 179 | style_header("Tagged Baselines"); |
| 206 | 180 | @ <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); | |
| 208 | 202 | db_prepare(&q, zSql); |
| 209 | 203 | free(zSql); |
| 210 | 204 | www_print_timeline(&q); |
| 211 | 205 | db_finalize(&q); |
| 212 | 206 | }else{ |
| @@ -217,28 +211,35 @@ | ||
| 217 | 211 | }else{ |
| 218 | 212 | Stmt q; |
| 219 | 213 | const char *prefix = "sym-"; |
| 220 | 214 | int preflen = strlen(prefix); |
| 221 | 215 | style_header("Tags"); |
| 222 | - db_prepare(&q, | |
| 216 | + db_prepare(&q, | |
| 223 | 217 | "SELECT tagname" |
| 224 | 218 | " FROM tag" |
| 225 | 219 | " WHERE EXISTS(SELECT 1 FROM tagxref" |
| 226 | 220 | " WHERE tagid=tag.tagid" |
| 227 | 221 | " 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 | |
| 229 | 227 | ); |
| 230 | 228 | @ <ul> |
| 231 | 229 | while( db_step(&q)==SQLITE_ROW ){ |
| 232 | 230 | const char *name = db_column_text(&q, 0); |
| 233 | 231 | if( strncmp(name, prefix, preflen)==0 ){ |
| 234 | 232 | @ <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> | |
| 236 | 237 | } |
| 237 | 238 | } |
| 238 | 239 | @ </ul> |
| 239 | 240 | db_finalize(&q); |
| 240 | 241 | } |
| 241 | 242 | style_footer(); |
| 242 | 243 | } |
| 243 | 244 | |
| 244 | 245 | #undef TAGVIEW_DEFAULT_FILTER |
| 245 | 246 |
| --- 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 @@ | ||
| 351 | 351 | ** Generate a ZIP archive for the baseline. |
| 352 | 352 | ** Return that ZIP archive as the HTTP reply content. |
| 353 | 353 | */ |
| 354 | 354 | void baseline_zip_page(void){ |
| 355 | 355 | int rid; |
| 356 | - char *zName; | |
| 357 | - int nName; | |
| 356 | + char *zName, *zRid; | |
| 357 | + int nName, nRid; | |
| 358 | 358 | Blob zip; |
| 359 | 359 | |
| 360 | 360 | login_check_credentials(); |
| 361 | - if( !g.okRead || !g.okHistory ){ login_needed(); return; } | |
| 361 | + if( !g.okZip && (!g.okRead || !g.okHistory) ){ login_needed(); return; } | |
| 362 | 362 | zName = mprintf("%s", PD("name","")); |
| 363 | 363 | nName = strlen(zName); |
| 364 | + zRid = mprintf("%s", PD("uuid","")); | |
| 365 | + nRid = strlen(zRid); | |
| 364 | 366 | for(nName=strlen(zName)-1; nName>5; nName--){ |
| 365 | 367 | if( zName[nName]=='.' ){ |
| 366 | 368 | zName[nName] = 0; |
| 367 | 369 | break; |
| 368 | 370 | } |
| 369 | 371 | } |
| 370 | - rid = name_to_rid(zName); | |
| 372 | + rid = name_to_rid(nRid?zRid:zName); | |
| 371 | 373 | if( rid==0 ){ |
| 372 | 374 | @ Not found |
| 373 | 375 | return; |
| 374 | 376 | } |
| 375 | - if( nName>10 ) zName[10] = 0; | |
| 377 | + if( nRid==0 && nName>10 ) zName[10] = 0; | |
| 376 | 378 | zip_of_baseline(rid, &zip, zName); |
| 377 | 379 | free( zName ); |
| 380 | + free( zRid ); | |
| 378 | 381 | cgi_set_content(&zip); |
| 379 | 382 | cgi_set_content_type("application/zip"); |
| 380 | 383 | cgi_reply(); |
| 381 | 384 | } |
| 382 | 385 |
| --- 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 |