Fossil SCM

Added new config option with the rather unwieldy name 'anon-login-enable-captcha-filler'

stephan 2009-12-07 22:42 trunk
Commit 00b778bd585d92646741bca9755cbe6fa7cf4567
3 files changed +7 +10 -4 +35 -24
+7
--- src/db.c
+++ src/db.c
@@ -1432,10 +1432,16 @@
14321432
** values. With just a property name it shows the value of that property.
14331433
** With a value argument it changes the property for the current repository.
14341434
**
14351435
** The "unset" command clears a property setting.
14361436
**
1437
+**
1438
+** anon-login-enable-captcha-filler
1439
+** If enabled, the Login page will provide a button
1440
+** which uses JavaScript to fill out the captcha for
1441
+** the user. (Most bots cannot use JavaScript.)
1442
+**
14371443
** autosync If enabled, automatically pull prior to
14381444
** commit or update and automatically push
14391445
** after commit or tag or branch creation.
14401446
**
14411447
** diff-command External command to run when performing a diff.
@@ -1477,10 +1483,11 @@
14771483
** Defaults to "start" on windows, "open" on Mac,
14781484
** and "firefox" on Unix.
14791485
*/
14801486
void setting_cmd(void){
14811487
static const char *azName[] = {
1488
+ "anon-login-enable-captcha-filler",
14821489
"autosync",
14831490
"diff-command",
14841491
"dont-push",
14851492
"editor",
14861493
"gdiff-command",
14871494
--- src/db.c
+++ src/db.c
@@ -1432,10 +1432,16 @@
1432 ** values. With just a property name it shows the value of that property.
1433 ** With a value argument it changes the property for the current repository.
1434 **
1435 ** The "unset" command clears a property setting.
1436 **
 
 
 
 
 
 
1437 ** autosync If enabled, automatically pull prior to
1438 ** commit or update and automatically push
1439 ** after commit or tag or branch creation.
1440 **
1441 ** diff-command External command to run when performing a diff.
@@ -1477,10 +1483,11 @@
1477 ** Defaults to "start" on windows, "open" on Mac,
1478 ** and "firefox" on Unix.
1479 */
1480 void setting_cmd(void){
1481 static const char *azName[] = {
 
1482 "autosync",
1483 "diff-command",
1484 "dont-push",
1485 "editor",
1486 "gdiff-command",
1487
--- src/db.c
+++ src/db.c
@@ -1432,10 +1432,16 @@
1432 ** values. With just a property name it shows the value of that property.
1433 ** With a value argument it changes the property for the current repository.
1434 **
1435 ** The "unset" command clears a property setting.
1436 **
1437 **
1438 ** anon-login-enable-captcha-filler
1439 ** If enabled, the Login page will provide a button
1440 ** which uses JavaScript to fill out the captcha for
1441 ** the user. (Most bots cannot use JavaScript.)
1442 **
1443 ** autosync If enabled, automatically pull prior to
1444 ** commit or update and automatically push
1445 ** after commit or tag or branch creation.
1446 **
1447 ** diff-command External command to run when performing a diff.
@@ -1477,10 +1483,11 @@
1483 ** Defaults to "start" on windows, "open" on Mac,
1484 ** and "firefox" on Unix.
1485 */
1486 void setting_cmd(void){
1487 static const char *azName[] = {
1488 "anon-login-enable-captcha-filler",
1489 "autosync",
1490 "diff-command",
1491 "dont-push",
1492 "editor",
1493 "gdiff-command",
1494
+10 -4
--- src/login.c
+++ src/login.c
@@ -225,11 +225,11 @@
225225
@ <td><input type="text" id="u" name="u" value="" size=30></td>
226226
}
227227
@ </tr>
228228
@ <tr>
229229
@ <td align="right">Password:</td>
230
- @ <td><input type="password" name="p" value="" size=30></td>
230
+ @ <td><input type="password" id="p" name="p" value="" size=30></td>
231231
@ </tr>
232232
if( g.zLogin==0 ){
233233
zAnonPw = db_text(0, "SELECT pw FROM user"
234234
" WHERE login='anonymous'"
235235
" AND cap!=''");
@@ -250,18 +250,24 @@
250250
@ "Login" button. Your user name will be stored in a browser cookie.
251251
@ You must configure your web browser to accept cookies in order for
252252
@ the login to take.</p>
253253
if( zAnonPw ){
254254
unsigned int uSeed = captcha_seed();
255
- char *zCaptcha = captcha_render(captcha_decode(uSeed));
255
+ char const * zDecoded = captcha_decode(uSeed);
256
+ int iAllowPasswordFill = db_get_boolean( "anon-login-enable-captcha-filler", 0 );
257
+ char *zCaptcha = captcha_render(zDecoded);
256258
257
- @ <input type="hidden" name="cs" value="%u(uSeed)">
259
+ @ <input type="hidden" name="cs" value="%u(uSeed)"/>
258260
@ <p>Visitors may enter <b>anonymous</b> as the user-ID with
259261
@ the 8-character hexadecimal password shown below:</p>
260262
@ <center><table border="1" cellpadding="10"><tr><td><pre>
261263
@ %s(zCaptcha)
262
- @ </pre></td></tr></table></center>
264
+ @ </pre></td></tr></table>
265
+ if( iAllowPasswordFill ) {
266
+ @ <input type="button" value="Fill out captcha" onclick="document.getElementById('u').value='anonymous'; document.getElementById('p').value='%s(zDecoded)';"/>
267
+ }
268
+ @ </center>
263269
free(zCaptcha);
264270
}
265271
if( g.zLogin ){
266272
@ <br clear="both"><hr>
267273
@ <p>To log off the system (and delete your login cookie)
268274
--- src/login.c
+++ src/login.c
@@ -225,11 +225,11 @@
225 @ <td><input type="text" id="u" name="u" value="" size=30></td>
226 }
227 @ </tr>
228 @ <tr>
229 @ <td align="right">Password:</td>
230 @ <td><input type="password" name="p" value="" size=30></td>
231 @ </tr>
232 if( g.zLogin==0 ){
233 zAnonPw = db_text(0, "SELECT pw FROM user"
234 " WHERE login='anonymous'"
235 " AND cap!=''");
@@ -250,18 +250,24 @@
250 @ "Login" button. Your user name will be stored in a browser cookie.
251 @ You must configure your web browser to accept cookies in order for
252 @ the login to take.</p>
253 if( zAnonPw ){
254 unsigned int uSeed = captcha_seed();
255 char *zCaptcha = captcha_render(captcha_decode(uSeed));
 
 
256
257 @ <input type="hidden" name="cs" value="%u(uSeed)">
258 @ <p>Visitors may enter <b>anonymous</b> as the user-ID with
259 @ the 8-character hexadecimal password shown below:</p>
260 @ <center><table border="1" cellpadding="10"><tr><td><pre>
261 @ %s(zCaptcha)
262 @ </pre></td></tr></table></center>
 
 
 
 
263 free(zCaptcha);
264 }
265 if( g.zLogin ){
266 @ <br clear="both"><hr>
267 @ <p>To log off the system (and delete your login cookie)
268
--- src/login.c
+++ src/login.c
@@ -225,11 +225,11 @@
225 @ <td><input type="text" id="u" name="u" value="" size=30></td>
226 }
227 @ </tr>
228 @ <tr>
229 @ <td align="right">Password:</td>
230 @ <td><input type="password" id="p" name="p" value="" size=30></td>
231 @ </tr>
232 if( g.zLogin==0 ){
233 zAnonPw = db_text(0, "SELECT pw FROM user"
234 " WHERE login='anonymous'"
235 " AND cap!=''");
@@ -250,18 +250,24 @@
250 @ "Login" button. Your user name will be stored in a browser cookie.
251 @ You must configure your web browser to accept cookies in order for
252 @ the login to take.</p>
253 if( zAnonPw ){
254 unsigned int uSeed = captcha_seed();
255 char const * zDecoded = captcha_decode(uSeed);
256 int iAllowPasswordFill = db_get_boolean( "anon-login-enable-captcha-filler", 0 );
257 char *zCaptcha = captcha_render(zDecoded);
258
259 @ <input type="hidden" name="cs" value="%u(uSeed)"/>
260 @ <p>Visitors may enter <b>anonymous</b> as the user-ID with
261 @ the 8-character hexadecimal password shown below:</p>
262 @ <center><table border="1" cellpadding="10"><tr><td><pre>
263 @ %s(zCaptcha)
264 @ </pre></td></tr></table>
265 if( iAllowPasswordFill ) {
266 @ <input type="button" value="Fill out captcha" onclick="document.getElementById('u').value='anonymous'; document.getElementById('p').value='%s(zDecoded)';"/>
267 }
268 @ </center>
269 free(zCaptcha);
270 }
271 if( g.zLogin ){
272 @ <br clear="both"><hr>
273 @ <p>To log off the system (and delete your login cookie)
274
+35 -24
--- src/setup.c
+++ src/setup.c
@@ -269,10 +269,11 @@
269269
** modified user record. After writing the user record, redirect
270270
** to the page that displays a list of users.
271271
*/
272272
doWrite = cgi_all("login","info","pw") && !higherUser;
273273
if( doWrite ){
274
+ char const * anonLoginCheckedbox = PD("anonymousEnableAutofill",0);
274275
char zCap[50];
275276
int i = 0;
276277
int aa = P("aa")!=0;
277278
int ad = P("ad")!=0;
278279
int ae = P("ae")!=0;
@@ -337,10 +338,16 @@
337338
db_multi_exec(
338339
"REPLACE INTO user(uid,login,info,pw,cap) "
339340
"VALUES(nullif(%d,0),%Q,%Q,%Q,'%s')",
340341
uid, P("login"), P("info"), zPw, zCap
341342
);
343
+ if( anonLoginCheckedbox && (*anonLoginCheckedbox) ){
344
+ db_set( "anon-login-enable-captcha-filler", "on", 0 );
345
+ }
346
+ else{
347
+ db_set( "anon-login-enable-captcha-filler", "off", 0 );
348
+ }
342349
cgi_redirect("setup_ulist");
343350
return;
344351
}
345352
346353
/* Load the existing information about the user, if any
@@ -445,39 +452,43 @@
445452
@ <tr>
446453
@ <td align="right" valign="top">Capabilities:</td>
447454
@ <td>
448455
#define B(x) inherit[x]
449456
if( g.okSetup ){
450
- @ <input type="checkbox" name="as"%s(oas)>%s(B('s'))Setup</input><br>
451
- }
452
- @ <input type="checkbox" name="aa"%s(oaa)>%s(B('a'))Admin</input><br>
453
- @ <input type="checkbox" name="ad"%s(oad)>%s(B('d'))Delete</input><br>
454
- @ <input type="checkbox" name="ae"%s(oae)>%s(B('e'))Email</input><br>
455
- @ <input type="checkbox" name="ap"%s(oap)>%s(B('p'))Password</input><br>
456
- @ <input type="checkbox" name="ai"%s(oai)>%s(B('i'))Check-In</input><br>
457
- @ <input type="checkbox" name="ao"%s(oao)>%s(B('o'))Check-Out</input><br>
458
- @ <input type="checkbox" name="ah"%s(oah)>%s(B('h'))History</input><br>
459
- @ <input type="checkbox" name="au"%s(oau)>%s(B('u'))Reader</input><br>
460
- @ <input type="checkbox" name="av"%s(oav)>%s(B('v'))Developer</input><br>
461
- @ <input type="checkbox" name="ag"%s(oag)>%s(B('g'))Clone</input><br>
462
- @ <input type="checkbox" name="aj"%s(oaj)>%s(B('j'))Read Wiki</input><br>
463
- @ <input type="checkbox" name="af"%s(oaf)>%s(B('f'))New Wiki</input><br>
464
- @ <input type="checkbox" name="am"%s(oam)>%s(B('m'))Append Wiki</input><br>
465
- @ <input type="checkbox" name="ak"%s(oak)>%s(B('k'))Write Wiki</input><br>
466
- @ <input type="checkbox" name="ar"%s(oar)>%s(B('r'))Read Tkt</input><br>
467
- @ <input type="checkbox" name="an"%s(oan)>%s(B('n'))New Tkt</input><br>
468
- @ <input type="checkbox" name="ac"%s(oac)>%s(B('c'))Append Tkt</input><br>
469
- @ <input type="checkbox" name="aw"%s(oaw)>%s(B('w'))Write Tkt</input><br>
470
- @ <input type="checkbox" name="at"%s(oat)>%s(B('t'))Tkt Report</input><br>
471
- @ <input type="checkbox" name="az"%s(oaz)>%s(B('z'))Download Zip</input>
457
+ @ <input type="checkbox" name="as"%s(oas)/>%s(B('s'))Setup<br>
458
+ }
459
+ @ <input type="checkbox" name="aa"%s(oaa)/>%s(B('a'))Admin<br>
460
+ @ <input type="checkbox" name="ad"%s(oad)/>%s(B('d'))Delete<br>
461
+ @ <input type="checkbox" name="ae"%s(oae)/>%s(B('e'))Email<br>
462
+ @ <input type="checkbox" name="ap"%s(oap)/>%s(B('p'))Password<br>
463
+ @ <input type="checkbox" name="ai"%s(oai)/>%s(B('i'))Check-In<br>
464
+ @ <input type="checkbox" name="ao"%s(oao)/>%s(B('o'))Check-Out<br>
465
+ @ <input type="checkbox" name="ah"%s(oah)/>%s(B('h'))History<br>
466
+ @ <input type="checkbox" name="au"%s(oau)/>%s(B('u'))Reader<br>
467
+ @ <input type="checkbox" name="av"%s(oav)/>%s(B('v'))Developer<br>
468
+ @ <input type="checkbox" name="ag"%s(oag)/>%s(B('g'))Clone<br>
469
+ @ <input type="checkbox" name="aj"%s(oaj)/>%s(B('j'))Read Wiki<br>
470
+ @ <input type="checkbox" name="af"%s(oaf)/>%s(B('f'))New Wiki<br>
471
+ @ <input type="checkbox" name="am"%s(oam)/>%s(B('m'))Append Wiki<br>
472
+ @ <input type="checkbox" name="ak"%s(oak)/>%s(B('k'))Write Wiki<br>
473
+ @ <input type="checkbox" name="ar"%s(oar)/>%s(B('r'))Read Tkt<br>
474
+ @ <input type="checkbox" name="an"%s(oan)/>%s(B('n'))New Tkt<br>
475
+ @ <input type="checkbox" name="ac"%s(oac)/>%s(B('c'))Append Tkt<br>
476
+ @ <input type="checkbox" name="aw"%s(oaw)/>%s(B('w'))Write Tkt<br>
477
+ @ <input type="checkbox" name="at"%s(oat)/>%s(B('t'))Tkt Report<br>
478
+ @ <input type="checkbox" name="az"%s(oaz)/>%s(B('z'))Download Zip
472479
@ </td>
473480
@ </tr>
474481
@ <tr>
475482
@ <td align="right">Password:</td>
476483
if( strcmp(zLogin, "anonymous")==0 ){
484
+ int enabled = db_get_boolean( "anon-login-enable-captcha-filler", 0 );
485
+ char const * checked = enabled ? "checked=\"checked\"" : "";
477486
/* User the password for "anonymous" as cleartext */
478
- @ <td><input type="text" name="pw" value="%h(zPw)"></td>
487
+ @ <td><input type="text" name="pw" value="%h(zPw)"/>
488
+ @ <br/>Enable password-filler button for anonymous login? <input type="checkbox" name="anonymousEnableAutofill" %s(checked)/><br/>
489
+ @ </td>
479490
}else if( zPw[0] ){
480491
/* Obscure the password for all other users */
481492
@ <td><input type="password" name="pw" value="**********"></td>
482493
}else{
483494
/* Show an empty password as an empty input field */
@@ -618,11 +629,11 @@
618629
@ with check-in privileges. When adding new trusted users, simply
619630
@ select the <b>Developer</b> privilege to cause the new user to inherit
620631
@ all privileges of the "developer" user. Similarly, the "<b>reader</b>"
621632
@ user is a template for users who are allowed more access than anonymous,
622633
@ but less than a developer.
623
- @ </li></p>
634
+ @ </p></li>
624635
@ </ul>
625636
@ </form>
626637
style_footer();
627638
}
628639
629640
--- src/setup.c
+++ src/setup.c
@@ -269,10 +269,11 @@
269 ** modified user record. After writing the user record, redirect
270 ** to the page that displays a list of users.
271 */
272 doWrite = cgi_all("login","info","pw") && !higherUser;
273 if( doWrite ){
 
274 char zCap[50];
275 int i = 0;
276 int aa = P("aa")!=0;
277 int ad = P("ad")!=0;
278 int ae = P("ae")!=0;
@@ -337,10 +338,16 @@
337 db_multi_exec(
338 "REPLACE INTO user(uid,login,info,pw,cap) "
339 "VALUES(nullif(%d,0),%Q,%Q,%Q,'%s')",
340 uid, P("login"), P("info"), zPw, zCap
341 );
 
 
 
 
 
 
342 cgi_redirect("setup_ulist");
343 return;
344 }
345
346 /* Load the existing information about the user, if any
@@ -445,39 +452,43 @@
445 @ <tr>
446 @ <td align="right" valign="top">Capabilities:</td>
447 @ <td>
448 #define B(x) inherit[x]
449 if( g.okSetup ){
450 @ <input type="checkbox" name="as"%s(oas)>%s(B('s'))Setup</input><br>
451 }
452 @ <input type="checkbox" name="aa"%s(oaa)>%s(B('a'))Admin</input><br>
453 @ <input type="checkbox" name="ad"%s(oad)>%s(B('d'))Delete</input><br>
454 @ <input type="checkbox" name="ae"%s(oae)>%s(B('e'))Email</input><br>
455 @ <input type="checkbox" name="ap"%s(oap)>%s(B('p'))Password</input><br>
456 @ <input type="checkbox" name="ai"%s(oai)>%s(B('i'))Check-In</input><br>
457 @ <input type="checkbox" name="ao"%s(oao)>%s(B('o'))Check-Out</input><br>
458 @ <input type="checkbox" name="ah"%s(oah)>%s(B('h'))History</input><br>
459 @ <input type="checkbox" name="au"%s(oau)>%s(B('u'))Reader</input><br>
460 @ <input type="checkbox" name="av"%s(oav)>%s(B('v'))Developer</input><br>
461 @ <input type="checkbox" name="ag"%s(oag)>%s(B('g'))Clone</input><br>
462 @ <input type="checkbox" name="aj"%s(oaj)>%s(B('j'))Read Wiki</input><br>
463 @ <input type="checkbox" name="af"%s(oaf)>%s(B('f'))New Wiki</input><br>
464 @ <input type="checkbox" name="am"%s(oam)>%s(B('m'))Append Wiki</input><br>
465 @ <input type="checkbox" name="ak"%s(oak)>%s(B('k'))Write Wiki</input><br>
466 @ <input type="checkbox" name="ar"%s(oar)>%s(B('r'))Read Tkt</input><br>
467 @ <input type="checkbox" name="an"%s(oan)>%s(B('n'))New Tkt</input><br>
468 @ <input type="checkbox" name="ac"%s(oac)>%s(B('c'))Append Tkt</input><br>
469 @ <input type="checkbox" name="aw"%s(oaw)>%s(B('w'))Write Tkt</input><br>
470 @ <input type="checkbox" name="at"%s(oat)>%s(B('t'))Tkt Report</input><br>
471 @ <input type="checkbox" name="az"%s(oaz)>%s(B('z'))Download Zip</input>
472 @ </td>
473 @ </tr>
474 @ <tr>
475 @ <td align="right">Password:</td>
476 if( strcmp(zLogin, "anonymous")==0 ){
 
 
477 /* User the password for "anonymous" as cleartext */
478 @ <td><input type="text" name="pw" value="%h(zPw)"></td>
 
 
479 }else if( zPw[0] ){
480 /* Obscure the password for all other users */
481 @ <td><input type="password" name="pw" value="**********"></td>
482 }else{
483 /* Show an empty password as an empty input field */
@@ -618,11 +629,11 @@
618 @ with check-in privileges. When adding new trusted users, simply
619 @ select the <b>Developer</b> privilege to cause the new user to inherit
620 @ all privileges of the "developer" user. Similarly, the "<b>reader</b>"
621 @ user is a template for users who are allowed more access than anonymous,
622 @ but less than a developer.
623 @ </li></p>
624 @ </ul>
625 @ </form>
626 style_footer();
627 }
628
629
--- src/setup.c
+++ src/setup.c
@@ -269,10 +269,11 @@
269 ** modified user record. After writing the user record, redirect
270 ** to the page that displays a list of users.
271 */
272 doWrite = cgi_all("login","info","pw") && !higherUser;
273 if( doWrite ){
274 char const * anonLoginCheckedbox = PD("anonymousEnableAutofill",0);
275 char zCap[50];
276 int i = 0;
277 int aa = P("aa")!=0;
278 int ad = P("ad")!=0;
279 int ae = P("ae")!=0;
@@ -337,10 +338,16 @@
338 db_multi_exec(
339 "REPLACE INTO user(uid,login,info,pw,cap) "
340 "VALUES(nullif(%d,0),%Q,%Q,%Q,'%s')",
341 uid, P("login"), P("info"), zPw, zCap
342 );
343 if( anonLoginCheckedbox && (*anonLoginCheckedbox) ){
344 db_set( "anon-login-enable-captcha-filler", "on", 0 );
345 }
346 else{
347 db_set( "anon-login-enable-captcha-filler", "off", 0 );
348 }
349 cgi_redirect("setup_ulist");
350 return;
351 }
352
353 /* Load the existing information about the user, if any
@@ -445,39 +452,43 @@
452 @ <tr>
453 @ <td align="right" valign="top">Capabilities:</td>
454 @ <td>
455 #define B(x) inherit[x]
456 if( g.okSetup ){
457 @ <input type="checkbox" name="as"%s(oas)/>%s(B('s'))Setup<br>
458 }
459 @ <input type="checkbox" name="aa"%s(oaa)/>%s(B('a'))Admin<br>
460 @ <input type="checkbox" name="ad"%s(oad)/>%s(B('d'))Delete<br>
461 @ <input type="checkbox" name="ae"%s(oae)/>%s(B('e'))Email<br>
462 @ <input type="checkbox" name="ap"%s(oap)/>%s(B('p'))Password<br>
463 @ <input type="checkbox" name="ai"%s(oai)/>%s(B('i'))Check-In<br>
464 @ <input type="checkbox" name="ao"%s(oao)/>%s(B('o'))Check-Out<br>
465 @ <input type="checkbox" name="ah"%s(oah)/>%s(B('h'))History<br>
466 @ <input type="checkbox" name="au"%s(oau)/>%s(B('u'))Reader<br>
467 @ <input type="checkbox" name="av"%s(oav)/>%s(B('v'))Developer<br>
468 @ <input type="checkbox" name="ag"%s(oag)/>%s(B('g'))Clone<br>
469 @ <input type="checkbox" name="aj"%s(oaj)/>%s(B('j'))Read Wiki<br>
470 @ <input type="checkbox" name="af"%s(oaf)/>%s(B('f'))New Wiki<br>
471 @ <input type="checkbox" name="am"%s(oam)/>%s(B('m'))Append Wiki<br>
472 @ <input type="checkbox" name="ak"%s(oak)/>%s(B('k'))Write Wiki<br>
473 @ <input type="checkbox" name="ar"%s(oar)/>%s(B('r'))Read Tkt<br>
474 @ <input type="checkbox" name="an"%s(oan)/>%s(B('n'))New Tkt<br>
475 @ <input type="checkbox" name="ac"%s(oac)/>%s(B('c'))Append Tkt<br>
476 @ <input type="checkbox" name="aw"%s(oaw)/>%s(B('w'))Write Tkt<br>
477 @ <input type="checkbox" name="at"%s(oat)/>%s(B('t'))Tkt Report<br>
478 @ <input type="checkbox" name="az"%s(oaz)/>%s(B('z'))Download Zip
479 @ </td>
480 @ </tr>
481 @ <tr>
482 @ <td align="right">Password:</td>
483 if( strcmp(zLogin, "anonymous")==0 ){
484 int enabled = db_get_boolean( "anon-login-enable-captcha-filler", 0 );
485 char const * checked = enabled ? "checked=\"checked\"" : "";
486 /* User the password for "anonymous" as cleartext */
487 @ <td><input type="text" name="pw" value="%h(zPw)"/>
488 @ <br/>Enable password-filler button for anonymous login? <input type="checkbox" name="anonymousEnableAutofill" %s(checked)/><br/>
489 @ </td>
490 }else if( zPw[0] ){
491 /* Obscure the password for all other users */
492 @ <td><input type="password" name="pw" value="**********"></td>
493 }else{
494 /* Show an empty password as an empty input field */
@@ -618,11 +629,11 @@
629 @ with check-in privileges. When adding new trusted users, simply
630 @ select the <b>Developer</b> privilege to cause the new user to inherit
631 @ all privileges of the "developer" user. Similarly, the "<b>reader</b>"
632 @ user is a template for users who are allowed more access than anonymous,
633 @ but less than a developer.
634 @ </p></li>
635 @ </ul>
636 @ </form>
637 style_footer();
638 }
639
640

Keyboard Shortcuts

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