/* ** Copyright (c) 2008 D. Richard Hipp ** ** This program is free software; you can redistribute it and/or ** modify it under the terms of the Simplified BSD License (also ** known as the "2-Clause License" or "FreeBSD License".) ** This program is distributed in the hope that it will be useful, ** but without any warranty; without even the implied warranty of ** merchantability or fitness for a particular purpose. ** ** Author contact information: ** drh@hwaci.com ** http://www.hwaci.com/drh/ ** ******************************************************************************* ** ** This file contains code used to manage repository configurations. ** By "responsitory configure" we mean the local state of a repository ** distinct from the versioned files. */ #include "config.h" #include "configure.h" #include #if INTERFACE /* ** Configuration transfers occur in groups. These are the allowed ** 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[] = { { "email", CONFIGSET_ADDR, "Concealed email addresses in tickets" }, { "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. ** ** Setting names that begin with an alphabetic characters refer to ** single entries in the CONFIG table. Setting names that begin with ** "@" are for special processing. */ static struct { const char *zName; /* Name of the configuration parameter */ int groupMask; /* Which config groups is it part of */ } aConfig[] = { { "css", CONFIGSET_SKIN }, { "header", CONFIGSET_SKIN }, { "footer", CONFIGSET_SKIN }, { "logo-mimetype", CONFIGSET_SKIN }, { "logo-image", CONFIGSET_SKIN }, { "project-name", CONFIGSET_PROJ }, { "project-description", CONFIGSET_PROJ }, { "index-page", CONFIGSET_SKIN }, { "timeline-block-markup", CONFIGSET_SKIN }, { "timeline-max-comment", CONFIGSET_SKIN }, { "ticket-table", CONFIGSET_TKT }, { "ticket-common", CONFIGSET_TKT }, { "ticket-newpage", CONFIGSET_TKT }, { "ticket-viewpage", CONFIGSET_TKT }, { "ticket-editpage", CONFIGSET_TKT }, { "ticket-reportlist", 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. */ const char *configure_first_name(int iMask){ iConfig = 0; return configure_next_name(iMask); } const char *configure_next_name(int iMask){ while( iConfigAdmin and use the subcommands ** */ void configuration_cmd(void){ int n; const char *zMethod; if( g.argc<3 ){ usage("export|import|merge|pull|reset ..."); } db_find_and_open_repository(1); zMethod = g.argv[2]; n = strlen(zMethod); if( strncmp(zMethod, "export", n)==0 ){ int mask; if( g.argc!=5 ){ usage("export AREA FILENAME"); } mask = find_area(g.argv[3]); export_config(mask, g.argv[3], g.argv[4]); }else if( strncmp(zMethod, "import", n)==0 || strncmp(zMethod, "merge", n)==0 ){ Blob in; if( g.argc!=4 ) usage(mprintf("%s FILENAME",zMethod)); 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 || strncmp(zMethod, "push", n)==0 ){ int mask; const char *zServer; const char *zPw; 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]; zPw = 0; g.dontKeepUrl = 1; }else{ zServer = db_get("last-sync-url", 0); if( zServer==0 ){ fossil_fatal("no server specified"); } zPw = unobscure(db_get("last-sync-pw", 0)); } url_parse(zServer); if( g.urlPasswd==0 && zPw ) g.urlPasswd = mprintf("%s", zPw); user_select(); url_enable_proxy("via proxy: "); if( strncmp(zMethod, "push", n)==0 ){ 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