Fossil SCM

Add the "default-skin" setting which defines which built-in skin to use if no skin is otherwise specified. On the /skins page, show how the current skin is selected, if that is relevant. Add the /fdscookie page that shows just the "fossil_display_settings" cookie rather than all cookies.

drh 2024-02-23 15:24 trunk
Commit 24e015de71cfdc79789b5cdbad2675f3133ca932f7b99499ac9198625df04d5a
4 files changed +2 -2 +21 -4 +1 -1 +97 -17
+2 -2
--- src/cgi.c
+++ src/cgi.c
@@ -1256,11 +1256,11 @@
12561256
++rc;
12571257
z = fossil_strdup(z);
12581258
add_param_list(z, '&');
12591259
z = (char*)P("skin");
12601260
if( z ){
1261
- char *zErr = skin_use_alternative(z, 2);
1261
+ char *zErr = skin_use_alternative(z, 2, SKIN_FROM_QPARAM);
12621262
++rc;
12631263
if( !zErr && P("once")==0 ){
12641264
cookie_write_parameter("skin","skin",z);
12651265
/* Per /chat discussion, passing ?skin=... without "once"
12661266
** implies the "udc" argument, so we force that into the
@@ -1407,11 +1407,11 @@
14071407
if( z ){
14081408
z = fossil_strdup(z);
14091409
add_param_list(z, ';');
14101410
z = (char*)cookie_value("skin",0);
14111411
if(z){
1412
- skin_use_alternative(z, 2);
1412
+ skin_use_alternative(z, 2, SKIN_FROM_COOKIE);
14131413
}
14141414
}
14151415
14161416
cgi_setup_query_string();
14171417
14181418
--- src/cgi.c
+++ src/cgi.c
@@ -1256,11 +1256,11 @@
1256 ++rc;
1257 z = fossil_strdup(z);
1258 add_param_list(z, '&');
1259 z = (char*)P("skin");
1260 if( z ){
1261 char *zErr = skin_use_alternative(z, 2);
1262 ++rc;
1263 if( !zErr && P("once")==0 ){
1264 cookie_write_parameter("skin","skin",z);
1265 /* Per /chat discussion, passing ?skin=... without "once"
1266 ** implies the "udc" argument, so we force that into the
@@ -1407,11 +1407,11 @@
1407 if( z ){
1408 z = fossil_strdup(z);
1409 add_param_list(z, ';');
1410 z = (char*)cookie_value("skin",0);
1411 if(z){
1412 skin_use_alternative(z, 2);
1413 }
1414 }
1415
1416 cgi_setup_query_string();
1417
1418
--- src/cgi.c
+++ src/cgi.c
@@ -1256,11 +1256,11 @@
1256 ++rc;
1257 z = fossil_strdup(z);
1258 add_param_list(z, '&');
1259 z = (char*)P("skin");
1260 if( z ){
1261 char *zErr = skin_use_alternative(z, 2, SKIN_FROM_QPARAM);
1262 ++rc;
1263 if( !zErr && P("once")==0 ){
1264 cookie_write_parameter("skin","skin",z);
1265 /* Per /chat discussion, passing ?skin=... without "once"
1266 ** implies the "udc" argument, so we force that into the
@@ -1407,11 +1407,11 @@
1407 if( z ){
1408 z = fossil_strdup(z);
1409 add_param_list(z, ';');
1410 z = (char*)cookie_value("skin",0);
1411 if(z){
1412 skin_use_alternative(z, 2, SKIN_FROM_COOKIE);
1413 }
1414 }
1415
1416 cgi_setup_query_string();
1417
1418
+21 -4
--- src/cookies.c
+++ src/cookies.c
@@ -213,11 +213,17 @@
213213
for(i=0; i<cookies.nParam && strcmp(zPName,cookies.aParam[i].zPName); i++){}
214214
return i<cookies.nParam ? cookies.aParam[i].zPValue : zDefault;
215215
}
216216
217217
/*
218
-** WEBPAGE: cookies
218
+** WEBPAGE: cookies
219
+**
220
+** Show all cookies associated with Fossil. This shows the text of the
221
+** login cookie and is hence dangerous if an adversary is looking over
222
+** your shoulder and is able to read and reproduce that cookie.
223
+**
224
+** WEBPAGE: fdscookie
219225
**
220226
** Show the current display settings contained in the
221227
** "fossil_display_settings" cookie.
222228
*/
223229
void cookie_page(void){
@@ -224,22 +230,28 @@
224230
int i;
225231
int nCookie = 0;
226232
const char *zName = 0;
227233
const char *zValue = 0;
228234
int isQP = 0;
235
+ int bFDSonly = strstr(g.zPath, "fdscookie")!=0;
229236
cookie_parse();
230
- style_header("Cookies");
237
+ if( bFDSonly ){
238
+ style_header("Display Preferences Cookie");
239
+ }else{
240
+ style_header("All Cookies");
241
+ }
231242
@ <form method="POST">
232243
@ <ol>
233244
for(i=0; cgi_param_info(i, &zName, &zValue, &isQP); i++){
234245
char *zDel;
235246
if( isQP ) continue;
236247
if( fossil_isupper(zName[0]) ) continue;
248
+ if( bFDSonly && strcmp(zName, "fossil_display_settings")!=0 ) continue;
237249
zDel = mprintf("del%s",zName);
238250
if( P(zDel)!=0 ){
239251
cgi_set_cookie(zName, "", 0, -1);
240
- cgi_redirect("cookies");
252
+ cgi_redirect(g.zPath);
241253
}
242254
nCookie++;
243255
@ <li><p><b>%h(zName)</b>: %h(zValue)
244256
@ <input type="submit" name="%h(zDel)" value="Delete">
245257
if( fossil_strcmp(zName, DISPLAY_SETTINGS_COOKIE)==0 && cookies.nParam>0 ){
@@ -253,9 +265,14 @@
253265
fossil_free(zDel);
254266
}
255267
@ </ol>
256268
@ </form>
257269
if( nCookie==0 ){
258
- @ <p><i>No cookies for this website</i></p>
270
+ if( bFDSonly ){
271
+ @ <p><i>Your browser is not holding a "fossil_display_setting" cookie
272
+ @ for this website</i></p>
273
+ }else{
274
+ @ <p><i>Your browser is not holding any cookies for this website</i></p>
275
+ }
259276
}
260277
style_finish_page();
261278
}
262279
--- src/cookies.c
+++ src/cookies.c
@@ -213,11 +213,17 @@
213 for(i=0; i<cookies.nParam && strcmp(zPName,cookies.aParam[i].zPName); i++){}
214 return i<cookies.nParam ? cookies.aParam[i].zPValue : zDefault;
215 }
216
217 /*
218 ** WEBPAGE: cookies
 
 
 
 
 
 
219 **
220 ** Show the current display settings contained in the
221 ** "fossil_display_settings" cookie.
222 */
223 void cookie_page(void){
@@ -224,22 +230,28 @@
224 int i;
225 int nCookie = 0;
226 const char *zName = 0;
227 const char *zValue = 0;
228 int isQP = 0;
 
229 cookie_parse();
230 style_header("Cookies");
 
 
 
 
231 @ <form method="POST">
232 @ <ol>
233 for(i=0; cgi_param_info(i, &zName, &zValue, &isQP); i++){
234 char *zDel;
235 if( isQP ) continue;
236 if( fossil_isupper(zName[0]) ) continue;
 
237 zDel = mprintf("del%s",zName);
238 if( P(zDel)!=0 ){
239 cgi_set_cookie(zName, "", 0, -1);
240 cgi_redirect("cookies");
241 }
242 nCookie++;
243 @ <li><p><b>%h(zName)</b>: %h(zValue)
244 @ <input type="submit" name="%h(zDel)" value="Delete">
245 if( fossil_strcmp(zName, DISPLAY_SETTINGS_COOKIE)==0 && cookies.nParam>0 ){
@@ -253,9 +265,14 @@
253 fossil_free(zDel);
254 }
255 @ </ol>
256 @ </form>
257 if( nCookie==0 ){
258 @ <p><i>No cookies for this website</i></p>
 
 
 
 
 
259 }
260 style_finish_page();
261 }
262
--- src/cookies.c
+++ src/cookies.c
@@ -213,11 +213,17 @@
213 for(i=0; i<cookies.nParam && strcmp(zPName,cookies.aParam[i].zPName); i++){}
214 return i<cookies.nParam ? cookies.aParam[i].zPValue : zDefault;
215 }
216
217 /*
218 ** WEBPAGE: cookies
219 **
220 ** Show all cookies associated with Fossil. This shows the text of the
221 ** login cookie and is hence dangerous if an adversary is looking over
222 ** your shoulder and is able to read and reproduce that cookie.
223 **
224 ** WEBPAGE: fdscookie
225 **
226 ** Show the current display settings contained in the
227 ** "fossil_display_settings" cookie.
228 */
229 void cookie_page(void){
@@ -224,22 +230,28 @@
230 int i;
231 int nCookie = 0;
232 const char *zName = 0;
233 const char *zValue = 0;
234 int isQP = 0;
235 int bFDSonly = strstr(g.zPath, "fdscookie")!=0;
236 cookie_parse();
237 if( bFDSonly ){
238 style_header("Display Preferences Cookie");
239 }else{
240 style_header("All Cookies");
241 }
242 @ <form method="POST">
243 @ <ol>
244 for(i=0; cgi_param_info(i, &zName, &zValue, &isQP); i++){
245 char *zDel;
246 if( isQP ) continue;
247 if( fossil_isupper(zName[0]) ) continue;
248 if( bFDSonly && strcmp(zName, "fossil_display_settings")!=0 ) continue;
249 zDel = mprintf("del%s",zName);
250 if( P(zDel)!=0 ){
251 cgi_set_cookie(zName, "", 0, -1);
252 cgi_redirect(g.zPath);
253 }
254 nCookie++;
255 @ <li><p><b>%h(zName)</b>: %h(zValue)
256 @ <input type="submit" name="%h(zDel)" value="Delete">
257 if( fossil_strcmp(zName, DISPLAY_SETTINGS_COOKIE)==0 && cookies.nParam>0 ){
@@ -253,9 +265,14 @@
265 fossil_free(zDel);
266 }
267 @ </ol>
268 @ </form>
269 if( nCookie==0 ){
270 if( bFDSonly ){
271 @ <p><i>Your browser is not holding a "fossil_display_setting" cookie
272 @ for this website</i></p>
273 }else{
274 @ <p><i>Your browser is not holding any cookies for this website</i></p>
275 }
276 }
277 style_finish_page();
278 }
279
+1 -1
--- src/main.c
+++ src/main.c
@@ -2525,11 +2525,11 @@
25252525
** an absolute path to a directory which holds skin definition
25262526
** files (header.txt, footer.txt, etc.). If LABEL is empty,
25272527
** the skin stored in the CONFIG db table is used.
25282528
*/
25292529
blob_token(&line, &value);
2530
- fossil_free(skin_use_alternative(blob_str(&value), 1));
2530
+ fossil_free(skin_use_alternative(blob_str(&value), 1, SKIN_FROM_CGI));
25312531
blob_reset(&value);
25322532
continue;
25332533
}
25342534
if( blob_eq(&key, "jsmode:") && blob_token(&line, &value) ){
25352535
/* jsmode: MODE
25362536
--- src/main.c
+++ src/main.c
@@ -2525,11 +2525,11 @@
2525 ** an absolute path to a directory which holds skin definition
2526 ** files (header.txt, footer.txt, etc.). If LABEL is empty,
2527 ** the skin stored in the CONFIG db table is used.
2528 */
2529 blob_token(&line, &value);
2530 fossil_free(skin_use_alternative(blob_str(&value), 1));
2531 blob_reset(&value);
2532 continue;
2533 }
2534 if( blob_eq(&key, "jsmode:") && blob_token(&line, &value) ){
2535 /* jsmode: MODE
2536
--- src/main.c
+++ src/main.c
@@ -2525,11 +2525,11 @@
2525 ** an absolute path to a directory which holds skin definition
2526 ** files (header.txt, footer.txt, etc.). If LABEL is empty,
2527 ** the skin stored in the CONFIG db table is used.
2528 */
2529 blob_token(&line, &value);
2530 fossil_free(skin_use_alternative(blob_str(&value), 1, SKIN_FROM_CGI));
2531 blob_reset(&value);
2532 continue;
2533 }
2534 if( blob_eq(&key, "jsmode:") && blob_token(&line, &value) ){
2535 /* jsmode: MODE
2536
+97 -17
--- src/skins.c
+++ src/skins.c
@@ -19,10 +19,17 @@
1919
*/
2020
#include "config.h"
2121
#include <assert.h>
2222
#include "skins.h"
2323
24
+/*
25
+** SETTING: default-skin width=16
26
+**
27
+** If the text value if this setting is the name of a built-in skin
28
+** then the named skin becomes the default skin for the repository.
29
+*/
30
+
2431
/*
2532
** An array of available built-in skins.
2633
**
2734
** To add new built-in skins:
2835
**
@@ -76,11 +83,28 @@
7683
/*
7784
** Used by skin_use_alternative() to store the current skin rank skin
7885
** so that the /skins page can, if warranted, warn the user that skin
7986
** changes won't have any effect.
8087
*/
81
-static int nSkinRank = 5;
88
+static int nSkinRank = 6;
89
+
90
+/*
91
+** How the specific skin being used was chosen
92
+*/
93
+#if INTERFACE
94
+#define SKIN_FROM_DRAFT 0 /* The "draftN" prefix on the PATH_INFO */
95
+#define SKIN_FROM_CMDLINE 1 /* --skin option to server command-line */
96
+#define SKIN_FROM_CGI 2 /* skin: parameter in CGI script */
97
+#define SKIN_FROM_QPARAM 3 /* skin= query parameter */
98
+#define SKIN_FROM_COOKIE 4 /* skin= from fossil_display_settings cookie*/
99
+#define SKIN_FROM_SETTING 5 /* Built-in named by "default-skin" setting */
100
+#define SKIN_FROM_CUSTOM 6 /* Skin values in CONFIG table */
101
+#define SKIN_FROM_DEFAULT 7 /* The built-in named "default" */
102
+#define SKIN_FROM_UNKNOWN 8 /* Do not yet know which skin to use */
103
+#endif /* INTERFACE */
104
+static int iSkinSource = SKIN_FROM_UNKNOWN;
105
+
82106
83107
/*
84108
** Skin details are a set of key/value pairs that define display
85109
** attributes of the skin that cannot be easily specified using CSS
86110
** or that need to be known on the server-side.
@@ -125,40 +149,50 @@
125149
** former gets initialized before both URL parameters and the /draft
126150
** path determination).
127151
**
128152
** The rankings were initially defined in
129153
** https://fossil-scm.org/forum/forumpost/caf8c9a8bb
130
-** and are:
154
+** but where subsequently revised:
131155
**
132
-** 0) A skin name matching the glob draft[1-9] trumps everything else.
156
+** 0) A skin name matching the glob pattern "draft[1-9]" at the start of
157
+** the PATH_INFO.
133158
**
134
-** 1) The --skin flag or skin: CGI config setting.
159
+** 1) The --skin flag for commands like "fossil ui", "fossil server", or
160
+** "fossil http", or the "skin:" CGI config setting.
135161
**
136162
** 2) The "skin" display setting cookie or URL argument, in that
137
-** order. If the "skin" URL argument is provided and refers to a legal
138
-** skin then that will update the display cookie. If the skin name is
139
-** illegal it is silently ignored.
163
+** order. If the "skin" URL argument is provided and refers to a legal
164
+** skin then that will update the display cookie. If the skin name is
165
+** illegal it is silently ignored.
166
+**
167
+** 3) The built-in skin identfied by the "default-skin" setting, if such
168
+** a setting exists and matches one of the built-in skin names.
169
+**
170
+** 4) Skin properties (settings "css", "details", "footer", "header",
171
+** and "js") from the CONFIG db table
172
+**
173
+** 5) The built-in skin named "default"
140174
**
141
-** 3) Skin properties from the CONFIG db table
142
-**
143
-** 4) Default skin.
175
+** The iSource integer privides additional detail about where the skin
144176
**
145177
** As a special case, a NULL or empty name resets zAltSkinDir and
146178
** pAltSkin to 0 to indicate that the current config-side skin should
147179
** be used (rank 3, above), then returns 0.
148180
*/
149
-char *skin_use_alternative(const char *zName, int rank){
181
+char *skin_use_alternative(const char *zName, int rank, int iSource){
150182
int i;
151183
Blob err = BLOB_INITIALIZER;
152184
if(rank > nSkinRank) return 0;
153185
nSkinRank = rank;
154186
if( zName && 1==rank && strchr(zName, '/')!=0 ){
155187
zAltSkinDir = fossil_strdup(zName);
188
+ iSkinSource = iSource;
156189
return 0;
157190
}
158191
if( zName && sqlite3_strglob("draft[1-9]", zName)==0 ){
159192
skin_use_draft(zName[5] - '0');
193
+ iSkinSource = iSource;
160194
return 0;
161195
}
162196
if(!zName || !*zName){
163197
pAltSkin = 0;
164198
zAltSkinDir = 0;
@@ -165,10 +199,11 @@
165199
return 0;
166200
}
167201
for(i=0; i<count(aBuiltinSkin); i++){
168202
if( fossil_strcmp(aBuiltinSkin[i].zLabel, zName)==0 ){
169203
pAltSkin = &aBuiltinSkin[i];
204
+ iSkinSource = iSource;
170205
return 0;
171206
}
172207
}
173208
blob_appendf(&err, "available skins: %s", aBuiltinSkin[0].zLabel);
174209
for(i=1; i<count(aBuiltinSkin); i++){
@@ -179,24 +214,28 @@
179214
}
180215
181216
/*
182217
** Look for the --skin command-line option and process it. Or
183218
** call fossil_fatal() if an unknown skin is specified.
219
+**
220
+** This routine is called during command-line parsing for commands
221
+** like "fossil ui" and "fossil http".
184222
*/
185223
void skin_override(void){
186224
const char *zSkin = find_option("skin",0,1);
187225
if( zSkin ){
188
- char *zErr = skin_use_alternative(zSkin, 1);
226
+ char *zErr = skin_use_alternative(zSkin, 1, SKIN_FROM_CMDLINE);
189227
if( zErr ) fossil_fatal("%s", zErr);
190228
}
191229
}
192230
193231
/*
194232
** Use one of the draft skins.
195233
*/
196234
void skin_use_draft(int i){
197235
iDraftSkin = i;
236
+ iSkinSource = SKIN_FROM_DRAFT;
198237
}
199238
200239
/*
201240
** The following routines return the various components of the skin
202241
** that should be used for the current run.
@@ -219,10 +258,24 @@
219258
blob_read_from_file(&x, z, ExtFILE);
220259
fossil_free(z);
221260
return blob_str(&x);
222261
}
223262
fossil_free(z);
263
+ }
264
+ if( iSkinSource==SKIN_FROM_UNKNOWN ){
265
+ const char *zDflt = db_get("default-skin", 0);
266
+ iSkinSource = SKIN_FROM_DEFAULT;
267
+ if( zDflt!=0 ){
268
+ int i;
269
+ for(i=0; i<count(aBuiltinSkin); i++){
270
+ if( fossil_strcmp(aBuiltinSkin[i].zLabel, zDflt)==0 ){
271
+ pAltSkin = &aBuiltinSkin[i];
272
+ iSkinSource = SKIN_FROM_SETTING;
273
+ break;
274
+ }
275
+ }
276
+ }
224277
}
225278
if( pAltSkin ){
226279
z = mprintf("skins/%s/%s.txt", pAltSkin->zLabel, zWhat);
227280
zOut = builtin_text(z);
228281
fossil_free(z);
@@ -230,10 +283,12 @@
230283
zOut = db_get(zWhat, 0);
231284
if( zOut==0 ){
232285
z = mprintf("skins/default/%s.txt", zWhat);
233286
zOut = builtin_text(z);
234287
fossil_free(z);
288
+ }else{
289
+ iSkinSource = SKIN_FROM_CUSTOM;
235290
}
236291
}
237292
return zOut;
238293
}
239294
@@ -1216,24 +1271,25 @@
12161271
@ <p class="warning">Warning:
12171272
if( iDraftSkin>0 ){
12181273
@ you are using a draft skin,
12191274
}else{
12201275
@ this fossil instance was started with a hard-coded skin
1221
- @ value,
1276
+ @ value
12221277
}
1223
- @ which trumps any option selected below. A skin selected
1224
- @ below will be recorded in your preference cookie
1278
+ @ which supercedes any option selected below. A skin selected
1279
+ @ below will be recorded in your
1280
+ @ "%z(href("%R/fdscookie"))fossil_display_settings</a>" cookie
12251281
@ but will not be used so long as the site has a
12261282
@ higher-priority skin in place.
12271283
@ </p>
12281284
}
12291285
@ <p>The following skins are available for this repository:</p>
12301286
@ <ul>
12311287
if( pAltSkin==0 && zAltSkinDir==0 && iDraftSkin==0 ){
1232
- @ <li> Standard skin for this repository &larr; <i>Currently in use</i>
1288
+ @ <li> Custom skin for this repository &larr; <i>Currently in use</i>
12331289
}else{
1234
- @ <li> %z(href("%R/skins?skin="))Standard skin for this repository</a>
1290
+ @ <li> %z(href("%R/skins?skin="))Custom skin for this repository</a>
12351291
}
12361292
for(i=0; i<count(aBuiltinSkin); i++){
12371293
if( pAltSkin==&aBuiltinSkin[i] ){
12381294
@ <li> %h(aBuiltinSkin[i].zDesc) &larr; <i>Currently in use</i>
12391295
}else{
@@ -1240,8 +1296,32 @@
12401296
char *zUrl = href("%R/skins?skin=%T", aBuiltinSkin[i].zLabel);
12411297
@ <li> %z(zUrl)%h(aBuiltinSkin[i].zDesc)</a>
12421298
}
12431299
}
12441300
@ </ul>
1301
+ if( iSkinSource<SKIN_FROM_CUSTOM ){
1302
+ @ <p>The current skin is selected by
1303
+ switch( iSkinSource ){
1304
+ case SKIN_FROM_DRAFT:
1305
+ @ the "debugN" prefix on the PATH_INFO portion of the URL.
1306
+ break;
1307
+ case SKIN_FROM_CMDLINE:
1308
+ @ the "--skin" command-line option on the Fossil server.
1309
+ break;
1310
+ case SKIN_FROM_CGI:
1311
+ @ the "skin:" property in the CGI script that runs the Fossil server.
1312
+ break;
1313
+ case SKIN_FROM_QPARAM:
1314
+ @ the "skin=NAME" query parameter on the URL.
1315
+ break;
1316
+ case SKIN_FROM_COOKIE:
1317
+ @ the "skin" property in the
1318
+ @ "%z(href("%R/fdscookie"))fossil_display_settings</a>" cookie.
1319
+ break;
1320
+ case SKIN_FROM_SETTING:
1321
+ @ the "default-skin" setting on the repository.
1322
+ break;
1323
+ }
1324
+ }
12451325
style_finish_page();
12461326
fossil_free(zBase);
12471327
}
12481328
--- src/skins.c
+++ src/skins.c
@@ -19,10 +19,17 @@
19 */
20 #include "config.h"
21 #include <assert.h>
22 #include "skins.h"
23
 
 
 
 
 
 
 
24 /*
25 ** An array of available built-in skins.
26 **
27 ** To add new built-in skins:
28 **
@@ -76,11 +83,28 @@
76 /*
77 ** Used by skin_use_alternative() to store the current skin rank skin
78 ** so that the /skins page can, if warranted, warn the user that skin
79 ** changes won't have any effect.
80 */
81 static int nSkinRank = 5;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
82
83 /*
84 ** Skin details are a set of key/value pairs that define display
85 ** attributes of the skin that cannot be easily specified using CSS
86 ** or that need to be known on the server-side.
@@ -125,40 +149,50 @@
125 ** former gets initialized before both URL parameters and the /draft
126 ** path determination).
127 **
128 ** The rankings were initially defined in
129 ** https://fossil-scm.org/forum/forumpost/caf8c9a8bb
130 ** and are:
131 **
132 ** 0) A skin name matching the glob draft[1-9] trumps everything else.
 
133 **
134 ** 1) The --skin flag or skin: CGI config setting.
 
135 **
136 ** 2) The "skin" display setting cookie or URL argument, in that
137 ** order. If the "skin" URL argument is provided and refers to a legal
138 ** skin then that will update the display cookie. If the skin name is
139 ** illegal it is silently ignored.
 
 
 
 
 
 
 
 
140 **
141 ** 3) Skin properties from the CONFIG db table
142 **
143 ** 4) Default skin.
144 **
145 ** As a special case, a NULL or empty name resets zAltSkinDir and
146 ** pAltSkin to 0 to indicate that the current config-side skin should
147 ** be used (rank 3, above), then returns 0.
148 */
149 char *skin_use_alternative(const char *zName, int rank){
150 int i;
151 Blob err = BLOB_INITIALIZER;
152 if(rank > nSkinRank) return 0;
153 nSkinRank = rank;
154 if( zName && 1==rank && strchr(zName, '/')!=0 ){
155 zAltSkinDir = fossil_strdup(zName);
 
156 return 0;
157 }
158 if( zName && sqlite3_strglob("draft[1-9]", zName)==0 ){
159 skin_use_draft(zName[5] - '0');
 
160 return 0;
161 }
162 if(!zName || !*zName){
163 pAltSkin = 0;
164 zAltSkinDir = 0;
@@ -165,10 +199,11 @@
165 return 0;
166 }
167 for(i=0; i<count(aBuiltinSkin); i++){
168 if( fossil_strcmp(aBuiltinSkin[i].zLabel, zName)==0 ){
169 pAltSkin = &aBuiltinSkin[i];
 
170 return 0;
171 }
172 }
173 blob_appendf(&err, "available skins: %s", aBuiltinSkin[0].zLabel);
174 for(i=1; i<count(aBuiltinSkin); i++){
@@ -179,24 +214,28 @@
179 }
180
181 /*
182 ** Look for the --skin command-line option and process it. Or
183 ** call fossil_fatal() if an unknown skin is specified.
 
 
 
184 */
185 void skin_override(void){
186 const char *zSkin = find_option("skin",0,1);
187 if( zSkin ){
188 char *zErr = skin_use_alternative(zSkin, 1);
189 if( zErr ) fossil_fatal("%s", zErr);
190 }
191 }
192
193 /*
194 ** Use one of the draft skins.
195 */
196 void skin_use_draft(int i){
197 iDraftSkin = i;
 
198 }
199
200 /*
201 ** The following routines return the various components of the skin
202 ** that should be used for the current run.
@@ -219,10 +258,24 @@
219 blob_read_from_file(&x, z, ExtFILE);
220 fossil_free(z);
221 return blob_str(&x);
222 }
223 fossil_free(z);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
224 }
225 if( pAltSkin ){
226 z = mprintf("skins/%s/%s.txt", pAltSkin->zLabel, zWhat);
227 zOut = builtin_text(z);
228 fossil_free(z);
@@ -230,10 +283,12 @@
230 zOut = db_get(zWhat, 0);
231 if( zOut==0 ){
232 z = mprintf("skins/default/%s.txt", zWhat);
233 zOut = builtin_text(z);
234 fossil_free(z);
 
 
235 }
236 }
237 return zOut;
238 }
239
@@ -1216,24 +1271,25 @@
1216 @ <p class="warning">Warning:
1217 if( iDraftSkin>0 ){
1218 @ you are using a draft skin,
1219 }else{
1220 @ this fossil instance was started with a hard-coded skin
1221 @ value,
1222 }
1223 @ which trumps any option selected below. A skin selected
1224 @ below will be recorded in your preference cookie
 
1225 @ but will not be used so long as the site has a
1226 @ higher-priority skin in place.
1227 @ </p>
1228 }
1229 @ <p>The following skins are available for this repository:</p>
1230 @ <ul>
1231 if( pAltSkin==0 && zAltSkinDir==0 && iDraftSkin==0 ){
1232 @ <li> Standard skin for this repository &larr; <i>Currently in use</i>
1233 }else{
1234 @ <li> %z(href("%R/skins?skin="))Standard skin for this repository</a>
1235 }
1236 for(i=0; i<count(aBuiltinSkin); i++){
1237 if( pAltSkin==&aBuiltinSkin[i] ){
1238 @ <li> %h(aBuiltinSkin[i].zDesc) &larr; <i>Currently in use</i>
1239 }else{
@@ -1240,8 +1296,32 @@
1240 char *zUrl = href("%R/skins?skin=%T", aBuiltinSkin[i].zLabel);
1241 @ <li> %z(zUrl)%h(aBuiltinSkin[i].zDesc)</a>
1242 }
1243 }
1244 @ </ul>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1245 style_finish_page();
1246 fossil_free(zBase);
1247 }
1248
--- src/skins.c
+++ src/skins.c
@@ -19,10 +19,17 @@
19 */
20 #include "config.h"
21 #include <assert.h>
22 #include "skins.h"
23
24 /*
25 ** SETTING: default-skin width=16
26 **
27 ** If the text value if this setting is the name of a built-in skin
28 ** then the named skin becomes the default skin for the repository.
29 */
30
31 /*
32 ** An array of available built-in skins.
33 **
34 ** To add new built-in skins:
35 **
@@ -76,11 +83,28 @@
83 /*
84 ** Used by skin_use_alternative() to store the current skin rank skin
85 ** so that the /skins page can, if warranted, warn the user that skin
86 ** changes won't have any effect.
87 */
88 static int nSkinRank = 6;
89
90 /*
91 ** How the specific skin being used was chosen
92 */
93 #if INTERFACE
94 #define SKIN_FROM_DRAFT 0 /* The "draftN" prefix on the PATH_INFO */
95 #define SKIN_FROM_CMDLINE 1 /* --skin option to server command-line */
96 #define SKIN_FROM_CGI 2 /* skin: parameter in CGI script */
97 #define SKIN_FROM_QPARAM 3 /* skin= query parameter */
98 #define SKIN_FROM_COOKIE 4 /* skin= from fossil_display_settings cookie*/
99 #define SKIN_FROM_SETTING 5 /* Built-in named by "default-skin" setting */
100 #define SKIN_FROM_CUSTOM 6 /* Skin values in CONFIG table */
101 #define SKIN_FROM_DEFAULT 7 /* The built-in named "default" */
102 #define SKIN_FROM_UNKNOWN 8 /* Do not yet know which skin to use */
103 #endif /* INTERFACE */
104 static int iSkinSource = SKIN_FROM_UNKNOWN;
105
106
107 /*
108 ** Skin details are a set of key/value pairs that define display
109 ** attributes of the skin that cannot be easily specified using CSS
110 ** or that need to be known on the server-side.
@@ -125,40 +149,50 @@
149 ** former gets initialized before both URL parameters and the /draft
150 ** path determination).
151 **
152 ** The rankings were initially defined in
153 ** https://fossil-scm.org/forum/forumpost/caf8c9a8bb
154 ** but where subsequently revised:
155 **
156 ** 0) A skin name matching the glob pattern "draft[1-9]" at the start of
157 ** the PATH_INFO.
158 **
159 ** 1) The --skin flag for commands like "fossil ui", "fossil server", or
160 ** "fossil http", or the "skin:" CGI config setting.
161 **
162 ** 2) The "skin" display setting cookie or URL argument, in that
163 ** order. If the "skin" URL argument is provided and refers to a legal
164 ** skin then that will update the display cookie. If the skin name is
165 ** illegal it is silently ignored.
166 **
167 ** 3) The built-in skin identfied by the "default-skin" setting, if such
168 ** a setting exists and matches one of the built-in skin names.
169 **
170 ** 4) Skin properties (settings "css", "details", "footer", "header",
171 ** and "js") from the CONFIG db table
172 **
173 ** 5) The built-in skin named "default"
174 **
175 ** The iSource integer privides additional detail about where the skin
 
 
176 **
177 ** As a special case, a NULL or empty name resets zAltSkinDir and
178 ** pAltSkin to 0 to indicate that the current config-side skin should
179 ** be used (rank 3, above), then returns 0.
180 */
181 char *skin_use_alternative(const char *zName, int rank, int iSource){
182 int i;
183 Blob err = BLOB_INITIALIZER;
184 if(rank > nSkinRank) return 0;
185 nSkinRank = rank;
186 if( zName && 1==rank && strchr(zName, '/')!=0 ){
187 zAltSkinDir = fossil_strdup(zName);
188 iSkinSource = iSource;
189 return 0;
190 }
191 if( zName && sqlite3_strglob("draft[1-9]", zName)==0 ){
192 skin_use_draft(zName[5] - '0');
193 iSkinSource = iSource;
194 return 0;
195 }
196 if(!zName || !*zName){
197 pAltSkin = 0;
198 zAltSkinDir = 0;
@@ -165,10 +199,11 @@
199 return 0;
200 }
201 for(i=0; i<count(aBuiltinSkin); i++){
202 if( fossil_strcmp(aBuiltinSkin[i].zLabel, zName)==0 ){
203 pAltSkin = &aBuiltinSkin[i];
204 iSkinSource = iSource;
205 return 0;
206 }
207 }
208 blob_appendf(&err, "available skins: %s", aBuiltinSkin[0].zLabel);
209 for(i=1; i<count(aBuiltinSkin); i++){
@@ -179,24 +214,28 @@
214 }
215
216 /*
217 ** Look for the --skin command-line option and process it. Or
218 ** call fossil_fatal() if an unknown skin is specified.
219 **
220 ** This routine is called during command-line parsing for commands
221 ** like "fossil ui" and "fossil http".
222 */
223 void skin_override(void){
224 const char *zSkin = find_option("skin",0,1);
225 if( zSkin ){
226 char *zErr = skin_use_alternative(zSkin, 1, SKIN_FROM_CMDLINE);
227 if( zErr ) fossil_fatal("%s", zErr);
228 }
229 }
230
231 /*
232 ** Use one of the draft skins.
233 */
234 void skin_use_draft(int i){
235 iDraftSkin = i;
236 iSkinSource = SKIN_FROM_DRAFT;
237 }
238
239 /*
240 ** The following routines return the various components of the skin
241 ** that should be used for the current run.
@@ -219,10 +258,24 @@
258 blob_read_from_file(&x, z, ExtFILE);
259 fossil_free(z);
260 return blob_str(&x);
261 }
262 fossil_free(z);
263 }
264 if( iSkinSource==SKIN_FROM_UNKNOWN ){
265 const char *zDflt = db_get("default-skin", 0);
266 iSkinSource = SKIN_FROM_DEFAULT;
267 if( zDflt!=0 ){
268 int i;
269 for(i=0; i<count(aBuiltinSkin); i++){
270 if( fossil_strcmp(aBuiltinSkin[i].zLabel, zDflt)==0 ){
271 pAltSkin = &aBuiltinSkin[i];
272 iSkinSource = SKIN_FROM_SETTING;
273 break;
274 }
275 }
276 }
277 }
278 if( pAltSkin ){
279 z = mprintf("skins/%s/%s.txt", pAltSkin->zLabel, zWhat);
280 zOut = builtin_text(z);
281 fossil_free(z);
@@ -230,10 +283,12 @@
283 zOut = db_get(zWhat, 0);
284 if( zOut==0 ){
285 z = mprintf("skins/default/%s.txt", zWhat);
286 zOut = builtin_text(z);
287 fossil_free(z);
288 }else{
289 iSkinSource = SKIN_FROM_CUSTOM;
290 }
291 }
292 return zOut;
293 }
294
@@ -1216,24 +1271,25 @@
1271 @ <p class="warning">Warning:
1272 if( iDraftSkin>0 ){
1273 @ you are using a draft skin,
1274 }else{
1275 @ this fossil instance was started with a hard-coded skin
1276 @ value
1277 }
1278 @ which supercedes any option selected below. A skin selected
1279 @ below will be recorded in your
1280 @ "%z(href("%R/fdscookie"))fossil_display_settings</a>" cookie
1281 @ but will not be used so long as the site has a
1282 @ higher-priority skin in place.
1283 @ </p>
1284 }
1285 @ <p>The following skins are available for this repository:</p>
1286 @ <ul>
1287 if( pAltSkin==0 && zAltSkinDir==0 && iDraftSkin==0 ){
1288 @ <li> Custom skin for this repository &larr; <i>Currently in use</i>
1289 }else{
1290 @ <li> %z(href("%R/skins?skin="))Custom skin for this repository</a>
1291 }
1292 for(i=0; i<count(aBuiltinSkin); i++){
1293 if( pAltSkin==&aBuiltinSkin[i] ){
1294 @ <li> %h(aBuiltinSkin[i].zDesc) &larr; <i>Currently in use</i>
1295 }else{
@@ -1240,8 +1296,32 @@
1296 char *zUrl = href("%R/skins?skin=%T", aBuiltinSkin[i].zLabel);
1297 @ <li> %z(zUrl)%h(aBuiltinSkin[i].zDesc)</a>
1298 }
1299 }
1300 @ </ul>
1301 if( iSkinSource<SKIN_FROM_CUSTOM ){
1302 @ <p>The current skin is selected by
1303 switch( iSkinSource ){
1304 case SKIN_FROM_DRAFT:
1305 @ the "debugN" prefix on the PATH_INFO portion of the URL.
1306 break;
1307 case SKIN_FROM_CMDLINE:
1308 @ the "--skin" command-line option on the Fossil server.
1309 break;
1310 case SKIN_FROM_CGI:
1311 @ the "skin:" property in the CGI script that runs the Fossil server.
1312 break;
1313 case SKIN_FROM_QPARAM:
1314 @ the "skin=NAME" query parameter on the URL.
1315 break;
1316 case SKIN_FROM_COOKIE:
1317 @ the "skin" property in the
1318 @ "%z(href("%R/fdscookie"))fossil_display_settings</a>" cookie.
1319 break;
1320 case SKIN_FROM_SETTING:
1321 @ the "default-skin" setting on the repository.
1322 break;
1323 }
1324 }
1325 style_finish_page();
1326 fossil_free(zBase);
1327 }
1328

Keyboard Shortcuts

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