Fossil SCM

Add the ability to transfer subscriber information using the "fossil config sync alert" command.

drh 2018-06-25 15:56 trunk
Commit 22c3354dcbb718927396250ca32e2579b96e9fa1de1b629fd94786d689aeb7ea
1 file changed +79 -36
+79 -36
--- src/configure.c
+++ src/configure.c
@@ -36,12 +36,14 @@
3636
#define CONFIGSET_SHUN 0x000010 /* Shun settings */
3737
#define CONFIGSET_USER 0x000020 /* The USER table */
3838
#define CONFIGSET_ADDR 0x000040 /* The CONCEALED table */
3939
#define CONFIGSET_XFER 0x000080 /* Transfer configuration */
4040
#define CONFIGSET_ALIAS 0x000100 /* URL Aliases */
41
+#define CONFIGSET_ALERT 0x000200 /* Email alerts */
42
+#define CONFIGSET_FORUM 0x000400 /* Forum posts */
4143
42
-#define CONFIGSET_ALL 0x0001ff /* Everything */
44
+#define CONFIGSET_ALL 0x0007ff /* Everything */
4345
4446
#define CONFIGSET_OVERWRITE 0x100000 /* Causes overwrite instead of merge */
4547
4648
/*
4749
** This mask is used for the common TH1 configuration settings (i.e. those
@@ -68,10 +70,12 @@
6870
{ "/shun", CONFIGSET_SHUN, "List of shunned artifacts" },
6971
{ "/ticket", CONFIGSET_TKT, "Ticket setup", },
7072
{ "/user", CONFIGSET_USER, "Users and privilege settings" },
7173
{ "/xfer", CONFIGSET_XFER, "Transfer setup", },
7274
{ "/alias", CONFIGSET_ALIAS, "URL Aliases", },
75
+ { "/alert", CONFIGSET_ALERT, "Notification sent by email", },
76
+ { "/forum", CONFIGSET_FORUM, "Forum posts", },
7377
{ "/all", CONFIGSET_ALL, "All of the above" },
7478
};
7579
7680
7781
/*
@@ -157,10 +161,12 @@
157161
158162
{ "@shun", CONFIGSET_SHUN },
159163
160164
{ "@alias", CONFIGSET_ALIAS },
161165
166
+ { "@subscriber", CONFIGSET_ALERT },
167
+
162168
{ "xfer-common-script", CONFIGSET_XFER },
163169
{ "xfer-push-script", CONFIGSET_XFER },
164170
{ "xfer-commit-script", CONFIGSET_XFER },
165171
{ "xfer-ticket-script", CONFIGSET_XFER },
166172
@@ -213,11 +219,11 @@
213219
214220
/*
215221
** Return the mask for the named configuration parameter if it can be
216222
** safely exported. Return 0 if the parameter is not safe to export.
217223
**
218
-** "Safe" in the previous paragraph means the permission is created to
224
+** "Safe" in the previous paragraph means the permission is granted to
219225
** export the property. In other words, the requesting side has presented
220226
** login credentials and has sufficient capabilities to access the requested
221227
** information.
222228
*/
223229
int configure_is_exportable(const char *zName){
@@ -229,11 +235,14 @@
229235
}
230236
for(i=0; i<count(aConfig); i++){
231237
if( strncmp(zName, aConfig[i].zName, n)==0 && aConfig[i].zName[n]==0 ){
232238
int m = aConfig[i].groupMask;
233239
if( !g.perm.Admin ){
234
- m &= ~CONFIGSET_USER;
240
+ m &= ~(CONFIGSET_USER|CONFIGSET_ALERT);
241
+ }
242
+ if( !g.perm.RdForum ){
243
+ m &= ~(CONFIGSET_FORUM);
235244
}
236245
if( !g.perm.RdAddr ){
237246
m &= ~CONFIGSET_ADDR;
238247
}
239248
return m;
@@ -312,11 +321,15 @@
312321
** Mask consists of one or more CONFIGSET_* values ORed together, to
313322
** designate what types of configuration we are allowed to receive.
314323
**
315324
** NEW FORMAT:
316325
**
317
-** zName is one of "/config", "/user", "/shun", "/reportfmt", or "/concealed".
326
+** zName is one of:
327
+**
328
+** "/config", "/user", "/shun", "/reportfmt", "/concealed",
329
+** "/alert", "/forum"
330
+**
318331
** zName indicates the table that holds the configuration information being
319332
** transferred. pContent is a string that consist of alternating Fossil
320333
** and SQL tokens. The First token is a timestamp in seconds since 1970.
321334
** The second token is a primary key for the table identified by zName. If
322335
** The entry with the corresponding primary key exists and has a more recent
@@ -332,48 +345,37 @@
332345
** /config $MTIME $NAME value $VALUE
333346
** /user $MTIME $LOGIN pw $VALUE cap $VALUE info $VALUE photo $VALUE
334347
** /shun $MTIME $UUID scom $VALUE
335348
** /reportfmt $MTIME $TITLE owner $VALUE cols $VALUE sqlcode $VALUE
336349
** /concealed $MTIME $HASH content $VALUE
337
-**
338
-** OLD FORMAT:
339
-**
340
-** The old format is retained for backwards compatibility, but is deprecated.
341
-** The cutover from old format to new was on 2011-04-25. After sufficient
342
-** time has passed, support for the old format will be removed.
343
-** Update: Support for the old format was removed on 2017-09-20.
344
-**
345
-** zName is either the NAME of an element of the CONFIG table, or else
346
-** one of the special names "@shun", "@reportfmt", "@user", or "@concealed".
347
-** If zName is a CONFIG table name, then CONTENT replaces (overwrites) the
348
-** element in the CONFIG table. For one of the @-labels, CONTENT is raw
349
-** SQL that is evaluated. Note that the raw SQL in CONTENT might not
350
-** insert directly into the target table but might instead use a proxy
351
-** table like _fer_reportfmt or _xfer_user. Such tables must be created
352
-** ahead of time using configure_prepare_to_receive(). Then after multiple
353
-** calls to this routine, configure_finalize_receive() to transfer the
354
-** information received into the true target table.
350
+** /subscriber $SMTIME $SEMAIL suname $V sdigest $V sdonotcall $V ssub $V
355351
*/
356352
void configure_receive(const char *zName, Blob *pContent, int groupMask){
353
+ int checkMask; /* Masks for which we must first check existance of tables */
354
+
355
+ checkMask = CONFIGSET_ALERT;
357356
if( zName[0]=='/' ){
358357
/* The new format */
359358
char *azToken[12];
360359
int nToken = 0;
361360
int ii, jj;
362361
int thisMask;
363362
Blob name, value, sql;
364363
static const struct receiveType {
365
- const char *zName;
366
- const char *zPrimKey;
367
- int nField;
368
- const char *azField[4];
364
+ const char *zName; /* Configuration key for this table */
365
+ const char *zPrimKey; /* Primary key column */
366
+ const char *zMTime; /* Column holding the mtime */
367
+ int nField; /* Number of data fields */
368
+ const char *azField[4]; /* Names of the data fields */
369369
} aType[] = {
370
- { "/config", "name", 1, { "value", 0, 0, 0 } },
371
- { "@user", "login", 4, { "pw", "cap", "info", "photo" } },
372
- { "@shun", "uuid", 1, { "scom", 0, 0, 0 } },
373
- { "@reportfmt", "title", 3, { "owner", "cols", "sqlcode", 0 } },
374
- { "@concealed", "hash", 1, { "content", 0, 0, 0 } },
370
+ { "/config", "name", "mtime", 1, { "value", 0, 0, 0 } },
371
+ { "@user", "login", "mtime", 4, { "pw", "cap", "info", "photo" } },
372
+ { "@shun", "uuid", "mtime", 1, { "scom", 0, 0, 0 } },
373
+ { "@reportfmt", "title", "mtime", 3, { "owner", "cols", "sqlcode", 0 } },
374
+ { "@concealed", "hash", "mtime", 1, { "content", 0, 0, 0 } },
375
+ { "@subscriber","semail","smtime",4, { "suname","sdigest",
376
+ "sdonotcall","ssub"} },
375377
};
376378
for(ii=0; ii<count(aType); ii++){
377379
if( fossil_strcmp(&aType[ii].zName[1],&zName[1])==0 ) break;
378380
}
379381
if( ii>=count(aType) ) return;
@@ -398,10 +400,17 @@
398400
thisMask = configure_is_exportable(azToken[1]);
399401
}else{
400402
thisMask = configure_is_exportable(aType[ii].zName);
401403
}
402404
if( (thisMask & groupMask)==0 ) return;
405
+ if( (thisMask & checkMask)!=0 ){
406
+ if( (thisMask & CONFIGSET_ALERT)!=0 ){
407
+ email_schema(1);
408
+ }
409
+ checkMask &= ~thisMask;
410
+ }
411
+
403412
404413
blob_zero(&sql);
405414
if( groupMask & CONFIGSET_OVERWRITE ){
406415
if( (thisMask & configHasBeenReset)==0 && aType[ii].zName[0]!='/' ){
407416
db_multi_exec("DELETE FROM \"%w\"", &aType[ii].zName[1]);
@@ -409,11 +418,12 @@
409418
}
410419
blob_append_sql(&sql, "REPLACE INTO ");
411420
}else{
412421
blob_append_sql(&sql, "INSERT OR IGNORE INTO ");
413422
}
414
- blob_append_sql(&sql, "\"%w\"(\"%w\", mtime", &zName[1], aType[ii].zPrimKey);
423
+ blob_append_sql(&sql, "\"%w\"(\"%w\", \"%w\"",
424
+ &zName[1], aType[ii].zPrimKey, aType[ii].zMTime);
415425
for(jj=2; jj<nToken; jj+=2){
416426
blob_append_sql(&sql, ",\"%w\"", azToken[jj]);
417427
}
418428
blob_append_sql(&sql,") VALUES(%s,%s",
419429
azToken[1] /*safe-for-%s*/, azToken[0] /*safe-for-%s*/);
@@ -421,19 +431,19 @@
421431
blob_append_sql(&sql, ",%s", azToken[jj+1] /*safe-for-%s*/);
422432
}
423433
db_multi_exec("%s)", blob_sql_text(&sql));
424434
if( db_changes()==0 ){
425435
blob_reset(&sql);
426
- blob_append_sql(&sql, "UPDATE \"%w\" SET mtime=%s",
427
- &zName[1], azToken[0]/*safe-for-%s*/);
436
+ blob_append_sql(&sql, "UPDATE \"%w\" SET \"%w\"=%s",
437
+ &zName[1], aType[ii].zMTime, azToken[0]/*safe-for-%s*/);
428438
for(jj=2; jj<nToken; jj+=2){
429439
blob_append_sql(&sql, ", \"%w\"=%s",
430440
azToken[jj], azToken[jj+1]/*safe-for-%s*/);
431441
}
432
- blob_append_sql(&sql, " WHERE \"%w\"=%s AND mtime<%s",
442
+ blob_append_sql(&sql, " WHERE \"%w\"=%s AND \"%w\"<%s",
433443
aType[ii].zPrimKey, azToken[1]/*safe-for-%s*/,
434
- azToken[0]/*safe-for-%s*/);
444
+ aType[ii].zMTime, azToken[0]/*safe-for-%s*/);
435445
db_multi_exec("%s", blob_sql_text(&sql));
436446
}
437447
blob_reset(&sql);
438448
rebuildMask |= thisMask;
439449
}
@@ -573,10 +583,34 @@
573583
blob_size(&rec), blob_str(&rec));
574584
nCard++;
575585
blob_reset(&rec);
576586
}
577587
db_finalize(&q);
588
+ }
589
+ if( (groupMask & CONFIGSET_ALERT)!=0
590
+ && db_table_exists("repository","subscriber")
591
+ ){
592
+ db_prepare(&q, "SELECT (smtime-2440587.5)*86400,"
593
+ " quote(semail), quote(suname), quote(sdigest),"
594
+ " quote(sdonotcall), quote(ssub)"
595
+ " FROM subscriber WHERE sverified"
596
+ " AND (smtime-2440587.5)*86400>=%lld", iStart);
597
+ while( db_step(&q)==SQLITE_ROW ){
598
+ blob_appendf(&rec,"%lld %s suname %s sdigest %s sdonotcall %s ssub %s",
599
+ db_column_int64(&q, 0), /* smtime */
600
+ db_column_text(&q, 1), /* semail (PK) */
601
+ db_column_text(&q, 2), /* suname */
602
+ db_column_text(&q, 3), /* sdigest */
603
+ db_column_text(&q, 4), /* sdonotcall */
604
+ db_column_text(&q, 5) /* ssub */
605
+ );
606
+ blob_appendf(pOut, "config /subscriber %d\n%s\n",
607
+ blob_size(&rec), blob_str(&rec));
608
+ nCard++;
609
+ blob_reset(&rec);
610
+ }
611
+ db_finalize(&q);
578612
}
579613
db_prepare(&q, "SELECT mtime, quote(name), quote(value) FROM config"
580614
" WHERE name=:name AND mtime>=%lld", iStart);
581615
for(ii=0; ii<count(aConfig); ii++){
582616
if( (aConfig[ii].groupMask & groupMask)!=0 && aConfig[ii].zName[0]!='@' ){
@@ -792,10 +826,19 @@
792826
db_create_default_users(0, 0);
793827
}else if( fossil_strcmp(zName,"@concealed")==0 ){
794828
db_multi_exec("DELETE FROM concealed");
795829
}else if( fossil_strcmp(zName,"@shun")==0 ){
796830
db_multi_exec("DELETE FROM shun");
831
+ }else if( fossil_strcmp(zName,"@alert")==0 ){
832
+ if( db_table_exists("repository","subscriber") ){
833
+ db_multi_exec("DELETE FROM subscriber");
834
+ }
835
+ }else if( fossil_strcmp(zName,"@forum")==0 ){
836
+ if( db_table_exists("repository","forumpost") ){
837
+ db_multi_exec("DELETE FROM forumpost");
838
+ db_multi_exec("DELETE FROM forumthread");
839
+ }
797840
}else if( fossil_strcmp(zName,"@reportfmt")==0 ){
798841
db_multi_exec("DELETE FROM reportfmt");
799842
assert( strchr(zRepositorySchemaDefaultReports,'%')==0 );
800843
db_multi_exec(zRepositorySchemaDefaultReports /*works-like:""*/);
801844
}
802845
--- src/configure.c
+++ src/configure.c
@@ -36,12 +36,14 @@
36 #define CONFIGSET_SHUN 0x000010 /* Shun settings */
37 #define CONFIGSET_USER 0x000020 /* The USER table */
38 #define CONFIGSET_ADDR 0x000040 /* The CONCEALED table */
39 #define CONFIGSET_XFER 0x000080 /* Transfer configuration */
40 #define CONFIGSET_ALIAS 0x000100 /* URL Aliases */
 
 
41
42 #define CONFIGSET_ALL 0x0001ff /* Everything */
43
44 #define CONFIGSET_OVERWRITE 0x100000 /* Causes overwrite instead of merge */
45
46 /*
47 ** This mask is used for the common TH1 configuration settings (i.e. those
@@ -68,10 +70,12 @@
68 { "/shun", CONFIGSET_SHUN, "List of shunned artifacts" },
69 { "/ticket", CONFIGSET_TKT, "Ticket setup", },
70 { "/user", CONFIGSET_USER, "Users and privilege settings" },
71 { "/xfer", CONFIGSET_XFER, "Transfer setup", },
72 { "/alias", CONFIGSET_ALIAS, "URL Aliases", },
 
 
73 { "/all", CONFIGSET_ALL, "All of the above" },
74 };
75
76
77 /*
@@ -157,10 +161,12 @@
157
158 { "@shun", CONFIGSET_SHUN },
159
160 { "@alias", CONFIGSET_ALIAS },
161
 
 
162 { "xfer-common-script", CONFIGSET_XFER },
163 { "xfer-push-script", CONFIGSET_XFER },
164 { "xfer-commit-script", CONFIGSET_XFER },
165 { "xfer-ticket-script", CONFIGSET_XFER },
166
@@ -213,11 +219,11 @@
213
214 /*
215 ** Return the mask for the named configuration parameter if it can be
216 ** safely exported. Return 0 if the parameter is not safe to export.
217 **
218 ** "Safe" in the previous paragraph means the permission is created to
219 ** export the property. In other words, the requesting side has presented
220 ** login credentials and has sufficient capabilities to access the requested
221 ** information.
222 */
223 int configure_is_exportable(const char *zName){
@@ -229,11 +235,14 @@
229 }
230 for(i=0; i<count(aConfig); i++){
231 if( strncmp(zName, aConfig[i].zName, n)==0 && aConfig[i].zName[n]==0 ){
232 int m = aConfig[i].groupMask;
233 if( !g.perm.Admin ){
234 m &= ~CONFIGSET_USER;
 
 
 
235 }
236 if( !g.perm.RdAddr ){
237 m &= ~CONFIGSET_ADDR;
238 }
239 return m;
@@ -312,11 +321,15 @@
312 ** Mask consists of one or more CONFIGSET_* values ORed together, to
313 ** designate what types of configuration we are allowed to receive.
314 **
315 ** NEW FORMAT:
316 **
317 ** zName is one of "/config", "/user", "/shun", "/reportfmt", or "/concealed".
 
 
 
 
318 ** zName indicates the table that holds the configuration information being
319 ** transferred. pContent is a string that consist of alternating Fossil
320 ** and SQL tokens. The First token is a timestamp in seconds since 1970.
321 ** The second token is a primary key for the table identified by zName. If
322 ** The entry with the corresponding primary key exists and has a more recent
@@ -332,48 +345,37 @@
332 ** /config $MTIME $NAME value $VALUE
333 ** /user $MTIME $LOGIN pw $VALUE cap $VALUE info $VALUE photo $VALUE
334 ** /shun $MTIME $UUID scom $VALUE
335 ** /reportfmt $MTIME $TITLE owner $VALUE cols $VALUE sqlcode $VALUE
336 ** /concealed $MTIME $HASH content $VALUE
337 **
338 ** OLD FORMAT:
339 **
340 ** The old format is retained for backwards compatibility, but is deprecated.
341 ** The cutover from old format to new was on 2011-04-25. After sufficient
342 ** time has passed, support for the old format will be removed.
343 ** Update: Support for the old format was removed on 2017-09-20.
344 **
345 ** zName is either the NAME of an element of the CONFIG table, or else
346 ** one of the special names "@shun", "@reportfmt", "@user", or "@concealed".
347 ** If zName is a CONFIG table name, then CONTENT replaces (overwrites) the
348 ** element in the CONFIG table. For one of the @-labels, CONTENT is raw
349 ** SQL that is evaluated. Note that the raw SQL in CONTENT might not
350 ** insert directly into the target table but might instead use a proxy
351 ** table like _fer_reportfmt or _xfer_user. Such tables must be created
352 ** ahead of time using configure_prepare_to_receive(). Then after multiple
353 ** calls to this routine, configure_finalize_receive() to transfer the
354 ** information received into the true target table.
355 */
356 void configure_receive(const char *zName, Blob *pContent, int groupMask){
 
 
 
357 if( zName[0]=='/' ){
358 /* The new format */
359 char *azToken[12];
360 int nToken = 0;
361 int ii, jj;
362 int thisMask;
363 Blob name, value, sql;
364 static const struct receiveType {
365 const char *zName;
366 const char *zPrimKey;
367 int nField;
368 const char *azField[4];
 
369 } aType[] = {
370 { "/config", "name", 1, { "value", 0, 0, 0 } },
371 { "@user", "login", 4, { "pw", "cap", "info", "photo" } },
372 { "@shun", "uuid", 1, { "scom", 0, 0, 0 } },
373 { "@reportfmt", "title", 3, { "owner", "cols", "sqlcode", 0 } },
374 { "@concealed", "hash", 1, { "content", 0, 0, 0 } },
 
 
375 };
376 for(ii=0; ii<count(aType); ii++){
377 if( fossil_strcmp(&aType[ii].zName[1],&zName[1])==0 ) break;
378 }
379 if( ii>=count(aType) ) return;
@@ -398,10 +400,17 @@
398 thisMask = configure_is_exportable(azToken[1]);
399 }else{
400 thisMask = configure_is_exportable(aType[ii].zName);
401 }
402 if( (thisMask & groupMask)==0 ) return;
 
 
 
 
 
 
 
403
404 blob_zero(&sql);
405 if( groupMask & CONFIGSET_OVERWRITE ){
406 if( (thisMask & configHasBeenReset)==0 && aType[ii].zName[0]!='/' ){
407 db_multi_exec("DELETE FROM \"%w\"", &aType[ii].zName[1]);
@@ -409,11 +418,12 @@
409 }
410 blob_append_sql(&sql, "REPLACE INTO ");
411 }else{
412 blob_append_sql(&sql, "INSERT OR IGNORE INTO ");
413 }
414 blob_append_sql(&sql, "\"%w\"(\"%w\", mtime", &zName[1], aType[ii].zPrimKey);
 
415 for(jj=2; jj<nToken; jj+=2){
416 blob_append_sql(&sql, ",\"%w\"", azToken[jj]);
417 }
418 blob_append_sql(&sql,") VALUES(%s,%s",
419 azToken[1] /*safe-for-%s*/, azToken[0] /*safe-for-%s*/);
@@ -421,19 +431,19 @@
421 blob_append_sql(&sql, ",%s", azToken[jj+1] /*safe-for-%s*/);
422 }
423 db_multi_exec("%s)", blob_sql_text(&sql));
424 if( db_changes()==0 ){
425 blob_reset(&sql);
426 blob_append_sql(&sql, "UPDATE \"%w\" SET mtime=%s",
427 &zName[1], azToken[0]/*safe-for-%s*/);
428 for(jj=2; jj<nToken; jj+=2){
429 blob_append_sql(&sql, ", \"%w\"=%s",
430 azToken[jj], azToken[jj+1]/*safe-for-%s*/);
431 }
432 blob_append_sql(&sql, " WHERE \"%w\"=%s AND mtime<%s",
433 aType[ii].zPrimKey, azToken[1]/*safe-for-%s*/,
434 azToken[0]/*safe-for-%s*/);
435 db_multi_exec("%s", blob_sql_text(&sql));
436 }
437 blob_reset(&sql);
438 rebuildMask |= thisMask;
439 }
@@ -573,10 +583,34 @@
573 blob_size(&rec), blob_str(&rec));
574 nCard++;
575 blob_reset(&rec);
576 }
577 db_finalize(&q);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
578 }
579 db_prepare(&q, "SELECT mtime, quote(name), quote(value) FROM config"
580 " WHERE name=:name AND mtime>=%lld", iStart);
581 for(ii=0; ii<count(aConfig); ii++){
582 if( (aConfig[ii].groupMask & groupMask)!=0 && aConfig[ii].zName[0]!='@' ){
@@ -792,10 +826,19 @@
792 db_create_default_users(0, 0);
793 }else if( fossil_strcmp(zName,"@concealed")==0 ){
794 db_multi_exec("DELETE FROM concealed");
795 }else if( fossil_strcmp(zName,"@shun")==0 ){
796 db_multi_exec("DELETE FROM shun");
 
 
 
 
 
 
 
 
 
797 }else if( fossil_strcmp(zName,"@reportfmt")==0 ){
798 db_multi_exec("DELETE FROM reportfmt");
799 assert( strchr(zRepositorySchemaDefaultReports,'%')==0 );
800 db_multi_exec(zRepositorySchemaDefaultReports /*works-like:""*/);
801 }
802
--- src/configure.c
+++ src/configure.c
@@ -36,12 +36,14 @@
36 #define CONFIGSET_SHUN 0x000010 /* Shun settings */
37 #define CONFIGSET_USER 0x000020 /* The USER table */
38 #define CONFIGSET_ADDR 0x000040 /* The CONCEALED table */
39 #define CONFIGSET_XFER 0x000080 /* Transfer configuration */
40 #define CONFIGSET_ALIAS 0x000100 /* URL Aliases */
41 #define CONFIGSET_ALERT 0x000200 /* Email alerts */
42 #define CONFIGSET_FORUM 0x000400 /* Forum posts */
43
44 #define CONFIGSET_ALL 0x0007ff /* Everything */
45
46 #define CONFIGSET_OVERWRITE 0x100000 /* Causes overwrite instead of merge */
47
48 /*
49 ** This mask is used for the common TH1 configuration settings (i.e. those
@@ -68,10 +70,12 @@
70 { "/shun", CONFIGSET_SHUN, "List of shunned artifacts" },
71 { "/ticket", CONFIGSET_TKT, "Ticket setup", },
72 { "/user", CONFIGSET_USER, "Users and privilege settings" },
73 { "/xfer", CONFIGSET_XFER, "Transfer setup", },
74 { "/alias", CONFIGSET_ALIAS, "URL Aliases", },
75 { "/alert", CONFIGSET_ALERT, "Notification sent by email", },
76 { "/forum", CONFIGSET_FORUM, "Forum posts", },
77 { "/all", CONFIGSET_ALL, "All of the above" },
78 };
79
80
81 /*
@@ -157,10 +161,12 @@
161
162 { "@shun", CONFIGSET_SHUN },
163
164 { "@alias", CONFIGSET_ALIAS },
165
166 { "@subscriber", CONFIGSET_ALERT },
167
168 { "xfer-common-script", CONFIGSET_XFER },
169 { "xfer-push-script", CONFIGSET_XFER },
170 { "xfer-commit-script", CONFIGSET_XFER },
171 { "xfer-ticket-script", CONFIGSET_XFER },
172
@@ -213,11 +219,11 @@
219
220 /*
221 ** Return the mask for the named configuration parameter if it can be
222 ** safely exported. Return 0 if the parameter is not safe to export.
223 **
224 ** "Safe" in the previous paragraph means the permission is granted to
225 ** export the property. In other words, the requesting side has presented
226 ** login credentials and has sufficient capabilities to access the requested
227 ** information.
228 */
229 int configure_is_exportable(const char *zName){
@@ -229,11 +235,14 @@
235 }
236 for(i=0; i<count(aConfig); i++){
237 if( strncmp(zName, aConfig[i].zName, n)==0 && aConfig[i].zName[n]==0 ){
238 int m = aConfig[i].groupMask;
239 if( !g.perm.Admin ){
240 m &= ~(CONFIGSET_USER|CONFIGSET_ALERT);
241 }
242 if( !g.perm.RdForum ){
243 m &= ~(CONFIGSET_FORUM);
244 }
245 if( !g.perm.RdAddr ){
246 m &= ~CONFIGSET_ADDR;
247 }
248 return m;
@@ -312,11 +321,15 @@
321 ** Mask consists of one or more CONFIGSET_* values ORed together, to
322 ** designate what types of configuration we are allowed to receive.
323 **
324 ** NEW FORMAT:
325 **
326 ** zName is one of:
327 **
328 ** "/config", "/user", "/shun", "/reportfmt", "/concealed",
329 ** "/alert", "/forum"
330 **
331 ** zName indicates the table that holds the configuration information being
332 ** transferred. pContent is a string that consist of alternating Fossil
333 ** and SQL tokens. The First token is a timestamp in seconds since 1970.
334 ** The second token is a primary key for the table identified by zName. If
335 ** The entry with the corresponding primary key exists and has a more recent
@@ -332,48 +345,37 @@
345 ** /config $MTIME $NAME value $VALUE
346 ** /user $MTIME $LOGIN pw $VALUE cap $VALUE info $VALUE photo $VALUE
347 ** /shun $MTIME $UUID scom $VALUE
348 ** /reportfmt $MTIME $TITLE owner $VALUE cols $VALUE sqlcode $VALUE
349 ** /concealed $MTIME $HASH content $VALUE
350 ** /subscriber $SMTIME $SEMAIL suname $V sdigest $V sdonotcall $V ssub $V
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
351 */
352 void configure_receive(const char *zName, Blob *pContent, int groupMask){
353 int checkMask; /* Masks for which we must first check existance of tables */
354
355 checkMask = CONFIGSET_ALERT;
356 if( zName[0]=='/' ){
357 /* The new format */
358 char *azToken[12];
359 int nToken = 0;
360 int ii, jj;
361 int thisMask;
362 Blob name, value, sql;
363 static const struct receiveType {
364 const char *zName; /* Configuration key for this table */
365 const char *zPrimKey; /* Primary key column */
366 const char *zMTime; /* Column holding the mtime */
367 int nField; /* Number of data fields */
368 const char *azField[4]; /* Names of the data fields */
369 } aType[] = {
370 { "/config", "name", "mtime", 1, { "value", 0, 0, 0 } },
371 { "@user", "login", "mtime", 4, { "pw", "cap", "info", "photo" } },
372 { "@shun", "uuid", "mtime", 1, { "scom", 0, 0, 0 } },
373 { "@reportfmt", "title", "mtime", 3, { "owner", "cols", "sqlcode", 0 } },
374 { "@concealed", "hash", "mtime", 1, { "content", 0, 0, 0 } },
375 { "@subscriber","semail","smtime",4, { "suname","sdigest",
376 "sdonotcall","ssub"} },
377 };
378 for(ii=0; ii<count(aType); ii++){
379 if( fossil_strcmp(&aType[ii].zName[1],&zName[1])==0 ) break;
380 }
381 if( ii>=count(aType) ) return;
@@ -398,10 +400,17 @@
400 thisMask = configure_is_exportable(azToken[1]);
401 }else{
402 thisMask = configure_is_exportable(aType[ii].zName);
403 }
404 if( (thisMask & groupMask)==0 ) return;
405 if( (thisMask & checkMask)!=0 ){
406 if( (thisMask & CONFIGSET_ALERT)!=0 ){
407 email_schema(1);
408 }
409 checkMask &= ~thisMask;
410 }
411
412
413 blob_zero(&sql);
414 if( groupMask & CONFIGSET_OVERWRITE ){
415 if( (thisMask & configHasBeenReset)==0 && aType[ii].zName[0]!='/' ){
416 db_multi_exec("DELETE FROM \"%w\"", &aType[ii].zName[1]);
@@ -409,11 +418,12 @@
418 }
419 blob_append_sql(&sql, "REPLACE INTO ");
420 }else{
421 blob_append_sql(&sql, "INSERT OR IGNORE INTO ");
422 }
423 blob_append_sql(&sql, "\"%w\"(\"%w\", \"%w\"",
424 &zName[1], aType[ii].zPrimKey, aType[ii].zMTime);
425 for(jj=2; jj<nToken; jj+=2){
426 blob_append_sql(&sql, ",\"%w\"", azToken[jj]);
427 }
428 blob_append_sql(&sql,") VALUES(%s,%s",
429 azToken[1] /*safe-for-%s*/, azToken[0] /*safe-for-%s*/);
@@ -421,19 +431,19 @@
431 blob_append_sql(&sql, ",%s", azToken[jj+1] /*safe-for-%s*/);
432 }
433 db_multi_exec("%s)", blob_sql_text(&sql));
434 if( db_changes()==0 ){
435 blob_reset(&sql);
436 blob_append_sql(&sql, "UPDATE \"%w\" SET \"%w\"=%s",
437 &zName[1], aType[ii].zMTime, azToken[0]/*safe-for-%s*/);
438 for(jj=2; jj<nToken; jj+=2){
439 blob_append_sql(&sql, ", \"%w\"=%s",
440 azToken[jj], azToken[jj+1]/*safe-for-%s*/);
441 }
442 blob_append_sql(&sql, " WHERE \"%w\"=%s AND \"%w\"<%s",
443 aType[ii].zPrimKey, azToken[1]/*safe-for-%s*/,
444 aType[ii].zMTime, azToken[0]/*safe-for-%s*/);
445 db_multi_exec("%s", blob_sql_text(&sql));
446 }
447 blob_reset(&sql);
448 rebuildMask |= thisMask;
449 }
@@ -573,10 +583,34 @@
583 blob_size(&rec), blob_str(&rec));
584 nCard++;
585 blob_reset(&rec);
586 }
587 db_finalize(&q);
588 }
589 if( (groupMask & CONFIGSET_ALERT)!=0
590 && db_table_exists("repository","subscriber")
591 ){
592 db_prepare(&q, "SELECT (smtime-2440587.5)*86400,"
593 " quote(semail), quote(suname), quote(sdigest),"
594 " quote(sdonotcall), quote(ssub)"
595 " FROM subscriber WHERE sverified"
596 " AND (smtime-2440587.5)*86400>=%lld", iStart);
597 while( db_step(&q)==SQLITE_ROW ){
598 blob_appendf(&rec,"%lld %s suname %s sdigest %s sdonotcall %s ssub %s",
599 db_column_int64(&q, 0), /* smtime */
600 db_column_text(&q, 1), /* semail (PK) */
601 db_column_text(&q, 2), /* suname */
602 db_column_text(&q, 3), /* sdigest */
603 db_column_text(&q, 4), /* sdonotcall */
604 db_column_text(&q, 5) /* ssub */
605 );
606 blob_appendf(pOut, "config /subscriber %d\n%s\n",
607 blob_size(&rec), blob_str(&rec));
608 nCard++;
609 blob_reset(&rec);
610 }
611 db_finalize(&q);
612 }
613 db_prepare(&q, "SELECT mtime, quote(name), quote(value) FROM config"
614 " WHERE name=:name AND mtime>=%lld", iStart);
615 for(ii=0; ii<count(aConfig); ii++){
616 if( (aConfig[ii].groupMask & groupMask)!=0 && aConfig[ii].zName[0]!='@' ){
@@ -792,10 +826,19 @@
826 db_create_default_users(0, 0);
827 }else if( fossil_strcmp(zName,"@concealed")==0 ){
828 db_multi_exec("DELETE FROM concealed");
829 }else if( fossil_strcmp(zName,"@shun")==0 ){
830 db_multi_exec("DELETE FROM shun");
831 }else if( fossil_strcmp(zName,"@alert")==0 ){
832 if( db_table_exists("repository","subscriber") ){
833 db_multi_exec("DELETE FROM subscriber");
834 }
835 }else if( fossil_strcmp(zName,"@forum")==0 ){
836 if( db_table_exists("repository","forumpost") ){
837 db_multi_exec("DELETE FROM forumpost");
838 db_multi_exec("DELETE FROM forumthread");
839 }
840 }else if( fossil_strcmp(zName,"@reportfmt")==0 ){
841 db_multi_exec("DELETE FROM reportfmt");
842 assert( strchr(zRepositorySchemaDefaultReports,'%')==0 );
843 db_multi_exec(zRepositorySchemaDefaultReports /*works-like:""*/);
844 }
845

Keyboard Shortcuts

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