File Annotation
Not logged in
e06ae9f6d2 2008-05-22       drh: /*
e06ae9f6d2 2008-05-22       drh: ** Copyright (c) 2008 D. Richard Hipp
e06ae9f6d2 2008-05-22       drh: **
e06ae9f6d2 2008-05-22       drh: ** This program is free software; you can redistribute it and/or
e06ae9f6d2 2008-05-22       drh: ** modify it under the terms of the GNU General Public
e06ae9f6d2 2008-05-22       drh: ** License version 2 as published by the Free Software Foundation.
e06ae9f6d2 2008-05-22       drh: **
e06ae9f6d2 2008-05-22       drh: ** This program is distributed in the hope that it will be useful,
e06ae9f6d2 2008-05-22       drh: ** but WITHOUT ANY WARRANTY; without even the implied warranty of
e06ae9f6d2 2008-05-22       drh: ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
e06ae9f6d2 2008-05-22       drh: ** General Public License for more details.
e06ae9f6d2 2008-05-22       drh: **
e06ae9f6d2 2008-05-22       drh: ** You should have received a copy of the GNU General Public
e06ae9f6d2 2008-05-22       drh: ** License along with this library; if not, write to the
e06ae9f6d2 2008-05-22       drh: ** Free Software Foundation, Inc., 59 Temple Place - Suite 330,
e06ae9f6d2 2008-05-22       drh: ** Boston, MA  02111-1307, USA.
e06ae9f6d2 2008-05-22       drh: **
e06ae9f6d2 2008-05-22       drh: ** Author contact information:
e06ae9f6d2 2008-05-22       drh: **   drh@hwaci.com
e06ae9f6d2 2008-05-22       drh: **   http://www.hwaci.com/drh/
e06ae9f6d2 2008-05-22       drh: **
e06ae9f6d2 2008-05-22       drh: *******************************************************************************
e06ae9f6d2 2008-05-22       drh: **
e06ae9f6d2 2008-05-22       drh: ** This file contains code used to manage repository configurations.
e06ae9f6d2 2008-05-22       drh: ** By "responsitory configure" we mean the local state of a repository
e06ae9f6d2 2008-05-22       drh: ** distinct from the versioned files.
e06ae9f6d2 2008-05-22       drh: */
e06ae9f6d2 2008-05-22       drh: #include "config.h"
e06ae9f6d2 2008-05-22       drh: #include "configure.h"
e06ae9f6d2 2008-05-22       drh: #include <assert.h>
e06ae9f6d2 2008-05-22       drh: 
e06ae9f6d2 2008-05-22       drh: #if INTERFACE
e06ae9f6d2 2008-05-22       drh: /*
e06ae9f6d2 2008-05-22       drh: ** Configuration transfers occur in groups.  These are the allowed
e06ae9f6d2 2008-05-22       drh: ** groupings:
e06ae9f6d2 2008-05-22       drh: */
e06ae9f6d2 2008-05-22       drh: #define CONFIGSET_SKIN   0x000001     /* WWW interface appearance */
e06ae9f6d2 2008-05-22       drh: #define CONFIGSET_TKT    0x000002     /* Ticket configuration */
e06ae9f6d2 2008-05-22       drh: #define CONFIGSET_PROJ   0x000004     /* Project name */
bf75ea9852 2008-10-04       drh: #define CONFIGSET_SHUN   0x000008     /* Shun settings */
bf75ea9852 2008-10-04       drh: #define CONFIGSET_USER   0x000010     /* The USER table */
6b0b57a924 2008-10-25       drh: #define CONFIGSET_ADDR   0x000020     /* The CONCEALED table */
e06ae9f6d2 2008-05-22       drh: 
e06ae9f6d2 2008-05-22       drh: #define CONFIGSET_ALL    0xffffff     /* Everything */
e06ae9f6d2 2008-05-22       drh: 
e06ae9f6d2 2008-05-22       drh: #endif /* INTERFACE */
e06ae9f6d2 2008-05-22       drh: 
e06ae9f6d2 2008-05-22       drh: /*
e06ae9f6d2 2008-05-22       drh: ** Names of the configuration sets
e06ae9f6d2 2008-05-22       drh: */
e06ae9f6d2 2008-05-22       drh: static struct {
e06ae9f6d2 2008-05-22       drh:   const char *zName;   /* Name of the configuration set */
e06ae9f6d2 2008-05-22       drh:   int groupMask;       /* Mask for that configuration set */
bf75ea9852 2008-10-04       drh:   const char *zHelp;   /* What it does */
e06ae9f6d2 2008-05-22       drh: } aGroupName[] = {
6b0b57a924 2008-10-25       drh:   { "email",        CONFIGSET_ADDR,  "Concealed email addresses in tickets" },
6b0b57a924 2008-10-25       drh:   { "project",      CONFIGSET_PROJ,  "Project name and description"         },
6b0b57a924 2008-10-25       drh:   { "skin",         CONFIGSET_SKIN,  "Web interface apparance settings"     },
6b0b57a924 2008-10-25       drh:   { "shun",         CONFIGSET_SHUN,  "List of shunned artifacts"            },
6b0b57a924 2008-10-25       drh:   { "ticket",       CONFIGSET_TKT,   "Ticket setup",                        },
6b0b57a924 2008-10-25       drh:   { "user",         CONFIGSET_USER,  "Users and privilege settings"         },
6b0b57a924 2008-10-25       drh:   { "all",          CONFIGSET_ALL,   "All of the above"                     },
e06ae9f6d2 2008-05-22       drh: };
e06ae9f6d2 2008-05-22       drh: 
e06ae9f6d2 2008-05-22       drh: 
e06ae9f6d2 2008-05-22       drh: /*
e06ae9f6d2 2008-05-22       drh: ** The following is a list of settings that we are willing to
e06ae9f6d2 2008-05-22       drh: ** transfer.
bf75ea9852 2008-10-04       drh: **
bf75ea9852 2008-10-04       drh: ** Setting names that begin with an alphabetic characters refer to
bf75ea9852 2008-10-04       drh: ** single entries in the CONFIG table.  Setting names that begin with
bf75ea9852 2008-10-04       drh: ** "@" are for special processing.
e06ae9f6d2 2008-05-22       drh: */
e06ae9f6d2 2008-05-22       drh: static struct {
e06ae9f6d2 2008-05-22       drh:   const char *zName;   /* Name of the configuration parameter */
e06ae9f6d2 2008-05-22       drh:   int groupMask;       /* Which config groups is it part of */
28e56282c9 2008-05-23       drh: } aConfig[] = {
bf75ea9852 2008-10-04       drh:   { "css",                    CONFIGSET_SKIN },
bf75ea9852 2008-10-04       drh:   { "header",                 CONFIGSET_SKIN },
bf75ea9852 2008-10-04       drh:   { "footer",                 CONFIGSET_SKIN },
43481115ed 2009-09-21       drh:   { "logo-mimetype",          CONFIGSET_SKIN },
43481115ed 2009-09-21       drh:   { "logo-image",             CONFIGSET_SKIN },
bf75ea9852 2008-10-04       drh:   { "project-name",           CONFIGSET_PROJ },
bf75ea9852 2008-10-04       drh:   { "project-description",    CONFIGSET_PROJ },
bf75ea9852 2008-10-04       drh:   { "index-page",             CONFIGSET_SKIN },
bf75ea9852 2008-10-04       drh:   { "timeline-block-markup",  CONFIGSET_SKIN },
bf75ea9852 2008-10-04       drh:   { "timeline-max-comment",   CONFIGSET_SKIN },
bf75ea9852 2008-10-04       drh:   { "ticket-table",           CONFIGSET_TKT  },
bf75ea9852 2008-10-04       drh:   { "ticket-common",          CONFIGSET_TKT  },
bf75ea9852 2008-10-04       drh:   { "ticket-newpage",         CONFIGSET_TKT  },
bf75ea9852 2008-10-04       drh:   { "ticket-viewpage",        CONFIGSET_TKT  },
bf75ea9852 2008-10-04       drh:   { "ticket-editpage",        CONFIGSET_TKT  },
bf75ea9852 2008-10-04       drh:   { "ticket-report-template", CONFIGSET_TKT  },
bf75ea9852 2008-10-04       drh:   { "ticket-key-template",    CONFIGSET_TKT  },
ac3f1f2ba7 2008-10-18       drh:   { "ticket-title-expr",      CONFIGSET_TKT  },
ac3f1f2ba7 2008-10-18       drh:   { "ticket-closed-expr",     CONFIGSET_TKT  },
bf75ea9852 2008-10-04       drh:   { "@reportfmt",             CONFIGSET_TKT  },
bf75ea9852 2008-10-04       drh:   { "@user",                  CONFIGSET_USER },
6b0b57a924 2008-10-25       drh:   { "@concealed",             CONFIGSET_ADDR },
bf75ea9852 2008-10-04       drh:   { "@shun",                  CONFIGSET_SHUN },
e06ae9f6d2 2008-05-22       drh: };
28e56282c9 2008-05-23       drh: static int iConfig = 0;
28e56282c9 2008-05-23       drh: 
28e56282c9 2008-05-23       drh: /*
28e56282c9 2008-05-23       drh: ** Return name of first configuration property matching the given mask.
28e56282c9 2008-05-23       drh: */
28e56282c9 2008-05-23       drh: const char *configure_first_name(int iMask){
28e56282c9 2008-05-23       drh:   iConfig = 0;
28e56282c9 2008-05-23       drh:   return configure_next_name(iMask);
28e56282c9 2008-05-23       drh: }
28e56282c9 2008-05-23       drh: const char *configure_next_name(int iMask){
28e56282c9 2008-05-23       drh:   while( iConfig<count(aConfig) ){
28e56282c9 2008-05-23       drh:     if( aConfig[iConfig].groupMask & iMask ){
28e56282c9 2008-05-23       drh:       return aConfig[iConfig++].zName;
28e56282c9 2008-05-23       drh:     }else{
28e56282c9 2008-05-23       drh:       iConfig++;
28e56282c9 2008-05-23       drh:     }
28e56282c9 2008-05-23       drh:   }
28e56282c9 2008-05-23       drh:   return 0;
28e56282c9 2008-05-23       drh: }
e06ae9f6d2 2008-05-22       drh: 
e06ae9f6d2 2008-05-22       drh: /*
bf75ea9852 2008-10-04       drh: ** Return the mask for the named configuration parameter if it can be
bf75ea9852 2008-10-04       drh: ** safely exported.  Return 0 if the parameter is not safe to export.
e06ae9f6d2 2008-05-22       drh: */
e06ae9f6d2 2008-05-22       drh: int configure_is_exportable(const char *zName){
e06ae9f6d2 2008-05-22       drh:   int i;
28e56282c9 2008-05-23       drh:   for(i=0; i<count(aConfig); i++){
28e56282c9 2008-05-23       drh:     if( strcmp(zName, aConfig[i].zName)==0 ){
bf75ea9852 2008-10-04       drh:       int m = aConfig[i].groupMask;
bf75ea9852 2008-10-04       drh:       if( !g.okAdmin ){
bf75ea9852 2008-10-04       drh:         m &= ~CONFIGSET_USER;
bf75ea9852 2008-10-04       drh:       }
6b0b57a924 2008-10-25       drh:       if( !g.okRdAddr ){
6b0b57a924 2008-10-25       drh:         m &= ~CONFIGSET_ADDR;
6b0b57a924 2008-10-25       drh:       }
bf75ea9852 2008-10-04       drh:       return m;
28e56282c9 2008-05-23       drh:     }
e06ae9f6d2 2008-05-22       drh:   }
e06ae9f6d2 2008-05-22       drh:   return 0;
bf75ea9852 2008-10-04       drh: }
bf75ea9852 2008-10-04       drh: 
bf75ea9852 2008-10-04       drh: /*
bf75ea9852 2008-10-04       drh: ** zName is one of the special configuration names that refers to an entire
bf75ea9852 2008-10-04       drh: ** table rather than a single entry in CONFIG.  Special names are "@reportfmt"
bf75ea9852 2008-10-04       drh: ** and "@shun" and "@user".  This routine writes SQL text into pOut that when
bf75ea9852 2008-10-04       drh: ** evaluated will populate the corresponding table with data.
bf75ea9852 2008-10-04       drh: */
bf75ea9852 2008-10-04       drh: void configure_render_special_name(const char *zName, Blob *pOut){
bf75ea9852 2008-10-04       drh:   Stmt q;
bf75ea9852 2008-10-04       drh:   if( strcmp(zName, "@shun")==0 ){
bf75ea9852 2008-10-04       drh:     db_prepare(&q, "SELECT uuid FROM shun");
bf75ea9852 2008-10-04       drh:     while( db_step(&q)==SQLITE_ROW ){
bf75ea9852 2008-10-04       drh:       blob_appendf(pOut, "INSERT OR IGNORE INTO shun VALUES('%s');\n",
bf75ea9852 2008-10-04       drh:         db_column_text(&q, 0)
bf75ea9852 2008-10-04       drh:       );
bf75ea9852 2008-10-04       drh:     }
bf75ea9852 2008-10-04       drh:     db_finalize(&q);
bf75ea9852 2008-10-04       drh:   }else if( strcmp(zName, "@reportfmt")==0 ){
bf75ea9852 2008-10-04       drh:     db_prepare(&q, "SELECT title, cols, sqlcode FROM reportfmt");
bf75ea9852 2008-10-04       drh:     while( db_step(&q)==SQLITE_ROW ){
6b0b57a924 2008-10-25       drh:       blob_appendf(pOut, "INSERT INTO _xfer_reportfmt(title,cols,sqlcode)"
bf75ea9852 2008-10-04       drh:                          " VALUES(%Q,%Q,%Q);\n",
bf75ea9852 2008-10-04       drh:         db_column_text(&q, 0),
bf75ea9852 2008-10-04       drh:         db_column_text(&q, 1),
bf75ea9852 2008-10-04       drh:         db_column_text(&q, 2)
bf75ea9852 2008-10-04       drh:       );
bf75ea9852 2008-10-04       drh:     }
bf75ea9852 2008-10-04       drh:     db_finalize(&q);
bf75ea9852 2008-10-04       drh:   }else if( strcmp(zName, "@user")==0 ){
bf75ea9852 2008-10-04       drh:     db_prepare(&q, "SELECT login, cap, info, quote(photo) FROM user");
bf75ea9852 2008-10-04       drh:     while( db_step(&q)==SQLITE_ROW ){
6b0b57a924 2008-10-25       drh:       blob_appendf(pOut, "INSERT INTO _xfer_user(login,cap,info,photo)"
bf75ea9852 2008-10-04       drh:                          " VALUES(%Q,%Q,%Q,%s);\n",
bf75ea9852 2008-10-04       drh:         db_column_text(&q, 0),
bf75ea9852 2008-10-04       drh:         db_column_text(&q, 1),
bf75ea9852 2008-10-04       drh:         db_column_text(&q, 2),
bf75ea9852 2008-10-04       drh:         db_column_text(&q, 3)
6b0b57a924 2008-10-25       drh:       );
6b0b57a924 2008-10-25       drh:     }
6b0b57a924 2008-10-25       drh:     db_finalize(&q);
6b0b57a924 2008-10-25       drh:   }else if( strcmp(zName, "@concealed")==0 ){
6b0b57a924 2008-10-25       drh:     db_prepare(&q, "SELECT hash, content FROM concealed");
6b0b57a924 2008-10-25       drh:     while( db_step(&q)==SQLITE_ROW ){
6b0b57a924 2008-10-25       drh:       blob_appendf(pOut, "INSERT OR IGNORE INTO concealed(hash,content)"
6b0b57a924 2008-10-25       drh:                          " VALUES(%Q,%Q);\n",
6b0b57a924 2008-10-25       drh:         db_column_text(&q, 0),
6b0b57a924 2008-10-25       drh:         db_column_text(&q, 1)
bf75ea9852 2008-10-04       drh:       );
bf75ea9852 2008-10-04       drh:     }
bf75ea9852 2008-10-04       drh:     db_finalize(&q);
bf75ea9852 2008-10-04       drh:   }
bf75ea9852 2008-10-04       drh: }
bf75ea9852 2008-10-04       drh: 
bf75ea9852 2008-10-04       drh: /*
bf75ea9852 2008-10-04       drh: ** Two SQL functions:
bf75ea9852 2008-10-04       drh: **
bf75ea9852 2008-10-04       drh: **        flag_test(int)
bf75ea9852 2008-10-04       drh: **        flag_clear(int)
bf75ea9852 2008-10-04       drh: **
bf75ea9852 2008-10-04       drh: ** The flag_test() function takes the integer valued argument and
bf75ea9852 2008-10-04       drh: ** ANDs it against the static variable "flag_value" below.  The
bf75ea9852 2008-10-04       drh: ** function returns TRUE or false depending on the result.  The
bf75ea9852 2008-10-04       drh: ** flag_clear() function masks off the bits from "flag_value" that
bf75ea9852 2008-10-04       drh: ** are given in the argument.
bf75ea9852 2008-10-04       drh: **
bf75ea9852 2008-10-04       drh: ** These functions are used below in the WHEN clause of a trigger to
bf75ea9852 2008-10-04       drh: ** get the trigger to fire exactly once.
bf75ea9852 2008-10-04       drh: */
bf75ea9852 2008-10-04       drh: static int flag_value = 0xffff;
bf75ea9852 2008-10-04       drh: static void flag_test_function(
bf75ea9852 2008-10-04       drh:   sqlite3_context *context,
bf75ea9852 2008-10-04       drh:   int argc,
bf75ea9852 2008-10-04       drh:   sqlite3_value **argv
bf75ea9852 2008-10-04       drh: ){
bf75ea9852 2008-10-04       drh:   int m = sqlite3_value_int(argv[0]);
bf75ea9852 2008-10-04       drh:   sqlite3_result_int(context, (flag_value&m)!=0 );
bf75ea9852 2008-10-04       drh: }
bf75ea9852 2008-10-04       drh: static void flag_clear_function(
bf75ea9852 2008-10-04       drh:   sqlite3_context *context,
bf75ea9852 2008-10-04       drh:   int argc,
bf75ea9852 2008-10-04       drh:   sqlite3_value **argv
bf75ea9852 2008-10-04       drh: ){
bf75ea9852 2008-10-04       drh:   int m = sqlite3_value_int(argv[0]);
bf75ea9852 2008-10-04       drh:   flag_value &= ~m;
bf75ea9852 2008-10-04       drh: }
bf75ea9852 2008-10-04       drh: 
bf75ea9852 2008-10-04       drh: /*
bf75ea9852 2008-10-04       drh: ** Create the temporary _xfer_reportfmt and _xfer_user tables that are
bf75ea9852 2008-10-04       drh: ** necessary in order to evalute the SQL text generated by the
bf75ea9852 2008-10-04       drh: ** configure_render_special_name() routine.
bf75ea9852 2008-10-04       drh: **
bf75ea9852 2008-10-04       drh: ** If replaceFlag is true, then the setup is such that the content in
bf75ea9852 2008-10-04       drh: ** the SQL text will completely replace the current repository configuration.
bf75ea9852 2008-10-04       drh: ** If replaceFlag is false, then the SQL text will be merged with the
bf75ea9852 2008-10-04       drh: ** existing configuration.  When merging, existing values take priority
bf75ea9852 2008-10-04       drh: ** over SQL text values.
bf75ea9852 2008-10-04       drh: */
bf75ea9852 2008-10-04       drh: void configure_prepare_to_receive(int replaceFlag){
bf75ea9852 2008-10-04       drh:   static const char zSQL1[] =
bf75ea9852 2008-10-04       drh:     @ CREATE TEMP TABLE _xfer_reportfmt(
bf75ea9852 2008-10-04       drh:     @    rn integer primary key,  -- Report number
bf75ea9852 2008-10-04       drh:     @    owner text,              -- Owner of this report format (not used)
bf75ea9852 2008-10-04       drh:     @    title text UNIQUE ON CONFLICT IGNORE,  -- Title of this report
bf75ea9852 2008-10-04       drh:     @    cols text,               -- A color-key specification
bf75ea9852 2008-10-04       drh:     @    sqlcode text             -- An SQL SELECT statement for this report
bf75ea9852 2008-10-04       drh:     @ );
bf75ea9852 2008-10-04       drh:     @ CREATE TEMP TABLE _xfer_user(
bf75ea9852 2008-10-04       drh:     @   uid INTEGER PRIMARY KEY,        -- User ID
bf75ea9852 2008-10-04       drh:     @   login TEXT UNIQUE ON CONFLICT IGNORE,   -- login name of the user
bf75ea9852 2008-10-04       drh:     @   pw TEXT,                        -- password
bf75ea9852 2008-10-04       drh:     @   cap TEXT,                       -- Capabilities of this user
bf75ea9852 2008-10-04       drh:     @   cookie TEXT,                    -- WWW login cookie
bf75ea9852 2008-10-04       drh:     @   ipaddr TEXT,                    -- IP address for which cookie is valid
bf75ea9852 2008-10-04       drh:     @   cexpire DATETIME,               -- Time when cookie expires
bf75ea9852 2008-10-04       drh:     @   info TEXT,                      -- contact information
bf75ea9852 2008-10-04       drh:     @   photo BLOB                      -- JPEG image of this user
bf75ea9852 2008-10-04       drh:     @ );
bf75ea9852 2008-10-04       drh:     @ INSERT INTO _xfer_reportfmt SELECT * FROM reportfmt;
bf75ea9852 2008-10-04       drh:     @ INSERT INTO _xfer_user SELECT * FROM user;
bf75ea9852 2008-10-04       drh:   ;
bf75ea9852 2008-10-04       drh:   db_multi_exec(zSQL1);
bf75ea9852 2008-10-04       drh: 
bf75ea9852 2008-10-04       drh:   /* When the replace flag is set, add triggers that run the first time
bf75ea9852 2008-10-04       drh:   ** that new data is seen.  The triggers run only once and delete all the
bf75ea9852 2008-10-04       drh:   ** existing data.
bf75ea9852 2008-10-04       drh:   */
bf75ea9852 2008-10-04       drh:   if( replaceFlag ){
bf75ea9852 2008-10-04       drh:     static const char zSQL2[] =
bf75ea9852 2008-10-04       drh:       @ CREATE TRIGGER _xfer_r1 BEFORE INSERT ON _xfer_reportfmt
bf75ea9852 2008-10-04       drh:       @ WHEN flag_test(1) BEGIN
bf75ea9852 2008-10-04       drh:       @   DELETE FROM _xfer_reportfmt;
bf75ea9852 2008-10-04       drh:       @   SELECT flag_clear(1);
bf75ea9852 2008-10-04       drh:       @ END;
bf75ea9852 2008-10-04       drh:       @ CREATE TRIGGER _xfer_r2 BEFORE INSERT ON _xfer_user
bf75ea9852 2008-10-04       drh:       @ WHEN flag_test(2) BEGIN
bf75ea9852 2008-10-04       drh:       @   DELETE FROM _xfer_user;
bf75ea9852 2008-10-04       drh:       @   SELECT flag_clear(2);
bf75ea9852 2008-10-04       drh:       @ END;
bf75ea9852 2008-10-04       drh:       @ CREATE TEMP TRIGGER _xfer_r3 BEFORE INSERT ON shun
bf75ea9852 2008-10-04       drh:       @ WHEN flag_test(4) BEGIN
bf75ea9852 2008-10-04       drh:       @   DELETE FROM shun;
bf75ea9852 2008-10-04       drh:       @   SELECT flag_clear(4);
bf75ea9852 2008-10-04       drh:       @ END;
bf75ea9852 2008-10-04       drh:     ;
bf75ea9852 2008-10-04       drh:     sqlite3_create_function(g.db, "flag_test", 1, SQLITE_UTF8, 0,
bf75ea9852 2008-10-04       drh:          flag_test_function, 0, 0);
bf75ea9852 2008-10-04       drh:     sqlite3_create_function(g.db, "flag_clear", 1, SQLITE_UTF8, 0,
bf75ea9852 2008-10-04       drh:          flag_clear_function, 0, 0);
bf75ea9852 2008-10-04       drh:     flag_value = 0xffff;
bf75ea9852 2008-10-04       drh:     db_multi_exec(zSQL2);
bf75ea9852 2008-10-04       drh:   }
bf75ea9852 2008-10-04       drh: }
bf75ea9852 2008-10-04       drh: 
bf75ea9852 2008-10-04       drh: /*
bf75ea9852 2008-10-04       drh: ** After receiving configuration data, call this routine to transfer
bf75ea9852 2008-10-04       drh: ** the results into the main database.
bf75ea9852 2008-10-04       drh: */
bf75ea9852 2008-10-04       drh: void configure_finalize_receive(void){
bf75ea9852 2008-10-04       drh:   static const char zSQL[] =
bf75ea9852 2008-10-04       drh:     @ DELETE FROM user;
bf75ea9852 2008-10-04       drh:     @ INSERT INTO user SELECT * FROM _xfer_user;
bf75ea9852 2008-10-04       drh:     @ DELETE FROM reportfmt;
bf75ea9852 2008-10-04       drh:     @ INSERT INTO reportfmt SELECT * FROM _xfer_reportfmt;
bf75ea9852 2008-10-04       drh:     @ DROP TABLE _xfer_user;
bf75ea9852 2008-10-04       drh:     @ DROP TABLE _xfer_reportfmt;
bf75ea9852 2008-10-04       drh:   ;
bf75ea9852 2008-10-04       drh:   db_multi_exec(zSQL);
e06ae9f6d2 2008-05-22       drh: }
e06ae9f6d2 2008-05-22       drh: 
e06ae9f6d2 2008-05-22       drh: /*
e06ae9f6d2 2008-05-22       drh: ** Identify a configuration group by name.  Return its mask.
e06ae9f6d2 2008-05-22       drh: ** Throw an error if no match.
e06ae9f6d2 2008-05-22       drh: */
e06ae9f6d2 2008-05-22       drh: static int find_area(const char *z){
e06ae9f6d2 2008-05-22       drh:   int i;
e06ae9f6d2 2008-05-22       drh:   int n = strlen(z);
e06ae9f6d2 2008-05-22       drh:   for(i=0; i<count(aGroupName); i++){
e06ae9f6d2 2008-05-22       drh:     if( strncmp(z, aGroupName[i].zName, n)==0 ){
e06ae9f6d2 2008-05-22       drh:       return aGroupName[i].groupMask;
e06ae9f6d2 2008-05-22       drh:     }
e06ae9f6d2 2008-05-22       drh:   }
bf75ea9852 2008-10-04       drh:   printf("Available configuration areas:\n");
bf75ea9852 2008-10-04       drh:   for(i=0; i<count(aGroupName); i++){
bf75ea9852 2008-10-04       drh:     printf("  %-10s %s\n", aGroupName[i].zName, aGroupName[i].zHelp);
bf75ea9852 2008-10-04       drh:   }
e06ae9f6d2 2008-05-22       drh:   fossil_fatal("no such configuration area: \"%s\"", z);
e06ae9f6d2 2008-05-22       drh:   return 0;
e06ae9f6d2 2008-05-22       drh: }
e06ae9f6d2 2008-05-22       drh: 
bf75ea9852 2008-10-04       drh: /*
bf75ea9852 2008-10-04       drh: ** Write SQL text into file zFilename that will restore the configuration
bf75ea9852 2008-10-04       drh: ** area identified by mask to its current state from any other state.
bf75ea9852 2008-10-04       drh: */
bf75ea9852 2008-10-04       drh: static void export_config(
bf75ea9852 2008-10-04       drh:   int mask,                 /* Mask indicating which configuration to export */
bf75ea9852 2008-10-04       drh:   const char *zMask,        /* Name of the configuration */
bf75ea9852 2008-10-04       drh:   const char *zFilename     /* Write into this file */
bf75ea9852 2008-10-04       drh: ){
bf75ea9852 2008-10-04       drh:   int i;
bf75ea9852 2008-10-04       drh:   Blob out;
bf75ea9852 2008-10-04       drh:   blob_zero(&out);
bf75ea9852 2008-10-04       drh:   blob_appendf(&out,
bf75ea9852 2008-10-04       drh:     "-- The \"%s\" configuration exported from\n"
bf75ea9852 2008-10-04       drh:     "-- repository \"%s\"\n"
bf75ea9852 2008-10-04       drh:     "-- on %s\n",
bf75ea9852 2008-10-04       drh:     zMask, g.zRepositoryName,
bf75ea9852 2008-10-04       drh:     db_text(0, "SELECT datetime('now')")
bf75ea9852 2008-10-04       drh:   );
bf75ea9852 2008-10-04       drh:   for(i=0; i<count(aConfig); i++){
bf75ea9852 2008-10-04       drh:     if( (aConfig[i].groupMask & mask)!=0 ){
bf75ea9852 2008-10-04       drh:       const char *zName = aConfig[i].zName;
bf75ea9852 2008-10-04       drh:       if( zName[0]!='@' ){
bf75ea9852 2008-10-04       drh:         char *zValue = db_text(0,
bf75ea9852 2008-10-04       drh:             "SELECT value FROM config WHERE name=%Q", zName);
bf75ea9852 2008-10-04       drh:         if( zValue ){
bf75ea9852 2008-10-04       drh:           blob_appendf(&out,"REPLACE INTO config VALUES(%Q,%Q);\n",
bf75ea9852 2008-10-04       drh:                        zName, zValue);
bf75ea9852 2008-10-04       drh:         }
bf75ea9852 2008-10-04       drh:         free(zValue);
bf75ea9852 2008-10-04       drh:       }else{
bf75ea9852 2008-10-04       drh:         configure_render_special_name(zName, &out);
bf75ea9852 2008-10-04       drh:       }
bf75ea9852 2008-10-04       drh:     }
bf75ea9852 2008-10-04       drh:   }
bf75ea9852 2008-10-04       drh:   blob_write_to_file(&out, zFilename);
bf75ea9852 2008-10-04       drh:   blob_reset(&out);
28e56282c9 2008-05-23       drh: }
28e56282c9 2008-05-23       drh: 
e06ae9f6d2 2008-05-22       drh: 
e06ae9f6d2 2008-05-22       drh: /*
28e56282c9 2008-05-23       drh: ** COMMAND: configuration
e06ae9f6d2 2008-05-22       drh: **
e06ae9f6d2 2008-05-22       drh: ** Usage: %fossil configure METHOD ...
e06ae9f6d2 2008-05-22       drh: **
6b0b57a924 2008-10-25       drh: ** Where METHOD is one of: export import merge pull push reset.  All methods
e06ae9f6d2 2008-05-22       drh: ** accept the -R or --repository option to specific a repository.
e06ae9f6d2 2008-05-22       drh: **
28e56282c9 2008-05-23       drh: **    %fossil configuration export AREA FILENAME
e06ae9f6d2 2008-05-22       drh: **
e06ae9f6d2 2008-05-22       drh: **         Write to FILENAME exported configuraton information for AREA.
e06ae9f6d2 2008-05-22       drh: **         AREA can be one of:  all ticket skin project
e06ae9f6d2 2008-05-22       drh: **
28e56282c9 2008-05-23       drh: **    %fossil configuration import FILENAME
e06ae9f6d2 2008-05-22       drh: **
e06ae9f6d2 2008-05-22       drh: **         Read a configuration from FILENAME, overwriting the current
bf75ea9852 2008-10-04       drh: **         configuration.
bf75ea9852 2008-10-04       drh: **
bf75ea9852 2008-10-04       drh: **    %fossil configuration merge FILENAME
bf75ea9852 2008-10-04       drh: **
bf75ea9852 2008-10-04       drh: **         Read a configuration from FILENAME and merge its values into
bf75ea9852 2008-10-04       drh: **         the current configuration.  Existing values take priority over
bf75ea9852 2008-10-04       drh: **         values read from FILENAME.
e06ae9f6d2 2008-05-22       drh: **
bf75ea9852 2008-10-04       drh: **    %fossil configuration pull AREA ?URL?
e06ae9f6d2 2008-05-22       drh: **
e06ae9f6d2 2008-05-22       drh: **         Pull and install the configuration from a different server
bf75ea9852 2008-10-04       drh: **         identified by URL.  If no URL is specified, then the default
bf75ea9852 2008-10-04       drh: **         server is used.
6b0b57a924 2008-10-25       drh: **
6b0b57a924 2008-10-25       drh: **    %fossil configuration push AREA ?URL?
6b0b57a924 2008-10-25       drh: **
6b0b57a924 2008-10-25       drh: **         Push the local configuration into the remote server identified
6b0b57a924 2008-10-25       drh: **         by URL.  Admin privilege is required on the remote server for
6b0b57a924 2008-10-25       drh: **         this to work.
e06ae9f6d2 2008-05-22       drh: **
28e56282c9 2008-05-23       drh: **    %fossil configuration reset AREA
e06ae9f6d2 2008-05-22       drh: **
e06ae9f6d2 2008-05-22       drh: **         Restore the configuration to the default.  AREA as above.
bf75ea9852 2008-10-04       drh: **
bf75ea9852 2008-10-04       drh: ** WARNING: Do not import, merge, or pull configurations from an untrusted
bf75ea9852 2008-10-04       drh: ** source.  The inbound configuration is not checked for safety and can
bf75ea9852 2008-10-04       drh: ** introduce security vulnerabilities.
e06ae9f6d2 2008-05-22       drh: */
28e56282c9 2008-05-23       drh: void configuration_cmd(void){
e06ae9f6d2 2008-05-22       drh:   int n;
e06ae9f6d2 2008-05-22       drh:   const char *zMethod;
e06ae9f6d2 2008-05-22       drh:   if( g.argc<3 ){
bf75ea9852 2008-10-04       drh:     usage("export|import|merge|pull|reset ...");
e06ae9f6d2 2008-05-22       drh:   }
e06ae9f6d2 2008-05-22       drh:   db_find_and_open_repository(1);
e06ae9f6d2 2008-05-22       drh:   zMethod = g.argv[2];
e06ae9f6d2 2008-05-22       drh:   n = strlen(zMethod);
e06ae9f6d2 2008-05-22       drh:   if( strncmp(zMethod, "export", n)==0 ){
bf75ea9852 2008-10-04       drh:     int mask;
e06ae9f6d2 2008-05-22       drh:     if( g.argc!=5 ){
e06ae9f6d2 2008-05-22       drh:       usage("export AREA FILENAME");
e06ae9f6d2 2008-05-22       drh:     }
e06ae9f6d2 2008-05-22       drh:     mask = find_area(g.argv[3]);
bf75ea9852 2008-10-04       drh:     export_config(mask, g.argv[3], g.argv[4]);
bf75ea9852 2008-10-04       drh:   }else
bf75ea9852 2008-10-04       drh:   if( strncmp(zMethod, "import", n)==0
bf75ea9852 2008-10-04       drh:        || strncmp(zMethod, "merge", n)==0 ){
bf75ea9852 2008-10-04       drh:     Blob in;
bf75ea9852 2008-10-04       drh:     if( g.argc!=4 ) usage(mprintf("%s FILENAME",zMethod));
bf75ea9852 2008-10-04       drh:     blob_read_from_file(&in, g.argv[3]);
bf75ea9852 2008-10-04       drh:     db_begin_transaction();
bf75ea9852 2008-10-04       drh:     configure_prepare_to_receive(zMethod[0]=='i');
bf75ea9852 2008-10-04       drh:     db_multi_exec("%s", blob_str(&in));
bf75ea9852 2008-10-04       drh:     configure_finalize_receive();
bf75ea9852 2008-10-04       drh:     db_end_transaction(0);
bf75ea9852 2008-10-04       drh:   }else
6b0b57a924 2008-10-25       drh:   if( strncmp(zMethod, "pull", n)==0 || strncmp(zMethod, "push", n)==0 ){
bf75ea9852 2008-10-04       drh:     int mask;
bf75ea9852 2008-10-04       drh:     const char *zServer;
bf75ea9852 2008-10-04       drh:     url_proxy_options();
bf75ea9852 2008-10-04       drh:     if( g.argc!=4 && g.argc!=5 ){
bf75ea9852 2008-10-04       drh:       usage("pull AREA ?URL?");
28e56282c9 2008-05-23       drh:     }
bf75ea9852 2008-10-04       drh:     mask = find_area(g.argv[3]);
bf75ea9852 2008-10-04       drh:     if( g.argc==5 ){
bf75ea9852 2008-10-04       drh:       zServer = g.argv[4];
bf75ea9852 2008-10-04       drh:     }else{
bf75ea9852 2008-10-04       drh:       zServer = db_get("last-sync-url", 0);
bf75ea9852 2008-10-04       drh:       if( zServer==0 ){
bf75ea9852 2008-10-04       drh:         fossil_fatal("no server specified");
e06ae9f6d2 2008-05-22       drh:       }
e06ae9f6d2 2008-05-22       drh:     }
bf75ea9852 2008-10-04       drh:     url_parse(zServer);
28e56282c9 2008-05-23       drh:     user_select();
6b0b57a924 2008-10-25       drh:     if( strncmp(zMethod, "push", n)==0 ){
6b0b57a924 2008-10-25       drh:       client_sync(0,0,0,0,mask);
6b0b57a924 2008-10-25       drh:     }else{
6b0b57a924 2008-10-25       drh:       client_sync(0,0,0,mask,0);
6b0b57a924 2008-10-25       drh:     }
e06ae9f6d2 2008-05-22       drh:   }else
e06ae9f6d2 2008-05-22       drh:   if( strncmp(zMethod, "reset", n)==0 ){
28e56282c9 2008-05-23       drh:     int mask, i;
bf75ea9852 2008-10-04       drh:     char *zBackup;
28e56282c9 2008-05-23       drh:     if( g.argc!=4 ) usage("reset AREA");
28e56282c9 2008-05-23       drh:     mask = find_area(g.argv[3]);
bf75ea9852 2008-10-04       drh:     zBackup = db_text(0,
bf75ea9852 2008-10-04       drh:        "SELECT strftime('config-backup-%%Y%%m%%d%%H%%M%%f','now')");
28e56282c9 2008-05-23       drh:     db_begin_transaction();
bf75ea9852 2008-10-04       drh:     export_config(mask, g.argv[3], zBackup);
28e56282c9 2008-05-23       drh:     for(i=0; i<count(aConfig); i++){
bf75ea9852 2008-10-04       drh:       const char *zName = aConfig[i].zName;
28e56282c9 2008-05-23       drh:       if( (aConfig[i].groupMask & mask)==0 ) continue;
bf75ea9852 2008-10-04       drh:       if( zName[0]!='@' ){
bf75ea9852 2008-10-04       drh:         db_multi_exec("DELETE FROM config WHERE name=%Q", zName);
bf75ea9852 2008-10-04       drh:       }else if( strcmp(zName,"@user")==0 ){
bf75ea9852 2008-10-04       drh:         db_multi_exec("DELETE FROM user");
0c6ea0d93f 2008-11-20       drh:         db_create_default_users(0);
6b0b57a924 2008-10-25       drh:       }else if( strcmp(zName,"@concealed")==0 ){
6b0b57a924 2008-10-25       drh:         db_multi_exec("DELETE FROM concealed");
6b0b57a924 2008-10-25       drh:       }else if( strcmp(zName,"@shun")==0 ){
6b0b57a924 2008-10-25       drh:         db_multi_exec("DELETE FROM shun");
bf75ea9852 2008-10-04       drh:       }else if( strcmp(zName,"@reportfmt")==0 ){
bf75ea9852 2008-10-04       drh:         db_multi_exec("DELETE FROM reportfmt");
bf75ea9852 2008-10-04       drh:       }
28e56282c9 2008-05-23       drh:     }
28e56282c9 2008-05-23       drh:     db_end_transaction(0);
bf75ea9852 2008-10-04       drh:     printf("Configuration reset to factory defaults.\n");
bf75ea9852 2008-10-04       drh:     printf("To recover, use:  %s %s import %s\n",
bf75ea9852 2008-10-04       drh:             g.argv[0], g.argv[1], zBackup);
e06ae9f6d2 2008-05-22       drh:   }else
e06ae9f6d2 2008-05-22       drh:   {
6b0b57a924 2008-10-25       drh:     fossil_fatal("METHOD should be one of:"
6b0b57a924 2008-10-25       drh:                  " export import merge pull push reset");
e06ae9f6d2 2008-05-22       drh:   }
e06ae9f6d2 2008-05-22       drh: }