Fossil SCM

Hook up the new configuration transfer logic to "push" and "pull". Compiles cleanly but otherwise untested.

drh 2011-04-26 23:11 UTC config-sync
Commit 9d35e1dbf0a3ee60ed4d8094af5ec9e5e9000ff2
2 files changed +91 -68 +33 -14
+91 -68
--- src/configure.c
+++ src/configure.c
@@ -2,11 +2,11 @@
22
** Copyright (c) 2008 D. Richard Hipp
33
**
44
** This program is free software; you can redistribute it and/or
55
** modify it under the terms of the Simplified BSD License (also
66
** known as the "2-Clause License" or "FreeBSD License".)
7
-
7
+**
88
** This program is distributed in the hope that it will be useful,
99
** but without any warranty; without even the implied warranty of
1010
** merchantability or fitness for a particular purpose.
1111
**
1212
** Author contact information:
@@ -37,10 +37,11 @@
3737
#define CONFIGSET_ADDR 0x000020 /* The CONCEALED table */
3838
3939
#define CONFIGSET_ALL 0x0000ff /* Everything */
4040
4141
#define CONFIGSET_OVERWRITE 0x100000 /* Causes overwrite instead of merge */
42
+#define CONFIGSET_OLDFORMAT 0x200000 /* Use the legacy format */
4243
4344
#endif /* INTERFACE */
4445
4546
/*
4647
** Names of the configuration sets
@@ -48,17 +49,17 @@
4849
static struct {
4950
const char *zName; /* Name of the configuration set */
5051
int groupMask; /* Mask for that configuration set */
5152
const char *zHelp; /* What it does */
5253
} aGroupName[] = {
53
- { "email", CONFIGSET_ADDR, "Concealed email addresses in tickets" },
54
- { "project", CONFIGSET_PROJ, "Project name and description" },
55
- { "skin", CONFIGSET_SKIN, "Web interface apparance settings" },
56
- { "shun", CONFIGSET_SHUN, "List of shunned artifacts" },
57
- { "ticket", CONFIGSET_TKT, "Ticket setup", },
58
- { "user", CONFIGSET_USER, "Users and privilege settings" },
59
- { "all", CONFIGSET_ALL, "All of the above" },
54
+ { "/email", CONFIGSET_ADDR, "Concealed email addresses in tickets" },
55
+ { "/project", CONFIGSET_PROJ, "Project name and description" },
56
+ { "/skin", CONFIGSET_SKIN, "Web interface apparance settings" },
57
+ { "/shun", CONFIGSET_SHUN, "List of shunned artifacts" },
58
+ { "/ticket", CONFIGSET_TKT, "Ticket setup", },
59
+ { "/user", CONFIGSET_USER, "Users and privilege settings" },
60
+ { "/all", CONFIGSET_ALL, "All of the above" },
6061
};
6162
6263
6364
/*
6465
** The following is a list of settings that we are willing to
@@ -108,15 +109,29 @@
108109
const char *configure_first_name(int iMask){
109110
iConfig = 0;
110111
return configure_next_name(iMask);
111112
}
112113
const char *configure_next_name(int iMask){
113
- while( iConfig<count(aConfig) ){
114
- if( aConfig[iConfig].groupMask & iMask ){
115
- return aConfig[iConfig++].zName;
116
- }else{
117
- iConfig++;
114
+ if( iMask & CONFIGSET_OLDFORMAT ){
115
+ while( iConfig<count(aConfig) ){
116
+ if( aConfig[iConfig].groupMask & iMask ){
117
+ return aConfig[iConfig++].zName;
118
+ }else{
119
+ iConfig++;
120
+ }
121
+ }
122
+ }else{
123
+ if( iConfig==0 && (iMask & CONFIGSET_ALL)==CONFIGSET_ALL ){
124
+ iConfig = count(aGroupName);
125
+ return "/all";
126
+ }
127
+ while( iConfig<count(aGroupName)-1 ){
128
+ if( aGroupName[iConfig].groupMask & iMask ){
129
+ return aGroupName[iConfig++].zName;
130
+ }else{
131
+ iConfig++;
132
+ }
118133
}
119134
}
120135
return 0;
121136
}
122137
@@ -304,10 +319,26 @@
304319
config_reset_function, 0, 0);
305320
configHasBeenReset = 0;
306321
db_multi_exec(zSQL2);
307322
}
308323
}
324
+
325
+/*
326
+** After receiving configuration data, call this routine to transfer
327
+** the results into the main database.
328
+*/
329
+void configure_finalize_receive(void){
330
+ static const char zSQL[] =
331
+ @ DELETE FROM user;
332
+ @ INSERT INTO user SELECT * FROM _xfer_user;
333
+ @ DELETE FROM reportfmt;
334
+ @ INSERT INTO reportfmt SELECT * FROM _xfer_reportfmt;
335
+ @ DROP TABLE _xfer_user;
336
+ @ DROP TABLE _xfer_reportfmt;
337
+ ;
338
+ db_multi_exec(zSQL);
339
+}
309340
310341
/*
311342
** Return true if z[] is not a "safe" SQL token. A safe token is one of:
312343
**
313344
** * A string literal
@@ -534,19 +565,22 @@
534565
** Send "config" cards using the new format for all elements of a group
535566
** that have recently changed.
536567
**
537568
** Output goes into pOut. The groupMask identifies the group(s) to be sent.
538569
** Send only entries whose timestamp is later than or equal to iStart.
570
+**
571
+** Return the number of cards sent.
539572
*/
540
-void configure_send_group(
573
+int configure_send_group(
541574
Blob *pOut, /* Write output here */
542575
int groupMask, /* Mask of groups to be send */
543576
sqlite3_int64 iStart /* Only write values changed since this time */
544577
){
545578
Stmt q;
546579
Blob rec;
547580
int ii;
581
+ int nCard = 0;
548582
549583
blob_zero(&rec);
550584
if( groupMask & CONFIGSET_SHUN ){
551585
db_prepare(&q, "SELECT mtime, quote(uuid), quote(scom) FROM shun"
552586
" WHERE mtime>=%lld", iStart);
@@ -556,10 +590,11 @@
556590
db_column_text(&q, 1),
557591
db_column_text(&q, 2)
558592
);
559593
blob_appendf(pOut, "config /shun %d\n%s",
560594
blob_size(&rec), blob_str(&rec));
595
+ nCard++;
561596
blob_reset(&rec);
562597
}
563598
db_finalize(&q);
564599
}
565600
if( groupMask & CONFIGSET_USER ){
@@ -575,10 +610,11 @@
575610
db_column_text(&q, 4),
576611
db_column_text(&q, 5)
577612
);
578613
blob_appendf(pOut, "config /user %d\n%s",
579614
blob_size(&rec), blob_str(&rec));
615
+ nCard++;
580616
blob_reset(&rec);
581617
}
582618
db_finalize(&q);
583619
}
584620
if( groupMask & CONFIGSET_TKT ){
@@ -593,10 +629,11 @@
593629
db_column_text(&q, 3),
594630
db_column_text(&q, 4)
595631
);
596632
blob_appendf(pOut, "config /reportfmt %d\n%s",
597633
blob_size(&rec), blob_str(&rec));
634
+ nCard++;
598635
blob_reset(&rec);
599636
}
600637
db_finalize(&q);
601638
}
602639
if( groupMask & CONFIGSET_ADDR ){
@@ -608,10 +645,11 @@
608645
db_column_text(&q, 1),
609646
db_column_text(&q, 2)
610647
);
611648
blob_appendf(pOut, "config /concealed %d\n%s",
612649
blob_size(&rec), blob_str(&rec));
650
+ nCard++;
613651
blob_reset(&rec);
614652
}
615653
db_finalize(&q);
616654
}
617655
db_prepare(&q, "SELECT mtime, quote(name), quote(value) FROM config"
@@ -625,73 +663,39 @@
625663
db_column_text(&q, 1),
626664
db_column_text(&q, 2)
627665
);
628666
blob_appendf(pOut, "config /config %d\n%s",
629667
blob_size(&rec), blob_str(&rec));
668
+ nCard++;
630669
blob_reset(&rec);
631670
}
632671
db_reset(&q);
633672
}
634673
}
635674
db_finalize(&q);
636
-}
637
-
638
-/*
639
-** COMMAND: test-config-send
640
-**
641
-** Usage: %fossil test-config-send GROUP START
642
-*/
643
-void test_config_send(void){
644
- Blob out;
645
- sqlite3_int64 iStart;
646
- int i;
647
- blob_zero(&out);
648
- db_find_and_open_repository(0,0);
649
- if( g.argc!=4 ) usage("GROUP START");
650
- iStart = db_int64(0, "SELECT strftime('%%s',%Q)", g.argv[3]);
651
- for(i=0; i<count(aGroupName); i++){
652
- if( fossil_strcmp(g.argv[2], aGroupName[i].zName)==0 ){
653
- configure_send_group(&out, aGroupName[i].groupMask, iStart);
654
- printf("%s", blob_str(&out));
655
- blob_reset(&out);
656
- }
657
- }
658
-}
659
-
660
-/*
661
-** After receiving configuration data, call this routine to transfer
662
-** the results into the main database.
663
-*/
664
-void configure_finalize_receive(void){
665
- static const char zSQL[] =
666
- @ DELETE FROM user;
667
- @ INSERT INTO user SELECT * FROM _xfer_user;
668
- @ DELETE FROM reportfmt;
669
- @ INSERT INTO reportfmt SELECT * FROM _xfer_reportfmt;
670
- @ DROP TABLE _xfer_user;
671
- @ DROP TABLE _xfer_reportfmt;
672
- ;
673
- db_multi_exec(zSQL);
675
+ return nCard;
674676
}
675677
676678
/*
677679
** Identify a configuration group by name. Return its mask.
678680
** Throw an error if no match.
679681
*/
680
-static int find_area(const char *z){
682
+int configure_name_to_mask(const char *z, int notFoundIsFatal){
681683
int i;
682684
int n = strlen(z);
683685
for(i=0; i<count(aGroupName); i++){
684
- if( strncmp(z, aGroupName[i].zName, n)==0 ){
686
+ if( strncmp(z, &aGroupName[i].zName[1], n)==0 ){
685687
return aGroupName[i].groupMask;
686688
}
687689
}
688
- printf("Available configuration areas:\n");
689
- for(i=0; i<count(aGroupName); i++){
690
- printf(" %-10s %s\n", aGroupName[i].zName, aGroupName[i].zHelp);
690
+ if( notFoundIsFatal ){
691
+ printf("Available configuration areas:\n");
692
+ for(i=0; i<count(aGroupName); i++){
693
+ printf(" %-10s %s\n", &aGroupName[i].zName[1], aGroupName[i].zHelp);
694
+ }
695
+ fossil_fatal("no such configuration area: \"%s\"", z);
691696
}
692
- fossil_fatal("no such configuration area: \"%s\"", z);
693697
return 0;
694698
}
695699
696700
/*
697701
** Write SQL text into file zFilename that will restore the configuration
@@ -744,25 +748,31 @@
744748
**
745749
** %fossil configuration pull AREA ?URL?
746750
**
747751
** Pull and install the configuration from a different server
748752
** identified by URL. If no URL is specified, then the default
749
-** server is used.
753
+** server is used. Use the --legacy option for the older protocol
754
+** (when talking to servers compiled prior to 2011-04-27.) Use
755
+** the --overwrite flag to completely replace local settings with
756
+** content received from URL.
750757
**
751758
** %fossil configuration push AREA ?URL?
752759
**
753760
** Push the local configuration into the remote server identified
754761
** by URL. Admin privilege is required on the remote server for
755
-** this to work.
762
+** this to work. When the same record exists both locally and on
763
+** the remote end, the one that was most recently changed wins.
764
+** Use the --legacy flag when talking to holder servers.
756765
**
757766
** %fossil configuration reset AREA
758767
**
759768
** Restore the configuration to the default. AREA as above.
760769
**
761
-** WARNING: Do not import, merge, or pull configurations from an untrusted
762
-** source. The inbound configuration is not checked for safety and can
763
-** introduce security vulnerabilities.
770
+** %fossil configuration sync AREA ?URL?
771
+**
772
+** Synchronize configuration changes in the local repository with
773
+** the remote repository at URL.
764774
*/
765775
void configuration_cmd(void){
766776
int n;
767777
const char *zMethod;
768778
if( g.argc<3 ){
@@ -776,11 +786,11 @@
776786
const char *zSince = find_option("since",0,1);
777787
sqlite3_int64 iStart;
778788
if( g.argc!=5 ){
779789
usage("export AREA FILENAME");
780790
}
781
- mask = find_area(g.argv[3]);
791
+ mask = configure_name_to_mask(g.argv[3], 1);
782792
if( zSince ){
783793
iStart = db_multi_exec(
784794
"SELECT coalesce(strftime('%%s',%Q),strftime('%%s','now',%Q))+0",
785795
zSince, zSince
786796
);
@@ -802,19 +812,28 @@
802812
groupMask = CONFIGSET_ALL;
803813
}
804814
configure_receive_all(&in, groupMask);
805815
db_end_transaction(0);
806816
}else
807
- if( strncmp(zMethod, "pull", n)==0 || strncmp(zMethod, "push", n)==0 ){
817
+ if( strncmp(zMethod, "pull", n)==0
818
+ || strncmp(zMethod, "push", n)==0
819
+ || strncmp(zMethod, "sync", n)==0
820
+ ){
808821
int mask;
809822
const char *zServer;
810823
const char *zPw;
824
+ int legacyFlag = 0;
825
+ int overwriteFlag = 0;
826
+ if( zMethod[0]!='s' ) legacyFlag = find_option("legacy",0,0)!=0;
827
+ if( strncmp(zMethod,"pull",n)==0 ){
828
+ overwriteFlag = find_option("overwrite",0,0)!=0;
829
+ }
811830
url_proxy_options();
812831
if( g.argc!=4 && g.argc!=5 ){
813832
usage("pull AREA ?URL?");
814833
}
815
- mask = find_area(g.argv[3]);
834
+ mask = configure_name_to_mask(g.argv[3], 1);
816835
if( g.argc==5 ){
817836
zServer = g.argv[4];
818837
zPw = 0;
819838
g.dontKeepUrl = 1;
820839
}else{
@@ -826,21 +845,25 @@
826845
}
827846
url_parse(zServer);
828847
if( g.urlPasswd==0 && zPw ) g.urlPasswd = mprintf("%s", zPw);
829848
user_select();
830849
url_enable_proxy("via proxy: ");
850
+ if( legacyFlag ) mask |= CONFIGSET_OLDFORMAT;
851
+ if( overwriteFlag ) mask |= CONFIGSET_OVERWRITE;
831852
if( strncmp(zMethod, "push", n)==0 ){
832853
client_sync(0,0,0,0,0,mask);
833
- }else{
854
+ }else if( strncmp(zMethod, "pull", n)==0 ){
834855
client_sync(0,0,0,0,mask,0);
856
+ }else{
857
+ client_sync(0,0,0,0,mask,mask);
835858
}
836859
}else
837860
if( strncmp(zMethod, "reset", n)==0 ){
838861
int mask, i;
839862
char *zBackup;
840863
if( g.argc!=4 ) usage("reset AREA");
841
- mask = find_area(g.argv[3]);
864
+ mask = configure_name_to_mask(g.argv[3], 1);
842865
zBackup = db_text(0,
843866
"SELECT strftime('config-backup-%%Y%%m%%d%%H%%M%%f','now')");
844867
db_begin_transaction();
845868
export_config(mask, g.argv[3], 0, zBackup);
846869
for(i=0; i<count(aConfig); i++){
847870
--- src/configure.c
+++ src/configure.c
@@ -2,11 +2,11 @@
2 ** Copyright (c) 2008 D. Richard Hipp
3 **
4 ** This program is free software; you can redistribute it and/or
5 ** modify it under the terms of the Simplified BSD License (also
6 ** known as the "2-Clause License" or "FreeBSD License".)
7
8 ** This program is distributed in the hope that it will be useful,
9 ** but without any warranty; without even the implied warranty of
10 ** merchantability or fitness for a particular purpose.
11 **
12 ** Author contact information:
@@ -37,10 +37,11 @@
37 #define CONFIGSET_ADDR 0x000020 /* The CONCEALED table */
38
39 #define CONFIGSET_ALL 0x0000ff /* Everything */
40
41 #define CONFIGSET_OVERWRITE 0x100000 /* Causes overwrite instead of merge */
 
42
43 #endif /* INTERFACE */
44
45 /*
46 ** Names of the configuration sets
@@ -48,17 +49,17 @@
48 static struct {
49 const char *zName; /* Name of the configuration set */
50 int groupMask; /* Mask for that configuration set */
51 const char *zHelp; /* What it does */
52 } aGroupName[] = {
53 { "email", CONFIGSET_ADDR, "Concealed email addresses in tickets" },
54 { "project", CONFIGSET_PROJ, "Project name and description" },
55 { "skin", CONFIGSET_SKIN, "Web interface apparance settings" },
56 { "shun", CONFIGSET_SHUN, "List of shunned artifacts" },
57 { "ticket", CONFIGSET_TKT, "Ticket setup", },
58 { "user", CONFIGSET_USER, "Users and privilege settings" },
59 { "all", CONFIGSET_ALL, "All of the above" },
60 };
61
62
63 /*
64 ** The following is a list of settings that we are willing to
@@ -108,15 +109,29 @@
108 const char *configure_first_name(int iMask){
109 iConfig = 0;
110 return configure_next_name(iMask);
111 }
112 const char *configure_next_name(int iMask){
113 while( iConfig<count(aConfig) ){
114 if( aConfig[iConfig].groupMask & iMask ){
115 return aConfig[iConfig++].zName;
116 }else{
117 iConfig++;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
118 }
119 }
120 return 0;
121 }
122
@@ -304,10 +319,26 @@
304 config_reset_function, 0, 0);
305 configHasBeenReset = 0;
306 db_multi_exec(zSQL2);
307 }
308 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
309
310 /*
311 ** Return true if z[] is not a "safe" SQL token. A safe token is one of:
312 **
313 ** * A string literal
@@ -534,19 +565,22 @@
534 ** Send "config" cards using the new format for all elements of a group
535 ** that have recently changed.
536 **
537 ** Output goes into pOut. The groupMask identifies the group(s) to be sent.
538 ** Send only entries whose timestamp is later than or equal to iStart.
 
 
539 */
540 void configure_send_group(
541 Blob *pOut, /* Write output here */
542 int groupMask, /* Mask of groups to be send */
543 sqlite3_int64 iStart /* Only write values changed since this time */
544 ){
545 Stmt q;
546 Blob rec;
547 int ii;
 
548
549 blob_zero(&rec);
550 if( groupMask & CONFIGSET_SHUN ){
551 db_prepare(&q, "SELECT mtime, quote(uuid), quote(scom) FROM shun"
552 " WHERE mtime>=%lld", iStart);
@@ -556,10 +590,11 @@
556 db_column_text(&q, 1),
557 db_column_text(&q, 2)
558 );
559 blob_appendf(pOut, "config /shun %d\n%s",
560 blob_size(&rec), blob_str(&rec));
 
561 blob_reset(&rec);
562 }
563 db_finalize(&q);
564 }
565 if( groupMask & CONFIGSET_USER ){
@@ -575,10 +610,11 @@
575 db_column_text(&q, 4),
576 db_column_text(&q, 5)
577 );
578 blob_appendf(pOut, "config /user %d\n%s",
579 blob_size(&rec), blob_str(&rec));
 
580 blob_reset(&rec);
581 }
582 db_finalize(&q);
583 }
584 if( groupMask & CONFIGSET_TKT ){
@@ -593,10 +629,11 @@
593 db_column_text(&q, 3),
594 db_column_text(&q, 4)
595 );
596 blob_appendf(pOut, "config /reportfmt %d\n%s",
597 blob_size(&rec), blob_str(&rec));
 
598 blob_reset(&rec);
599 }
600 db_finalize(&q);
601 }
602 if( groupMask & CONFIGSET_ADDR ){
@@ -608,10 +645,11 @@
608 db_column_text(&q, 1),
609 db_column_text(&q, 2)
610 );
611 blob_appendf(pOut, "config /concealed %d\n%s",
612 blob_size(&rec), blob_str(&rec));
 
613 blob_reset(&rec);
614 }
615 db_finalize(&q);
616 }
617 db_prepare(&q, "SELECT mtime, quote(name), quote(value) FROM config"
@@ -625,73 +663,39 @@
625 db_column_text(&q, 1),
626 db_column_text(&q, 2)
627 );
628 blob_appendf(pOut, "config /config %d\n%s",
629 blob_size(&rec), blob_str(&rec));
 
630 blob_reset(&rec);
631 }
632 db_reset(&q);
633 }
634 }
635 db_finalize(&q);
636 }
637
638 /*
639 ** COMMAND: test-config-send
640 **
641 ** Usage: %fossil test-config-send GROUP START
642 */
643 void test_config_send(void){
644 Blob out;
645 sqlite3_int64 iStart;
646 int i;
647 blob_zero(&out);
648 db_find_and_open_repository(0,0);
649 if( g.argc!=4 ) usage("GROUP START");
650 iStart = db_int64(0, "SELECT strftime('%%s',%Q)", g.argv[3]);
651 for(i=0; i<count(aGroupName); i++){
652 if( fossil_strcmp(g.argv[2], aGroupName[i].zName)==0 ){
653 configure_send_group(&out, aGroupName[i].groupMask, iStart);
654 printf("%s", blob_str(&out));
655 blob_reset(&out);
656 }
657 }
658 }
659
660 /*
661 ** After receiving configuration data, call this routine to transfer
662 ** the results into the main database.
663 */
664 void configure_finalize_receive(void){
665 static const char zSQL[] =
666 @ DELETE FROM user;
667 @ INSERT INTO user SELECT * FROM _xfer_user;
668 @ DELETE FROM reportfmt;
669 @ INSERT INTO reportfmt SELECT * FROM _xfer_reportfmt;
670 @ DROP TABLE _xfer_user;
671 @ DROP TABLE _xfer_reportfmt;
672 ;
673 db_multi_exec(zSQL);
674 }
675
676 /*
677 ** Identify a configuration group by name. Return its mask.
678 ** Throw an error if no match.
679 */
680 static int find_area(const char *z){
681 int i;
682 int n = strlen(z);
683 for(i=0; i<count(aGroupName); i++){
684 if( strncmp(z, aGroupName[i].zName, n)==0 ){
685 return aGroupName[i].groupMask;
686 }
687 }
688 printf("Available configuration areas:\n");
689 for(i=0; i<count(aGroupName); i++){
690 printf(" %-10s %s\n", aGroupName[i].zName, aGroupName[i].zHelp);
 
 
 
691 }
692 fossil_fatal("no such configuration area: \"%s\"", z);
693 return 0;
694 }
695
696 /*
697 ** Write SQL text into file zFilename that will restore the configuration
@@ -744,25 +748,31 @@
744 **
745 ** %fossil configuration pull AREA ?URL?
746 **
747 ** Pull and install the configuration from a different server
748 ** identified by URL. If no URL is specified, then the default
749 ** server is used.
 
 
 
750 **
751 ** %fossil configuration push AREA ?URL?
752 **
753 ** Push the local configuration into the remote server identified
754 ** by URL. Admin privilege is required on the remote server for
755 ** this to work.
 
 
756 **
757 ** %fossil configuration reset AREA
758 **
759 ** Restore the configuration to the default. AREA as above.
760 **
761 ** WARNING: Do not import, merge, or pull configurations from an untrusted
762 ** source. The inbound configuration is not checked for safety and can
763 ** introduce security vulnerabilities.
 
764 */
765 void configuration_cmd(void){
766 int n;
767 const char *zMethod;
768 if( g.argc<3 ){
@@ -776,11 +786,11 @@
776 const char *zSince = find_option("since",0,1);
777 sqlite3_int64 iStart;
778 if( g.argc!=5 ){
779 usage("export AREA FILENAME");
780 }
781 mask = find_area(g.argv[3]);
782 if( zSince ){
783 iStart = db_multi_exec(
784 "SELECT coalesce(strftime('%%s',%Q),strftime('%%s','now',%Q))+0",
785 zSince, zSince
786 );
@@ -802,19 +812,28 @@
802 groupMask = CONFIGSET_ALL;
803 }
804 configure_receive_all(&in, groupMask);
805 db_end_transaction(0);
806 }else
807 if( strncmp(zMethod, "pull", n)==0 || strncmp(zMethod, "push", n)==0 ){
 
 
 
808 int mask;
809 const char *zServer;
810 const char *zPw;
 
 
 
 
 
 
811 url_proxy_options();
812 if( g.argc!=4 && g.argc!=5 ){
813 usage("pull AREA ?URL?");
814 }
815 mask = find_area(g.argv[3]);
816 if( g.argc==5 ){
817 zServer = g.argv[4];
818 zPw = 0;
819 g.dontKeepUrl = 1;
820 }else{
@@ -826,21 +845,25 @@
826 }
827 url_parse(zServer);
828 if( g.urlPasswd==0 && zPw ) g.urlPasswd = mprintf("%s", zPw);
829 user_select();
830 url_enable_proxy("via proxy: ");
 
 
831 if( strncmp(zMethod, "push", n)==0 ){
832 client_sync(0,0,0,0,0,mask);
833 }else{
834 client_sync(0,0,0,0,mask,0);
 
 
835 }
836 }else
837 if( strncmp(zMethod, "reset", n)==0 ){
838 int mask, i;
839 char *zBackup;
840 if( g.argc!=4 ) usage("reset AREA");
841 mask = find_area(g.argv[3]);
842 zBackup = db_text(0,
843 "SELECT strftime('config-backup-%%Y%%m%%d%%H%%M%%f','now')");
844 db_begin_transaction();
845 export_config(mask, g.argv[3], 0, zBackup);
846 for(i=0; i<count(aConfig); i++){
847
--- src/configure.c
+++ src/configure.c
@@ -2,11 +2,11 @@
2 ** Copyright (c) 2008 D. Richard Hipp
3 **
4 ** This program is free software; you can redistribute it and/or
5 ** modify it under the terms of the Simplified BSD License (also
6 ** known as the "2-Clause License" or "FreeBSD License".)
7 **
8 ** This program is distributed in the hope that it will be useful,
9 ** but without any warranty; without even the implied warranty of
10 ** merchantability or fitness for a particular purpose.
11 **
12 ** Author contact information:
@@ -37,10 +37,11 @@
37 #define CONFIGSET_ADDR 0x000020 /* The CONCEALED table */
38
39 #define CONFIGSET_ALL 0x0000ff /* Everything */
40
41 #define CONFIGSET_OVERWRITE 0x100000 /* Causes overwrite instead of merge */
42 #define CONFIGSET_OLDFORMAT 0x200000 /* Use the legacy format */
43
44 #endif /* INTERFACE */
45
46 /*
47 ** Names of the configuration sets
@@ -48,17 +49,17 @@
49 static struct {
50 const char *zName; /* Name of the configuration set */
51 int groupMask; /* Mask for that configuration set */
52 const char *zHelp; /* What it does */
53 } aGroupName[] = {
54 { "/email", CONFIGSET_ADDR, "Concealed email addresses in tickets" },
55 { "/project", CONFIGSET_PROJ, "Project name and description" },
56 { "/skin", CONFIGSET_SKIN, "Web interface apparance settings" },
57 { "/shun", CONFIGSET_SHUN, "List of shunned artifacts" },
58 { "/ticket", CONFIGSET_TKT, "Ticket setup", },
59 { "/user", CONFIGSET_USER, "Users and privilege settings" },
60 { "/all", CONFIGSET_ALL, "All of the above" },
61 };
62
63
64 /*
65 ** The following is a list of settings that we are willing to
@@ -108,15 +109,29 @@
109 const char *configure_first_name(int iMask){
110 iConfig = 0;
111 return configure_next_name(iMask);
112 }
113 const char *configure_next_name(int iMask){
114 if( iMask & CONFIGSET_OLDFORMAT ){
115 while( iConfig<count(aConfig) ){
116 if( aConfig[iConfig].groupMask & iMask ){
117 return aConfig[iConfig++].zName;
118 }else{
119 iConfig++;
120 }
121 }
122 }else{
123 if( iConfig==0 && (iMask & CONFIGSET_ALL)==CONFIGSET_ALL ){
124 iConfig = count(aGroupName);
125 return "/all";
126 }
127 while( iConfig<count(aGroupName)-1 ){
128 if( aGroupName[iConfig].groupMask & iMask ){
129 return aGroupName[iConfig++].zName;
130 }else{
131 iConfig++;
132 }
133 }
134 }
135 return 0;
136 }
137
@@ -304,10 +319,26 @@
319 config_reset_function, 0, 0);
320 configHasBeenReset = 0;
321 db_multi_exec(zSQL2);
322 }
323 }
324
325 /*
326 ** After receiving configuration data, call this routine to transfer
327 ** the results into the main database.
328 */
329 void configure_finalize_receive(void){
330 static const char zSQL[] =
331 @ DELETE FROM user;
332 @ INSERT INTO user SELECT * FROM _xfer_user;
333 @ DELETE FROM reportfmt;
334 @ INSERT INTO reportfmt SELECT * FROM _xfer_reportfmt;
335 @ DROP TABLE _xfer_user;
336 @ DROP TABLE _xfer_reportfmt;
337 ;
338 db_multi_exec(zSQL);
339 }
340
341 /*
342 ** Return true if z[] is not a "safe" SQL token. A safe token is one of:
343 **
344 ** * A string literal
@@ -534,19 +565,22 @@
565 ** Send "config" cards using the new format for all elements of a group
566 ** that have recently changed.
567 **
568 ** Output goes into pOut. The groupMask identifies the group(s) to be sent.
569 ** Send only entries whose timestamp is later than or equal to iStart.
570 **
571 ** Return the number of cards sent.
572 */
573 int configure_send_group(
574 Blob *pOut, /* Write output here */
575 int groupMask, /* Mask of groups to be send */
576 sqlite3_int64 iStart /* Only write values changed since this time */
577 ){
578 Stmt q;
579 Blob rec;
580 int ii;
581 int nCard = 0;
582
583 blob_zero(&rec);
584 if( groupMask & CONFIGSET_SHUN ){
585 db_prepare(&q, "SELECT mtime, quote(uuid), quote(scom) FROM shun"
586 " WHERE mtime>=%lld", iStart);
@@ -556,10 +590,11 @@
590 db_column_text(&q, 1),
591 db_column_text(&q, 2)
592 );
593 blob_appendf(pOut, "config /shun %d\n%s",
594 blob_size(&rec), blob_str(&rec));
595 nCard++;
596 blob_reset(&rec);
597 }
598 db_finalize(&q);
599 }
600 if( groupMask & CONFIGSET_USER ){
@@ -575,10 +610,11 @@
610 db_column_text(&q, 4),
611 db_column_text(&q, 5)
612 );
613 blob_appendf(pOut, "config /user %d\n%s",
614 blob_size(&rec), blob_str(&rec));
615 nCard++;
616 blob_reset(&rec);
617 }
618 db_finalize(&q);
619 }
620 if( groupMask & CONFIGSET_TKT ){
@@ -593,10 +629,11 @@
629 db_column_text(&q, 3),
630 db_column_text(&q, 4)
631 );
632 blob_appendf(pOut, "config /reportfmt %d\n%s",
633 blob_size(&rec), blob_str(&rec));
634 nCard++;
635 blob_reset(&rec);
636 }
637 db_finalize(&q);
638 }
639 if( groupMask & CONFIGSET_ADDR ){
@@ -608,10 +645,11 @@
645 db_column_text(&q, 1),
646 db_column_text(&q, 2)
647 );
648 blob_appendf(pOut, "config /concealed %d\n%s",
649 blob_size(&rec), blob_str(&rec));
650 nCard++;
651 blob_reset(&rec);
652 }
653 db_finalize(&q);
654 }
655 db_prepare(&q, "SELECT mtime, quote(name), quote(value) FROM config"
@@ -625,73 +663,39 @@
663 db_column_text(&q, 1),
664 db_column_text(&q, 2)
665 );
666 blob_appendf(pOut, "config /config %d\n%s",
667 blob_size(&rec), blob_str(&rec));
668 nCard++;
669 blob_reset(&rec);
670 }
671 db_reset(&q);
672 }
673 }
674 db_finalize(&q);
675 return nCard;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
676 }
677
678 /*
679 ** Identify a configuration group by name. Return its mask.
680 ** Throw an error if no match.
681 */
682 int configure_name_to_mask(const char *z, int notFoundIsFatal){
683 int i;
684 int n = strlen(z);
685 for(i=0; i<count(aGroupName); i++){
686 if( strncmp(z, &aGroupName[i].zName[1], n)==0 ){
687 return aGroupName[i].groupMask;
688 }
689 }
690 if( notFoundIsFatal ){
691 printf("Available configuration areas:\n");
692 for(i=0; i<count(aGroupName); i++){
693 printf(" %-10s %s\n", &aGroupName[i].zName[1], aGroupName[i].zHelp);
694 }
695 fossil_fatal("no such configuration area: \"%s\"", z);
696 }
 
697 return 0;
698 }
699
700 /*
701 ** Write SQL text into file zFilename that will restore the configuration
@@ -744,25 +748,31 @@
748 **
749 ** %fossil configuration pull AREA ?URL?
750 **
751 ** Pull and install the configuration from a different server
752 ** identified by URL. If no URL is specified, then the default
753 ** server is used. Use the --legacy option for the older protocol
754 ** (when talking to servers compiled prior to 2011-04-27.) Use
755 ** the --overwrite flag to completely replace local settings with
756 ** content received from URL.
757 **
758 ** %fossil configuration push AREA ?URL?
759 **
760 ** Push the local configuration into the remote server identified
761 ** by URL. Admin privilege is required on the remote server for
762 ** this to work. When the same record exists both locally and on
763 ** the remote end, the one that was most recently changed wins.
764 ** Use the --legacy flag when talking to holder servers.
765 **
766 ** %fossil configuration reset AREA
767 **
768 ** Restore the configuration to the default. AREA as above.
769 **
770 ** %fossil configuration sync AREA ?URL?
771 **
772 ** Synchronize configuration changes in the local repository with
773 ** the remote repository at URL.
774 */
775 void configuration_cmd(void){
776 int n;
777 const char *zMethod;
778 if( g.argc<3 ){
@@ -776,11 +786,11 @@
786 const char *zSince = find_option("since",0,1);
787 sqlite3_int64 iStart;
788 if( g.argc!=5 ){
789 usage("export AREA FILENAME");
790 }
791 mask = configure_name_to_mask(g.argv[3], 1);
792 if( zSince ){
793 iStart = db_multi_exec(
794 "SELECT coalesce(strftime('%%s',%Q),strftime('%%s','now',%Q))+0",
795 zSince, zSince
796 );
@@ -802,19 +812,28 @@
812 groupMask = CONFIGSET_ALL;
813 }
814 configure_receive_all(&in, groupMask);
815 db_end_transaction(0);
816 }else
817 if( strncmp(zMethod, "pull", n)==0
818 || strncmp(zMethod, "push", n)==0
819 || strncmp(zMethod, "sync", n)==0
820 ){
821 int mask;
822 const char *zServer;
823 const char *zPw;
824 int legacyFlag = 0;
825 int overwriteFlag = 0;
826 if( zMethod[0]!='s' ) legacyFlag = find_option("legacy",0,0)!=0;
827 if( strncmp(zMethod,"pull",n)==0 ){
828 overwriteFlag = find_option("overwrite",0,0)!=0;
829 }
830 url_proxy_options();
831 if( g.argc!=4 && g.argc!=5 ){
832 usage("pull AREA ?URL?");
833 }
834 mask = configure_name_to_mask(g.argv[3], 1);
835 if( g.argc==5 ){
836 zServer = g.argv[4];
837 zPw = 0;
838 g.dontKeepUrl = 1;
839 }else{
@@ -826,21 +845,25 @@
845 }
846 url_parse(zServer);
847 if( g.urlPasswd==0 && zPw ) g.urlPasswd = mprintf("%s", zPw);
848 user_select();
849 url_enable_proxy("via proxy: ");
850 if( legacyFlag ) mask |= CONFIGSET_OLDFORMAT;
851 if( overwriteFlag ) mask |= CONFIGSET_OVERWRITE;
852 if( strncmp(zMethod, "push", n)==0 ){
853 client_sync(0,0,0,0,0,mask);
854 }else if( strncmp(zMethod, "pull", n)==0 ){
855 client_sync(0,0,0,0,mask,0);
856 }else{
857 client_sync(0,0,0,0,mask,mask);
858 }
859 }else
860 if( strncmp(zMethod, "reset", n)==0 ){
861 int mask, i;
862 char *zBackup;
863 if( g.argc!=4 ) usage("reset AREA");
864 mask = configure_name_to_mask(g.argv[3], 1);
865 zBackup = db_text(0,
866 "SELECT strftime('config-backup-%%Y%%m%%d%%H%%M%%f','now')");
867 db_begin_transaction();
868 export_config(mask, g.argv[3], 0, zBackup);
869 for(i=0; i<count(aConfig); i++){
870
+33 -14
--- src/xfer.c
+++ src/xfer.c
@@ -738,13 +738,16 @@
738738
}
739739
db_finalize(&q);
740740
}
741741
742742
/*
743
-** Send a single old-style config card for configuration item zName
743
+** Send a single old-style config card for configuration item zName.
744
+**
745
+** This routine and the functionality it implements is scheduled for
746
+** removal on 2012-05-01.
744747
*/
745
-static void send_config_card(Xfer *pXfer, const char *zName){
748
+static void send_legacy_config_card(Xfer *pXfer, const char *zName){
746749
if( zName[0]!='@' ){
747750
Blob val;
748751
blob_zero(&val);
749752
db_blob(&val, "SELECT value FROM config WHERE name=%Q", zName);
750753
if( blob_size(&val)>0 ){
@@ -1028,12 +1031,19 @@
10281031
if( blob_eq(&xfer.aToken[0], "reqconfig")
10291032
&& xfer.nToken==2
10301033
){
10311034
if( g.okRead ){
10321035
char *zName = blob_str(&xfer.aToken[1]);
1033
- if( configure_is_exportable(zName) ){
1034
- send_config_card(&xfer, zName);
1036
+ if( zName[0]=='/' ){
1037
+ /* New style configuration transfer */
1038
+ int groupMask = configure_name_to_mask(&zName[0], 0);
1039
+ if( !g.okAdmin ) groupMask &= ~CONFIGSET_USER;
1040
+ if( !g.okRdAddr ) groupMask &= ~CONFIGSET_ADDR;
1041
+ configure_send_group(xfer.pOut, groupMask, 0);
1042
+ }else if( configure_is_exportable(zName) ){
1043
+ /* Old style configuration transfer */
1044
+ send_legacy_config_card(&xfer, zName);
10351045
}
10361046
}
10371047
}else
10381048
10391049
/* config NAME SIZE \n CONTENT
@@ -1051,11 +1061,11 @@
10511061
cgi_reset_content();
10521062
@ error not\sauthorized\sto\spush\sconfiguration
10531063
nErr++;
10541064
break;
10551065
}
1056
- if( !recvConfig ){
1066
+ if( !recvConfig && zName[0]=='@' ){
10571067
configure_prepare_to_receive(0);
10581068
recvConfig = 1;
10591069
}
10601070
configure_receive(zName, &content, CONFIGSET_ALL);
10611071
blob_reset(&content);
@@ -1330,25 +1340,32 @@
13301340
while( zName ){
13311341
blob_appendf(&send, "reqconfig %s\n", zName);
13321342
zName = configure_next_name(configRcvMask);
13331343
nCardSent++;
13341344
}
1335
- if( configRcvMask & (CONFIGSET_USER|CONFIGSET_TKT) ){
1336
- configure_prepare_to_receive(0);
1345
+ if( (configRcvMask & (CONFIGSET_USER|CONFIGSET_TKT))!=0
1346
+ && (configRcvMask & CONFIGSET_OLDFORMAT)!=0
1347
+ ){
1348
+ int overwrite = (configRcvMask & CONFIGSET_OVERWRITE)!=0;
1349
+ configure_prepare_to_receive(overwrite);
13371350
}
13381351
origConfigRcvMask = configRcvMask;
13391352
configRcvMask = 0;
13401353
}
13411354
13421355
/* Send configuration parameters being pushed */
13431356
if( configSendMask ){
1344
- const char *zName;
1345
- zName = configure_first_name(configSendMask);
1346
- while( zName ){
1347
- send_config_card(&xfer, zName);
1348
- zName = configure_next_name(configSendMask);
1349
- nCardSent++;
1357
+ if( configSendMask & CONFIGSET_OLDFORMAT ){
1358
+ const char *zName;
1359
+ zName = configure_first_name(configSendMask);
1360
+ while( zName ){
1361
+ send_legacy_config_card(&xfer, zName);
1362
+ zName = configure_next_name(configSendMask);
1363
+ nCardSent++;
1364
+ }
1365
+ }else{
1366
+ nCardSent += configure_send_group(xfer.pOut, configSendMask, 0);
13501367
}
13511368
configSendMask = 0;
13521369
}
13531370
13541371
/* Append randomness to the end of the message. This makes all
@@ -1646,11 +1663,13 @@
16461663
break;
16471664
}
16481665
blobarray_reset(xfer.aToken, xfer.nToken);
16491666
blob_reset(&xfer.line);
16501667
}
1651
- if( origConfigRcvMask & (CONFIGSET_TKT|CONFIGSET_USER) ){
1668
+ if( (configRcvMask & (CONFIGSET_USER|CONFIGSET_TKT))!=0
1669
+ && (configRcvMask & CONFIGSET_OLDFORMAT)!=0
1670
+ ){
16521671
configure_finalize_receive();
16531672
}
16541673
origConfigRcvMask = 0;
16551674
if( nCardRcvd>0 ){
16561675
fossil_print(zValueFormat, "Received:",
16571676
--- src/xfer.c
+++ src/xfer.c
@@ -738,13 +738,16 @@
738 }
739 db_finalize(&q);
740 }
741
742 /*
743 ** Send a single old-style config card for configuration item zName
 
 
 
744 */
745 static void send_config_card(Xfer *pXfer, const char *zName){
746 if( zName[0]!='@' ){
747 Blob val;
748 blob_zero(&val);
749 db_blob(&val, "SELECT value FROM config WHERE name=%Q", zName);
750 if( blob_size(&val)>0 ){
@@ -1028,12 +1031,19 @@
1028 if( blob_eq(&xfer.aToken[0], "reqconfig")
1029 && xfer.nToken==2
1030 ){
1031 if( g.okRead ){
1032 char *zName = blob_str(&xfer.aToken[1]);
1033 if( configure_is_exportable(zName) ){
1034 send_config_card(&xfer, zName);
 
 
 
 
 
 
 
1035 }
1036 }
1037 }else
1038
1039 /* config NAME SIZE \n CONTENT
@@ -1051,11 +1061,11 @@
1051 cgi_reset_content();
1052 @ error not\sauthorized\sto\spush\sconfiguration
1053 nErr++;
1054 break;
1055 }
1056 if( !recvConfig ){
1057 configure_prepare_to_receive(0);
1058 recvConfig = 1;
1059 }
1060 configure_receive(zName, &content, CONFIGSET_ALL);
1061 blob_reset(&content);
@@ -1330,25 +1340,32 @@
1330 while( zName ){
1331 blob_appendf(&send, "reqconfig %s\n", zName);
1332 zName = configure_next_name(configRcvMask);
1333 nCardSent++;
1334 }
1335 if( configRcvMask & (CONFIGSET_USER|CONFIGSET_TKT) ){
1336 configure_prepare_to_receive(0);
 
 
 
1337 }
1338 origConfigRcvMask = configRcvMask;
1339 configRcvMask = 0;
1340 }
1341
1342 /* Send configuration parameters being pushed */
1343 if( configSendMask ){
1344 const char *zName;
1345 zName = configure_first_name(configSendMask);
1346 while( zName ){
1347 send_config_card(&xfer, zName);
1348 zName = configure_next_name(configSendMask);
1349 nCardSent++;
 
 
 
 
1350 }
1351 configSendMask = 0;
1352 }
1353
1354 /* Append randomness to the end of the message. This makes all
@@ -1646,11 +1663,13 @@
1646 break;
1647 }
1648 blobarray_reset(xfer.aToken, xfer.nToken);
1649 blob_reset(&xfer.line);
1650 }
1651 if( origConfigRcvMask & (CONFIGSET_TKT|CONFIGSET_USER) ){
 
 
1652 configure_finalize_receive();
1653 }
1654 origConfigRcvMask = 0;
1655 if( nCardRcvd>0 ){
1656 fossil_print(zValueFormat, "Received:",
1657
--- src/xfer.c
+++ src/xfer.c
@@ -738,13 +738,16 @@
738 }
739 db_finalize(&q);
740 }
741
742 /*
743 ** Send a single old-style config card for configuration item zName.
744 **
745 ** This routine and the functionality it implements is scheduled for
746 ** removal on 2012-05-01.
747 */
748 static void send_legacy_config_card(Xfer *pXfer, const char *zName){
749 if( zName[0]!='@' ){
750 Blob val;
751 blob_zero(&val);
752 db_blob(&val, "SELECT value FROM config WHERE name=%Q", zName);
753 if( blob_size(&val)>0 ){
@@ -1028,12 +1031,19 @@
1031 if( blob_eq(&xfer.aToken[0], "reqconfig")
1032 && xfer.nToken==2
1033 ){
1034 if( g.okRead ){
1035 char *zName = blob_str(&xfer.aToken[1]);
1036 if( zName[0]=='/' ){
1037 /* New style configuration transfer */
1038 int groupMask = configure_name_to_mask(&zName[0], 0);
1039 if( !g.okAdmin ) groupMask &= ~CONFIGSET_USER;
1040 if( !g.okRdAddr ) groupMask &= ~CONFIGSET_ADDR;
1041 configure_send_group(xfer.pOut, groupMask, 0);
1042 }else if( configure_is_exportable(zName) ){
1043 /* Old style configuration transfer */
1044 send_legacy_config_card(&xfer, zName);
1045 }
1046 }
1047 }else
1048
1049 /* config NAME SIZE \n CONTENT
@@ -1051,11 +1061,11 @@
1061 cgi_reset_content();
1062 @ error not\sauthorized\sto\spush\sconfiguration
1063 nErr++;
1064 break;
1065 }
1066 if( !recvConfig && zName[0]=='@' ){
1067 configure_prepare_to_receive(0);
1068 recvConfig = 1;
1069 }
1070 configure_receive(zName, &content, CONFIGSET_ALL);
1071 blob_reset(&content);
@@ -1330,25 +1340,32 @@
1340 while( zName ){
1341 blob_appendf(&send, "reqconfig %s\n", zName);
1342 zName = configure_next_name(configRcvMask);
1343 nCardSent++;
1344 }
1345 if( (configRcvMask & (CONFIGSET_USER|CONFIGSET_TKT))!=0
1346 && (configRcvMask & CONFIGSET_OLDFORMAT)!=0
1347 ){
1348 int overwrite = (configRcvMask & CONFIGSET_OVERWRITE)!=0;
1349 configure_prepare_to_receive(overwrite);
1350 }
1351 origConfigRcvMask = configRcvMask;
1352 configRcvMask = 0;
1353 }
1354
1355 /* Send configuration parameters being pushed */
1356 if( configSendMask ){
1357 if( configSendMask & CONFIGSET_OLDFORMAT ){
1358 const char *zName;
1359 zName = configure_first_name(configSendMask);
1360 while( zName ){
1361 send_legacy_config_card(&xfer, zName);
1362 zName = configure_next_name(configSendMask);
1363 nCardSent++;
1364 }
1365 }else{
1366 nCardSent += configure_send_group(xfer.pOut, configSendMask, 0);
1367 }
1368 configSendMask = 0;
1369 }
1370
1371 /* Append randomness to the end of the message. This makes all
@@ -1646,11 +1663,13 @@
1663 break;
1664 }
1665 blobarray_reset(xfer.aToken, xfer.nToken);
1666 blob_reset(&xfer.line);
1667 }
1668 if( (configRcvMask & (CONFIGSET_USER|CONFIGSET_TKT))!=0
1669 && (configRcvMask & CONFIGSET_OLDFORMAT)!=0
1670 ){
1671 configure_finalize_receive();
1672 }
1673 origConfigRcvMask = 0;
1674 if( nCardRcvd>0 ){
1675 fossil_print(zValueFormat, "Received:",
1676

Keyboard Shortcuts

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