Diff
Not logged in

Differences From Artifact [2cb2adc7b4]:

To Artifact [2a0972b75d]:


35
36
37
38
39
40
41

42
43
44
45
46
47
48
49
50
51
52
53
54
55

56
57
58
59
60






61
62
63
64
65
66
67
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55

56





57
58
59
60
61
62
63
64
65
66
67
68
69







+













-
+
-
-
-
-
-
+
+
+
+
+
+







** groupings:
*/
#define CONFIGSET_SKIN   0x000001     /* WWW interface appearance */
#define CONFIGSET_TKT    0x000002     /* Ticket configuration */
#define CONFIGSET_PROJ   0x000004     /* Project name */
#define CONFIGSET_SHUN   0x000008     /* Shun settings */
#define CONFIGSET_USER   0x000010     /* The USER table */
#define CONFIGSET_ADDR   0x000020     /* The CONCEALED table */

#define CONFIGSET_ALL    0xffffff     /* Everything */

#endif /* INTERFACE */

/*
** Names of the configuration sets
*/
static struct {
  const char *zName;   /* Name of the configuration set */
  int groupMask;       /* Mask for that configuration set */
  const char *zHelp;   /* What it does */
} aGroupName[] = {
  { "skin",         CONFIGSET_SKIN,  "Web interface apparance settings" },
  { "email",        CONFIGSET_ADDR,  "Concealed email addresses in tickets" },
  { "ticket",       CONFIGSET_TKT,   "Ticket setup",                    },
  { "project",      CONFIGSET_PROJ,  "Project name and description"     },
  { "shun",         CONFIGSET_SHUN,  "List of shunned artifacts"        },
  { "user",         CONFIGSET_USER,  "Users and privilege settings"     },
  { "all",          CONFIGSET_ALL,   "All of the above"                 },
  { "project",      CONFIGSET_PROJ,  "Project name and description"         },
  { "skin",         CONFIGSET_SKIN,  "Web interface apparance settings"     },
  { "shun",         CONFIGSET_SHUN,  "List of shunned artifacts"            },
  { "ticket",       CONFIGSET_TKT,   "Ticket setup",                        },
  { "user",         CONFIGSET_USER,  "Users and privilege settings"         },
  { "all",          CONFIGSET_ALL,   "All of the above"                     },
};


/*
** The following is a list of settings that we are willing to
** transfer.  
**
88
89
90
91
92
93
94

95
96
97
98
99
100
101
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104







+







  { "ticket-editpage",        CONFIGSET_TKT  },
  { "ticket-report-template", CONFIGSET_TKT  },
  { "ticket-key-template",    CONFIGSET_TKT  },
  { "ticket-title-expr",      CONFIGSET_TKT  },
  { "ticket-closed-expr",     CONFIGSET_TKT  },
  { "@reportfmt",             CONFIGSET_TKT  },
  { "@user",                  CONFIGSET_USER },
  { "@concealed",             CONFIGSET_ADDR },
  { "@shun",                  CONFIGSET_SHUN },
};
static int iConfig = 0;

/*
** Return name of first configuration property matching the given mask.
*/
122
123
124
125
126
127
128



129
130
131
132
133
134
135
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141







+
+
+







  int i;
  for(i=0; i<count(aConfig); i++){
    if( strcmp(zName, aConfig[i].zName)==0 ){
      int m = aConfig[i].groupMask;
      if( !g.okAdmin ){
        m &= ~CONFIGSET_USER;
      }
      if( !g.okRdAddr ){
        m &= ~CONFIGSET_ADDR;
      }
      return m;
    }
  }
  return 0;
}

/*
147
148
149
150
151
152
153
154

155
156
157
158
159
160
161
162
163
164
165

166
167
168
169
170
171










172
173
174
175
176
177
178
153
154
155
156
157
158
159

160
161
162
163
164
165
166
167
168
169
170

171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194







-
+










-
+






+
+
+
+
+
+
+
+
+
+







        db_column_text(&q, 0)
      );
    }
    db_finalize(&q);
  }else if( strcmp(zName, "@reportfmt")==0 ){
    db_prepare(&q, "SELECT title, cols, sqlcode FROM reportfmt");
    while( db_step(&q)==SQLITE_ROW ){
      blob_appendf(pOut, "INSERT INTO _xfer_reportfmt(title,cols,sqlcode) "
      blob_appendf(pOut, "INSERT INTO _xfer_reportfmt(title,cols,sqlcode)"
                         " VALUES(%Q,%Q,%Q);\n", 
        db_column_text(&q, 0),
        db_column_text(&q, 1),
        db_column_text(&q, 2)
      );
    }
    db_finalize(&q);
  }else if( strcmp(zName, "@user")==0 ){
    db_prepare(&q, "SELECT login, cap, info, quote(photo) FROM user");
    while( db_step(&q)==SQLITE_ROW ){
      blob_appendf(pOut, "INSERT INTO _xfer_user(login,cap,info,photo) "
      blob_appendf(pOut, "INSERT INTO _xfer_user(login,cap,info,photo)"
                         " VALUES(%Q,%Q,%Q,%s);\n",
        db_column_text(&q, 0),
        db_column_text(&q, 1),
        db_column_text(&q, 2),
        db_column_text(&q, 3)
      );
    }
    db_finalize(&q);
  }else if( strcmp(zName, "@concealed")==0 ){
    db_prepare(&q, "SELECT hash, content FROM concealed");
    while( db_step(&q)==SQLITE_ROW ){
      blob_appendf(pOut, "INSERT OR IGNORE INTO concealed(hash,content)"
                         " VALUES(%Q,%Q);\n",
        db_column_text(&q, 0),
        db_column_text(&q, 1)
      );
    }
    db_finalize(&q);
  }
}

/*
** Two SQL functions:
351
352
353
354
355
356
357
358

359
360
361
362
363
364
365
367
368
369
370
371
372
373

374
375
376
377
378
379
380
381







-
+









/*
** COMMAND: configuration
**
** Usage: %fossil configure METHOD ...
**
** Where METHOD is one of: export import merge pull reset.  All methods
** Where METHOD is one of: export import merge pull push reset.  All methods
** accept the -R or --repository option to specific a repository.
**
**    %fossil configuration export AREA FILENAME
**
**         Write to FILENAME exported configuraton information for AREA.
**         AREA can be one of:  all ticket skin project
**
374
375
376
377
378
379
380
381







382
383
384
385
386
387
388
390
391
392
393
394
395
396

397
398
399
400
401
402
403
404
405
406
407
408
409
410







-
+
+
+
+
+
+
+







**         the current configuration.  Existing values take priority over
**         values read from FILENAME.
**
**    %fossil configuration pull AREA ?URL?
**
**         Pull and install the configuration from a different server
**         identified by URL.  If no URL is specified, then the default
**         server is used.
**         server is used. 
**
**    %fossil configuration push AREA ?URL?
**
**         Push the local configuration into the remote server identified
**         by URL.  Admin privilege is required on the remote server for
**         this to work.
**
**    %fossil configuration reset AREA
**
**         Restore the configuration to the default.  AREA as above.
**
** WARNING: Do not import, merge, or pull configurations from an untrusted
** source.  The inbound configuration is not checked for safety and can
412
413
414
415
416
417
418
419

420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439

440




441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458




459
460
461
462
463
464
465
466
467
468
469


470
471
434
435
436
437
438
439
440

441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462

463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498

499
500
501
502







-
+




















+
-
+
+
+
+


















+
+
+
+










-
+
+


    blob_read_from_file(&in, g.argv[3]);
    db_begin_transaction();
    configure_prepare_to_receive(zMethod[0]=='i');
    db_multi_exec("%s", blob_str(&in));
    configure_finalize_receive();
    db_end_transaction(0);
  }else
  if( strncmp(zMethod, "pull", n)==0 ){
  if( strncmp(zMethod, "pull", n)==0 || strncmp(zMethod, "push", n)==0 ){
    int mask;
    const char *zServer;
    url_proxy_options();
    if( g.argc!=4 && g.argc!=5 ){
      usage("pull AREA ?URL?");
    }
    mask = find_area(g.argv[3]);
    if( g.argc==5 ){
      zServer = g.argv[4];
    }else{
      zServer = db_get("last-sync-url", 0);
      if( zServer==0 ){
        fossil_fatal("no server specified");
      }
    }
    url_parse(zServer);
    if( g.urlIsFile ){
      fossil_fatal("network sync only");
    }
    user_select();
    if( strncmp(zMethod, "push", n)==0 ){
    client_sync(0,0,0,mask);
      client_sync(0,0,0,0,mask);
    }else{
      client_sync(0,0,0,mask,0);
    }
  }else
  if( strncmp(zMethod, "reset", n)==0 ){
    int mask, i;
    char *zBackup;
    if( g.argc!=4 ) usage("reset AREA");
    mask = find_area(g.argv[3]);
    zBackup = db_text(0, 
       "SELECT strftime('config-backup-%%Y%%m%%d%%H%%M%%f','now')");
    db_begin_transaction();
    export_config(mask, g.argv[3], zBackup);
    for(i=0; i<count(aConfig); i++){
      const char *zName = aConfig[i].zName;
      if( (aConfig[i].groupMask & mask)==0 ) continue;
      if( zName[0]!='@' ){
        db_multi_exec("DELETE FROM config WHERE name=%Q", zName);
      }else if( strcmp(zName,"@user")==0 ){
        db_multi_exec("DELETE FROM user");
        db_create_default_users();
      }else if( strcmp(zName,"@concealed")==0 ){
        db_multi_exec("DELETE FROM concealed");
      }else if( strcmp(zName,"@shun")==0 ){
        db_multi_exec("DELETE FROM shun");
      }else if( strcmp(zName,"@reportfmt")==0 ){
        db_multi_exec("DELETE FROM reportfmt");
      }
    }
    db_end_transaction(0);
    printf("Configuration reset to factory defaults.\n");
    printf("To recover, use:  %s %s import %s\n", 
            g.argv[0], g.argv[1], zBackup);
  }else
  {
    fossil_fatal("METHOD should be one of:  export import merge pull reset");
    fossil_fatal("METHOD should be one of:"
                 " export import merge pull push reset");
  }
}