Fossil SCM

merge trunk

jan.nijtmans 2012-11-27 09:10 UTC convert_before_commit_v2 merge
Commit 43caa73788d12261569591d0b3d28ca0d0dffb9b
+2 -1
--- src/add.c
+++ src/add.c
@@ -138,11 +138,12 @@
138138
int vid, /* Add to this VFILE */
139139
int caseSensitive /* True if filenames are case sensitive */
140140
){
141141
const char *zCollate = caseSensitive ? "binary" : "nocase";
142142
if( !file_is_simple_pathname(zPath) ){
143
- fossil_fatal("filename contains illegal characters: %s", zPath);
143
+ fossil_warning("filename contains illegal characters: %s", zPath);
144
+ return 0;
144145
}
145146
if( db_exists("SELECT 1 FROM vfile"
146147
" WHERE pathname=%Q COLLATE %s", zPath, zCollate) ){
147148
db_multi_exec("UPDATE vfile SET deleted=0"
148149
" WHERE pathname=%Q COLLATE %s", zPath, zCollate);
149150
--- src/add.c
+++ src/add.c
@@ -138,11 +138,12 @@
138 int vid, /* Add to this VFILE */
139 int caseSensitive /* True if filenames are case sensitive */
140 ){
141 const char *zCollate = caseSensitive ? "binary" : "nocase";
142 if( !file_is_simple_pathname(zPath) ){
143 fossil_fatal("filename contains illegal characters: %s", zPath);
 
144 }
145 if( db_exists("SELECT 1 FROM vfile"
146 " WHERE pathname=%Q COLLATE %s", zPath, zCollate) ){
147 db_multi_exec("UPDATE vfile SET deleted=0"
148 " WHERE pathname=%Q COLLATE %s", zPath, zCollate);
149
--- src/add.c
+++ src/add.c
@@ -138,11 +138,12 @@
138 int vid, /* Add to this VFILE */
139 int caseSensitive /* True if filenames are case sensitive */
140 ){
141 const char *zCollate = caseSensitive ? "binary" : "nocase";
142 if( !file_is_simple_pathname(zPath) ){
143 fossil_warning("filename contains illegal characters: %s", zPath);
144 return 0;
145 }
146 if( db_exists("SELECT 1 FROM vfile"
147 " WHERE pathname=%Q COLLATE %s", zPath, zCollate) ){
148 db_multi_exec("UPDATE vfile SET deleted=0"
149 " WHERE pathname=%Q COLLATE %s", zPath, zCollate);
150
+16 -8
--- src/attach.c
+++ src/attach.c
@@ -71,10 +71,11 @@
7171
const char *zFilename = db_column_text(&q, 3);
7272
const char *zComment = db_column_text(&q, 4);
7373
const char *zUser = db_column_text(&q, 5);
7474
const char *zUuid = db_column_text(&q, 6);
7575
int attachid = db_column_int(&q, 7);
76
+ const char *zDispUser = zUser && zUser[0] ? zUser : "anonymous";
7677
int i;
7778
char *zUrlTail;
7879
for(i=0; zFilename[i]; i++){
7980
if( zFilename[i]=='/' && zFilename[i+1]!=0 ){
8081
zFilename = &zFilename[i+1];
@@ -115,11 +116,11 @@
115116
@ Deleted
116117
}else {
117118
@ Added
118119
}
119120
}
120
- @ by %h(zUser) on
121
+ @ by %h(zDispUser) on
121122
hyperlink_to_date(zDate, ".");
122123
free(zUrlTail);
123124
}
124125
db_finalize(&q);
125126
@ </ol>
@@ -235,10 +236,11 @@
235236
const char *aContent = P("f");
236237
const char *zName = PD("f:filename","unknown");
237238
const char *zTarget;
238239
const char *zTargetType;
239240
int szContent = atoi(PD("f:bytes","0"));
241
+ int goodCaptcha = 1;
240242
241243
if( P("cancel") ) cgi_redirect(zFrom);
242244
if( zPage && zTkt ) fossil_redirect_home();
243245
if( zPage==0 && zTkt==0 ) fossil_redirect_home();
244246
login_check_credentials();
@@ -263,11 +265,11 @@
263265
}
264266
if( zFrom==0 ) zFrom = mprintf("%s/home", g.zTop);
265267
if( P("cancel") ){
266268
cgi_redirect(zFrom);
267269
}
268
- if( P("ok") && szContent>0 ){
270
+ if( P("ok") && szContent>0 && (goodCaptcha = captcha_is_correct()) ){
269271
Blob content;
270272
Blob manifest;
271273
Blob cksum;
272274
char *zUUID;
273275
const char *zComment;
@@ -316,13 +318,16 @@
316318
assert( blob_is_reset(&manifest) );
317319
db_end_transaction(0);
318320
cgi_redirect(zFrom);
319321
}
320322
style_header("Add Attachment");
323
+ if( !goodCaptcha ){
324
+ @ <p class="generalError">Error: Incorrect security code.</p>
325
+ }
321326
@ <h2>Add Attachment To %s(zTargetType)</h2>
322
- @ <form action="%s(g.zTop)/attachadd" method="post"
323
- @ enctype="multipart/form-data"><div>
327
+ form_begin("enctype='multipart/form-data'", "%R/attachadd");
328
+ @ <div>
324329
@ File to Attach:
325330
@ <input type="file" name="f" size="60" /><br />
326331
@ Description:<br />
327332
@ <textarea name="comment" cols="80" rows="5" wrap="virtual"></textarea><br />
328333
if( zTkt ){
@@ -331,11 +336,13 @@
331336
@ <input type="hidden" name="page" value="%h(zPage)" />
332337
}
333338
@ <input type="hidden" name="from" value="%h(zFrom)" />
334339
@ <input type="submit" name="ok" value="Add Attachment" />
335340
@ <input type="submit" name="cancel" value="Cancel" />
336
- @ </div></form>
341
+ @ </div>
342
+ captcha_generate();
343
+ @ </form>
337344
style_footer();
338345
}
339346
340347
/*
341348
** WEBPAGE: ainfo
@@ -432,11 +439,11 @@
432439
}
433440
434441
if( P("del")
435442
&& ((zTktUuid && g.perm.WrTkt) || (zWikiName && g.perm.WrWiki))
436443
){
437
- @ <form method="post" action="%R/ainfo/%s(zUuid)">
444
+ form_begin(0, "%R/ainfo/%s", zUuid);
438445
@ <p>Confirm you want to delete the attachment shown below.
439446
@ <input type="submit" name="confirm" value="Confirm">
440447
@ </form>
441448
}
442449
@@ -496,11 +503,11 @@
496503
@ </table>
497504
498505
if( isModerator && modPending ){
499506
@ <div class="section">Moderation</div>
500507
@ <blockquote>
501
- @ <form method="POST" action="%R/ainfo/%s(zUuid)">
508
+ form_begin(0, "%R/ainfo/%s", zUuid);
502509
@ <label><input type="radio" name="modaction" value="delete">
503510
@ Delete this change</label><br />
504511
@ <label><input type="radio" name="modaction" value="approve">
505512
@ Approve this change</label><br />
506513
@ <input type="submit" value="Submit">
@@ -557,17 +564,18 @@
557564
const char *zDate = db_column_text(&q, 0);
558565
const char *zFile = db_column_text(&q, 1);
559566
const char *zUser = db_column_text(&q, 2);
560567
const char *zUuid = db_column_text(&q, 3);
561568
const char *zSrc = db_column_text(&q, 4);
569
+ const char *zDispUser = zUser && zUser[0] ? zUser : "anonymous";
562570
if( cnt==0 ){
563571
@ %s(zHeader)
564572
}
565573
cnt++;
566574
@ <li>
567575
@ %z(href("%R/artifact/%s",zSrc))%h(zFile)</a>
568
- @ added by %h(zUser) on
576
+ @ added by %h(zDispUser) on
569577
hyperlink_to_date(zDate, ".");
570578
@ [%z(href("%R/ainfo/%s",zUuid))details</a>]
571579
@ </li>
572580
}
573581
if( cnt ){
574582
--- src/attach.c
+++ src/attach.c
@@ -71,10 +71,11 @@
71 const char *zFilename = db_column_text(&q, 3);
72 const char *zComment = db_column_text(&q, 4);
73 const char *zUser = db_column_text(&q, 5);
74 const char *zUuid = db_column_text(&q, 6);
75 int attachid = db_column_int(&q, 7);
 
76 int i;
77 char *zUrlTail;
78 for(i=0; zFilename[i]; i++){
79 if( zFilename[i]=='/' && zFilename[i+1]!=0 ){
80 zFilename = &zFilename[i+1];
@@ -115,11 +116,11 @@
115 @ Deleted
116 }else {
117 @ Added
118 }
119 }
120 @ by %h(zUser) on
121 hyperlink_to_date(zDate, ".");
122 free(zUrlTail);
123 }
124 db_finalize(&q);
125 @ </ol>
@@ -235,10 +236,11 @@
235 const char *aContent = P("f");
236 const char *zName = PD("f:filename","unknown");
237 const char *zTarget;
238 const char *zTargetType;
239 int szContent = atoi(PD("f:bytes","0"));
 
240
241 if( P("cancel") ) cgi_redirect(zFrom);
242 if( zPage && zTkt ) fossil_redirect_home();
243 if( zPage==0 && zTkt==0 ) fossil_redirect_home();
244 login_check_credentials();
@@ -263,11 +265,11 @@
263 }
264 if( zFrom==0 ) zFrom = mprintf("%s/home", g.zTop);
265 if( P("cancel") ){
266 cgi_redirect(zFrom);
267 }
268 if( P("ok") && szContent>0 ){
269 Blob content;
270 Blob manifest;
271 Blob cksum;
272 char *zUUID;
273 const char *zComment;
@@ -316,13 +318,16 @@
316 assert( blob_is_reset(&manifest) );
317 db_end_transaction(0);
318 cgi_redirect(zFrom);
319 }
320 style_header("Add Attachment");
 
 
 
321 @ <h2>Add Attachment To %s(zTargetType)</h2>
322 @ <form action="%s(g.zTop)/attachadd" method="post"
323 @ enctype="multipart/form-data"><div>
324 @ File to Attach:
325 @ <input type="file" name="f" size="60" /><br />
326 @ Description:<br />
327 @ <textarea name="comment" cols="80" rows="5" wrap="virtual"></textarea><br />
328 if( zTkt ){
@@ -331,11 +336,13 @@
331 @ <input type="hidden" name="page" value="%h(zPage)" />
332 }
333 @ <input type="hidden" name="from" value="%h(zFrom)" />
334 @ <input type="submit" name="ok" value="Add Attachment" />
335 @ <input type="submit" name="cancel" value="Cancel" />
336 @ </div></form>
 
 
337 style_footer();
338 }
339
340 /*
341 ** WEBPAGE: ainfo
@@ -432,11 +439,11 @@
432 }
433
434 if( P("del")
435 && ((zTktUuid && g.perm.WrTkt) || (zWikiName && g.perm.WrWiki))
436 ){
437 @ <form method="post" action="%R/ainfo/%s(zUuid)">
438 @ <p>Confirm you want to delete the attachment shown below.
439 @ <input type="submit" name="confirm" value="Confirm">
440 @ </form>
441 }
442
@@ -496,11 +503,11 @@
496 @ </table>
497
498 if( isModerator && modPending ){
499 @ <div class="section">Moderation</div>
500 @ <blockquote>
501 @ <form method="POST" action="%R/ainfo/%s(zUuid)">
502 @ <label><input type="radio" name="modaction" value="delete">
503 @ Delete this change</label><br />
504 @ <label><input type="radio" name="modaction" value="approve">
505 @ Approve this change</label><br />
506 @ <input type="submit" value="Submit">
@@ -557,17 +564,18 @@
557 const char *zDate = db_column_text(&q, 0);
558 const char *zFile = db_column_text(&q, 1);
559 const char *zUser = db_column_text(&q, 2);
560 const char *zUuid = db_column_text(&q, 3);
561 const char *zSrc = db_column_text(&q, 4);
 
562 if( cnt==0 ){
563 @ %s(zHeader)
564 }
565 cnt++;
566 @ <li>
567 @ %z(href("%R/artifact/%s",zSrc))%h(zFile)</a>
568 @ added by %h(zUser) on
569 hyperlink_to_date(zDate, ".");
570 @ [%z(href("%R/ainfo/%s",zUuid))details</a>]
571 @ </li>
572 }
573 if( cnt ){
574
--- src/attach.c
+++ src/attach.c
@@ -71,10 +71,11 @@
71 const char *zFilename = db_column_text(&q, 3);
72 const char *zComment = db_column_text(&q, 4);
73 const char *zUser = db_column_text(&q, 5);
74 const char *zUuid = db_column_text(&q, 6);
75 int attachid = db_column_int(&q, 7);
76 const char *zDispUser = zUser && zUser[0] ? zUser : "anonymous";
77 int i;
78 char *zUrlTail;
79 for(i=0; zFilename[i]; i++){
80 if( zFilename[i]=='/' && zFilename[i+1]!=0 ){
81 zFilename = &zFilename[i+1];
@@ -115,11 +116,11 @@
116 @ Deleted
117 }else {
118 @ Added
119 }
120 }
121 @ by %h(zDispUser) on
122 hyperlink_to_date(zDate, ".");
123 free(zUrlTail);
124 }
125 db_finalize(&q);
126 @ </ol>
@@ -235,10 +236,11 @@
236 const char *aContent = P("f");
237 const char *zName = PD("f:filename","unknown");
238 const char *zTarget;
239 const char *zTargetType;
240 int szContent = atoi(PD("f:bytes","0"));
241 int goodCaptcha = 1;
242
243 if( P("cancel") ) cgi_redirect(zFrom);
244 if( zPage && zTkt ) fossil_redirect_home();
245 if( zPage==0 && zTkt==0 ) fossil_redirect_home();
246 login_check_credentials();
@@ -263,11 +265,11 @@
265 }
266 if( zFrom==0 ) zFrom = mprintf("%s/home", g.zTop);
267 if( P("cancel") ){
268 cgi_redirect(zFrom);
269 }
270 if( P("ok") && szContent>0 && (goodCaptcha = captcha_is_correct()) ){
271 Blob content;
272 Blob manifest;
273 Blob cksum;
274 char *zUUID;
275 const char *zComment;
@@ -316,13 +318,16 @@
318 assert( blob_is_reset(&manifest) );
319 db_end_transaction(0);
320 cgi_redirect(zFrom);
321 }
322 style_header("Add Attachment");
323 if( !goodCaptcha ){
324 @ <p class="generalError">Error: Incorrect security code.</p>
325 }
326 @ <h2>Add Attachment To %s(zTargetType)</h2>
327 form_begin("enctype='multipart/form-data'", "%R/attachadd");
328 @ <div>
329 @ File to Attach:
330 @ <input type="file" name="f" size="60" /><br />
331 @ Description:<br />
332 @ <textarea name="comment" cols="80" rows="5" wrap="virtual"></textarea><br />
333 if( zTkt ){
@@ -331,11 +336,13 @@
336 @ <input type="hidden" name="page" value="%h(zPage)" />
337 }
338 @ <input type="hidden" name="from" value="%h(zFrom)" />
339 @ <input type="submit" name="ok" value="Add Attachment" />
340 @ <input type="submit" name="cancel" value="Cancel" />
341 @ </div>
342 captcha_generate();
343 @ </form>
344 style_footer();
345 }
346
347 /*
348 ** WEBPAGE: ainfo
@@ -432,11 +439,11 @@
439 }
440
441 if( P("del")
442 && ((zTktUuid && g.perm.WrTkt) || (zWikiName && g.perm.WrWiki))
443 ){
444 form_begin(0, "%R/ainfo/%s", zUuid);
445 @ <p>Confirm you want to delete the attachment shown below.
446 @ <input type="submit" name="confirm" value="Confirm">
447 @ </form>
448 }
449
@@ -496,11 +503,11 @@
503 @ </table>
504
505 if( isModerator && modPending ){
506 @ <div class="section">Moderation</div>
507 @ <blockquote>
508 form_begin(0, "%R/ainfo/%s", zUuid);
509 @ <label><input type="radio" name="modaction" value="delete">
510 @ Delete this change</label><br />
511 @ <label><input type="radio" name="modaction" value="approve">
512 @ Approve this change</label><br />
513 @ <input type="submit" value="Submit">
@@ -557,17 +564,18 @@
564 const char *zDate = db_column_text(&q, 0);
565 const char *zFile = db_column_text(&q, 1);
566 const char *zUser = db_column_text(&q, 2);
567 const char *zUuid = db_column_text(&q, 3);
568 const char *zSrc = db_column_text(&q, 4);
569 const char *zDispUser = zUser && zUser[0] ? zUser : "anonymous";
570 if( cnt==0 ){
571 @ %s(zHeader)
572 }
573 cnt++;
574 @ <li>
575 @ %z(href("%R/artifact/%s",zSrc))%h(zFile)</a>
576 @ added by %h(zDispUser) on
577 hyperlink_to_date(zDate, ".");
578 @ [%z(href("%R/ainfo/%s",zUuid))details</a>]
579 @ </li>
580 }
581 if( cnt ){
582
+9 -8
--- src/blob.c
+++ src/blob.c
@@ -1095,38 +1095,39 @@
10951095
** done. If useMbcs is false and there is no BOM, the input string is assumed
10961096
** to be UTF-8 already, so no conversion is done.
10971097
*/
10981098
void blob_to_utf8_no_bom(Blob *pBlob, int useMbcs){
10991099
char *zUtf8;
1100
- if( starts_with_utf8_bom(pBlob) ){
1100
+ int bomSize = 0;
1101
+ if( starts_with_utf8_bom(pBlob, &bomSize) ){
11011102
struct Blob temp;
1102
- zUtf8 = blob_str(pBlob) + 3;
1103
+ zUtf8 = blob_str(pBlob) + bomSize;
11031104
blob_zero(&temp);
11041105
blob_append(&temp, zUtf8, -1);
11051106
blob_swap(pBlob, &temp);
11061107
blob_reset(&temp);
11071108
#ifdef _WIN32
1108
- }else if( starts_with_utf16be_bom(pBlob) ){
1109
+ }else if( starts_with_utf16be_bom(pBlob, &bomSize) ){
11091110
/* Make sure the blob contains two terminating 0-bytes */
11101111
blob_append(pBlob, "", 1);
1111
- zUtf8 = blob_str(pBlob) + 2;
1112
+ zUtf8 = blob_str(pBlob) + bomSize;
11121113
zUtf8 = fossil_unicode_to_utf8(zUtf8);
11131114
blob_zero(pBlob);
11141115
blob_append(pBlob, zUtf8, -1);
11151116
fossil_mbcs_free(zUtf8);
1116
- }else if( starts_with_utf16le_bom(pBlob) ){
1117
+ }else if( starts_with_utf16le_bom(pBlob, &bomSize) ){
11171118
unsigned int i = blob_size(pBlob);
11181119
zUtf8 = blob_buffer(pBlob);
11191120
while( i > 0 ){
11201121
/* swap bytes of unicode representation */
1121
- char temp = zUtf8[--i];
1122
+ char zTemp = zUtf8[--i];
11221123
zUtf8[i] = zUtf8[i-1];
1123
- zUtf8[--i] = temp;
1124
+ zUtf8[--i] = zTemp;
11241125
}
11251126
/* Make sure the blob contains two terminating 0-bytes */
11261127
blob_append(pBlob, "", 1);
1127
- zUtf8 = blob_str(pBlob) + 2;
1128
+ zUtf8 = blob_str(pBlob) + bomSize;
11281129
zUtf8 = fossil_unicode_to_utf8(zUtf8);
11291130
blob_zero(pBlob);
11301131
blob_append(pBlob, zUtf8, -1);
11311132
fossil_mbcs_free(zUtf8);
11321133
}else if( useMbcs ){
11331134
--- src/blob.c
+++ src/blob.c
@@ -1095,38 +1095,39 @@
1095 ** done. If useMbcs is false and there is no BOM, the input string is assumed
1096 ** to be UTF-8 already, so no conversion is done.
1097 */
1098 void blob_to_utf8_no_bom(Blob *pBlob, int useMbcs){
1099 char *zUtf8;
1100 if( starts_with_utf8_bom(pBlob) ){
 
1101 struct Blob temp;
1102 zUtf8 = blob_str(pBlob) + 3;
1103 blob_zero(&temp);
1104 blob_append(&temp, zUtf8, -1);
1105 blob_swap(pBlob, &temp);
1106 blob_reset(&temp);
1107 #ifdef _WIN32
1108 }else if( starts_with_utf16be_bom(pBlob) ){
1109 /* Make sure the blob contains two terminating 0-bytes */
1110 blob_append(pBlob, "", 1);
1111 zUtf8 = blob_str(pBlob) + 2;
1112 zUtf8 = fossil_unicode_to_utf8(zUtf8);
1113 blob_zero(pBlob);
1114 blob_append(pBlob, zUtf8, -1);
1115 fossil_mbcs_free(zUtf8);
1116 }else if( starts_with_utf16le_bom(pBlob) ){
1117 unsigned int i = blob_size(pBlob);
1118 zUtf8 = blob_buffer(pBlob);
1119 while( i > 0 ){
1120 /* swap bytes of unicode representation */
1121 char temp = zUtf8[--i];
1122 zUtf8[i] = zUtf8[i-1];
1123 zUtf8[--i] = temp;
1124 }
1125 /* Make sure the blob contains two terminating 0-bytes */
1126 blob_append(pBlob, "", 1);
1127 zUtf8 = blob_str(pBlob) + 2;
1128 zUtf8 = fossil_unicode_to_utf8(zUtf8);
1129 blob_zero(pBlob);
1130 blob_append(pBlob, zUtf8, -1);
1131 fossil_mbcs_free(zUtf8);
1132 }else if( useMbcs ){
1133
--- src/blob.c
+++ src/blob.c
@@ -1095,38 +1095,39 @@
1095 ** done. If useMbcs is false and there is no BOM, the input string is assumed
1096 ** to be UTF-8 already, so no conversion is done.
1097 */
1098 void blob_to_utf8_no_bom(Blob *pBlob, int useMbcs){
1099 char *zUtf8;
1100 int bomSize = 0;
1101 if( starts_with_utf8_bom(pBlob, &bomSize) ){
1102 struct Blob temp;
1103 zUtf8 = blob_str(pBlob) + bomSize;
1104 blob_zero(&temp);
1105 blob_append(&temp, zUtf8, -1);
1106 blob_swap(pBlob, &temp);
1107 blob_reset(&temp);
1108 #ifdef _WIN32
1109 }else if( starts_with_utf16be_bom(pBlob, &bomSize) ){
1110 /* Make sure the blob contains two terminating 0-bytes */
1111 blob_append(pBlob, "", 1);
1112 zUtf8 = blob_str(pBlob) + bomSize;
1113 zUtf8 = fossil_unicode_to_utf8(zUtf8);
1114 blob_zero(pBlob);
1115 blob_append(pBlob, zUtf8, -1);
1116 fossil_mbcs_free(zUtf8);
1117 }else if( starts_with_utf16le_bom(pBlob, &bomSize) ){
1118 unsigned int i = blob_size(pBlob);
1119 zUtf8 = blob_buffer(pBlob);
1120 while( i > 0 ){
1121 /* swap bytes of unicode representation */
1122 char zTemp = zUtf8[--i];
1123 zUtf8[i] = zUtf8[i-1];
1124 zUtf8[--i] = zTemp;
1125 }
1126 /* Make sure the blob contains two terminating 0-bytes */
1127 blob_append(pBlob, "", 1);
1128 zUtf8 = blob_str(pBlob) + bomSize;
1129 zUtf8 = fossil_unicode_to_utf8(zUtf8);
1130 blob_zero(pBlob);
1131 blob_append(pBlob, zUtf8, -1);
1132 fossil_mbcs_free(zUtf8);
1133 }else if( useMbcs ){
1134
+1 -1
--- src/branch.c
+++ src/branch.c
@@ -176,11 +176,11 @@
176176
177177
/* Commit */
178178
db_end_transaction(0);
179179
180180
/* Do an autosync push, if requested */
181
- if( !isPrivate ) autosync(AUTOSYNC_PUSH);
181
+ if( !isPrivate ) autosync(SYNC_PUSH);
182182
}
183183
184184
/*
185185
** Prepare a query that will list branches.
186186
**
187187
--- src/branch.c
+++ src/branch.c
@@ -176,11 +176,11 @@
176
177 /* Commit */
178 db_end_transaction(0);
179
180 /* Do an autosync push, if requested */
181 if( !isPrivate ) autosync(AUTOSYNC_PUSH);
182 }
183
184 /*
185 ** Prepare a query that will list branches.
186 **
187
--- src/branch.c
+++ src/branch.c
@@ -176,11 +176,11 @@
176
177 /* Commit */
178 db_end_transaction(0);
179
180 /* Do an autosync push, if requested */
181 if( !isPrivate ) autosync(SYNC_PUSH);
182 }
183
184 /*
185 ** Prepare a query that will list branches.
186 **
187
--- src/captcha.c
+++ src/captcha.c
@@ -438,5 +438,70 @@
438438
z = blob_buffer(&b);
439439
memcpy(zRes, z, 8);
440440
zRes[8] = 0;
441441
return zRes;
442442
}
443
+
444
+/*
445
+** Return true if a CAPTCHA is required for editing wiki or tickets or for
446
+** adding attachments.
447
+**
448
+** A CAPTCHA is required in those cases if the user is not logged in (if they
449
+** are user "nobody") and if the "require-captcha" setting is true. The
450
+** "require-captcha" setting is controlled on the Admin/Access page. It
451
+** defaults to true.
452
+*/
453
+int captcha_needed(void){
454
+ if( g.zLogin!=0 ) return 0;
455
+ return db_get_boolean("require-captcha", 1);
456
+}
457
+
458
+/*
459
+** If a captcha is required but the correct captcha code is not supplied
460
+** in the query parameters, then return false (0).
461
+**
462
+** If no captcha is required or if the correct captcha is supplied, return
463
+** true (non-zero).
464
+**
465
+** The query parameters examined are "captchaseed" for the seed value and
466
+** "captcha" for text that the user types in response to the captcha prompt.
467
+*/
468
+int captcha_is_correct(void){
469
+ const char *zSeed;
470
+ const char *zEntered;
471
+ const char *zDecode;
472
+ if( !captcha_needed() ){
473
+ return 1; /* No captcha needed */
474
+ }
475
+ zSeed = P("captchaseed");
476
+ if( zSeed==0 ) return 0;
477
+ zEntered = P("captcha");
478
+ if( zEntered==0 || strlen(zEntered)!=8 ) return 0;
479
+ zDecode = captcha_decode((unsigned int)atoi(zSeed));
480
+ if( strcmp(zDecode,zEntered)!=0 ) return 0;
481
+ return 1;
482
+}
483
+
484
+/*
485
+** Generate a captcha display together with the necessary hidden parameter
486
+** for the seed and the entry box into which the user will type the text of
487
+** the captcha. This is typically done at the very bottom of a form.
488
+**
489
+** This routine is a no-op if no captcha is required.
490
+*/
491
+void captcha_generate(void){
492
+ unsigned int uSeed;
493
+ const char *zDecoded;
494
+ char *zCaptcha;
495
+
496
+ if( !captcha_needed() ) return;
497
+ uSeed = captcha_seed();
498
+ zDecoded = captcha_decode(uSeed);
499
+ zCaptcha = captcha_render(zDecoded);
500
+ @ <div class="captcha"><table class="captcha"><tr><td><pre>
501
+ @ %h(zCaptcha)
502
+ @ </pre>
503
+ @ Enter security code shown above:
504
+ @ <input type="hidden" name="captchaseed" value="%u(uSeed)" />
505
+ @ <input type="text" name="captcha" size=8 />
506
+ @ </td></tr></table></div>
507
+}
443508
--- src/captcha.c
+++ src/captcha.c
@@ -438,5 +438,70 @@
438 z = blob_buffer(&b);
439 memcpy(zRes, z, 8);
440 zRes[8] = 0;
441 return zRes;
442 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
443
--- src/captcha.c
+++ src/captcha.c
@@ -438,5 +438,70 @@
438 z = blob_buffer(&b);
439 memcpy(zRes, z, 8);
440 zRes[8] = 0;
441 return zRes;
442 }
443
444 /*
445 ** Return true if a CAPTCHA is required for editing wiki or tickets or for
446 ** adding attachments.
447 **
448 ** A CAPTCHA is required in those cases if the user is not logged in (if they
449 ** are user "nobody") and if the "require-captcha" setting is true. The
450 ** "require-captcha" setting is controlled on the Admin/Access page. It
451 ** defaults to true.
452 */
453 int captcha_needed(void){
454 if( g.zLogin!=0 ) return 0;
455 return db_get_boolean("require-captcha", 1);
456 }
457
458 /*
459 ** If a captcha is required but the correct captcha code is not supplied
460 ** in the query parameters, then return false (0).
461 **
462 ** If no captcha is required or if the correct captcha is supplied, return
463 ** true (non-zero).
464 **
465 ** The query parameters examined are "captchaseed" for the seed value and
466 ** "captcha" for text that the user types in response to the captcha prompt.
467 */
468 int captcha_is_correct(void){
469 const char *zSeed;
470 const char *zEntered;
471 const char *zDecode;
472 if( !captcha_needed() ){
473 return 1; /* No captcha needed */
474 }
475 zSeed = P("captchaseed");
476 if( zSeed==0 ) return 0;
477 zEntered = P("captcha");
478 if( zEntered==0 || strlen(zEntered)!=8 ) return 0;
479 zDecode = captcha_decode((unsigned int)atoi(zSeed));
480 if( strcmp(zDecode,zEntered)!=0 ) return 0;
481 return 1;
482 }
483
484 /*
485 ** Generate a captcha display together with the necessary hidden parameter
486 ** for the seed and the entry box into which the user will type the text of
487 ** the captcha. This is typically done at the very bottom of a form.
488 **
489 ** This routine is a no-op if no captcha is required.
490 */
491 void captcha_generate(void){
492 unsigned int uSeed;
493 const char *zDecoded;
494 char *zCaptcha;
495
496 if( !captcha_needed() ) return;
497 uSeed = captcha_seed();
498 zDecoded = captcha_decode(uSeed);
499 zCaptcha = captcha_render(zDecoded);
500 @ <div class="captcha"><table class="captcha"><tr><td><pre>
501 @ %h(zCaptcha)
502 @ </pre>
503 @ Enter security code shown above:
504 @ <input type="hidden" name="captchaseed" value="%u(uSeed)" />
505 @ <input type="text" name="captcha" size=8 />
506 @ </td></tr></table></div>
507 }
508
+68 -35
--- src/checkin.c
+++ src/checkin.c
@@ -582,11 +582,10 @@
582582
blob_init(&prompt, zInit, -1);
583583
#endif
584584
blob_append(&prompt,
585585
"\n"
586586
"# Enter comments on this check-in. Lines beginning with # are ignored.\n"
587
- "# The check-in comment follows wiki formatting rules.\n"
588587
"#\n", -1
589588
);
590589
blob_appendf(&prompt, "# user: %s\n", zUserOvrd ? zUserOvrd : g.zLogin);
591590
if( zBranch && zBranch[0] ){
592591
blob_appendf(&prompt, "# tags: %s\n#\n", zBranch);
@@ -658,11 +657,11 @@
658657
" AND type='ci' AND objid=%d",
659658
zDate, rid
660659
);
661660
if( b ){
662661
fossil_fatal("ancestor check-in [%.10s] (%s) is not older (clock skew?)"
663
- " Use -f to override.", zUuid, zDate);
662
+ " Use --allow-older to override.", zUuid, zDate);
664663
}
665664
#endif
666665
}
667666
668667
/*
@@ -896,28 +895,32 @@
896895
*/
897896
static int commit_warning(
898897
Blob *p, /* The content of the file being committed. */
899898
int crnlOk, /* Non-zero if CR/NL warnings should be disabled. */
900899
int binOk, /* Non-zero if binary warnings should be disabled. */
900
+ int unicodeOk, /* Non-zero if unicode warnings should be disabled. */
901901
const char *zFilename /* The full name of the file being committed. */
902902
){
903903
int eType; /* return value of looks_like_utf8/utf16() */
904904
int fUnicode; /* return value of starts_with_utf16_bom() */
905905
char *zMsg; /* Warning message */
906906
Blob fname; /* Relative pathname of the file */
907907
static int allOk = 0; /* Set to true to disable this routine */
908908
909909
if( allOk ) return 0;
910
- fUnicode = starts_with_utf16_bom(p);
910
+ fUnicode = starts_with_utf16_bom(p, 0);
911911
eType = fUnicode ? looks_like_utf16(p) : looks_like_utf8(p);
912912
if( eType==0 || eType==-1 || fUnicode ){
913913
const char *zWarning;
914914
const char *zConvert = "c=convert/";
915915
Blob ans;
916916
char cReply;
917917
918918
if( eType==-1 && fUnicode ){
919
+ if ( crnlOk && unicodeOk ){
920
+ return 0; /* We don't want Unicode/CR/NL warnings for this file. */
921
+ }
919922
zWarning = "Unicode and CR/NL line endings";
920923
}else if( eType==-1 ){
921924
if( crnlOk ){
922925
return 0; /* We don't want CR/NL warnings for this file. */
923926
}
@@ -927,10 +930,13 @@
927930
return 0; /* We don't want binary warnings for this file. */
928931
}
929932
zWarning = "binary data";
930933
zConvert = ""; /* We cannot convert binary files. */
931934
}else{
935
+ if ( unicodeOk ){
936
+ return 0; /* We don't want unicode warnings for this file. */
937
+ }
932938
zWarning = "Unicode";
933939
#ifndef _WIN32
934940
zConvert = ""; /* On Unix, we cannot easily convert Unicode files. */
935941
#endif
936942
}
@@ -1008,32 +1014,45 @@
10081014
**
10091015
** The --bgcolor option works like --branchcolor but only sets the
10101016
** background color for a single check-in. Subsequent check-ins revert
10111017
** to the default color.
10121018
**
1013
-** A check-in is not permitted to fork unless the --force or -f
1014
-** option appears. A check-in is not allowed against a closed leaf.
1019
+** A check-in is not permitted to fork unless the --allow-fork option
1020
+** appears. An empty check-in (i.e. with nothing changed) is not
1021
+** allowed unless the --allow-empty option appears. A check-in may not
1022
+** be older than its ancestor unless the --allow-older option appears.
1023
+** If any of files in the check-in appear to contain unresolved merge
1024
+** conflicts, the check-in will not be allowed unless the
1025
+** --allow-conflict option is present. In addition, the entire
1026
+** check-in process may be aborted if a file contains content that
1027
+** appears to be binary, Unicode text, or text with CR/NL line endings
1028
+** unless the interactive user chooses to proceed. If there is no
1029
+** interactive user or these warnings should be skipped for some other
1030
+** reason, the --no-warnings option may be used. A check-in is not
1031
+** allowed against a closed leaf.
10151032
**
10161033
** The --private option creates a private check-in that is never synced.
10171034
** Children of private check-ins are automatically private.
10181035
**
10191036
** the --tag option applies the symbolic tag name to the check-in.
10201037
**
10211038
** Options:
1039
+** --allow-conflict allow unresolved merge conflicts
1040
+** --allow-empty allow a commit with no changes
1041
+** --allow-fork allow the commit to fork
1042
+** --allow-older allow a commit older than its ancestor
10221043
** --baseline use a baseline manifest in the commit process
10231044
** --bgcolor COLOR apply COLOR to this one check-in only
10241045
** --branch NEW-BRANCH-NAME check in to this new branch
10251046
** --branchcolor COLOR apply given COLOR to the branch
10261047
** --comment|-m COMMENT-TEXT use COMMENT-TEXT as commit comment
10271048
** --delta use a delta manifest in the commit process
1028
-** --force|-f allow forking with this commit
10291049
** --message-file|-M FILE read the commit comment from given file
1050
+** --no-warnings omit all warnings about file contents
10301051
** --nosign do not attempt to sign this commit with gpg
10311052
** --private do not sync changes and their descendants
10321053
** --tag TAG-NAME assign given tag TAG-NAME to the checkin
1033
-** --conflict allow unresolved merge conflicts
1034
-** --binary-ok do not warn about committing binary files
10351054
**
10361055
** See also: branch, changes, checkout, extra, sync
10371056
*/
10381057
void commit_cmd(void){
10391058
int hasChanges; /* True if unsaved changes exist */
@@ -1044,15 +1063,18 @@
10441063
const char *zComment; /* Check-in comment */
10451064
Stmt q; /* Query to find files that have been modified */
10461065
char *zUuid; /* UUID of the new check-in */
10471066
int noSign = 0; /* True to omit signing the manifest using GPG */
10481067
int isAMerge = 0; /* True if checking in a merge */
1049
- int forceFlag = 0; /* Force a fork */
1068
+ int noWarningFlag = 0; /* True if skipping all warnings */
1069
+ int forceFlag = 0; /* Undocumented: Disables all checks */
10501070
int forceDelta = 0; /* Force a delta-manifest */
10511071
int forceBaseline = 0; /* Force a baseline-manifest */
10521072
int allowConflict = 0; /* Allow unresolve merge conflicts */
1053
- int binaryOk = 0; /* The --binary-ok flag */
1073
+ int allowEmpty = 0; /* Allow a commit with no changes */
1074
+ int allowFork = 0; /* Allow the commit to fork */
1075
+ int allowOlder = 0; /* Allow a commit older than its ancestor */
10541076
char *zManifestFile; /* Name of the manifest file */
10551077
int useCksum; /* True if checksums should be computed and verified */
10561078
int outputManifest; /* True to output "manifest" and "manifest.uuid" */
10571079
int testRun; /* True for a test run. Debugging only */
10581080
const char *zBranch; /* Create a new branch with this name */
@@ -1069,11 +1091,10 @@
10691091
Blob cksum1, cksum2; /* Before and after commit checksums */
10701092
Blob cksum1b; /* Checksum recorded in the manifest */
10711093
int szD; /* Size of the delta manifest */
10721094
int szB; /* Size of the baseline manifest */
10731095
int nConflict = 0; /* Number of unresolved merge conflicts */
1074
- int abortCommit = 0;
10751096
Blob ans;
10761097
char cReply;
10771098
10781099
url_proxy_options();
10791100
noSign = find_option("nosign",0,0)!=0;
@@ -1083,14 +1104,18 @@
10831104
fossil_fatal("cannot use --delta and --baseline together");
10841105
}
10851106
testRun = find_option("test",0,0)!=0;
10861107
zComment = find_option("comment","m",1);
10871108
forceFlag = find_option("force", "f", 0)!=0;
1109
+ allowConflict = find_option("allow-conflict",0,0)!=0;
1110
+ allowEmpty = find_option("allow-empty",0,0)!=0;
1111
+ allowFork = find_option("allow-fork",0,0)!=0;
1112
+ allowOlder = find_option("allow-older",0,0)!=0;
1113
+ noWarningFlag = find_option("no-warnings", 0, 0)!=0;
10881114
zBranch = find_option("branch","b",1);
10891115
zColor = find_option("bgcolor",0,1);
10901116
zBrClr = find_option("branchcolor",0,1);
1091
- binaryOk = find_option("binary-ok",0,0)!=0;
10921117
while( (zTag = find_option("tag",0,1))!=0 ){
10931118
if( zTag[0]==0 ) continue;
10941119
azTag = fossil_realloc((void *)azTag, sizeof(char*)*(nTag+2));
10951120
azTag[nTag++] = zTag;
10961121
azTag[nTag] = 0;
@@ -1101,11 +1126,10 @@
11011126
if( zBranch==0 ) zBranch = "private";
11021127
if( zBrClr==0 && zColor==0 ) zBrClr = "#fec084"; /* Orange */
11031128
}
11041129
zDateOvrd = find_option("date-override",0,1);
11051130
zUserOvrd = find_option("user-override",0,1);
1106
- allowConflict = find_option("conflict",0,0)!=0;
11071131
db_must_be_within_tree();
11081132
noSign = db_get_boolean("omitsign", 0)|noSign;
11091133
if( db_get_boolean("clearsign", 0)==0 ){ noSign = 1; }
11101134
useCksum = db_get_boolean("repo-cksum", 1);
11111135
outputManifest = db_get_boolean("manifest", 0);
@@ -1136,11 +1160,11 @@
11361160
11371161
/*
11381162
** Autosync if autosync is enabled and this is not a private check-in.
11391163
*/
11401164
if( !g.markPrivate ){
1141
- if( autosync(AUTOSYNC_PULL) ){
1165
+ if( autosync(SYNC_PULL) ){
11421166
blob_zero(&ans);
11431167
prompt_user("continue in spite of sync failure (y/N)? ", &ans);
11441168
cReply = blob_str(&ans)[0];
11451169
if( cReply!='y' && cReply!='Y' ){
11461170
fossil_exit(1);
@@ -1208,34 +1232,38 @@
12081232
}
12091233
12101234
hasChanges = unsaved_changes();
12111235
db_begin_transaction();
12121236
db_record_repository_filename(0);
1213
- if( hasChanges==0 && !isAMerge && !forceFlag ){
1214
- fossil_fatal("nothing has changed");
1237
+ if( hasChanges==0 && !isAMerge && !allowEmpty && !forceFlag ){
1238
+ fossil_fatal("nothing has changed; use --allow-empty to override");
12151239
}
12161240
12171241
/* If none of the files that were named on the command line have
1218
- ** been modified, bail out now unless the --force flag is used.
1242
+ ** been modified, bail out now unless the --allow-empty or --force
1243
+ ** flags is used.
12191244
*/
12201245
if( g.aCommitFile
1246
+ && !allowEmpty
12211247
&& !forceFlag
12221248
&& !db_exists(
12231249
"SELECT 1 FROM vfile "
12241250
" WHERE is_selected(id)"
12251251
" AND (chnged OR deleted OR rid=0 OR pathname!=origname)")
12261252
){
1227
- fossil_fatal("none of the selected files have changed; use -f"
1228
- " or --force.");
1253
+ fossil_fatal("none of the selected files have changed; use "
1254
+ "--allow-empty to override.");
12291255
}
12301256
12311257
/*
1232
- ** Do not allow a commit that will cause a fork unless the --force flag
1233
- ** is used or unless this is a private check-in.
1258
+ ** Do not allow a commit that will cause a fork unless the --allow-fork
1259
+ ** or --force flags is used, or unless this is a private check-in.
12341260
*/
1235
- if( zBranch==0 && forceFlag==0 && g.markPrivate==0 && !is_a_leaf(vid) ){
1236
- fossil_fatal("would fork. \"update\" first or use -f or --force.");
1261
+ if( zBranch==0 && allowFork==0 && forceFlag==0
1262
+ && g.markPrivate==0 && !is_a_leaf(vid)
1263
+ ){
1264
+ fossil_fatal("would fork. \"update\" first or use --allow-fork.");
12371265
}
12381266
12391267
/*
12401268
** Do not allow a commit against a closed leaf
12411269
*/
@@ -1280,36 +1308,42 @@
12801308
/* Step 1: Insert records for all modified files into the blob
12811309
** table. If there were arguments passed to this command, only
12821310
** the identified files are inserted (if they have been modified).
12831311
*/
12841312
db_prepare(&q,
1285
- "SELECT id, %Q || pathname, mrid, %s, chnged, %s FROM vfile "
1313
+ "SELECT id, %Q || pathname, mrid, %s, chnged, %s, %s FROM vfile "
12861314
"WHERE chnged==1 AND NOT deleted AND is_selected(id)",
1287
- g.zLocalRoot, glob_expr("pathname", db_get("crnl-glob","")),
1288
- glob_expr("pathname", db_get("binary-glob",""))
1315
+ g.zLocalRoot,
1316
+ glob_expr("pathname", db_get("crnl-glob","")),
1317
+ glob_expr("pathname", db_get("binary-glob","")),
1318
+ glob_expr("pathname", db_get("unicode-glob",""))
12891319
);
12901320
while( db_step(&q)==SQLITE_ROW ){
12911321
int id, rid;
12921322
const char *zFullname;
12931323
Blob content;
1294
- int crnlOk, binOk, chnged;
1324
+ int crnlOk, binOk, unicodeOk, chnged;
12951325
12961326
id = db_column_int(&q, 0);
12971327
zFullname = db_column_text(&q, 1);
12981328
rid = db_column_int(&q, 2);
12991329
crnlOk = db_column_int(&q, 3);
13001330
chnged = db_column_int(&q, 4);
1301
- binOk = binaryOk || db_column_int(&q, 5);
1331
+ binOk = db_column_int(&q, 5);
1332
+ unicodeOk = db_column_int(&q, 6);
13021333
13031334
blob_zero(&content);
13041335
if( file_wd_islink(zFullname) ){
13051336
/* Instead of file content, put link destination path */
13061337
blob_read_link(&content, zFullname);
13071338
}else{
13081339
blob_read_from_file(&content, zFullname);
13091340
}
1310
- abortCommit |= commit_warning(&content, crnlOk, binOk, zFullname);
1341
+ /* Do not emit any warnings when they are disabled. */
1342
+ if( !noWarningFlag ){
1343
+ commit_warning(&content, crnlOk, binOk, unicodeOk, zFullname);
1344
+ }
13111345
if( chnged==1 && contains_merge_marker(&content) ){
13121346
Blob fname; /* Relative pathname of the file */
13131347
13141348
nConflict++;
13151349
file_relative_name(zFullname, &fname, 0);
@@ -1325,13 +1359,12 @@
13251359
db_multi_exec("UPDATE vfile SET mrid=%d, rid=%d WHERE id=%d", nrid,nrid,id);
13261360
db_multi_exec("INSERT OR IGNORE INTO unsent VALUES(%d)", nrid);
13271361
}
13281362
db_finalize(&q);
13291363
if( nConflict && !allowConflict ){
1330
- fossil_fatal("abort due to unresolve merge conflicts");
1331
- } else if( abortCommit ){
1332
- fossil_fatal("files are converted on your request. Please re-test before committing");
1364
+ fossil_fatal("abort due to unresolved merge conflicts; "
1365
+ "use --allow-conflict to override");
13331366
}
13341367
13351368
/* Create the new manifest */
13361369
if( blob_size(&comment)==0 ){
13371370
blob_append(&comment, "(no comment)", -1);
@@ -1338,11 +1371,11 @@
13381371
}
13391372
if( forceDelta ){
13401373
blob_zero(&manifest);
13411374
}else{
13421375
create_manifest(&manifest, 0, 0, &comment, vid,
1343
- !forceFlag, useCksum ? &cksum1 : 0,
1376
+ !allowOlder && !forceFlag, useCksum ? &cksum1 : 0,
13441377
zDateOvrd, zUserOvrd, zBranch, zColor, zBrClr,
13451378
azTag, &szB);
13461379
}
13471380
13481381
/* See if a delta-manifest would be more appropriate */
@@ -1359,11 +1392,11 @@
13591392
pBaseline = pParent;
13601393
}
13611394
if( pBaseline ){
13621395
Blob delta;
13631396
create_manifest(&delta, zBaselineUuid, pBaseline, &comment, vid,
1364
- !forceFlag, useCksum ? &cksum1 : 0,
1397
+ !allowOlder && !forceFlag, useCksum ? &cksum1 : 0,
13651398
zDateOvrd, zUserOvrd, zBranch, zColor, zBrClr,
13661399
azTag, &szD);
13671400
/*
13681401
** At this point, two manifests have been constructed, either of
13691402
** which would work for this checkin. The first manifest (held
@@ -1489,11 +1522,11 @@
14891522
exit(1);
14901523
}
14911524
db_end_transaction(0);
14921525
14931526
if( !g.markPrivate ){
1494
- autosync(AUTOSYNC_PUSH);
1527
+ autosync(SYNC_PUSH);
14951528
}
14961529
if( count_nonbranch_children(vid)>1 ){
14971530
fossil_print("**** warning: a fork has occurred *****\n");
14981531
}
14991532
}
15001533
--- src/checkin.c
+++ src/checkin.c
@@ -582,11 +582,10 @@
582 blob_init(&prompt, zInit, -1);
583 #endif
584 blob_append(&prompt,
585 "\n"
586 "# Enter comments on this check-in. Lines beginning with # are ignored.\n"
587 "# The check-in comment follows wiki formatting rules.\n"
588 "#\n", -1
589 );
590 blob_appendf(&prompt, "# user: %s\n", zUserOvrd ? zUserOvrd : g.zLogin);
591 if( zBranch && zBranch[0] ){
592 blob_appendf(&prompt, "# tags: %s\n#\n", zBranch);
@@ -658,11 +657,11 @@
658 " AND type='ci' AND objid=%d",
659 zDate, rid
660 );
661 if( b ){
662 fossil_fatal("ancestor check-in [%.10s] (%s) is not older (clock skew?)"
663 " Use -f to override.", zUuid, zDate);
664 }
665 #endif
666 }
667
668 /*
@@ -896,28 +895,32 @@
896 */
897 static int commit_warning(
898 Blob *p, /* The content of the file being committed. */
899 int crnlOk, /* Non-zero if CR/NL warnings should be disabled. */
900 int binOk, /* Non-zero if binary warnings should be disabled. */
 
901 const char *zFilename /* The full name of the file being committed. */
902 ){
903 int eType; /* return value of looks_like_utf8/utf16() */
904 int fUnicode; /* return value of starts_with_utf16_bom() */
905 char *zMsg; /* Warning message */
906 Blob fname; /* Relative pathname of the file */
907 static int allOk = 0; /* Set to true to disable this routine */
908
909 if( allOk ) return 0;
910 fUnicode = starts_with_utf16_bom(p);
911 eType = fUnicode ? looks_like_utf16(p) : looks_like_utf8(p);
912 if( eType==0 || eType==-1 || fUnicode ){
913 const char *zWarning;
914 const char *zConvert = "c=convert/";
915 Blob ans;
916 char cReply;
917
918 if( eType==-1 && fUnicode ){
 
 
 
919 zWarning = "Unicode and CR/NL line endings";
920 }else if( eType==-1 ){
921 if( crnlOk ){
922 return 0; /* We don't want CR/NL warnings for this file. */
923 }
@@ -927,10 +930,13 @@
927 return 0; /* We don't want binary warnings for this file. */
928 }
929 zWarning = "binary data";
930 zConvert = ""; /* We cannot convert binary files. */
931 }else{
 
 
 
932 zWarning = "Unicode";
933 #ifndef _WIN32
934 zConvert = ""; /* On Unix, we cannot easily convert Unicode files. */
935 #endif
936 }
@@ -1008,32 +1014,45 @@
1008 **
1009 ** The --bgcolor option works like --branchcolor but only sets the
1010 ** background color for a single check-in. Subsequent check-ins revert
1011 ** to the default color.
1012 **
1013 ** A check-in is not permitted to fork unless the --force or -f
1014 ** option appears. A check-in is not allowed against a closed leaf.
 
 
 
 
 
 
 
 
 
 
 
1015 **
1016 ** The --private option creates a private check-in that is never synced.
1017 ** Children of private check-ins are automatically private.
1018 **
1019 ** the --tag option applies the symbolic tag name to the check-in.
1020 **
1021 ** Options:
 
 
 
 
1022 ** --baseline use a baseline manifest in the commit process
1023 ** --bgcolor COLOR apply COLOR to this one check-in only
1024 ** --branch NEW-BRANCH-NAME check in to this new branch
1025 ** --branchcolor COLOR apply given COLOR to the branch
1026 ** --comment|-m COMMENT-TEXT use COMMENT-TEXT as commit comment
1027 ** --delta use a delta manifest in the commit process
1028 ** --force|-f allow forking with this commit
1029 ** --message-file|-M FILE read the commit comment from given file
 
1030 ** --nosign do not attempt to sign this commit with gpg
1031 ** --private do not sync changes and their descendants
1032 ** --tag TAG-NAME assign given tag TAG-NAME to the checkin
1033 ** --conflict allow unresolved merge conflicts
1034 ** --binary-ok do not warn about committing binary files
1035 **
1036 ** See also: branch, changes, checkout, extra, sync
1037 */
1038 void commit_cmd(void){
1039 int hasChanges; /* True if unsaved changes exist */
@@ -1044,15 +1063,18 @@
1044 const char *zComment; /* Check-in comment */
1045 Stmt q; /* Query to find files that have been modified */
1046 char *zUuid; /* UUID of the new check-in */
1047 int noSign = 0; /* True to omit signing the manifest using GPG */
1048 int isAMerge = 0; /* True if checking in a merge */
1049 int forceFlag = 0; /* Force a fork */
 
1050 int forceDelta = 0; /* Force a delta-manifest */
1051 int forceBaseline = 0; /* Force a baseline-manifest */
1052 int allowConflict = 0; /* Allow unresolve merge conflicts */
1053 int binaryOk = 0; /* The --binary-ok flag */
 
 
1054 char *zManifestFile; /* Name of the manifest file */
1055 int useCksum; /* True if checksums should be computed and verified */
1056 int outputManifest; /* True to output "manifest" and "manifest.uuid" */
1057 int testRun; /* True for a test run. Debugging only */
1058 const char *zBranch; /* Create a new branch with this name */
@@ -1069,11 +1091,10 @@
1069 Blob cksum1, cksum2; /* Before and after commit checksums */
1070 Blob cksum1b; /* Checksum recorded in the manifest */
1071 int szD; /* Size of the delta manifest */
1072 int szB; /* Size of the baseline manifest */
1073 int nConflict = 0; /* Number of unresolved merge conflicts */
1074 int abortCommit = 0;
1075 Blob ans;
1076 char cReply;
1077
1078 url_proxy_options();
1079 noSign = find_option("nosign",0,0)!=0;
@@ -1083,14 +1104,18 @@
1083 fossil_fatal("cannot use --delta and --baseline together");
1084 }
1085 testRun = find_option("test",0,0)!=0;
1086 zComment = find_option("comment","m",1);
1087 forceFlag = find_option("force", "f", 0)!=0;
 
 
 
 
 
1088 zBranch = find_option("branch","b",1);
1089 zColor = find_option("bgcolor",0,1);
1090 zBrClr = find_option("branchcolor",0,1);
1091 binaryOk = find_option("binary-ok",0,0)!=0;
1092 while( (zTag = find_option("tag",0,1))!=0 ){
1093 if( zTag[0]==0 ) continue;
1094 azTag = fossil_realloc((void *)azTag, sizeof(char*)*(nTag+2));
1095 azTag[nTag++] = zTag;
1096 azTag[nTag] = 0;
@@ -1101,11 +1126,10 @@
1101 if( zBranch==0 ) zBranch = "private";
1102 if( zBrClr==0 && zColor==0 ) zBrClr = "#fec084"; /* Orange */
1103 }
1104 zDateOvrd = find_option("date-override",0,1);
1105 zUserOvrd = find_option("user-override",0,1);
1106 allowConflict = find_option("conflict",0,0)!=0;
1107 db_must_be_within_tree();
1108 noSign = db_get_boolean("omitsign", 0)|noSign;
1109 if( db_get_boolean("clearsign", 0)==0 ){ noSign = 1; }
1110 useCksum = db_get_boolean("repo-cksum", 1);
1111 outputManifest = db_get_boolean("manifest", 0);
@@ -1136,11 +1160,11 @@
1136
1137 /*
1138 ** Autosync if autosync is enabled and this is not a private check-in.
1139 */
1140 if( !g.markPrivate ){
1141 if( autosync(AUTOSYNC_PULL) ){
1142 blob_zero(&ans);
1143 prompt_user("continue in spite of sync failure (y/N)? ", &ans);
1144 cReply = blob_str(&ans)[0];
1145 if( cReply!='y' && cReply!='Y' ){
1146 fossil_exit(1);
@@ -1208,34 +1232,38 @@
1208 }
1209
1210 hasChanges = unsaved_changes();
1211 db_begin_transaction();
1212 db_record_repository_filename(0);
1213 if( hasChanges==0 && !isAMerge && !forceFlag ){
1214 fossil_fatal("nothing has changed");
1215 }
1216
1217 /* If none of the files that were named on the command line have
1218 ** been modified, bail out now unless the --force flag is used.
 
1219 */
1220 if( g.aCommitFile
 
1221 && !forceFlag
1222 && !db_exists(
1223 "SELECT 1 FROM vfile "
1224 " WHERE is_selected(id)"
1225 " AND (chnged OR deleted OR rid=0 OR pathname!=origname)")
1226 ){
1227 fossil_fatal("none of the selected files have changed; use -f"
1228 " or --force.");
1229 }
1230
1231 /*
1232 ** Do not allow a commit that will cause a fork unless the --force flag
1233 ** is used or unless this is a private check-in.
1234 */
1235 if( zBranch==0 && forceFlag==0 && g.markPrivate==0 && !is_a_leaf(vid) ){
1236 fossil_fatal("would fork. \"update\" first or use -f or --force.");
 
 
1237 }
1238
1239 /*
1240 ** Do not allow a commit against a closed leaf
1241 */
@@ -1280,36 +1308,42 @@
1280 /* Step 1: Insert records for all modified files into the blob
1281 ** table. If there were arguments passed to this command, only
1282 ** the identified files are inserted (if they have been modified).
1283 */
1284 db_prepare(&q,
1285 "SELECT id, %Q || pathname, mrid, %s, chnged, %s FROM vfile "
1286 "WHERE chnged==1 AND NOT deleted AND is_selected(id)",
1287 g.zLocalRoot, glob_expr("pathname", db_get("crnl-glob","")),
1288 glob_expr("pathname", db_get("binary-glob",""))
 
 
1289 );
1290 while( db_step(&q)==SQLITE_ROW ){
1291 int id, rid;
1292 const char *zFullname;
1293 Blob content;
1294 int crnlOk, binOk, chnged;
1295
1296 id = db_column_int(&q, 0);
1297 zFullname = db_column_text(&q, 1);
1298 rid = db_column_int(&q, 2);
1299 crnlOk = db_column_int(&q, 3);
1300 chnged = db_column_int(&q, 4);
1301 binOk = binaryOk || db_column_int(&q, 5);
 
1302
1303 blob_zero(&content);
1304 if( file_wd_islink(zFullname) ){
1305 /* Instead of file content, put link destination path */
1306 blob_read_link(&content, zFullname);
1307 }else{
1308 blob_read_from_file(&content, zFullname);
1309 }
1310 abortCommit |= commit_warning(&content, crnlOk, binOk, zFullname);
 
 
 
1311 if( chnged==1 && contains_merge_marker(&content) ){
1312 Blob fname; /* Relative pathname of the file */
1313
1314 nConflict++;
1315 file_relative_name(zFullname, &fname, 0);
@@ -1325,13 +1359,12 @@
1325 db_multi_exec("UPDATE vfile SET mrid=%d, rid=%d WHERE id=%d", nrid,nrid,id);
1326 db_multi_exec("INSERT OR IGNORE INTO unsent VALUES(%d)", nrid);
1327 }
1328 db_finalize(&q);
1329 if( nConflict && !allowConflict ){
1330 fossil_fatal("abort due to unresolve merge conflicts");
1331 } else if( abortCommit ){
1332 fossil_fatal("files are converted on your request. Please re-test before committing");
1333 }
1334
1335 /* Create the new manifest */
1336 if( blob_size(&comment)==0 ){
1337 blob_append(&comment, "(no comment)", -1);
@@ -1338,11 +1371,11 @@
1338 }
1339 if( forceDelta ){
1340 blob_zero(&manifest);
1341 }else{
1342 create_manifest(&manifest, 0, 0, &comment, vid,
1343 !forceFlag, useCksum ? &cksum1 : 0,
1344 zDateOvrd, zUserOvrd, zBranch, zColor, zBrClr,
1345 azTag, &szB);
1346 }
1347
1348 /* See if a delta-manifest would be more appropriate */
@@ -1359,11 +1392,11 @@
1359 pBaseline = pParent;
1360 }
1361 if( pBaseline ){
1362 Blob delta;
1363 create_manifest(&delta, zBaselineUuid, pBaseline, &comment, vid,
1364 !forceFlag, useCksum ? &cksum1 : 0,
1365 zDateOvrd, zUserOvrd, zBranch, zColor, zBrClr,
1366 azTag, &szD);
1367 /*
1368 ** At this point, two manifests have been constructed, either of
1369 ** which would work for this checkin. The first manifest (held
@@ -1489,11 +1522,11 @@
1489 exit(1);
1490 }
1491 db_end_transaction(0);
1492
1493 if( !g.markPrivate ){
1494 autosync(AUTOSYNC_PUSH);
1495 }
1496 if( count_nonbranch_children(vid)>1 ){
1497 fossil_print("**** warning: a fork has occurred *****\n");
1498 }
1499 }
1500
--- src/checkin.c
+++ src/checkin.c
@@ -582,11 +582,10 @@
582 blob_init(&prompt, zInit, -1);
583 #endif
584 blob_append(&prompt,
585 "\n"
586 "# Enter comments on this check-in. Lines beginning with # are ignored.\n"
 
587 "#\n", -1
588 );
589 blob_appendf(&prompt, "# user: %s\n", zUserOvrd ? zUserOvrd : g.zLogin);
590 if( zBranch && zBranch[0] ){
591 blob_appendf(&prompt, "# tags: %s\n#\n", zBranch);
@@ -658,11 +657,11 @@
657 " AND type='ci' AND objid=%d",
658 zDate, rid
659 );
660 if( b ){
661 fossil_fatal("ancestor check-in [%.10s] (%s) is not older (clock skew?)"
662 " Use --allow-older to override.", zUuid, zDate);
663 }
664 #endif
665 }
666
667 /*
@@ -896,28 +895,32 @@
895 */
896 static int commit_warning(
897 Blob *p, /* The content of the file being committed. */
898 int crnlOk, /* Non-zero if CR/NL warnings should be disabled. */
899 int binOk, /* Non-zero if binary warnings should be disabled. */
900 int unicodeOk, /* Non-zero if unicode warnings should be disabled. */
901 const char *zFilename /* The full name of the file being committed. */
902 ){
903 int eType; /* return value of looks_like_utf8/utf16() */
904 int fUnicode; /* return value of starts_with_utf16_bom() */
905 char *zMsg; /* Warning message */
906 Blob fname; /* Relative pathname of the file */
907 static int allOk = 0; /* Set to true to disable this routine */
908
909 if( allOk ) return 0;
910 fUnicode = starts_with_utf16_bom(p, 0);
911 eType = fUnicode ? looks_like_utf16(p) : looks_like_utf8(p);
912 if( eType==0 || eType==-1 || fUnicode ){
913 const char *zWarning;
914 const char *zConvert = "c=convert/";
915 Blob ans;
916 char cReply;
917
918 if( eType==-1 && fUnicode ){
919 if ( crnlOk && unicodeOk ){
920 return 0; /* We don't want Unicode/CR/NL warnings for this file. */
921 }
922 zWarning = "Unicode and CR/NL line endings";
923 }else if( eType==-1 ){
924 if( crnlOk ){
925 return 0; /* We don't want CR/NL warnings for this file. */
926 }
@@ -927,10 +930,13 @@
930 return 0; /* We don't want binary warnings for this file. */
931 }
932 zWarning = "binary data";
933 zConvert = ""; /* We cannot convert binary files. */
934 }else{
935 if ( unicodeOk ){
936 return 0; /* We don't want unicode warnings for this file. */
937 }
938 zWarning = "Unicode";
939 #ifndef _WIN32
940 zConvert = ""; /* On Unix, we cannot easily convert Unicode files. */
941 #endif
942 }
@@ -1008,32 +1014,45 @@
1014 **
1015 ** The --bgcolor option works like --branchcolor but only sets the
1016 ** background color for a single check-in. Subsequent check-ins revert
1017 ** to the default color.
1018 **
1019 ** A check-in is not permitted to fork unless the --allow-fork option
1020 ** appears. An empty check-in (i.e. with nothing changed) is not
1021 ** allowed unless the --allow-empty option appears. A check-in may not
1022 ** be older than its ancestor unless the --allow-older option appears.
1023 ** If any of files in the check-in appear to contain unresolved merge
1024 ** conflicts, the check-in will not be allowed unless the
1025 ** --allow-conflict option is present. In addition, the entire
1026 ** check-in process may be aborted if a file contains content that
1027 ** appears to be binary, Unicode text, or text with CR/NL line endings
1028 ** unless the interactive user chooses to proceed. If there is no
1029 ** interactive user or these warnings should be skipped for some other
1030 ** reason, the --no-warnings option may be used. A check-in is not
1031 ** allowed against a closed leaf.
1032 **
1033 ** The --private option creates a private check-in that is never synced.
1034 ** Children of private check-ins are automatically private.
1035 **
1036 ** the --tag option applies the symbolic tag name to the check-in.
1037 **
1038 ** Options:
1039 ** --allow-conflict allow unresolved merge conflicts
1040 ** --allow-empty allow a commit with no changes
1041 ** --allow-fork allow the commit to fork
1042 ** --allow-older allow a commit older than its ancestor
1043 ** --baseline use a baseline manifest in the commit process
1044 ** --bgcolor COLOR apply COLOR to this one check-in only
1045 ** --branch NEW-BRANCH-NAME check in to this new branch
1046 ** --branchcolor COLOR apply given COLOR to the branch
1047 ** --comment|-m COMMENT-TEXT use COMMENT-TEXT as commit comment
1048 ** --delta use a delta manifest in the commit process
 
1049 ** --message-file|-M FILE read the commit comment from given file
1050 ** --no-warnings omit all warnings about file contents
1051 ** --nosign do not attempt to sign this commit with gpg
1052 ** --private do not sync changes and their descendants
1053 ** --tag TAG-NAME assign given tag TAG-NAME to the checkin
 
 
1054 **
1055 ** See also: branch, changes, checkout, extra, sync
1056 */
1057 void commit_cmd(void){
1058 int hasChanges; /* True if unsaved changes exist */
@@ -1044,15 +1063,18 @@
1063 const char *zComment; /* Check-in comment */
1064 Stmt q; /* Query to find files that have been modified */
1065 char *zUuid; /* UUID of the new check-in */
1066 int noSign = 0; /* True to omit signing the manifest using GPG */
1067 int isAMerge = 0; /* True if checking in a merge */
1068 int noWarningFlag = 0; /* True if skipping all warnings */
1069 int forceFlag = 0; /* Undocumented: Disables all checks */
1070 int forceDelta = 0; /* Force a delta-manifest */
1071 int forceBaseline = 0; /* Force a baseline-manifest */
1072 int allowConflict = 0; /* Allow unresolve merge conflicts */
1073 int allowEmpty = 0; /* Allow a commit with no changes */
1074 int allowFork = 0; /* Allow the commit to fork */
1075 int allowOlder = 0; /* Allow a commit older than its ancestor */
1076 char *zManifestFile; /* Name of the manifest file */
1077 int useCksum; /* True if checksums should be computed and verified */
1078 int outputManifest; /* True to output "manifest" and "manifest.uuid" */
1079 int testRun; /* True for a test run. Debugging only */
1080 const char *zBranch; /* Create a new branch with this name */
@@ -1069,11 +1091,10 @@
1091 Blob cksum1, cksum2; /* Before and after commit checksums */
1092 Blob cksum1b; /* Checksum recorded in the manifest */
1093 int szD; /* Size of the delta manifest */
1094 int szB; /* Size of the baseline manifest */
1095 int nConflict = 0; /* Number of unresolved merge conflicts */
 
1096 Blob ans;
1097 char cReply;
1098
1099 url_proxy_options();
1100 noSign = find_option("nosign",0,0)!=0;
@@ -1083,14 +1104,18 @@
1104 fossil_fatal("cannot use --delta and --baseline together");
1105 }
1106 testRun = find_option("test",0,0)!=0;
1107 zComment = find_option("comment","m",1);
1108 forceFlag = find_option("force", "f", 0)!=0;
1109 allowConflict = find_option("allow-conflict",0,0)!=0;
1110 allowEmpty = find_option("allow-empty",0,0)!=0;
1111 allowFork = find_option("allow-fork",0,0)!=0;
1112 allowOlder = find_option("allow-older",0,0)!=0;
1113 noWarningFlag = find_option("no-warnings", 0, 0)!=0;
1114 zBranch = find_option("branch","b",1);
1115 zColor = find_option("bgcolor",0,1);
1116 zBrClr = find_option("branchcolor",0,1);
 
1117 while( (zTag = find_option("tag",0,1))!=0 ){
1118 if( zTag[0]==0 ) continue;
1119 azTag = fossil_realloc((void *)azTag, sizeof(char*)*(nTag+2));
1120 azTag[nTag++] = zTag;
1121 azTag[nTag] = 0;
@@ -1101,11 +1126,10 @@
1126 if( zBranch==0 ) zBranch = "private";
1127 if( zBrClr==0 && zColor==0 ) zBrClr = "#fec084"; /* Orange */
1128 }
1129 zDateOvrd = find_option("date-override",0,1);
1130 zUserOvrd = find_option("user-override",0,1);
 
1131 db_must_be_within_tree();
1132 noSign = db_get_boolean("omitsign", 0)|noSign;
1133 if( db_get_boolean("clearsign", 0)==0 ){ noSign = 1; }
1134 useCksum = db_get_boolean("repo-cksum", 1);
1135 outputManifest = db_get_boolean("manifest", 0);
@@ -1136,11 +1160,11 @@
1160
1161 /*
1162 ** Autosync if autosync is enabled and this is not a private check-in.
1163 */
1164 if( !g.markPrivate ){
1165 if( autosync(SYNC_PULL) ){
1166 blob_zero(&ans);
1167 prompt_user("continue in spite of sync failure (y/N)? ", &ans);
1168 cReply = blob_str(&ans)[0];
1169 if( cReply!='y' && cReply!='Y' ){
1170 fossil_exit(1);
@@ -1208,34 +1232,38 @@
1232 }
1233
1234 hasChanges = unsaved_changes();
1235 db_begin_transaction();
1236 db_record_repository_filename(0);
1237 if( hasChanges==0 && !isAMerge && !allowEmpty && !forceFlag ){
1238 fossil_fatal("nothing has changed; use --allow-empty to override");
1239 }
1240
1241 /* If none of the files that were named on the command line have
1242 ** been modified, bail out now unless the --allow-empty or --force
1243 ** flags is used.
1244 */
1245 if( g.aCommitFile
1246 && !allowEmpty
1247 && !forceFlag
1248 && !db_exists(
1249 "SELECT 1 FROM vfile "
1250 " WHERE is_selected(id)"
1251 " AND (chnged OR deleted OR rid=0 OR pathname!=origname)")
1252 ){
1253 fossil_fatal("none of the selected files have changed; use "
1254 "--allow-empty to override.");
1255 }
1256
1257 /*
1258 ** Do not allow a commit that will cause a fork unless the --allow-fork
1259 ** or --force flags is used, or unless this is a private check-in.
1260 */
1261 if( zBranch==0 && allowFork==0 && forceFlag==0
1262 && g.markPrivate==0 && !is_a_leaf(vid)
1263 ){
1264 fossil_fatal("would fork. \"update\" first or use --allow-fork.");
1265 }
1266
1267 /*
1268 ** Do not allow a commit against a closed leaf
1269 */
@@ -1280,36 +1308,42 @@
1308 /* Step 1: Insert records for all modified files into the blob
1309 ** table. If there were arguments passed to this command, only
1310 ** the identified files are inserted (if they have been modified).
1311 */
1312 db_prepare(&q,
1313 "SELECT id, %Q || pathname, mrid, %s, chnged, %s, %s FROM vfile "
1314 "WHERE chnged==1 AND NOT deleted AND is_selected(id)",
1315 g.zLocalRoot,
1316 glob_expr("pathname", db_get("crnl-glob","")),
1317 glob_expr("pathname", db_get("binary-glob","")),
1318 glob_expr("pathname", db_get("unicode-glob",""))
1319 );
1320 while( db_step(&q)==SQLITE_ROW ){
1321 int id, rid;
1322 const char *zFullname;
1323 Blob content;
1324 int crnlOk, binOk, unicodeOk, chnged;
1325
1326 id = db_column_int(&q, 0);
1327 zFullname = db_column_text(&q, 1);
1328 rid = db_column_int(&q, 2);
1329 crnlOk = db_column_int(&q, 3);
1330 chnged = db_column_int(&q, 4);
1331 binOk = db_column_int(&q, 5);
1332 unicodeOk = db_column_int(&q, 6);
1333
1334 blob_zero(&content);
1335 if( file_wd_islink(zFullname) ){
1336 /* Instead of file content, put link destination path */
1337 blob_read_link(&content, zFullname);
1338 }else{
1339 blob_read_from_file(&content, zFullname);
1340 }
1341 /* Do not emit any warnings when they are disabled. */
1342 if( !noWarningFlag ){
1343 commit_warning(&content, crnlOk, binOk, unicodeOk, zFullname);
1344 }
1345 if( chnged==1 && contains_merge_marker(&content) ){
1346 Blob fname; /* Relative pathname of the file */
1347
1348 nConflict++;
1349 file_relative_name(zFullname, &fname, 0);
@@ -1325,13 +1359,12 @@
1359 db_multi_exec("UPDATE vfile SET mrid=%d, rid=%d WHERE id=%d", nrid,nrid,id);
1360 db_multi_exec("INSERT OR IGNORE INTO unsent VALUES(%d)", nrid);
1361 }
1362 db_finalize(&q);
1363 if( nConflict && !allowConflict ){
1364 fossil_fatal("abort due to unresolved merge conflicts; "
1365 "use --allow-conflict to override");
 
1366 }
1367
1368 /* Create the new manifest */
1369 if( blob_size(&comment)==0 ){
1370 blob_append(&comment, "(no comment)", -1);
@@ -1338,11 +1371,11 @@
1371 }
1372 if( forceDelta ){
1373 blob_zero(&manifest);
1374 }else{
1375 create_manifest(&manifest, 0, 0, &comment, vid,
1376 !allowOlder && !forceFlag, useCksum ? &cksum1 : 0,
1377 zDateOvrd, zUserOvrd, zBranch, zColor, zBrClr,
1378 azTag, &szB);
1379 }
1380
1381 /* See if a delta-manifest would be more appropriate */
@@ -1359,11 +1392,11 @@
1392 pBaseline = pParent;
1393 }
1394 if( pBaseline ){
1395 Blob delta;
1396 create_manifest(&delta, zBaselineUuid, pBaseline, &comment, vid,
1397 !allowOlder && !forceFlag, useCksum ? &cksum1 : 0,
1398 zDateOvrd, zUserOvrd, zBranch, zColor, zBrClr,
1399 azTag, &szD);
1400 /*
1401 ** At this point, two manifests have been constructed, either of
1402 ** which would work for this checkin. The first manifest (held
@@ -1489,11 +1522,11 @@
1522 exit(1);
1523 }
1524 db_end_transaction(0);
1525
1526 if( !g.markPrivate ){
1527 autosync(SYNC_PUSH);
1528 }
1529 if( count_nonbranch_children(vid)>1 ){
1530 fossil_print("**** warning: a fork has occurred *****\n");
1531 }
1532 }
1533
+68 -35
--- src/checkin.c
+++ src/checkin.c
@@ -582,11 +582,10 @@
582582
blob_init(&prompt, zInit, -1);
583583
#endif
584584
blob_append(&prompt,
585585
"\n"
586586
"# Enter comments on this check-in. Lines beginning with # are ignored.\n"
587
- "# The check-in comment follows wiki formatting rules.\n"
588587
"#\n", -1
589588
);
590589
blob_appendf(&prompt, "# user: %s\n", zUserOvrd ? zUserOvrd : g.zLogin);
591590
if( zBranch && zBranch[0] ){
592591
blob_appendf(&prompt, "# tags: %s\n#\n", zBranch);
@@ -658,11 +657,11 @@
658657
" AND type='ci' AND objid=%d",
659658
zDate, rid
660659
);
661660
if( b ){
662661
fossil_fatal("ancestor check-in [%.10s] (%s) is not older (clock skew?)"
663
- " Use -f to override.", zUuid, zDate);
662
+ " Use --allow-older to override.", zUuid, zDate);
664663
}
665664
#endif
666665
}
667666
668667
/*
@@ -896,28 +895,32 @@
896895
*/
897896
static int commit_warning(
898897
Blob *p, /* The content of the file being committed. */
899898
int crnlOk, /* Non-zero if CR/NL warnings should be disabled. */
900899
int binOk, /* Non-zero if binary warnings should be disabled. */
900
+ int unicodeOk, /* Non-zero if unicode warnings should be disabled. */
901901
const char *zFilename /* The full name of the file being committed. */
902902
){
903903
int eType; /* return value of looks_like_utf8/utf16() */
904904
int fUnicode; /* return value of starts_with_utf16_bom() */
905905
char *zMsg; /* Warning message */
906906
Blob fname; /* Relative pathname of the file */
907907
static int allOk = 0; /* Set to true to disable this routine */
908908
909909
if( allOk ) return 0;
910
- fUnicode = starts_with_utf16_bom(p);
910
+ fUnicode = starts_with_utf16_bom(p, 0);
911911
eType = fUnicode ? looks_like_utf16(p) : looks_like_utf8(p);
912912
if( eType==0 || eType==-1 || fUnicode ){
913913
const char *zWarning;
914914
const char *zConvert = "c=convert/";
915915
Blob ans;
916916
char cReply;
917917
918918
if( eType==-1 && fUnicode ){
919
+ if ( crnlOk && unicodeOk ){
920
+ return 0; /* We don't want Unicode/CR/NL warnings for this file. */
921
+ }
919922
zWarning = "Unicode and CR/NL line endings";
920923
}else if( eType==-1 ){
921924
if( crnlOk ){
922925
return 0; /* We don't want CR/NL warnings for this file. */
923926
}
@@ -927,10 +930,13 @@
927930
return 0; /* We don't want binary warnings for this file. */
928931
}
929932
zWarning = "binary data";
930933
zConvert = ""; /* We cannot convert binary files. */
931934
}else{
935
+ if ( unicodeOk ){
936
+ return 0; /* We don't want unicode warnings for this file. */
937
+ }
932938
zWarning = "Unicode";
933939
#ifndef _WIN32
934940
zConvert = ""; /* On Unix, we cannot easily convert Unicode files. */
935941
#endif
936942
}
@@ -1008,32 +1014,45 @@
10081014
**
10091015
** The --bgcolor option works like --branchcolor but only sets the
10101016
** background color for a single check-in. Subsequent check-ins revert
10111017
** to the default color.
10121018
**
1013
-** A check-in is not permitted to fork unless the --force or -f
1014
-** option appears. A check-in is not allowed against a closed leaf.
1019
+** A check-in is not permitted to fork unless the --allow-fork option
1020
+** appears. An empty check-in (i.e. with nothing changed) is not
1021
+** allowed unless the --allow-empty option appears. A check-in may not
1022
+** be older than its ancestor unless the --allow-older option appears.
1023
+** If any of files in the check-in appear to contain unresolved merge
1024
+** conflicts, the check-in will not be allowed unless the
1025
+** --allow-conflict option is present. In addition, the entire
1026
+** check-in process may be aborted if a file contains content that
1027
+** appears to be binary, Unicode text, or text with CR/NL line endings
1028
+** unless the interactive user chooses to proceed. If there is no
1029
+** interactive user or these warnings should be skipped for some other
1030
+** reason, the --no-warnings option may be used. A check-in is not
1031
+** allowed against a closed leaf.
10151032
**
10161033
** The --private option creates a private check-in that is never synced.
10171034
** Children of private check-ins are automatically private.
10181035
**
10191036
** the --tag option applies the symbolic tag name to the check-in.
10201037
**
10211038
** Options:
1039
+** --allow-conflict allow unresolved merge conflicts
1040
+** --allow-empty allow a commit with no changes
1041
+** --allow-fork allow the commit to fork
1042
+** --allow-older allow a commit older than its ancestor
10221043
** --baseline use a baseline manifest in the commit process
10231044
** --bgcolor COLOR apply COLOR to this one check-in only
10241045
** --branch NEW-BRANCH-NAME check in to this new branch
10251046
** --branchcolor COLOR apply given COLOR to the branch
10261047
** --comment|-m COMMENT-TEXT use COMMENT-TEXT as commit comment
10271048
** --delta use a delta manifest in the commit process
1028
-** --force|-f allow forking with this commit
10291049
** --message-file|-M FILE read the commit comment from given file
1050
+** --no-warnings omit all warnings about file contents
10301051
** --nosign do not attempt to sign this commit with gpg
10311052
** --private do not sync changes and their descendants
10321053
** --tag TAG-NAME assign given tag TAG-NAME to the checkin
1033
-** --conflict allow unresolved merge conflicts
1034
-** --binary-ok do not warn about committing binary files
10351054
**
10361055
** See also: branch, changes, checkout, extra, sync
10371056
*/
10381057
void commit_cmd(void){
10391058
int hasChanges; /* True if unsaved changes exist */
@@ -1044,15 +1063,18 @@
10441063
const char *zComment; /* Check-in comment */
10451064
Stmt q; /* Query to find files that have been modified */
10461065
char *zUuid; /* UUID of the new check-in */
10471066
int noSign = 0; /* True to omit signing the manifest using GPG */
10481067
int isAMerge = 0; /* True if checking in a merge */
1049
- int forceFlag = 0; /* Force a fork */
1068
+ int noWarningFlag = 0; /* True if skipping all warnings */
1069
+ int forceFlag = 0; /* Undocumented: Disables all checks */
10501070
int forceDelta = 0; /* Force a delta-manifest */
10511071
int forceBaseline = 0; /* Force a baseline-manifest */
10521072
int allowConflict = 0; /* Allow unresolve merge conflicts */
1053
- int binaryOk = 0; /* The --binary-ok flag */
1073
+ int allowEmpty = 0; /* Allow a commit with no changes */
1074
+ int allowFork = 0; /* Allow the commit to fork */
1075
+ int allowOlder = 0; /* Allow a commit older than its ancestor */
10541076
char *zManifestFile; /* Name of the manifest file */
10551077
int useCksum; /* True if checksums should be computed and verified */
10561078
int outputManifest; /* True to output "manifest" and "manifest.uuid" */
10571079
int testRun; /* True for a test run. Debugging only */
10581080
const char *zBranch; /* Create a new branch with this name */
@@ -1069,11 +1091,10 @@
10691091
Blob cksum1, cksum2; /* Before and after commit checksums */
10701092
Blob cksum1b; /* Checksum recorded in the manifest */
10711093
int szD; /* Size of the delta manifest */
10721094
int szB; /* Size of the baseline manifest */
10731095
int nConflict = 0; /* Number of unresolved merge conflicts */
1074
- int abortCommit = 0;
10751096
Blob ans;
10761097
char cReply;
10771098
10781099
url_proxy_options();
10791100
noSign = find_option("nosign",0,0)!=0;
@@ -1083,14 +1104,18 @@
10831104
fossil_fatal("cannot use --delta and --baseline together");
10841105
}
10851106
testRun = find_option("test",0,0)!=0;
10861107
zComment = find_option("comment","m",1);
10871108
forceFlag = find_option("force", "f", 0)!=0;
1109
+ allowConflict = find_option("allow-conflict",0,0)!=0;
1110
+ allowEmpty = find_option("allow-empty",0,0)!=0;
1111
+ allowFork = find_option("allow-fork",0,0)!=0;
1112
+ allowOlder = find_option("allow-older",0,0)!=0;
1113
+ noWarningFlag = find_option("no-warnings", 0, 0)!=0;
10881114
zBranch = find_option("branch","b",1);
10891115
zColor = find_option("bgcolor",0,1);
10901116
zBrClr = find_option("branchcolor",0,1);
1091
- binaryOk = find_option("binary-ok",0,0)!=0;
10921117
while( (zTag = find_option("tag",0,1))!=0 ){
10931118
if( zTag[0]==0 ) continue;
10941119
azTag = fossil_realloc((void *)azTag, sizeof(char*)*(nTag+2));
10951120
azTag[nTag++] = zTag;
10961121
azTag[nTag] = 0;
@@ -1101,11 +1126,10 @@
11011126
if( zBranch==0 ) zBranch = "private";
11021127
if( zBrClr==0 && zColor==0 ) zBrClr = "#fec084"; /* Orange */
11031128
}
11041129
zDateOvrd = find_option("date-override",0,1);
11051130
zUserOvrd = find_option("user-override",0,1);
1106
- allowConflict = find_option("conflict",0,0)!=0;
11071131
db_must_be_within_tree();
11081132
noSign = db_get_boolean("omitsign", 0)|noSign;
11091133
if( db_get_boolean("clearsign", 0)==0 ){ noSign = 1; }
11101134
useCksum = db_get_boolean("repo-cksum", 1);
11111135
outputManifest = db_get_boolean("manifest", 0);
@@ -1136,11 +1160,11 @@
11361160
11371161
/*
11381162
** Autosync if autosync is enabled and this is not a private check-in.
11391163
*/
11401164
if( !g.markPrivate ){
1141
- if( autosync(AUTOSYNC_PULL) ){
1165
+ if( autosync(SYNC_PULL) ){
11421166
blob_zero(&ans);
11431167
prompt_user("continue in spite of sync failure (y/N)? ", &ans);
11441168
cReply = blob_str(&ans)[0];
11451169
if( cReply!='y' && cReply!='Y' ){
11461170
fossil_exit(1);
@@ -1208,34 +1232,38 @@
12081232
}
12091233
12101234
hasChanges = unsaved_changes();
12111235
db_begin_transaction();
12121236
db_record_repository_filename(0);
1213
- if( hasChanges==0 && !isAMerge && !forceFlag ){
1214
- fossil_fatal("nothing has changed");
1237
+ if( hasChanges==0 && !isAMerge && !allowEmpty && !forceFlag ){
1238
+ fossil_fatal("nothing has changed; use --allow-empty to override");
12151239
}
12161240
12171241
/* If none of the files that were named on the command line have
1218
- ** been modified, bail out now unless the --force flag is used.
1242
+ ** been modified, bail out now unless the --allow-empty or --force
1243
+ ** flags is used.
12191244
*/
12201245
if( g.aCommitFile
1246
+ && !allowEmpty
12211247
&& !forceFlag
12221248
&& !db_exists(
12231249
"SELECT 1 FROM vfile "
12241250
" WHERE is_selected(id)"
12251251
" AND (chnged OR deleted OR rid=0 OR pathname!=origname)")
12261252
){
1227
- fossil_fatal("none of the selected files have changed; use -f"
1228
- " or --force.");
1253
+ fossil_fatal("none of the selected files have changed; use "
1254
+ "--allow-empty to override.");
12291255
}
12301256
12311257
/*
1232
- ** Do not allow a commit that will cause a fork unless the --force flag
1233
- ** is used or unless this is a private check-in.
1258
+ ** Do not allow a commit that will cause a fork unless the --allow-fork
1259
+ ** or --force flags is used, or unless this is a private check-in.
12341260
*/
1235
- if( zBranch==0 && forceFlag==0 && g.markPrivate==0 && !is_a_leaf(vid) ){
1236
- fossil_fatal("would fork. \"update\" first or use -f or --force.");
1261
+ if( zBranch==0 && allowFork==0 && forceFlag==0
1262
+ && g.markPrivate==0 && !is_a_leaf(vid)
1263
+ ){
1264
+ fossil_fatal("would fork. \"update\" first or use --allow-fork.");
12371265
}
12381266
12391267
/*
12401268
** Do not allow a commit against a closed leaf
12411269
*/
@@ -1280,36 +1308,42 @@
12801308
/* Step 1: Insert records for all modified files into the blob
12811309
** table. If there were arguments passed to this command, only
12821310
** the identified files are inserted (if they have been modified).
12831311
*/
12841312
db_prepare(&q,
1285
- "SELECT id, %Q || pathname, mrid, %s, chnged, %s FROM vfile "
1313
+ "SELECT id, %Q || pathname, mrid, %s, chnged, %s, %s FROM vfile "
12861314
"WHERE chnged==1 AND NOT deleted AND is_selected(id)",
1287
- g.zLocalRoot, glob_expr("pathname", db_get("crnl-glob","")),
1288
- glob_expr("pathname", db_get("binary-glob",""))
1315
+ g.zLocalRoot,
1316
+ glob_expr("pathname", db_get("crnl-glob","")),
1317
+ glob_expr("pathname", db_get("binary-glob","")),
1318
+ glob_expr("pathname", db_get("unicode-glob",""))
12891319
);
12901320
while( db_step(&q)==SQLITE_ROW ){
12911321
int id, rid;
12921322
const char *zFullname;
12931323
Blob content;
1294
- int crnlOk, binOk, chnged;
1324
+ int crnlOk, binOk, unicodeOk, chnged;
12951325
12961326
id = db_column_int(&q, 0);
12971327
zFullname = db_column_text(&q, 1);
12981328
rid = db_column_int(&q, 2);
12991329
crnlOk = db_column_int(&q, 3);
13001330
chnged = db_column_int(&q, 4);
1301
- binOk = binaryOk || db_column_int(&q, 5);
1331
+ binOk = db_column_int(&q, 5);
1332
+ unicodeOk = db_column_int(&q, 6);
13021333
13031334
blob_zero(&content);
13041335
if( file_wd_islink(zFullname) ){
13051336
/* Instead of file content, put link destination path */
13061337
blob_read_link(&content, zFullname);
13071338
}else{
13081339
blob_read_from_file(&content, zFullname);
13091340
}
1310
- abortCommit |= commit_warning(&content, crnlOk, binOk, zFullname);
1341
+ /* Do not emit any warnings when they are disabled. */
1342
+ if( !noWarningFlag ){
1343
+ commit_warning(&content, crnlOk, binOk, unicodeOk, zFullname);
1344
+ }
13111345
if( chnged==1 && contains_merge_marker(&content) ){
13121346
Blob fname; /* Relative pathname of the file */
13131347
13141348
nConflict++;
13151349
file_relative_name(zFullname, &fname, 0);
@@ -1325,13 +1359,12 @@
13251359
db_multi_exec("UPDATE vfile SET mrid=%d, rid=%d WHERE id=%d", nrid,nrid,id);
13261360
db_multi_exec("INSERT OR IGNORE INTO unsent VALUES(%d)", nrid);
13271361
}
13281362
db_finalize(&q);
13291363
if( nConflict && !allowConflict ){
1330
- fossil_fatal("abort due to unresolve merge conflicts");
1331
- } else if( abortCommit ){
1332
- fossil_fatal("files are converted on your request. Please re-test before committing");
1364
+ fossil_fatal("abort due to unresolved merge conflicts; "
1365
+ "use --allow-conflict to override");
13331366
}
13341367
13351368
/* Create the new manifest */
13361369
if( blob_size(&comment)==0 ){
13371370
blob_append(&comment, "(no comment)", -1);
@@ -1338,11 +1371,11 @@
13381371
}
13391372
if( forceDelta ){
13401373
blob_zero(&manifest);
13411374
}else{
13421375
create_manifest(&manifest, 0, 0, &comment, vid,
1343
- !forceFlag, useCksum ? &cksum1 : 0,
1376
+ !allowOlder && !forceFlag, useCksum ? &cksum1 : 0,
13441377
zDateOvrd, zUserOvrd, zBranch, zColor, zBrClr,
13451378
azTag, &szB);
13461379
}
13471380
13481381
/* See if a delta-manifest would be more appropriate */
@@ -1359,11 +1392,11 @@
13591392
pBaseline = pParent;
13601393
}
13611394
if( pBaseline ){
13621395
Blob delta;
13631396
create_manifest(&delta, zBaselineUuid, pBaseline, &comment, vid,
1364
- !forceFlag, useCksum ? &cksum1 : 0,
1397
+ !allowOlder && !forceFlag, useCksum ? &cksum1 : 0,
13651398
zDateOvrd, zUserOvrd, zBranch, zColor, zBrClr,
13661399
azTag, &szD);
13671400
/*
13681401
** At this point, two manifests have been constructed, either of
13691402
** which would work for this checkin. The first manifest (held
@@ -1489,11 +1522,11 @@
14891522
exit(1);
14901523
}
14911524
db_end_transaction(0);
14921525
14931526
if( !g.markPrivate ){
1494
- autosync(AUTOSYNC_PUSH);
1527
+ autosync(SYNC_PUSH);
14951528
}
14961529
if( count_nonbranch_children(vid)>1 ){
14971530
fossil_print("**** warning: a fork has occurred *****\n");
14981531
}
14991532
}
15001533
--- src/checkin.c
+++ src/checkin.c
@@ -582,11 +582,10 @@
582 blob_init(&prompt, zInit, -1);
583 #endif
584 blob_append(&prompt,
585 "\n"
586 "# Enter comments on this check-in. Lines beginning with # are ignored.\n"
587 "# The check-in comment follows wiki formatting rules.\n"
588 "#\n", -1
589 );
590 blob_appendf(&prompt, "# user: %s\n", zUserOvrd ? zUserOvrd : g.zLogin);
591 if( zBranch && zBranch[0] ){
592 blob_appendf(&prompt, "# tags: %s\n#\n", zBranch);
@@ -658,11 +657,11 @@
658 " AND type='ci' AND objid=%d",
659 zDate, rid
660 );
661 if( b ){
662 fossil_fatal("ancestor check-in [%.10s] (%s) is not older (clock skew?)"
663 " Use -f to override.", zUuid, zDate);
664 }
665 #endif
666 }
667
668 /*
@@ -896,28 +895,32 @@
896 */
897 static int commit_warning(
898 Blob *p, /* The content of the file being committed. */
899 int crnlOk, /* Non-zero if CR/NL warnings should be disabled. */
900 int binOk, /* Non-zero if binary warnings should be disabled. */
 
901 const char *zFilename /* The full name of the file being committed. */
902 ){
903 int eType; /* return value of looks_like_utf8/utf16() */
904 int fUnicode; /* return value of starts_with_utf16_bom() */
905 char *zMsg; /* Warning message */
906 Blob fname; /* Relative pathname of the file */
907 static int allOk = 0; /* Set to true to disable this routine */
908
909 if( allOk ) return 0;
910 fUnicode = starts_with_utf16_bom(p);
911 eType = fUnicode ? looks_like_utf16(p) : looks_like_utf8(p);
912 if( eType==0 || eType==-1 || fUnicode ){
913 const char *zWarning;
914 const char *zConvert = "c=convert/";
915 Blob ans;
916 char cReply;
917
918 if( eType==-1 && fUnicode ){
 
 
 
919 zWarning = "Unicode and CR/NL line endings";
920 }else if( eType==-1 ){
921 if( crnlOk ){
922 return 0; /* We don't want CR/NL warnings for this file. */
923 }
@@ -927,10 +930,13 @@
927 return 0; /* We don't want binary warnings for this file. */
928 }
929 zWarning = "binary data";
930 zConvert = ""; /* We cannot convert binary files. */
931 }else{
 
 
 
932 zWarning = "Unicode";
933 #ifndef _WIN32
934 zConvert = ""; /* On Unix, we cannot easily convert Unicode files. */
935 #endif
936 }
@@ -1008,32 +1014,45 @@
1008 **
1009 ** The --bgcolor option works like --branchcolor but only sets the
1010 ** background color for a single check-in. Subsequent check-ins revert
1011 ** to the default color.
1012 **
1013 ** A check-in is not permitted to fork unless the --force or -f
1014 ** option appears. A check-in is not allowed against a closed leaf.
 
 
 
 
 
 
 
 
 
 
 
1015 **
1016 ** The --private option creates a private check-in that is never synced.
1017 ** Children of private check-ins are automatically private.
1018 **
1019 ** the --tag option applies the symbolic tag name to the check-in.
1020 **
1021 ** Options:
 
 
 
 
1022 ** --baseline use a baseline manifest in the commit process
1023 ** --bgcolor COLOR apply COLOR to this one check-in only
1024 ** --branch NEW-BRANCH-NAME check in to this new branch
1025 ** --branchcolor COLOR apply given COLOR to the branch
1026 ** --comment|-m COMMENT-TEXT use COMMENT-TEXT as commit comment
1027 ** --delta use a delta manifest in the commit process
1028 ** --force|-f allow forking with this commit
1029 ** --message-file|-M FILE read the commit comment from given file
 
1030 ** --nosign do not attempt to sign this commit with gpg
1031 ** --private do not sync changes and their descendants
1032 ** --tag TAG-NAME assign given tag TAG-NAME to the checkin
1033 ** --conflict allow unresolved merge conflicts
1034 ** --binary-ok do not warn about committing binary files
1035 **
1036 ** See also: branch, changes, checkout, extra, sync
1037 */
1038 void commit_cmd(void){
1039 int hasChanges; /* True if unsaved changes exist */
@@ -1044,15 +1063,18 @@
1044 const char *zComment; /* Check-in comment */
1045 Stmt q; /* Query to find files that have been modified */
1046 char *zUuid; /* UUID of the new check-in */
1047 int noSign = 0; /* True to omit signing the manifest using GPG */
1048 int isAMerge = 0; /* True if checking in a merge */
1049 int forceFlag = 0; /* Force a fork */
 
1050 int forceDelta = 0; /* Force a delta-manifest */
1051 int forceBaseline = 0; /* Force a baseline-manifest */
1052 int allowConflict = 0; /* Allow unresolve merge conflicts */
1053 int binaryOk = 0; /* The --binary-ok flag */
 
 
1054 char *zManifestFile; /* Name of the manifest file */
1055 int useCksum; /* True if checksums should be computed and verified */
1056 int outputManifest; /* True to output "manifest" and "manifest.uuid" */
1057 int testRun; /* True for a test run. Debugging only */
1058 const char *zBranch; /* Create a new branch with this name */
@@ -1069,11 +1091,10 @@
1069 Blob cksum1, cksum2; /* Before and after commit checksums */
1070 Blob cksum1b; /* Checksum recorded in the manifest */
1071 int szD; /* Size of the delta manifest */
1072 int szB; /* Size of the baseline manifest */
1073 int nConflict = 0; /* Number of unresolved merge conflicts */
1074 int abortCommit = 0;
1075 Blob ans;
1076 char cReply;
1077
1078 url_proxy_options();
1079 noSign = find_option("nosign",0,0)!=0;
@@ -1083,14 +1104,18 @@
1083 fossil_fatal("cannot use --delta and --baseline together");
1084 }
1085 testRun = find_option("test",0,0)!=0;
1086 zComment = find_option("comment","m",1);
1087 forceFlag = find_option("force", "f", 0)!=0;
 
 
 
 
 
1088 zBranch = find_option("branch","b",1);
1089 zColor = find_option("bgcolor",0,1);
1090 zBrClr = find_option("branchcolor",0,1);
1091 binaryOk = find_option("binary-ok",0,0)!=0;
1092 while( (zTag = find_option("tag",0,1))!=0 ){
1093 if( zTag[0]==0 ) continue;
1094 azTag = fossil_realloc((void *)azTag, sizeof(char*)*(nTag+2));
1095 azTag[nTag++] = zTag;
1096 azTag[nTag] = 0;
@@ -1101,11 +1126,10 @@
1101 if( zBranch==0 ) zBranch = "private";
1102 if( zBrClr==0 && zColor==0 ) zBrClr = "#fec084"; /* Orange */
1103 }
1104 zDateOvrd = find_option("date-override",0,1);
1105 zUserOvrd = find_option("user-override",0,1);
1106 allowConflict = find_option("conflict",0,0)!=0;
1107 db_must_be_within_tree();
1108 noSign = db_get_boolean("omitsign", 0)|noSign;
1109 if( db_get_boolean("clearsign", 0)==0 ){ noSign = 1; }
1110 useCksum = db_get_boolean("repo-cksum", 1);
1111 outputManifest = db_get_boolean("manifest", 0);
@@ -1136,11 +1160,11 @@
1136
1137 /*
1138 ** Autosync if autosync is enabled and this is not a private check-in.
1139 */
1140 if( !g.markPrivate ){
1141 if( autosync(AUTOSYNC_PULL) ){
1142 blob_zero(&ans);
1143 prompt_user("continue in spite of sync failure (y/N)? ", &ans);
1144 cReply = blob_str(&ans)[0];
1145 if( cReply!='y' && cReply!='Y' ){
1146 fossil_exit(1);
@@ -1208,34 +1232,38 @@
1208 }
1209
1210 hasChanges = unsaved_changes();
1211 db_begin_transaction();
1212 db_record_repository_filename(0);
1213 if( hasChanges==0 && !isAMerge && !forceFlag ){
1214 fossil_fatal("nothing has changed");
1215 }
1216
1217 /* If none of the files that were named on the command line have
1218 ** been modified, bail out now unless the --force flag is used.
 
1219 */
1220 if( g.aCommitFile
 
1221 && !forceFlag
1222 && !db_exists(
1223 "SELECT 1 FROM vfile "
1224 " WHERE is_selected(id)"
1225 " AND (chnged OR deleted OR rid=0 OR pathname!=origname)")
1226 ){
1227 fossil_fatal("none of the selected files have changed; use -f"
1228 " or --force.");
1229 }
1230
1231 /*
1232 ** Do not allow a commit that will cause a fork unless the --force flag
1233 ** is used or unless this is a private check-in.
1234 */
1235 if( zBranch==0 && forceFlag==0 && g.markPrivate==0 && !is_a_leaf(vid) ){
1236 fossil_fatal("would fork. \"update\" first or use -f or --force.");
 
 
1237 }
1238
1239 /*
1240 ** Do not allow a commit against a closed leaf
1241 */
@@ -1280,36 +1308,42 @@
1280 /* Step 1: Insert records for all modified files into the blob
1281 ** table. If there were arguments passed to this command, only
1282 ** the identified files are inserted (if they have been modified).
1283 */
1284 db_prepare(&q,
1285 "SELECT id, %Q || pathname, mrid, %s, chnged, %s FROM vfile "
1286 "WHERE chnged==1 AND NOT deleted AND is_selected(id)",
1287 g.zLocalRoot, glob_expr("pathname", db_get("crnl-glob","")),
1288 glob_expr("pathname", db_get("binary-glob",""))
 
 
1289 );
1290 while( db_step(&q)==SQLITE_ROW ){
1291 int id, rid;
1292 const char *zFullname;
1293 Blob content;
1294 int crnlOk, binOk, chnged;
1295
1296 id = db_column_int(&q, 0);
1297 zFullname = db_column_text(&q, 1);
1298 rid = db_column_int(&q, 2);
1299 crnlOk = db_column_int(&q, 3);
1300 chnged = db_column_int(&q, 4);
1301 binOk = binaryOk || db_column_int(&q, 5);
 
1302
1303 blob_zero(&content);
1304 if( file_wd_islink(zFullname) ){
1305 /* Instead of file content, put link destination path */
1306 blob_read_link(&content, zFullname);
1307 }else{
1308 blob_read_from_file(&content, zFullname);
1309 }
1310 abortCommit |= commit_warning(&content, crnlOk, binOk, zFullname);
 
 
 
1311 if( chnged==1 && contains_merge_marker(&content) ){
1312 Blob fname; /* Relative pathname of the file */
1313
1314 nConflict++;
1315 file_relative_name(zFullname, &fname, 0);
@@ -1325,13 +1359,12 @@
1325 db_multi_exec("UPDATE vfile SET mrid=%d, rid=%d WHERE id=%d", nrid,nrid,id);
1326 db_multi_exec("INSERT OR IGNORE INTO unsent VALUES(%d)", nrid);
1327 }
1328 db_finalize(&q);
1329 if( nConflict && !allowConflict ){
1330 fossil_fatal("abort due to unresolve merge conflicts");
1331 } else if( abortCommit ){
1332 fossil_fatal("files are converted on your request. Please re-test before committing");
1333 }
1334
1335 /* Create the new manifest */
1336 if( blob_size(&comment)==0 ){
1337 blob_append(&comment, "(no comment)", -1);
@@ -1338,11 +1371,11 @@
1338 }
1339 if( forceDelta ){
1340 blob_zero(&manifest);
1341 }else{
1342 create_manifest(&manifest, 0, 0, &comment, vid,
1343 !forceFlag, useCksum ? &cksum1 : 0,
1344 zDateOvrd, zUserOvrd, zBranch, zColor, zBrClr,
1345 azTag, &szB);
1346 }
1347
1348 /* See if a delta-manifest would be more appropriate */
@@ -1359,11 +1392,11 @@
1359 pBaseline = pParent;
1360 }
1361 if( pBaseline ){
1362 Blob delta;
1363 create_manifest(&delta, zBaselineUuid, pBaseline, &comment, vid,
1364 !forceFlag, useCksum ? &cksum1 : 0,
1365 zDateOvrd, zUserOvrd, zBranch, zColor, zBrClr,
1366 azTag, &szD);
1367 /*
1368 ** At this point, two manifests have been constructed, either of
1369 ** which would work for this checkin. The first manifest (held
@@ -1489,11 +1522,11 @@
1489 exit(1);
1490 }
1491 db_end_transaction(0);
1492
1493 if( !g.markPrivate ){
1494 autosync(AUTOSYNC_PUSH);
1495 }
1496 if( count_nonbranch_children(vid)>1 ){
1497 fossil_print("**** warning: a fork has occurred *****\n");
1498 }
1499 }
1500
--- src/checkin.c
+++ src/checkin.c
@@ -582,11 +582,10 @@
582 blob_init(&prompt, zInit, -1);
583 #endif
584 blob_append(&prompt,
585 "\n"
586 "# Enter comments on this check-in. Lines beginning with # are ignored.\n"
 
587 "#\n", -1
588 );
589 blob_appendf(&prompt, "# user: %s\n", zUserOvrd ? zUserOvrd : g.zLogin);
590 if( zBranch && zBranch[0] ){
591 blob_appendf(&prompt, "# tags: %s\n#\n", zBranch);
@@ -658,11 +657,11 @@
657 " AND type='ci' AND objid=%d",
658 zDate, rid
659 );
660 if( b ){
661 fossil_fatal("ancestor check-in [%.10s] (%s) is not older (clock skew?)"
662 " Use --allow-older to override.", zUuid, zDate);
663 }
664 #endif
665 }
666
667 /*
@@ -896,28 +895,32 @@
895 */
896 static int commit_warning(
897 Blob *p, /* The content of the file being committed. */
898 int crnlOk, /* Non-zero if CR/NL warnings should be disabled. */
899 int binOk, /* Non-zero if binary warnings should be disabled. */
900 int unicodeOk, /* Non-zero if unicode warnings should be disabled. */
901 const char *zFilename /* The full name of the file being committed. */
902 ){
903 int eType; /* return value of looks_like_utf8/utf16() */
904 int fUnicode; /* return value of starts_with_utf16_bom() */
905 char *zMsg; /* Warning message */
906 Blob fname; /* Relative pathname of the file */
907 static int allOk = 0; /* Set to true to disable this routine */
908
909 if( allOk ) return 0;
910 fUnicode = starts_with_utf16_bom(p, 0);
911 eType = fUnicode ? looks_like_utf16(p) : looks_like_utf8(p);
912 if( eType==0 || eType==-1 || fUnicode ){
913 const char *zWarning;
914 const char *zConvert = "c=convert/";
915 Blob ans;
916 char cReply;
917
918 if( eType==-1 && fUnicode ){
919 if ( crnlOk && unicodeOk ){
920 return 0; /* We don't want Unicode/CR/NL warnings for this file. */
921 }
922 zWarning = "Unicode and CR/NL line endings";
923 }else if( eType==-1 ){
924 if( crnlOk ){
925 return 0; /* We don't want CR/NL warnings for this file. */
926 }
@@ -927,10 +930,13 @@
930 return 0; /* We don't want binary warnings for this file. */
931 }
932 zWarning = "binary data";
933 zConvert = ""; /* We cannot convert binary files. */
934 }else{
935 if ( unicodeOk ){
936 return 0; /* We don't want unicode warnings for this file. */
937 }
938 zWarning = "Unicode";
939 #ifndef _WIN32
940 zConvert = ""; /* On Unix, we cannot easily convert Unicode files. */
941 #endif
942 }
@@ -1008,32 +1014,45 @@
1014 **
1015 ** The --bgcolor option works like --branchcolor but only sets the
1016 ** background color for a single check-in. Subsequent check-ins revert
1017 ** to the default color.
1018 **
1019 ** A check-in is not permitted to fork unless the --allow-fork option
1020 ** appears. An empty check-in (i.e. with nothing changed) is not
1021 ** allowed unless the --allow-empty option appears. A check-in may not
1022 ** be older than its ancestor unless the --allow-older option appears.
1023 ** If any of files in the check-in appear to contain unresolved merge
1024 ** conflicts, the check-in will not be allowed unless the
1025 ** --allow-conflict option is present. In addition, the entire
1026 ** check-in process may be aborted if a file contains content that
1027 ** appears to be binary, Unicode text, or text with CR/NL line endings
1028 ** unless the interactive user chooses to proceed. If there is no
1029 ** interactive user or these warnings should be skipped for some other
1030 ** reason, the --no-warnings option may be used. A check-in is not
1031 ** allowed against a closed leaf.
1032 **
1033 ** The --private option creates a private check-in that is never synced.
1034 ** Children of private check-ins are automatically private.
1035 **
1036 ** the --tag option applies the symbolic tag name to the check-in.
1037 **
1038 ** Options:
1039 ** --allow-conflict allow unresolved merge conflicts
1040 ** --allow-empty allow a commit with no changes
1041 ** --allow-fork allow the commit to fork
1042 ** --allow-older allow a commit older than its ancestor
1043 ** --baseline use a baseline manifest in the commit process
1044 ** --bgcolor COLOR apply COLOR to this one check-in only
1045 ** --branch NEW-BRANCH-NAME check in to this new branch
1046 ** --branchcolor COLOR apply given COLOR to the branch
1047 ** --comment|-m COMMENT-TEXT use COMMENT-TEXT as commit comment
1048 ** --delta use a delta manifest in the commit process
 
1049 ** --message-file|-M FILE read the commit comment from given file
1050 ** --no-warnings omit all warnings about file contents
1051 ** --nosign do not attempt to sign this commit with gpg
1052 ** --private do not sync changes and their descendants
1053 ** --tag TAG-NAME assign given tag TAG-NAME to the checkin
 
 
1054 **
1055 ** See also: branch, changes, checkout, extra, sync
1056 */
1057 void commit_cmd(void){
1058 int hasChanges; /* True if unsaved changes exist */
@@ -1044,15 +1063,18 @@
1063 const char *zComment; /* Check-in comment */
1064 Stmt q; /* Query to find files that have been modified */
1065 char *zUuid; /* UUID of the new check-in */
1066 int noSign = 0; /* True to omit signing the manifest using GPG */
1067 int isAMerge = 0; /* True if checking in a merge */
1068 int noWarningFlag = 0; /* True if skipping all warnings */
1069 int forceFlag = 0; /* Undocumented: Disables all checks */
1070 int forceDelta = 0; /* Force a delta-manifest */
1071 int forceBaseline = 0; /* Force a baseline-manifest */
1072 int allowConflict = 0; /* Allow unresolve merge conflicts */
1073 int allowEmpty = 0; /* Allow a commit with no changes */
1074 int allowFork = 0; /* Allow the commit to fork */
1075 int allowOlder = 0; /* Allow a commit older than its ancestor */
1076 char *zManifestFile; /* Name of the manifest file */
1077 int useCksum; /* True if checksums should be computed and verified */
1078 int outputManifest; /* True to output "manifest" and "manifest.uuid" */
1079 int testRun; /* True for a test run. Debugging only */
1080 const char *zBranch; /* Create a new branch with this name */
@@ -1069,11 +1091,10 @@
1091 Blob cksum1, cksum2; /* Before and after commit checksums */
1092 Blob cksum1b; /* Checksum recorded in the manifest */
1093 int szD; /* Size of the delta manifest */
1094 int szB; /* Size of the baseline manifest */
1095 int nConflict = 0; /* Number of unresolved merge conflicts */
 
1096 Blob ans;
1097 char cReply;
1098
1099 url_proxy_options();
1100 noSign = find_option("nosign",0,0)!=0;
@@ -1083,14 +1104,18 @@
1104 fossil_fatal("cannot use --delta and --baseline together");
1105 }
1106 testRun = find_option("test",0,0)!=0;
1107 zComment = find_option("comment","m",1);
1108 forceFlag = find_option("force", "f", 0)!=0;
1109 allowConflict = find_option("allow-conflict",0,0)!=0;
1110 allowEmpty = find_option("allow-empty",0,0)!=0;
1111 allowFork = find_option("allow-fork",0,0)!=0;
1112 allowOlder = find_option("allow-older",0,0)!=0;
1113 noWarningFlag = find_option("no-warnings", 0, 0)!=0;
1114 zBranch = find_option("branch","b",1);
1115 zColor = find_option("bgcolor",0,1);
1116 zBrClr = find_option("branchcolor",0,1);
 
1117 while( (zTag = find_option("tag",0,1))!=0 ){
1118 if( zTag[0]==0 ) continue;
1119 azTag = fossil_realloc((void *)azTag, sizeof(char*)*(nTag+2));
1120 azTag[nTag++] = zTag;
1121 azTag[nTag] = 0;
@@ -1101,11 +1126,10 @@
1126 if( zBranch==0 ) zBranch = "private";
1127 if( zBrClr==0 && zColor==0 ) zBrClr = "#fec084"; /* Orange */
1128 }
1129 zDateOvrd = find_option("date-override",0,1);
1130 zUserOvrd = find_option("user-override",0,1);
 
1131 db_must_be_within_tree();
1132 noSign = db_get_boolean("omitsign", 0)|noSign;
1133 if( db_get_boolean("clearsign", 0)==0 ){ noSign = 1; }
1134 useCksum = db_get_boolean("repo-cksum", 1);
1135 outputManifest = db_get_boolean("manifest", 0);
@@ -1136,11 +1160,11 @@
1160
1161 /*
1162 ** Autosync if autosync is enabled and this is not a private check-in.
1163 */
1164 if( !g.markPrivate ){
1165 if( autosync(SYNC_PULL) ){
1166 blob_zero(&ans);
1167 prompt_user("continue in spite of sync failure (y/N)? ", &ans);
1168 cReply = blob_str(&ans)[0];
1169 if( cReply!='y' && cReply!='Y' ){
1170 fossil_exit(1);
@@ -1208,34 +1232,38 @@
1232 }
1233
1234 hasChanges = unsaved_changes();
1235 db_begin_transaction();
1236 db_record_repository_filename(0);
1237 if( hasChanges==0 && !isAMerge && !allowEmpty && !forceFlag ){
1238 fossil_fatal("nothing has changed; use --allow-empty to override");
1239 }
1240
1241 /* If none of the files that were named on the command line have
1242 ** been modified, bail out now unless the --allow-empty or --force
1243 ** flags is used.
1244 */
1245 if( g.aCommitFile
1246 && !allowEmpty
1247 && !forceFlag
1248 && !db_exists(
1249 "SELECT 1 FROM vfile "
1250 " WHERE is_selected(id)"
1251 " AND (chnged OR deleted OR rid=0 OR pathname!=origname)")
1252 ){
1253 fossil_fatal("none of the selected files have changed; use "
1254 "--allow-empty to override.");
1255 }
1256
1257 /*
1258 ** Do not allow a commit that will cause a fork unless the --allow-fork
1259 ** or --force flags is used, or unless this is a private check-in.
1260 */
1261 if( zBranch==0 && allowFork==0 && forceFlag==0
1262 && g.markPrivate==0 && !is_a_leaf(vid)
1263 ){
1264 fossil_fatal("would fork. \"update\" first or use --allow-fork.");
1265 }
1266
1267 /*
1268 ** Do not allow a commit against a closed leaf
1269 */
@@ -1280,36 +1308,42 @@
1308 /* Step 1: Insert records for all modified files into the blob
1309 ** table. If there were arguments passed to this command, only
1310 ** the identified files are inserted (if they have been modified).
1311 */
1312 db_prepare(&q,
1313 "SELECT id, %Q || pathname, mrid, %s, chnged, %s, %s FROM vfile "
1314 "WHERE chnged==1 AND NOT deleted AND is_selected(id)",
1315 g.zLocalRoot,
1316 glob_expr("pathname", db_get("crnl-glob","")),
1317 glob_expr("pathname", db_get("binary-glob","")),
1318 glob_expr("pathname", db_get("unicode-glob",""))
1319 );
1320 while( db_step(&q)==SQLITE_ROW ){
1321 int id, rid;
1322 const char *zFullname;
1323 Blob content;
1324 int crnlOk, binOk, unicodeOk, chnged;
1325
1326 id = db_column_int(&q, 0);
1327 zFullname = db_column_text(&q, 1);
1328 rid = db_column_int(&q, 2);
1329 crnlOk = db_column_int(&q, 3);
1330 chnged = db_column_int(&q, 4);
1331 binOk = db_column_int(&q, 5);
1332 unicodeOk = db_column_int(&q, 6);
1333
1334 blob_zero(&content);
1335 if( file_wd_islink(zFullname) ){
1336 /* Instead of file content, put link destination path */
1337 blob_read_link(&content, zFullname);
1338 }else{
1339 blob_read_from_file(&content, zFullname);
1340 }
1341 /* Do not emit any warnings when they are disabled. */
1342 if( !noWarningFlag ){
1343 commit_warning(&content, crnlOk, binOk, unicodeOk, zFullname);
1344 }
1345 if( chnged==1 && contains_merge_marker(&content) ){
1346 Blob fname; /* Relative pathname of the file */
1347
1348 nConflict++;
1349 file_relative_name(zFullname, &fname, 0);
@@ -1325,13 +1359,12 @@
1359 db_multi_exec("UPDATE vfile SET mrid=%d, rid=%d WHERE id=%d", nrid,nrid,id);
1360 db_multi_exec("INSERT OR IGNORE INTO unsent VALUES(%d)", nrid);
1361 }
1362 db_finalize(&q);
1363 if( nConflict && !allowConflict ){
1364 fossil_fatal("abort due to unresolved merge conflicts; "
1365 "use --allow-conflict to override");
 
1366 }
1367
1368 /* Create the new manifest */
1369 if( blob_size(&comment)==0 ){
1370 blob_append(&comment, "(no comment)", -1);
@@ -1338,11 +1371,11 @@
1371 }
1372 if( forceDelta ){
1373 blob_zero(&manifest);
1374 }else{
1375 create_manifest(&manifest, 0, 0, &comment, vid,
1376 !allowOlder && !forceFlag, useCksum ? &cksum1 : 0,
1377 zDateOvrd, zUserOvrd, zBranch, zColor, zBrClr,
1378 azTag, &szB);
1379 }
1380
1381 /* See if a delta-manifest would be more appropriate */
@@ -1359,11 +1392,11 @@
1392 pBaseline = pParent;
1393 }
1394 if( pBaseline ){
1395 Blob delta;
1396 create_manifest(&delta, zBaselineUuid, pBaseline, &comment, vid,
1397 !allowOlder && !forceFlag, useCksum ? &cksum1 : 0,
1398 zDateOvrd, zUserOvrd, zBranch, zColor, zBrClr,
1399 azTag, &szD);
1400 /*
1401 ** At this point, two manifests have been constructed, either of
1402 ** which would work for this checkin. The first manifest (held
@@ -1489,11 +1522,11 @@
1522 exit(1);
1523 }
1524 db_end_transaction(0);
1525
1526 if( !g.markPrivate ){
1527 autosync(SYNC_PUSH);
1528 }
1529 if( count_nonbranch_children(vid)>1 ){
1530 fossil_print("**** warning: a fork has occurred *****\n");
1531 }
1532 }
1533
+1 -1
--- src/checkout.c
+++ src/checkout.c
@@ -106,11 +106,11 @@
106106
/* Check the EXE permission status of all files
107107
*/
108108
pManifest = manifest_get(vid, CFTYPE_MANIFEST);
109109
if( pManifest==0 ) return;
110110
blob_zero(&filename);
111
- blob_appendf(&filename, "%s/", g.zLocalRoot);
111
+ blob_appendf(&filename, "%s", g.zLocalRoot);
112112
baseLen = blob_size(&filename);
113113
manifest_file_rewind(pManifest);
114114
while( (pFile = manifest_file_next(pManifest, 0))!=0 ){
115115
int isExe;
116116
blob_append(&filename, pFile->zName, -1);
117117
--- src/checkout.c
+++ src/checkout.c
@@ -106,11 +106,11 @@
106 /* Check the EXE permission status of all files
107 */
108 pManifest = manifest_get(vid, CFTYPE_MANIFEST);
109 if( pManifest==0 ) return;
110 blob_zero(&filename);
111 blob_appendf(&filename, "%s/", g.zLocalRoot);
112 baseLen = blob_size(&filename);
113 manifest_file_rewind(pManifest);
114 while( (pFile = manifest_file_next(pManifest, 0))!=0 ){
115 int isExe;
116 blob_append(&filename, pFile->zName, -1);
117
--- src/checkout.c
+++ src/checkout.c
@@ -106,11 +106,11 @@
106 /* Check the EXE permission status of all files
107 */
108 pManifest = manifest_get(vid, CFTYPE_MANIFEST);
109 if( pManifest==0 ) return;
110 blob_zero(&filename);
111 blob_appendf(&filename, "%s", g.zLocalRoot);
112 baseLen = blob_size(&filename);
113 manifest_file_rewind(pManifest);
114 while( (pFile = manifest_file_next(pManifest, 0))!=0 ){
115 int isExe;
116 blob_append(&filename, pFile->zName, -1);
117
+4 -4
--- src/clone.c
+++ src/clone.c
@@ -99,15 +99,15 @@
9999
** See also: init
100100
*/
101101
void clone_cmd(void){
102102
char *zPassword;
103103
const char *zDefaultUser; /* Optional name of the default user */
104
- const char *zPw; /* The user clone password */
104
+ const char *zPw; /* The user clone password */
105105
int nErr = 0;
106
- int bPrivate; /* Also clone private branches */
106
+ int bPrivate = 0; /* Also clone private branches */
107107
108
- bPrivate = find_option("private",0,0)!=0;
108
+ if( find_option("private",0,0)!=0 ) bPrivate = SYNC_PRIVATE;
109109
url_proxy_options();
110110
if( g.argc < 4 ){
111111
usage("?OPTIONS? FILE-OR-URL NEW-REPOSITORY");
112112
}
113113
db_open_config(0);
@@ -162,11 +162,11 @@
162162
" VALUES('server-code', lower(hex(randomblob(20))), now());"
163163
);
164164
url_enable_proxy(0);
165165
url_get_password_if_needed();
166166
g.xlinkClusterOnly = 1;
167
- nErr = client_sync(0,0,1,bPrivate,CONFIGSET_ALL,0);
167
+ nErr = client_sync(SYNC_CLONE | bPrivate,CONFIGSET_ALL,0);
168168
g.xlinkClusterOnly = 0;
169169
verify_cancel();
170170
db_end_transaction(0);
171171
db_close(1);
172172
if( nErr ){
173173
--- src/clone.c
+++ src/clone.c
@@ -99,15 +99,15 @@
99 ** See also: init
100 */
101 void clone_cmd(void){
102 char *zPassword;
103 const char *zDefaultUser; /* Optional name of the default user */
104 const char *zPw; /* The user clone password */
105 int nErr = 0;
106 int bPrivate; /* Also clone private branches */
107
108 bPrivate = find_option("private",0,0)!=0;
109 url_proxy_options();
110 if( g.argc < 4 ){
111 usage("?OPTIONS? FILE-OR-URL NEW-REPOSITORY");
112 }
113 db_open_config(0);
@@ -162,11 +162,11 @@
162 " VALUES('server-code', lower(hex(randomblob(20))), now());"
163 );
164 url_enable_proxy(0);
165 url_get_password_if_needed();
166 g.xlinkClusterOnly = 1;
167 nErr = client_sync(0,0,1,bPrivate,CONFIGSET_ALL,0);
168 g.xlinkClusterOnly = 0;
169 verify_cancel();
170 db_end_transaction(0);
171 db_close(1);
172 if( nErr ){
173
--- src/clone.c
+++ src/clone.c
@@ -99,15 +99,15 @@
99 ** See also: init
100 */
101 void clone_cmd(void){
102 char *zPassword;
103 const char *zDefaultUser; /* Optional name of the default user */
104 const char *zPw; /* The user clone password */
105 int nErr = 0;
106 int bPrivate = 0; /* Also clone private branches */
107
108 if( find_option("private",0,0)!=0 ) bPrivate = SYNC_PRIVATE;
109 url_proxy_options();
110 if( g.argc < 4 ){
111 usage("?OPTIONS? FILE-OR-URL NEW-REPOSITORY");
112 }
113 db_open_config(0);
@@ -162,11 +162,11 @@
162 " VALUES('server-code', lower(hex(randomblob(20))), now());"
163 );
164 url_enable_proxy(0);
165 url_get_password_if_needed();
166 g.xlinkClusterOnly = 1;
167 nErr = client_sync(SYNC_CLONE | bPrivate,CONFIGSET_ALL,0);
168 g.xlinkClusterOnly = 0;
169 verify_cancel();
170 db_end_transaction(0);
171 db_close(1);
172 if( nErr ){
173
+6 -3
--- src/configure.c
+++ src/configure.c
@@ -86,13 +86,15 @@
8686
{ "background-mimetype", CONFIGSET_SKIN },
8787
{ "background-image", CONFIGSET_SKIN },
8888
{ "index-page", CONFIGSET_SKIN },
8989
{ "timeline-block-markup", CONFIGSET_SKIN },
9090
{ "timeline-max-comment", CONFIGSET_SKIN },
91
+ { "timeline-plaintext", CONFIGSET_SKIN },
9192
{ "adunit", CONFIGSET_SKIN },
9293
{ "adunit-omit-if-admin", CONFIGSET_SKIN },
9394
{ "adunit-omit-if-user", CONFIGSET_SKIN },
95
+ { "th1-setup", CONFIGSET_ALL },
9496
9597
#ifdef FOSSIL_ENABLE_TCL
9698
{ "tcl", CONFIGSET_SKIN|CONFIGSET_TKT|CONFIGSET_XFER },
9799
{ "tcl-setup", CONFIGSET_SKIN|CONFIGSET_TKT|CONFIGSET_XFER },
98100
#endif
@@ -101,10 +103,11 @@
101103
{ "project-description", CONFIGSET_PROJ },
102104
{ "manifest", CONFIGSET_PROJ },
103105
{ "binary-glob", CONFIGSET_PROJ },
104106
{ "ignore-glob", CONFIGSET_PROJ },
105107
{ "crnl-glob", CONFIGSET_PROJ },
108
+ { "unicode-glob", CONFIGSET_PROJ },
106109
{ "empty-dirs", CONFIGSET_PROJ },
107110
{ "allow-symlinks", CONFIGSET_PROJ },
108111
109112
{ "ticket-table", CONFIGSET_TKT },
110113
{ "ticket-common", CONFIGSET_TKT },
@@ -906,15 +909,15 @@
906909
user_select();
907910
url_enable_proxy("via proxy: ");
908911
if( legacyFlag ) mask |= CONFIGSET_OLDFORMAT;
909912
if( overwriteFlag ) mask |= CONFIGSET_OVERWRITE;
910913
if( strncmp(zMethod, "push", n)==0 ){
911
- client_sync(0,0,0,0,0,mask);
914
+ client_sync(0,0,(unsigned)mask);
912915
}else if( strncmp(zMethod, "pull", n)==0 ){
913
- client_sync(0,0,0,0,mask,0);
916
+ client_sync(0,(unsigned)mask,0);
914917
}else{
915
- client_sync(0,0,0,0,mask,mask);
918
+ client_sync(0,(unsigned)mask,(unsigned)mask);
916919
}
917920
}else
918921
if( strncmp(zMethod, "reset", n)==0 ){
919922
int mask, i;
920923
char *zBackup;
921924
--- src/configure.c
+++ src/configure.c
@@ -86,13 +86,15 @@
86 { "background-mimetype", CONFIGSET_SKIN },
87 { "background-image", CONFIGSET_SKIN },
88 { "index-page", CONFIGSET_SKIN },
89 { "timeline-block-markup", CONFIGSET_SKIN },
90 { "timeline-max-comment", CONFIGSET_SKIN },
 
91 { "adunit", CONFIGSET_SKIN },
92 { "adunit-omit-if-admin", CONFIGSET_SKIN },
93 { "adunit-omit-if-user", CONFIGSET_SKIN },
 
94
95 #ifdef FOSSIL_ENABLE_TCL
96 { "tcl", CONFIGSET_SKIN|CONFIGSET_TKT|CONFIGSET_XFER },
97 { "tcl-setup", CONFIGSET_SKIN|CONFIGSET_TKT|CONFIGSET_XFER },
98 #endif
@@ -101,10 +103,11 @@
101 { "project-description", CONFIGSET_PROJ },
102 { "manifest", CONFIGSET_PROJ },
103 { "binary-glob", CONFIGSET_PROJ },
104 { "ignore-glob", CONFIGSET_PROJ },
105 { "crnl-glob", CONFIGSET_PROJ },
 
106 { "empty-dirs", CONFIGSET_PROJ },
107 { "allow-symlinks", CONFIGSET_PROJ },
108
109 { "ticket-table", CONFIGSET_TKT },
110 { "ticket-common", CONFIGSET_TKT },
@@ -906,15 +909,15 @@
906 user_select();
907 url_enable_proxy("via proxy: ");
908 if( legacyFlag ) mask |= CONFIGSET_OLDFORMAT;
909 if( overwriteFlag ) mask |= CONFIGSET_OVERWRITE;
910 if( strncmp(zMethod, "push", n)==0 ){
911 client_sync(0,0,0,0,0,mask);
912 }else if( strncmp(zMethod, "pull", n)==0 ){
913 client_sync(0,0,0,0,mask,0);
914 }else{
915 client_sync(0,0,0,0,mask,mask);
916 }
917 }else
918 if( strncmp(zMethod, "reset", n)==0 ){
919 int mask, i;
920 char *zBackup;
921
--- src/configure.c
+++ src/configure.c
@@ -86,13 +86,15 @@
86 { "background-mimetype", CONFIGSET_SKIN },
87 { "background-image", CONFIGSET_SKIN },
88 { "index-page", CONFIGSET_SKIN },
89 { "timeline-block-markup", CONFIGSET_SKIN },
90 { "timeline-max-comment", CONFIGSET_SKIN },
91 { "timeline-plaintext", CONFIGSET_SKIN },
92 { "adunit", CONFIGSET_SKIN },
93 { "adunit-omit-if-admin", CONFIGSET_SKIN },
94 { "adunit-omit-if-user", CONFIGSET_SKIN },
95 { "th1-setup", CONFIGSET_ALL },
96
97 #ifdef FOSSIL_ENABLE_TCL
98 { "tcl", CONFIGSET_SKIN|CONFIGSET_TKT|CONFIGSET_XFER },
99 { "tcl-setup", CONFIGSET_SKIN|CONFIGSET_TKT|CONFIGSET_XFER },
100 #endif
@@ -101,10 +103,11 @@
103 { "project-description", CONFIGSET_PROJ },
104 { "manifest", CONFIGSET_PROJ },
105 { "binary-glob", CONFIGSET_PROJ },
106 { "ignore-glob", CONFIGSET_PROJ },
107 { "crnl-glob", CONFIGSET_PROJ },
108 { "unicode-glob", CONFIGSET_PROJ },
109 { "empty-dirs", CONFIGSET_PROJ },
110 { "allow-symlinks", CONFIGSET_PROJ },
111
112 { "ticket-table", CONFIGSET_TKT },
113 { "ticket-common", CONFIGSET_TKT },
@@ -906,15 +909,15 @@
909 user_select();
910 url_enable_proxy("via proxy: ");
911 if( legacyFlag ) mask |= CONFIGSET_OLDFORMAT;
912 if( overwriteFlag ) mask |= CONFIGSET_OVERWRITE;
913 if( strncmp(zMethod, "push", n)==0 ){
914 client_sync(0,0,(unsigned)mask);
915 }else if( strncmp(zMethod, "pull", n)==0 ){
916 client_sync(0,(unsigned)mask,0);
917 }else{
918 client_sync(0,(unsigned)mask,(unsigned)mask);
919 }
920 }else
921 if( strncmp(zMethod, "reset", n)==0 ){
922 int mask, i;
923 char *zBackup;
924
+4 -1
--- src/content.c
+++ src/content.c
@@ -667,11 +667,14 @@
667667
668668
669669
/*
670670
** COMMAND: test-content-put
671671
**
672
-** Extract a blob from a file and write it into the database
672
+** Usage: %fossil test-content-put FILE
673
+**
674
+** Read the content of FILE and add it to the Blob table as a new
675
+** artifact using a direct call to content_put().
673676
*/
674677
void test_content_put_cmd(void){
675678
int rid;
676679
Blob content;
677680
if( g.argc!=3 ) usage("FILENAME");
678681
--- src/content.c
+++ src/content.c
@@ -667,11 +667,14 @@
667
668
669 /*
670 ** COMMAND: test-content-put
671 **
672 ** Extract a blob from a file and write it into the database
 
 
 
673 */
674 void test_content_put_cmd(void){
675 int rid;
676 Blob content;
677 if( g.argc!=3 ) usage("FILENAME");
678
--- src/content.c
+++ src/content.c
@@ -667,11 +667,14 @@
667
668
669 /*
670 ** COMMAND: test-content-put
671 **
672 ** Usage: %fossil test-content-put FILE
673 **
674 ** Read the content of FILE and add it to the Blob table as a new
675 ** artifact using a direct call to content_put().
676 */
677 void test_content_put_cmd(void){
678 int rid;
679 Blob content;
680 if( g.argc!=3 ) usage("FILENAME");
681
+47 -11
--- src/db.c
+++ src/db.c
@@ -740,17 +740,25 @@
740740
/*
741741
** zDbName is the name of a database file. If no other database
742742
** file is open, then open this one. If another database file is
743743
** already open, then attach zDbName using the name zLabel.
744744
*/
745
-void db_open_or_attach(const char *zDbName, const char *zLabel){
745
+void db_open_or_attach(
746
+ const char *zDbName,
747
+ const char *zLabel,
748
+ int *pWasAttached
749
+){
746750
if( !g.db ){
751
+ assert( g.zMainDbType==0 );
747752
g.db = openDatabase(zDbName);
748753
g.zMainDbType = zLabel;
749754
db_connection_init();
755
+ if ( pWasAttached ) *pWasAttached = 0;
750756
}else{
757
+ assert( g.zMainDbType!=0 );
751758
db_attach(zDbName, zLabel);
759
+ if ( pWasAttached ) *pWasAttached = 1;
752760
}
753761
}
754762
755763
/*
756764
** Open the user database in "~/.fossil". Create the database anew if
@@ -806,16 +814,18 @@
806814
zDbName = mprintf("%s/.fossil", zHome);
807815
#endif
808816
if( file_size(zDbName)<1024*3 ){
809817
db_init_database(zDbName, zConfigSchema, (char*)0);
810818
}
811
- g.useAttach = useAttach;
812819
if( useAttach ){
813
- db_open_or_attach(zDbName, "configdb");
820
+ db_open_or_attach(zDbName, "configdb", &g.useAttach);
814821
g.dbConfig = 0;
822
+ g.zConfigDbType = 0;
815823
}else{
824
+ g.useAttach = 0;
816825
g.dbConfig = openDatabase(zDbName);
826
+ g.zConfigDbType = "configdb";
817827
}
818828
g.configOpen = 1;
819829
free(zDbName);
820830
}
821831
@@ -850,11 +860,11 @@
850860
char *zVFileDef;
851861
852862
if( file_access(zDbName, F_OK) ) return 0;
853863
lsize = file_size(zDbName);
854864
if( lsize%1024!=0 || lsize<4096 ) return 0;
855
- db_open_or_attach(zDbName, "localdb");
865
+ db_open_or_attach(zDbName, "localdb", 0);
856866
zVFileDef = db_text(0, "SELECT sql FROM %s.sqlite_master"
857867
" WHERE name=='vfile'", db_name("localdb"));
858868
859869
/* If the "isexe" column is missing from the vfile table, then
860870
** add it now. This code added on 2010-03-06. After all users have
@@ -986,11 +996,11 @@
986996
g.json.resultCode = FSL_JSON_E_DB_NOT_VALID;
987997
#endif
988998
fossil_panic("not a valid repository: %s", zDbName);
989999
}
9901000
}
991
- db_open_or_attach(zDbName, "repository");
1001
+ db_open_or_attach(zDbName, "repository", 0);
9921002
g.repositoryOpen = 1;
9931003
g.zRepositoryName = mprintf("%s", zDbName);
9941004
/* Cache "allow-symlinks" option, because we'll need it on every stat call */
9951005
g.allowSymlinks = db_get_boolean("allow-symlinks", 0);
9961006
}
@@ -1109,11 +1119,11 @@
11091119
file_canonical_name(g.argv[2], &repo, 0);
11101120
zRepo = blob_str(&repo);
11111121
if( file_access(zRepo, 0) ){
11121122
fossil_fatal("no such file: %s", zRepo);
11131123
}
1114
- db_open_or_attach(zRepo, "test_repo");
1124
+ db_open_or_attach(zRepo, "test_repo", 0);
11151125
db_lset("repository", blob_str(&repo));
11161126
db_close(1);
11171127
}
11181128
11191129
@@ -1177,13 +1187,15 @@
11771187
g.localOpen = 0;
11781188
g.configOpen = 0;
11791189
sqlite3_wal_checkpoint(g.db, 0);
11801190
sqlite3_close(g.db);
11811191
g.db = 0;
1192
+ g.zMainDbType = 0;
11821193
if( g.dbConfig ){
11831194
sqlite3_close(g.dbConfig);
11841195
g.dbConfig = 0;
1196
+ g.zConfigDbType = 0;
11851197
}
11861198
}
11871199
11881200
11891201
/*
@@ -1630,19 +1642,32 @@
16301642
/*
16311643
** Swap the g.db and g.dbConfig connections so that the various db_* routines
16321644
** work on the ~/.fossil database instead of on the repository database.
16331645
** Be sure to swap them back after doing the operation.
16341646
**
1635
-** If g.useAttach that means the ~/.fossil database was opened with
1636
-** the useAttach flag set to 1. In that case no connection swap is required
1637
-** so this routine is a no-op.
1647
+** If the ~/.fossil database has already been opened as the main database or
1648
+** is attached to the main database, no connection swaps are required so this
1649
+** routine is a no-op.
16381650
*/
16391651
void db_swap_connections(void){
1640
- if( !g.useAttach ){
1652
+ /*
1653
+ ** When swapping the main database connection with the config database
1654
+ ** connection, the config database connection must be open (not simply
1655
+ ** attached); otherwise, the swap would end up leaving the main database
1656
+ ** connection invalid, defeating the very purpose of this routine. This
1657
+ ** same constraint also holds true when restoring the previously swapped
1658
+ ** database connection; otherwise, it means that no swap was performed
1659
+ ** because the main database connection was already pointing to the config
1660
+ ** database.
1661
+ */
1662
+ if( g.dbConfig ){
16411663
sqlite3 *dbTemp = g.db;
1664
+ const char *zTempDbType = g.zMainDbType;
16421665
g.db = g.dbConfig;
1666
+ g.zMainDbType = g.zConfigDbType;
16431667
g.dbConfig = dbTemp;
1668
+ g.zConfigDbType = zTempDbType;
16441669
}
16451670
}
16461671
16471672
/*
16481673
** Logic for reading potentially versioned settings from
@@ -1672,11 +1697,11 @@
16721697
** and a checkout is open. */
16731698
if( cacheEntry==0 ){
16741699
Blob versionedPathname;
16751700
char *zVersionedPathname;
16761701
blob_zero(&versionedPathname);
1677
- blob_appendf(&versionedPathname, "%s/.fossil-settings/%s",
1702
+ blob_appendf(&versionedPathname, "%s.fossil-settings/%s",
16781703
g.zLocalRoot, zName);
16791704
zVersionedPathname = blob_str(&versionedPathname);
16801705
if( file_size(zVersionedPathname)>=0 ){
16811706
/* File exists, and contains the value for this setting. Load from
16821707
** the file. */
@@ -2055,14 +2080,16 @@
20552080
{ "repo-cksum", 0, 0, 0, "on" },
20562081
{ "self-register", 0, 0, 0, "off" },
20572082
{ "ssl-ca-location",0, 40, 0, "" },
20582083
{ "ssl-identity", 0, 40, 0, "" },
20592084
{ "ssh-command", 0, 40, 0, "" },
2085
+ { "th1-setup", 0, 40, 0, "" },
20602086
#ifdef FOSSIL_ENABLE_TCL
20612087
{ "tcl", 0, 0, 0, "off" },
20622088
{ "tcl-setup", 0, 40, 0, "" },
20632089
#endif
2090
+ { "unicode-glob", 0, 40, 1, "" },
20642091
{ "web-browser", 0, 32, 0, "" },
20652092
{ "white-foreground", 0, 0, 0, "off" },
20662093
{ 0,0,0,0,0 }
20672094
};
20682095
@@ -2233,10 +2260,19 @@
22332260
**
22342261
** tcl-setup This is the setup script to be evaluated after creating
22352262
** and initializing the Tcl interpreter. By default, this
22362263
** is empty and no extra setup is performed.
22372264
**
2265
+** th1-setup This is the setup script to be evaluated after creating
2266
+** and initializing the TH1 interpreter. By default, this
2267
+** is empty and no extra setup is performed.
2268
+**
2269
+** unicode-glob The VALUE is a comma or newline-separated list of GLOB
2270
+** (versionable) patterns specifying files that the "commit" command will
2271
+** ignore when issuing warnings about text files that may
2272
+** contain Unicode. Set to "*" to disable Unicode checking.
2273
+**
22382274
** web-browser A shell command used to launch your preferred
22392275
** web browser when given a URL as an argument.
22402276
** Defaults to "start" on windows, "open" on Mac,
22412277
** and "firefox" on Unix.
22422278
**
22432279
--- src/db.c
+++ src/db.c
@@ -740,17 +740,25 @@
740 /*
741 ** zDbName is the name of a database file. If no other database
742 ** file is open, then open this one. If another database file is
743 ** already open, then attach zDbName using the name zLabel.
744 */
745 void db_open_or_attach(const char *zDbName, const char *zLabel){
 
 
 
 
746 if( !g.db ){
 
747 g.db = openDatabase(zDbName);
748 g.zMainDbType = zLabel;
749 db_connection_init();
 
750 }else{
 
751 db_attach(zDbName, zLabel);
 
752 }
753 }
754
755 /*
756 ** Open the user database in "~/.fossil". Create the database anew if
@@ -806,16 +814,18 @@
806 zDbName = mprintf("%s/.fossil", zHome);
807 #endif
808 if( file_size(zDbName)<1024*3 ){
809 db_init_database(zDbName, zConfigSchema, (char*)0);
810 }
811 g.useAttach = useAttach;
812 if( useAttach ){
813 db_open_or_attach(zDbName, "configdb");
814 g.dbConfig = 0;
 
815 }else{
 
816 g.dbConfig = openDatabase(zDbName);
 
817 }
818 g.configOpen = 1;
819 free(zDbName);
820 }
821
@@ -850,11 +860,11 @@
850 char *zVFileDef;
851
852 if( file_access(zDbName, F_OK) ) return 0;
853 lsize = file_size(zDbName);
854 if( lsize%1024!=0 || lsize<4096 ) return 0;
855 db_open_or_attach(zDbName, "localdb");
856 zVFileDef = db_text(0, "SELECT sql FROM %s.sqlite_master"
857 " WHERE name=='vfile'", db_name("localdb"));
858
859 /* If the "isexe" column is missing from the vfile table, then
860 ** add it now. This code added on 2010-03-06. After all users have
@@ -986,11 +996,11 @@
986 g.json.resultCode = FSL_JSON_E_DB_NOT_VALID;
987 #endif
988 fossil_panic("not a valid repository: %s", zDbName);
989 }
990 }
991 db_open_or_attach(zDbName, "repository");
992 g.repositoryOpen = 1;
993 g.zRepositoryName = mprintf("%s", zDbName);
994 /* Cache "allow-symlinks" option, because we'll need it on every stat call */
995 g.allowSymlinks = db_get_boolean("allow-symlinks", 0);
996 }
@@ -1109,11 +1119,11 @@
1109 file_canonical_name(g.argv[2], &repo, 0);
1110 zRepo = blob_str(&repo);
1111 if( file_access(zRepo, 0) ){
1112 fossil_fatal("no such file: %s", zRepo);
1113 }
1114 db_open_or_attach(zRepo, "test_repo");
1115 db_lset("repository", blob_str(&repo));
1116 db_close(1);
1117 }
1118
1119
@@ -1177,13 +1187,15 @@
1177 g.localOpen = 0;
1178 g.configOpen = 0;
1179 sqlite3_wal_checkpoint(g.db, 0);
1180 sqlite3_close(g.db);
1181 g.db = 0;
 
1182 if( g.dbConfig ){
1183 sqlite3_close(g.dbConfig);
1184 g.dbConfig = 0;
 
1185 }
1186 }
1187
1188
1189 /*
@@ -1630,19 +1642,32 @@
1630 /*
1631 ** Swap the g.db and g.dbConfig connections so that the various db_* routines
1632 ** work on the ~/.fossil database instead of on the repository database.
1633 ** Be sure to swap them back after doing the operation.
1634 **
1635 ** If g.useAttach that means the ~/.fossil database was opened with
1636 ** the useAttach flag set to 1. In that case no connection swap is required
1637 ** so this routine is a no-op.
1638 */
1639 void db_swap_connections(void){
1640 if( !g.useAttach ){
 
 
 
 
 
 
 
 
 
 
1641 sqlite3 *dbTemp = g.db;
 
1642 g.db = g.dbConfig;
 
1643 g.dbConfig = dbTemp;
 
1644 }
1645 }
1646
1647 /*
1648 ** Logic for reading potentially versioned settings from
@@ -1672,11 +1697,11 @@
1672 ** and a checkout is open. */
1673 if( cacheEntry==0 ){
1674 Blob versionedPathname;
1675 char *zVersionedPathname;
1676 blob_zero(&versionedPathname);
1677 blob_appendf(&versionedPathname, "%s/.fossil-settings/%s",
1678 g.zLocalRoot, zName);
1679 zVersionedPathname = blob_str(&versionedPathname);
1680 if( file_size(zVersionedPathname)>=0 ){
1681 /* File exists, and contains the value for this setting. Load from
1682 ** the file. */
@@ -2055,14 +2080,16 @@
2055 { "repo-cksum", 0, 0, 0, "on" },
2056 { "self-register", 0, 0, 0, "off" },
2057 { "ssl-ca-location",0, 40, 0, "" },
2058 { "ssl-identity", 0, 40, 0, "" },
2059 { "ssh-command", 0, 40, 0, "" },
 
2060 #ifdef FOSSIL_ENABLE_TCL
2061 { "tcl", 0, 0, 0, "off" },
2062 { "tcl-setup", 0, 40, 0, "" },
2063 #endif
 
2064 { "web-browser", 0, 32, 0, "" },
2065 { "white-foreground", 0, 0, 0, "off" },
2066 { 0,0,0,0,0 }
2067 };
2068
@@ -2233,10 +2260,19 @@
2233 **
2234 ** tcl-setup This is the setup script to be evaluated after creating
2235 ** and initializing the Tcl interpreter. By default, this
2236 ** is empty and no extra setup is performed.
2237 **
 
 
 
 
 
 
 
 
 
2238 ** web-browser A shell command used to launch your preferred
2239 ** web browser when given a URL as an argument.
2240 ** Defaults to "start" on windows, "open" on Mac,
2241 ** and "firefox" on Unix.
2242 **
2243
--- src/db.c
+++ src/db.c
@@ -740,17 +740,25 @@
740 /*
741 ** zDbName is the name of a database file. If no other database
742 ** file is open, then open this one. If another database file is
743 ** already open, then attach zDbName using the name zLabel.
744 */
745 void db_open_or_attach(
746 const char *zDbName,
747 const char *zLabel,
748 int *pWasAttached
749 ){
750 if( !g.db ){
751 assert( g.zMainDbType==0 );
752 g.db = openDatabase(zDbName);
753 g.zMainDbType = zLabel;
754 db_connection_init();
755 if ( pWasAttached ) *pWasAttached = 0;
756 }else{
757 assert( g.zMainDbType!=0 );
758 db_attach(zDbName, zLabel);
759 if ( pWasAttached ) *pWasAttached = 1;
760 }
761 }
762
763 /*
764 ** Open the user database in "~/.fossil". Create the database anew if
@@ -806,16 +814,18 @@
814 zDbName = mprintf("%s/.fossil", zHome);
815 #endif
816 if( file_size(zDbName)<1024*3 ){
817 db_init_database(zDbName, zConfigSchema, (char*)0);
818 }
 
819 if( useAttach ){
820 db_open_or_attach(zDbName, "configdb", &g.useAttach);
821 g.dbConfig = 0;
822 g.zConfigDbType = 0;
823 }else{
824 g.useAttach = 0;
825 g.dbConfig = openDatabase(zDbName);
826 g.zConfigDbType = "configdb";
827 }
828 g.configOpen = 1;
829 free(zDbName);
830 }
831
@@ -850,11 +860,11 @@
860 char *zVFileDef;
861
862 if( file_access(zDbName, F_OK) ) return 0;
863 lsize = file_size(zDbName);
864 if( lsize%1024!=0 || lsize<4096 ) return 0;
865 db_open_or_attach(zDbName, "localdb", 0);
866 zVFileDef = db_text(0, "SELECT sql FROM %s.sqlite_master"
867 " WHERE name=='vfile'", db_name("localdb"));
868
869 /* If the "isexe" column is missing from the vfile table, then
870 ** add it now. This code added on 2010-03-06. After all users have
@@ -986,11 +996,11 @@
996 g.json.resultCode = FSL_JSON_E_DB_NOT_VALID;
997 #endif
998 fossil_panic("not a valid repository: %s", zDbName);
999 }
1000 }
1001 db_open_or_attach(zDbName, "repository", 0);
1002 g.repositoryOpen = 1;
1003 g.zRepositoryName = mprintf("%s", zDbName);
1004 /* Cache "allow-symlinks" option, because we'll need it on every stat call */
1005 g.allowSymlinks = db_get_boolean("allow-symlinks", 0);
1006 }
@@ -1109,11 +1119,11 @@
1119 file_canonical_name(g.argv[2], &repo, 0);
1120 zRepo = blob_str(&repo);
1121 if( file_access(zRepo, 0) ){
1122 fossil_fatal("no such file: %s", zRepo);
1123 }
1124 db_open_or_attach(zRepo, "test_repo", 0);
1125 db_lset("repository", blob_str(&repo));
1126 db_close(1);
1127 }
1128
1129
@@ -1177,13 +1187,15 @@
1187 g.localOpen = 0;
1188 g.configOpen = 0;
1189 sqlite3_wal_checkpoint(g.db, 0);
1190 sqlite3_close(g.db);
1191 g.db = 0;
1192 g.zMainDbType = 0;
1193 if( g.dbConfig ){
1194 sqlite3_close(g.dbConfig);
1195 g.dbConfig = 0;
1196 g.zConfigDbType = 0;
1197 }
1198 }
1199
1200
1201 /*
@@ -1630,19 +1642,32 @@
1642 /*
1643 ** Swap the g.db and g.dbConfig connections so that the various db_* routines
1644 ** work on the ~/.fossil database instead of on the repository database.
1645 ** Be sure to swap them back after doing the operation.
1646 **
1647 ** If the ~/.fossil database has already been opened as the main database or
1648 ** is attached to the main database, no connection swaps are required so this
1649 ** routine is a no-op.
1650 */
1651 void db_swap_connections(void){
1652 /*
1653 ** When swapping the main database connection with the config database
1654 ** connection, the config database connection must be open (not simply
1655 ** attached); otherwise, the swap would end up leaving the main database
1656 ** connection invalid, defeating the very purpose of this routine. This
1657 ** same constraint also holds true when restoring the previously swapped
1658 ** database connection; otherwise, it means that no swap was performed
1659 ** because the main database connection was already pointing to the config
1660 ** database.
1661 */
1662 if( g.dbConfig ){
1663 sqlite3 *dbTemp = g.db;
1664 const char *zTempDbType = g.zMainDbType;
1665 g.db = g.dbConfig;
1666 g.zMainDbType = g.zConfigDbType;
1667 g.dbConfig = dbTemp;
1668 g.zConfigDbType = zTempDbType;
1669 }
1670 }
1671
1672 /*
1673 ** Logic for reading potentially versioned settings from
@@ -1672,11 +1697,11 @@
1697 ** and a checkout is open. */
1698 if( cacheEntry==0 ){
1699 Blob versionedPathname;
1700 char *zVersionedPathname;
1701 blob_zero(&versionedPathname);
1702 blob_appendf(&versionedPathname, "%s.fossil-settings/%s",
1703 g.zLocalRoot, zName);
1704 zVersionedPathname = blob_str(&versionedPathname);
1705 if( file_size(zVersionedPathname)>=0 ){
1706 /* File exists, and contains the value for this setting. Load from
1707 ** the file. */
@@ -2055,14 +2080,16 @@
2080 { "repo-cksum", 0, 0, 0, "on" },
2081 { "self-register", 0, 0, 0, "off" },
2082 { "ssl-ca-location",0, 40, 0, "" },
2083 { "ssl-identity", 0, 40, 0, "" },
2084 { "ssh-command", 0, 40, 0, "" },
2085 { "th1-setup", 0, 40, 0, "" },
2086 #ifdef FOSSIL_ENABLE_TCL
2087 { "tcl", 0, 0, 0, "off" },
2088 { "tcl-setup", 0, 40, 0, "" },
2089 #endif
2090 { "unicode-glob", 0, 40, 1, "" },
2091 { "web-browser", 0, 32, 0, "" },
2092 { "white-foreground", 0, 0, 0, "off" },
2093 { 0,0,0,0,0 }
2094 };
2095
@@ -2233,10 +2260,19 @@
2260 **
2261 ** tcl-setup This is the setup script to be evaluated after creating
2262 ** and initializing the Tcl interpreter. By default, this
2263 ** is empty and no extra setup is performed.
2264 **
2265 ** th1-setup This is the setup script to be evaluated after creating
2266 ** and initializing the TH1 interpreter. By default, this
2267 ** is empty and no extra setup is performed.
2268 **
2269 ** unicode-glob The VALUE is a comma or newline-separated list of GLOB
2270 ** (versionable) patterns specifying files that the "commit" command will
2271 ** ignore when issuing warnings about text files that may
2272 ** contain Unicode. Set to "*" to disable Unicode checking.
2273 **
2274 ** web-browser A shell command used to launch your preferred
2275 ** web browser when given a URL as an argument.
2276 ** Defaults to "start" on windows, "open" on Mac,
2277 ** and "firefox" on Unix.
2278 **
2279
--- src/descendants.c
+++ src/descendants.c
@@ -506,6 +506,5 @@
506506
db_finalize(&q);
507507
db_finalize(&ins);
508508
bag_clear(&seen);
509509
bag_clear(&pending);
510510
}
511
-
512511
--- src/descendants.c
+++ src/descendants.c
@@ -506,6 +506,5 @@
506 db_finalize(&q);
507 db_finalize(&ins);
508 bag_clear(&seen);
509 bag_clear(&pending);
510 }
511
512
--- src/descendants.c
+++ src/descendants.c
@@ -506,6 +506,5 @@
506 db_finalize(&q);
507 db_finalize(&ins);
508 bag_clear(&seen);
509 bag_clear(&pending);
510 }
 
511
+12 -6
--- src/diff.c
+++ src/diff.c
@@ -327,36 +327,40 @@
327327
/*
328328
** This function returns an array of bytes representing the byte-order-mark
329329
** for UTF-8.
330330
*/
331331
const unsigned char *get_utf8_bom(int *pnByte){
332
- static const unsigned char bom[] = { 0xEF, 0xBB, 0xBF, 0x00, 0x00, 0x00 };
332
+ static const unsigned char bom[] = {
333
+ 0xEF, 0xBB, 0xBF, 0x00, 0x00, 0x00
334
+ };
333335
if( pnByte ) *pnByte = 3;
334336
return bom;
335337
}
336338
337339
/*
338340
** This function returns non-zero if the blob starts with a UTF-8
339341
** byte-order-mark (BOM).
340342
*/
341
-int starts_with_utf8_bom(const Blob *pContent){
343
+int starts_with_utf8_bom(const Blob *pContent, int *pnByte){
342344
const char *z = blob_buffer(pContent);
343
- int bomSize;
345
+ int bomSize = 0;
344346
const unsigned char *bom = get_utf8_bom(&bomSize);
345347
348
+ if( pnByte ) *pnByte = bomSize;
346349
if( blob_size(pContent)<bomSize ) return 0;
347350
return memcmp(z, bom, bomSize)==0;
348351
}
349352
350353
/*
351354
** This function returns non-zero if the blob starts with a UTF-16le or
352355
** UTF-16be byte-order-mark (BOM).
353356
*/
354
-int starts_with_utf16_bom(const Blob *pContent){
357
+int starts_with_utf16_bom(const Blob *pContent, int *pnByte){
355358
const char *z = blob_buffer(pContent);
356359
int c1, c2;
357360
361
+ if( pnByte ) *pnByte = 2;
358362
if( blob_size(pContent)<2 ) return 0;
359363
c1 = z[0]; c2 = z[1];
360364
if( (c1==(char)0xff) && (c2==(char)0xfe) ){
361365
return 1;
362366
}else if( (c1==(char)0xfe) && (c2==(char)0xff) ){
@@ -367,14 +371,15 @@
367371
368372
/*
369373
** This function returns non-zero if the blob starts with a UTF-16le
370374
** byte-order-mark (BOM).
371375
*/
372
-int starts_with_utf16le_bom(const Blob *pContent){
376
+int starts_with_utf16le_bom(const Blob *pContent, int *pnByte){
373377
const char *z = blob_buffer(pContent);
374378
int c1, c2;
375379
380
+ if( pnByte ) *pnByte = 2;
376381
if( blob_size(pContent)<2 ) return 0;
377382
c1 = z[0]; c2 = z[1];
378383
if( (c1==(char)0xff) && (c2==(char)0xfe) ){
379384
return 1;
380385
}
@@ -383,14 +388,15 @@
383388
384389
/*
385390
** This function returns non-zero if the blob starts with a UTF-16be
386391
** byte-order-mark (BOM).
387392
*/
388
-int starts_with_utf16be_bom(const Blob *pContent){
393
+int starts_with_utf16be_bom(const Blob *pContent, int *pnByte){
389394
const char *z = blob_buffer(pContent);
390395
int c1, c2;
391396
397
+ if( pnByte ) *pnByte = 2;
392398
if( blob_size(pContent)<2 ) return 0;
393399
c1 = z[0]; c2 = z[1];
394400
if( (c1==(char)0xfe) && (c2==(char)0xff) ){
395401
return 1;
396402
}
397403
--- src/diff.c
+++ src/diff.c
@@ -327,36 +327,40 @@
327 /*
328 ** This function returns an array of bytes representing the byte-order-mark
329 ** for UTF-8.
330 */
331 const unsigned char *get_utf8_bom(int *pnByte){
332 static const unsigned char bom[] = { 0xEF, 0xBB, 0xBF, 0x00, 0x00, 0x00 };
 
 
333 if( pnByte ) *pnByte = 3;
334 return bom;
335 }
336
337 /*
338 ** This function returns non-zero if the blob starts with a UTF-8
339 ** byte-order-mark (BOM).
340 */
341 int starts_with_utf8_bom(const Blob *pContent){
342 const char *z = blob_buffer(pContent);
343 int bomSize;
344 const unsigned char *bom = get_utf8_bom(&bomSize);
345
 
346 if( blob_size(pContent)<bomSize ) return 0;
347 return memcmp(z, bom, bomSize)==0;
348 }
349
350 /*
351 ** This function returns non-zero if the blob starts with a UTF-16le or
352 ** UTF-16be byte-order-mark (BOM).
353 */
354 int starts_with_utf16_bom(const Blob *pContent){
355 const char *z = blob_buffer(pContent);
356 int c1, c2;
357
 
358 if( blob_size(pContent)<2 ) return 0;
359 c1 = z[0]; c2 = z[1];
360 if( (c1==(char)0xff) && (c2==(char)0xfe) ){
361 return 1;
362 }else if( (c1==(char)0xfe) && (c2==(char)0xff) ){
@@ -367,14 +371,15 @@
367
368 /*
369 ** This function returns non-zero if the blob starts with a UTF-16le
370 ** byte-order-mark (BOM).
371 */
372 int starts_with_utf16le_bom(const Blob *pContent){
373 const char *z = blob_buffer(pContent);
374 int c1, c2;
375
 
376 if( blob_size(pContent)<2 ) return 0;
377 c1 = z[0]; c2 = z[1];
378 if( (c1==(char)0xff) && (c2==(char)0xfe) ){
379 return 1;
380 }
@@ -383,14 +388,15 @@
383
384 /*
385 ** This function returns non-zero if the blob starts with a UTF-16be
386 ** byte-order-mark (BOM).
387 */
388 int starts_with_utf16be_bom(const Blob *pContent){
389 const char *z = blob_buffer(pContent);
390 int c1, c2;
391
 
392 if( blob_size(pContent)<2 ) return 0;
393 c1 = z[0]; c2 = z[1];
394 if( (c1==(char)0xfe) && (c2==(char)0xff) ){
395 return 1;
396 }
397
--- src/diff.c
+++ src/diff.c
@@ -327,36 +327,40 @@
327 /*
328 ** This function returns an array of bytes representing the byte-order-mark
329 ** for UTF-8.
330 */
331 const unsigned char *get_utf8_bom(int *pnByte){
332 static const unsigned char bom[] = {
333 0xEF, 0xBB, 0xBF, 0x00, 0x00, 0x00
334 };
335 if( pnByte ) *pnByte = 3;
336 return bom;
337 }
338
339 /*
340 ** This function returns non-zero if the blob starts with a UTF-8
341 ** byte-order-mark (BOM).
342 */
343 int starts_with_utf8_bom(const Blob *pContent, int *pnByte){
344 const char *z = blob_buffer(pContent);
345 int bomSize = 0;
346 const unsigned char *bom = get_utf8_bom(&bomSize);
347
348 if( pnByte ) *pnByte = bomSize;
349 if( blob_size(pContent)<bomSize ) return 0;
350 return memcmp(z, bom, bomSize)==0;
351 }
352
353 /*
354 ** This function returns non-zero if the blob starts with a UTF-16le or
355 ** UTF-16be byte-order-mark (BOM).
356 */
357 int starts_with_utf16_bom(const Blob *pContent, int *pnByte){
358 const char *z = blob_buffer(pContent);
359 int c1, c2;
360
361 if( pnByte ) *pnByte = 2;
362 if( blob_size(pContent)<2 ) return 0;
363 c1 = z[0]; c2 = z[1];
364 if( (c1==(char)0xff) && (c2==(char)0xfe) ){
365 return 1;
366 }else if( (c1==(char)0xfe) && (c2==(char)0xff) ){
@@ -367,14 +371,15 @@
371
372 /*
373 ** This function returns non-zero if the blob starts with a UTF-16le
374 ** byte-order-mark (BOM).
375 */
376 int starts_with_utf16le_bom(const Blob *pContent, int *pnByte){
377 const char *z = blob_buffer(pContent);
378 int c1, c2;
379
380 if( pnByte ) *pnByte = 2;
381 if( blob_size(pContent)<2 ) return 0;
382 c1 = z[0]; c2 = z[1];
383 if( (c1==(char)0xff) && (c2==(char)0xfe) ){
384 return 1;
385 }
@@ -383,14 +388,15 @@
388
389 /*
390 ** This function returns non-zero if the blob starts with a UTF-16be
391 ** byte-order-mark (BOM).
392 */
393 int starts_with_utf16be_bom(const Blob *pContent, int *pnByte){
394 const char *z = blob_buffer(pContent);
395 int c1, c2;
396
397 if( pnByte ) *pnByte = 2;
398 if( blob_size(pContent)<2 ) return 0;
399 c1 = z[0]; c2 = z[1];
400 if( (c1==(char)0xfe) && (c2==(char)0xff) ){
401 return 1;
402 }
403
+34
--- src/encode.c
+++ src/encode.c
@@ -83,10 +83,44 @@
8383
zIn++;
8484
}
8585
zOut[i] = 0;
8686
return zOut;
8787
}
88
+
89
+/*
90
+** Append HTML-escaped text to a Blob.
91
+*/
92
+void htmlize_to_blob(Blob *p, const char *zIn, int n){
93
+ int c, i, j;
94
+ if( n<0 ) n = strlen(zIn);
95
+ for(i=j=0; i<n; i++){
96
+ c = zIn[i];
97
+ switch( c ){
98
+ case '<':
99
+ if( j<i ) blob_append(p, zIn+j, i-j);
100
+ blob_append(p, "&lt;", 4);
101
+ j = i+1;
102
+ break;
103
+ case '>':
104
+ if( j<i ) blob_append(p, zIn+j, i-j);
105
+ blob_append(p, "&gt;", 4);
106
+ j = i+1;
107
+ break;
108
+ case '&':
109
+ if( j<i ) blob_append(p, zIn+j, i-j);
110
+ blob_append(p, "&amp;", 5);
111
+ j = i+1;
112
+ break;
113
+ case '"':
114
+ if( j<i ) blob_append(p, zIn+j, i-j);
115
+ blob_append(p, "&quot;", 6);
116
+ j = i+1;
117
+ break;
118
+ }
119
+ }
120
+ if( j<i ) blob_append(p, zIn+j, i-j);
121
+}
88122
89123
90124
/*
91125
** Encode a string for HTTP. This means converting lots of
92126
** characters into the "%HH" where H is a hex digit. It also
93127
--- src/encode.c
+++ src/encode.c
@@ -83,10 +83,44 @@
83 zIn++;
84 }
85 zOut[i] = 0;
86 return zOut;
87 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
88
89
90 /*
91 ** Encode a string for HTTP. This means converting lots of
92 ** characters into the "%HH" where H is a hex digit. It also
93
--- src/encode.c
+++ src/encode.c
@@ -83,10 +83,44 @@
83 zIn++;
84 }
85 zOut[i] = 0;
86 return zOut;
87 }
88
89 /*
90 ** Append HTML-escaped text to a Blob.
91 */
92 void htmlize_to_blob(Blob *p, const char *zIn, int n){
93 int c, i, j;
94 if( n<0 ) n = strlen(zIn);
95 for(i=j=0; i<n; i++){
96 c = zIn[i];
97 switch( c ){
98 case '<':
99 if( j<i ) blob_append(p, zIn+j, i-j);
100 blob_append(p, "&lt;", 4);
101 j = i+1;
102 break;
103 case '>':
104 if( j<i ) blob_append(p, zIn+j, i-j);
105 blob_append(p, "&gt;", 4);
106 j = i+1;
107 break;
108 case '&':
109 if( j<i ) blob_append(p, zIn+j, i-j);
110 blob_append(p, "&amp;", 5);
111 j = i+1;
112 break;
113 case '"':
114 if( j<i ) blob_append(p, zIn+j, i-j);
115 blob_append(p, "&quot;", 6);
116 j = i+1;
117 break;
118 }
119 }
120 if( j<i ) blob_append(p, zIn+j, i-j);
121 }
122
123
124 /*
125 ** Encode a string for HTTP. This means converting lots of
126 ** characters into the "%HH" where H is a hex digit. It also
127
+1 -1
--- src/event.c
+++ src/event.c
@@ -365,11 +365,11 @@
365365
}else{
366366
@ <tr><td>
367367
}
368368
blob_zero(&com);
369369
blob_append(&com, zComment, -1);
370
- wiki_convert(&com, 0, WIKI_INLINE);
370
+ wiki_convert(&com, 0, WIKI_INLINE|WIKI_NOBADLINKS);
371371
@ </td></tr></table>
372372
@ </blockquote>
373373
@ <p><b>Page content preview:</b><p>
374374
@ <blockquote>
375375
blob_zero(&event);
376376
--- src/event.c
+++ src/event.c
@@ -365,11 +365,11 @@
365 }else{
366 @ <tr><td>
367 }
368 blob_zero(&com);
369 blob_append(&com, zComment, -1);
370 wiki_convert(&com, 0, WIKI_INLINE);
371 @ </td></tr></table>
372 @ </blockquote>
373 @ <p><b>Page content preview:</b><p>
374 @ <blockquote>
375 blob_zero(&event);
376
--- src/event.c
+++ src/event.c
@@ -365,11 +365,11 @@
365 }else{
366 @ <tr><td>
367 }
368 blob_zero(&com);
369 blob_append(&com, zComment, -1);
370 wiki_convert(&com, 0, WIKI_INLINE|WIKI_NOBADLINKS);
371 @ </td></tr></table>
372 @ </blockquote>
373 @ <p><b>Page content preview:</b><p>
374 @ <blockquote>
375 blob_zero(&event);
376
+11 -3
--- src/export.c
+++ src/export.c
@@ -166,16 +166,19 @@
166166
167167
/* Step 1: Generate "blob" records for every artifact that is part
168168
** of a check-in
169169
*/
170170
fossil_binary_mode(stdout);
171
- db_multi_exec("CREATE TEMPORARY TABLE newblob(rid INTEGER KEY, srcid INTEGER)");
171
+ db_multi_exec("CREATE TEMP TABLE newblob(rid INTEGER KEY, srcid INTEGER)");
172172
db_multi_exec("CREATE INDEX newblob_src ON newblob(srcid)");
173173
db_multi_exec(
174174
"INSERT INTO newblob"
175175
" SELECT DISTINCT fid,"
176
- " CASE WHEN EXISTS(SELECT 1 FROM delta WHERE rid=fid AND NOT EXISTS(SELECT 1 FROM oldblob WHERE srcid=fid))"
176
+ " CASE WHEN EXISTS(SELECT 1 FROM delta"
177
+ " WHERE rid=fid"
178
+ " AND NOT EXISTS(SELECT 1 FROM oldblob"
179
+ " WHERE srcid=fid))"
177180
" THEN (SELECT srcid FROM delta WHERE rid=fid)"
178181
" ELSE 0"
179182
" END"
180183
" FROM mlink"
181184
" WHERE fid>0 AND NOT EXISTS(SELECT 1 FROM oldblob WHERE rid=fid)");
@@ -247,11 +250,16 @@
247250
printf("committer");
248251
print_person(zUser);
249252
printf(" %s +0000\n", zSecondsSince1970);
250253
if( zComment==0 ) zComment = "null comment";
251254
printf("data %d\n%s\n", (int)strlen(zComment), zComment);
252
- db_prepare(&q3, "SELECT pid FROM plink WHERE cid=%d AND isprim", ckinId);
255
+ db_prepare(&q3,
256
+ "SELECT pid FROM plink"
257
+ " WHERE cid=%d AND isprim"
258
+ " AND pid IN (SELECT objid FROM event)",
259
+ ckinId
260
+ );
253261
if( db_step(&q3) == SQLITE_ROW ){
254262
printf("from :%d\n", COMMITMARK(db_column_int(&q3, 0)));
255263
db_prepare(&q4,
256264
"SELECT pid FROM plink"
257265
" WHERE cid=%d AND NOT isprim"
258266
--- src/export.c
+++ src/export.c
@@ -166,16 +166,19 @@
166
167 /* Step 1: Generate "blob" records for every artifact that is part
168 ** of a check-in
169 */
170 fossil_binary_mode(stdout);
171 db_multi_exec("CREATE TEMPORARY TABLE newblob(rid INTEGER KEY, srcid INTEGER)");
172 db_multi_exec("CREATE INDEX newblob_src ON newblob(srcid)");
173 db_multi_exec(
174 "INSERT INTO newblob"
175 " SELECT DISTINCT fid,"
176 " CASE WHEN EXISTS(SELECT 1 FROM delta WHERE rid=fid AND NOT EXISTS(SELECT 1 FROM oldblob WHERE srcid=fid))"
 
 
 
177 " THEN (SELECT srcid FROM delta WHERE rid=fid)"
178 " ELSE 0"
179 " END"
180 " FROM mlink"
181 " WHERE fid>0 AND NOT EXISTS(SELECT 1 FROM oldblob WHERE rid=fid)");
@@ -247,11 +250,16 @@
247 printf("committer");
248 print_person(zUser);
249 printf(" %s +0000\n", zSecondsSince1970);
250 if( zComment==0 ) zComment = "null comment";
251 printf("data %d\n%s\n", (int)strlen(zComment), zComment);
252 db_prepare(&q3, "SELECT pid FROM plink WHERE cid=%d AND isprim", ckinId);
 
 
 
 
 
253 if( db_step(&q3) == SQLITE_ROW ){
254 printf("from :%d\n", COMMITMARK(db_column_int(&q3, 0)));
255 db_prepare(&q4,
256 "SELECT pid FROM plink"
257 " WHERE cid=%d AND NOT isprim"
258
--- src/export.c
+++ src/export.c
@@ -166,16 +166,19 @@
166
167 /* Step 1: Generate "blob" records for every artifact that is part
168 ** of a check-in
169 */
170 fossil_binary_mode(stdout);
171 db_multi_exec("CREATE TEMP TABLE newblob(rid INTEGER KEY, srcid INTEGER)");
172 db_multi_exec("CREATE INDEX newblob_src ON newblob(srcid)");
173 db_multi_exec(
174 "INSERT INTO newblob"
175 " SELECT DISTINCT fid,"
176 " CASE WHEN EXISTS(SELECT 1 FROM delta"
177 " WHERE rid=fid"
178 " AND NOT EXISTS(SELECT 1 FROM oldblob"
179 " WHERE srcid=fid))"
180 " THEN (SELECT srcid FROM delta WHERE rid=fid)"
181 " ELSE 0"
182 " END"
183 " FROM mlink"
184 " WHERE fid>0 AND NOT EXISTS(SELECT 1 FROM oldblob WHERE rid=fid)");
@@ -247,11 +250,16 @@
250 printf("committer");
251 print_person(zUser);
252 printf(" %s +0000\n", zSecondsSince1970);
253 if( zComment==0 ) zComment = "null comment";
254 printf("data %d\n%s\n", (int)strlen(zComment), zComment);
255 db_prepare(&q3,
256 "SELECT pid FROM plink"
257 " WHERE cid=%d AND isprim"
258 " AND pid IN (SELECT objid FROM event)",
259 ckinId
260 );
261 if( db_step(&q3) == SQLITE_ROW ){
262 printf("from :%d\n", COMMITMARK(db_column_int(&q3, 0)));
263 db_prepare(&q4,
264 "SELECT pid FROM plink"
265 " WHERE cid=%d AND NOT isprim"
266
+26 -1
--- src/file.c
+++ src/file.c
@@ -425,11 +425,11 @@
425425
char *zDate;
426426
i64 iMTime;
427427
if( g.argc!=4 ){
428428
usage("test-set-mtime FILENAME DATE/TIME");
429429
}
430
- db_open_or_attach(":memory:", "mem");
430
+ db_open_or_attach(":memory:", "mem", 0);
431431
iMTime = db_int64(0, "SELECT strftime('%%s',%Q)", g.argv[3]);
432432
zFile = g.argv[2];
433433
file_set_mtime(zFile, iMTime);
434434
iMTime = file_wd_mtime(zFile);
435435
zDate = db_text(0, "SELECT datetime(%lld, 'unixepoch')", iMTime);
@@ -495,10 +495,35 @@
495495
if( c=='.' ){
496496
if( z[1]=='/' || z[1]==0 ) return 0;
497497
if( z[1]=='.' && (z[2]=='/' || z[2]==0) ) return 0;
498498
}
499499
for(i=0; (c=z[i])!=0; i++){
500
+ if( (c & 0xf0) == 0xf0 ) {
501
+ /* Unicode characters > U+FFFF are not supported.
502
+ * Windows XP and earlier cannot handle them.
503
+ */
504
+ return 0;
505
+ }
506
+ if( (c & 0xf0) == 0xe0 ) {
507
+ /* This is a 3-byte UTF-8 character */
508
+ if ( (c & 0xfe) == 0xee ){
509
+ /* Range U+E000 - U+FFFF (Starting with 0xee or 0xef in UTF-8 ) */
510
+ if ( (c & 1) && ((z[i+1] & 0xff) >= 0xa4) ){
511
+ /* But exclude U+F900 - U+FFFF (0xef followed by byte >= 0xa4),
512
+ * which contain valid characters. */
513
+ continue;
514
+ }
515
+ /* Unicode character in the range U+E000 - U+F8FF are for
516
+ * private use, they shouldn't occur in filenames. */
517
+ return 0;
518
+ }
519
+ if( ((c & 0xff) == 0xed) && ((z[i+1] & 0xe0) == 0xa0) ){
520
+ /* Unicode character in the range U+D800 - U+DFFF are for
521
+ * surrogate pairs, they shouldn't occur in filenames. */
522
+ return 0;
523
+ }
524
+ }
500525
if( c=='\\' || c=='*' || c=='[' || c==']' || c=='?' ){
501526
return 0;
502527
}
503528
if( c=='/' ){
504529
if( z[i+1]=='/' ) return 0;
505530
--- src/file.c
+++ src/file.c
@@ -425,11 +425,11 @@
425 char *zDate;
426 i64 iMTime;
427 if( g.argc!=4 ){
428 usage("test-set-mtime FILENAME DATE/TIME");
429 }
430 db_open_or_attach(":memory:", "mem");
431 iMTime = db_int64(0, "SELECT strftime('%%s',%Q)", g.argv[3]);
432 zFile = g.argv[2];
433 file_set_mtime(zFile, iMTime);
434 iMTime = file_wd_mtime(zFile);
435 zDate = db_text(0, "SELECT datetime(%lld, 'unixepoch')", iMTime);
@@ -495,10 +495,35 @@
495 if( c=='.' ){
496 if( z[1]=='/' || z[1]==0 ) return 0;
497 if( z[1]=='.' && (z[2]=='/' || z[2]==0) ) return 0;
498 }
499 for(i=0; (c=z[i])!=0; i++){
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
500 if( c=='\\' || c=='*' || c=='[' || c==']' || c=='?' ){
501 return 0;
502 }
503 if( c=='/' ){
504 if( z[i+1]=='/' ) return 0;
505
--- src/file.c
+++ src/file.c
@@ -425,11 +425,11 @@
425 char *zDate;
426 i64 iMTime;
427 if( g.argc!=4 ){
428 usage("test-set-mtime FILENAME DATE/TIME");
429 }
430 db_open_or_attach(":memory:", "mem", 0);
431 iMTime = db_int64(0, "SELECT strftime('%%s',%Q)", g.argv[3]);
432 zFile = g.argv[2];
433 file_set_mtime(zFile, iMTime);
434 iMTime = file_wd_mtime(zFile);
435 zDate = db_text(0, "SELECT datetime(%lld, 'unixepoch')", iMTime);
@@ -495,10 +495,35 @@
495 if( c=='.' ){
496 if( z[1]=='/' || z[1]==0 ) return 0;
497 if( z[1]=='.' && (z[2]=='/' || z[2]==0) ) return 0;
498 }
499 for(i=0; (c=z[i])!=0; i++){
500 if( (c & 0xf0) == 0xf0 ) {
501 /* Unicode characters > U+FFFF are not supported.
502 * Windows XP and earlier cannot handle them.
503 */
504 return 0;
505 }
506 if( (c & 0xf0) == 0xe0 ) {
507 /* This is a 3-byte UTF-8 character */
508 if ( (c & 0xfe) == 0xee ){
509 /* Range U+E000 - U+FFFF (Starting with 0xee or 0xef in UTF-8 ) */
510 if ( (c & 1) && ((z[i+1] & 0xff) >= 0xa4) ){
511 /* But exclude U+F900 - U+FFFF (0xef followed by byte >= 0xa4),
512 * which contain valid characters. */
513 continue;
514 }
515 /* Unicode character in the range U+E000 - U+F8FF are for
516 * private use, they shouldn't occur in filenames. */
517 return 0;
518 }
519 if( ((c & 0xff) == 0xed) && ((z[i+1] & 0xe0) == 0xa0) ){
520 /* Unicode character in the range U+D800 - U+DFFF are for
521 * surrogate pairs, they shouldn't occur in filenames. */
522 return 0;
523 }
524 }
525 if( c=='\\' || c=='*' || c=='[' || c==']' || c=='?' ){
526 return 0;
527 }
528 if( c=='/' ){
529 if( z[i+1]=='/' ) return 0;
530
+4 -4
--- src/info.c
+++ src/info.c
@@ -865,11 +865,11 @@
865865
const char *zDate = db_column_text(&q, 0);
866866
const char *zUser = db_column_text(&q, 1);
867867
const char *zUuid = db_column_text(&q, 3);
868868
const char *zTagList = db_column_text(&q, 4);
869869
Blob comment;
870
- int wikiFlags = WIKI_INLINE;
870
+ int wikiFlags = WIKI_INLINE|WIKI_NOBADLINKS;
871871
if( db_get_boolean("timeline-block-markup", 0)==0 ){
872872
wikiFlags |= WIKI_NOBLOCK;
873873
}
874874
hyperlink_to_uuid(zUuid);
875875
blob_zero(&comment);
@@ -2153,11 +2153,11 @@
21532153
if( zNewColor && zNewColor[0] ){
21542154
@ <tr><td style="background-color: %h(zNewColor);">
21552155
}else{
21562156
@ <tr><td>
21572157
}
2158
- wiki_convert(&comment, 0, WIKI_INLINE);
2158
+ @ %w(blob_str(&comment))
21592159
blob_zero(&suffix);
21602160
blob_appendf(&suffix, "(user: %h", zNewUser);
21612161
db_prepare(&q, "SELECT substr(tagname,5) FROM tagxref, tag"
21622162
" WHERE tagname GLOB 'sym-*' AND tagxref.rid=%d"
21632163
" AND tagtype>1 AND tag.tagid=tagxref.tagid",
@@ -2183,13 +2183,13 @@
21832183
@ <hr />
21842184
blob_reset(&suffix);
21852185
}
21862186
@ <p>Make changes to attributes of check-in
21872187
@ [%z(href("%R/ci/%s",zUuid))%s(zUuid)</a>]:</p>
2188
- @ <form action="%s(g.zTop)/ci_edit" method="post"><div>
2188
+ form_begin(0, "%R/ci_edit");
21892189
login_insert_csrf_secret();
2190
- @ <input type="hidden" name="r" value="%S(zUuid)" />
2190
+ @ <div><input type="hidden" name="r" value="%S(zUuid)" />
21912191
@ <table border="0" cellspacing="10">
21922192
21932193
@ <tr><td align="right" valign="top"><b>User:</b></td>
21942194
@ <td valign="top">
21952195
@ <input type="text" name="u" size="20" value="%h(zNewUser)" />
21962196
--- src/info.c
+++ src/info.c
@@ -865,11 +865,11 @@
865 const char *zDate = db_column_text(&q, 0);
866 const char *zUser = db_column_text(&q, 1);
867 const char *zUuid = db_column_text(&q, 3);
868 const char *zTagList = db_column_text(&q, 4);
869 Blob comment;
870 int wikiFlags = WIKI_INLINE;
871 if( db_get_boolean("timeline-block-markup", 0)==0 ){
872 wikiFlags |= WIKI_NOBLOCK;
873 }
874 hyperlink_to_uuid(zUuid);
875 blob_zero(&comment);
@@ -2153,11 +2153,11 @@
2153 if( zNewColor && zNewColor[0] ){
2154 @ <tr><td style="background-color: %h(zNewColor);">
2155 }else{
2156 @ <tr><td>
2157 }
2158 wiki_convert(&comment, 0, WIKI_INLINE);
2159 blob_zero(&suffix);
2160 blob_appendf(&suffix, "(user: %h", zNewUser);
2161 db_prepare(&q, "SELECT substr(tagname,5) FROM tagxref, tag"
2162 " WHERE tagname GLOB 'sym-*' AND tagxref.rid=%d"
2163 " AND tagtype>1 AND tag.tagid=tagxref.tagid",
@@ -2183,13 +2183,13 @@
2183 @ <hr />
2184 blob_reset(&suffix);
2185 }
2186 @ <p>Make changes to attributes of check-in
2187 @ [%z(href("%R/ci/%s",zUuid))%s(zUuid)</a>]:</p>
2188 @ <form action="%s(g.zTop)/ci_edit" method="post"><div>
2189 login_insert_csrf_secret();
2190 @ <input type="hidden" name="r" value="%S(zUuid)" />
2191 @ <table border="0" cellspacing="10">
2192
2193 @ <tr><td align="right" valign="top"><b>User:</b></td>
2194 @ <td valign="top">
2195 @ <input type="text" name="u" size="20" value="%h(zNewUser)" />
2196
--- src/info.c
+++ src/info.c
@@ -865,11 +865,11 @@
865 const char *zDate = db_column_text(&q, 0);
866 const char *zUser = db_column_text(&q, 1);
867 const char *zUuid = db_column_text(&q, 3);
868 const char *zTagList = db_column_text(&q, 4);
869 Blob comment;
870 int wikiFlags = WIKI_INLINE|WIKI_NOBADLINKS;
871 if( db_get_boolean("timeline-block-markup", 0)==0 ){
872 wikiFlags |= WIKI_NOBLOCK;
873 }
874 hyperlink_to_uuid(zUuid);
875 blob_zero(&comment);
@@ -2153,11 +2153,11 @@
2153 if( zNewColor && zNewColor[0] ){
2154 @ <tr><td style="background-color: %h(zNewColor);">
2155 }else{
2156 @ <tr><td>
2157 }
2158 @ %w(blob_str(&comment))
2159 blob_zero(&suffix);
2160 blob_appendf(&suffix, "(user: %h", zNewUser);
2161 db_prepare(&q, "SELECT substr(tagname,5) FROM tagxref, tag"
2162 " WHERE tagname GLOB 'sym-*' AND tagxref.rid=%d"
2163 " AND tagtype>1 AND tag.tagid=tagxref.tagid",
@@ -2183,13 +2183,13 @@
2183 @ <hr />
2184 blob_reset(&suffix);
2185 }
2186 @ <p>Make changes to attributes of check-in
2187 @ [%z(href("%R/ci/%s",zUuid))%s(zUuid)</a>]:</p>
2188 form_begin(0, "%R/ci_edit");
2189 login_insert_csrf_secret();
2190 @ <div><input type="hidden" name="r" value="%S(zUuid)" />
2191 @ <table border="0" cellspacing="10">
2192
2193 @ <tr><td align="right" valign="top"><b>User:</b></td>
2194 @ <td valign="top">
2195 @ <input type="text" name="u" size="20" value="%h(zNewUser)" />
2196
+1
--- src/json.c
+++ src/json.c
@@ -1409,10 +1409,11 @@
14091409
INT(g, isHome);
14101410
INT(g, nAux);
14111411
INT(g, allowSymlinks);
14121412
14131413
CSTR(g, zMainDbType);
1414
+ CSTR(g, zConfigDbType);
14141415
CSTR(g, zHome);
14151416
CSTR(g, zLocalRoot);
14161417
CSTR(g, zPath);
14171418
CSTR(g, zExtra);
14181419
CSTR(g, zBaseURL);
14191420
--- src/json.c
+++ src/json.c
@@ -1409,10 +1409,11 @@
1409 INT(g, isHome);
1410 INT(g, nAux);
1411 INT(g, allowSymlinks);
1412
1413 CSTR(g, zMainDbType);
 
1414 CSTR(g, zHome);
1415 CSTR(g, zLocalRoot);
1416 CSTR(g, zPath);
1417 CSTR(g, zExtra);
1418 CSTR(g, zBaseURL);
1419
--- src/json.c
+++ src/json.c
@@ -1409,10 +1409,11 @@
1409 INT(g, isHome);
1410 INT(g, nAux);
1411 INT(g, allowSymlinks);
1412
1413 CSTR(g, zMainDbType);
1414 CSTR(g, zConfigDbType);
1415 CSTR(g, zHome);
1416 CSTR(g, zLocalRoot);
1417 CSTR(g, zPath);
1418 CSTR(g, zExtra);
1419 CSTR(g, zBaseURL);
1420
--- src/json_branch.c
+++ src/json_branch.c
@@ -305,11 +305,11 @@
305305
/* Commit */
306306
db_end_transaction(0);
307307
308308
#if 0 /* Do an autosync push, if requested */
309309
/* arugable for JSON mode? */
310
- if( !g.isHTTP && !isPrivate ) autosync(AUTOSYNC_PUSH);
310
+ if( !g.isHTTP && !isPrivate ) autosync(SYNC_PUSH);
311311
#endif
312312
return 0;
313313
}
314314
315315
316316
--- src/json_branch.c
+++ src/json_branch.c
@@ -305,11 +305,11 @@
305 /* Commit */
306 db_end_transaction(0);
307
308 #if 0 /* Do an autosync push, if requested */
309 /* arugable for JSON mode? */
310 if( !g.isHTTP && !isPrivate ) autosync(AUTOSYNC_PUSH);
311 #endif
312 return 0;
313 }
314
315
316
--- src/json_branch.c
+++ src/json_branch.c
@@ -305,11 +305,11 @@
305 /* Commit */
306 db_end_transaction(0);
307
308 #if 0 /* Do an autosync push, if requested */
309 /* arugable for JSON mode? */
310 if( !g.isHTTP && !isPrivate ) autosync(SYNC_PUSH);
311 #endif
312 return 0;
313 }
314
315
316
+6 -5
--- src/login.c
+++ src/login.c
@@ -404,10 +404,11 @@
404404
return 0;
405405
}
406406
if( memcmp(zAgent, "Opera/", 6)==0 ) return 1;
407407
if( memcmp(zAgent, "Safari/", 7)==0 ) return 1;
408408
if( memcmp(zAgent, "Lynx/", 5)==0 ) return 1;
409
+ if( memcmp(zAgent, "NetSurf/", 8)==0 ) return 1;
409410
return 0;
410411
}
411412
412413
/*
413414
** COMMAND: test-ishuman
@@ -565,11 +566,11 @@
565566
style_header("Login/Logout");
566567
@ %s(zErrMsg)
567568
if( zGoto && P("anon")==0 ){
568569
@ <p>A login is required for <a href="%h(zGoto)">%h(zGoto)</a>.</p>
569570
}
570
- @ <form action="login" method="post">
571
+ form_begin(0, "%R/login");
571572
if( zGoto ){
572573
@ <input type="hidden" name="g" value="%h(zGoto)" />
573574
}
574575
@ <table class="login_out">
575576
@ <tr>
@@ -631,11 +632,11 @@
631632
632633
@ <p><input type="hidden" name="cs" value="%u(uSeed)" />
633634
@ Visitors may enter <b>anonymous</b> as the user-ID with
634635
@ the 8-character hexadecimal password shown below:</p>
635636
@ <div class="captcha"><table class="captcha"><tr><td><pre>
636
- @ %s(zCaptcha)
637
+ @ %h(zCaptcha)
637638
@ </pre></td></tr></table>
638639
if( bAutoCaptcha ) {
639640
@ <input type="button" value="Fill out captcha"
640641
@ onclick="gebi('u').value='anonymous'; gebi('p').value='%s(zDecoded)';" />
641642
}
@@ -652,11 +653,11 @@
652653
if( g.perm.Password ){
653654
@ <hr />
654655
@ <p>To change your password, enter your old password and your
655656
@ new password twice below then press the "Change Password"
656657
@ button.</p>
657
- @ <form action="login" method="post">
658
+ form_begin(0, "%R/login");
658659
@ <table>
659660
@ <tr><td class="login_out_label">Old Password:</td>
660661
@ <td><input type="password" name="p" size="30" /></td></tr>
661662
@ <tr><td class="login_out_label">New Password:</td>
662663
@ <td><input type="password" name="n1" size="30" /></td></tr>
@@ -1260,11 +1261,11 @@
12601261
uSeed = captcha_seed();
12611262
zDecoded = captcha_decode(uSeed);
12621263
zCaptcha = captcha_render(zDecoded);
12631264
12641265
/* Print out the registration form. */
1265
- @ <form action="register" method="post">
1266
+ form_begin(0, "%R/register");
12661267
if( P("g") ){
12671268
@ <input type="hidden" name="g" value="%h(P("g"))" />
12681269
}
12691270
@ <p><input type="hidden" name="cs" value="%u(uSeed)" />
12701271
@ <table class="login_out">
@@ -1290,11 +1291,11 @@
12901291
@ </tr>
12911292
@ <tr><td></td>
12921293
@ <td><input type="submit" name="new" value="Register" /></td></tr>
12931294
@ </table>
12941295
@ <div class="captcha"><table class="captcha"><tr><td><pre>
1295
- @ %s(zCaptcha)
1296
+ @ %h(zCaptcha)
12961297
@ </pre></td></tr></table>
12971298
@ </form>
12981299
style_footer();
12991300
13001301
free(zCaptcha);
13011302
--- src/login.c
+++ src/login.c
@@ -404,10 +404,11 @@
404 return 0;
405 }
406 if( memcmp(zAgent, "Opera/", 6)==0 ) return 1;
407 if( memcmp(zAgent, "Safari/", 7)==0 ) return 1;
408 if( memcmp(zAgent, "Lynx/", 5)==0 ) return 1;
 
409 return 0;
410 }
411
412 /*
413 ** COMMAND: test-ishuman
@@ -565,11 +566,11 @@
565 style_header("Login/Logout");
566 @ %s(zErrMsg)
567 if( zGoto && P("anon")==0 ){
568 @ <p>A login is required for <a href="%h(zGoto)">%h(zGoto)</a>.</p>
569 }
570 @ <form action="login" method="post">
571 if( zGoto ){
572 @ <input type="hidden" name="g" value="%h(zGoto)" />
573 }
574 @ <table class="login_out">
575 @ <tr>
@@ -631,11 +632,11 @@
631
632 @ <p><input type="hidden" name="cs" value="%u(uSeed)" />
633 @ Visitors may enter <b>anonymous</b> as the user-ID with
634 @ the 8-character hexadecimal password shown below:</p>
635 @ <div class="captcha"><table class="captcha"><tr><td><pre>
636 @ %s(zCaptcha)
637 @ </pre></td></tr></table>
638 if( bAutoCaptcha ) {
639 @ <input type="button" value="Fill out captcha"
640 @ onclick="gebi('u').value='anonymous'; gebi('p').value='%s(zDecoded)';" />
641 }
@@ -652,11 +653,11 @@
652 if( g.perm.Password ){
653 @ <hr />
654 @ <p>To change your password, enter your old password and your
655 @ new password twice below then press the "Change Password"
656 @ button.</p>
657 @ <form action="login" method="post">
658 @ <table>
659 @ <tr><td class="login_out_label">Old Password:</td>
660 @ <td><input type="password" name="p" size="30" /></td></tr>
661 @ <tr><td class="login_out_label">New Password:</td>
662 @ <td><input type="password" name="n1" size="30" /></td></tr>
@@ -1260,11 +1261,11 @@
1260 uSeed = captcha_seed();
1261 zDecoded = captcha_decode(uSeed);
1262 zCaptcha = captcha_render(zDecoded);
1263
1264 /* Print out the registration form. */
1265 @ <form action="register" method="post">
1266 if( P("g") ){
1267 @ <input type="hidden" name="g" value="%h(P("g"))" />
1268 }
1269 @ <p><input type="hidden" name="cs" value="%u(uSeed)" />
1270 @ <table class="login_out">
@@ -1290,11 +1291,11 @@
1290 @ </tr>
1291 @ <tr><td></td>
1292 @ <td><input type="submit" name="new" value="Register" /></td></tr>
1293 @ </table>
1294 @ <div class="captcha"><table class="captcha"><tr><td><pre>
1295 @ %s(zCaptcha)
1296 @ </pre></td></tr></table>
1297 @ </form>
1298 style_footer();
1299
1300 free(zCaptcha);
1301
--- src/login.c
+++ src/login.c
@@ -404,10 +404,11 @@
404 return 0;
405 }
406 if( memcmp(zAgent, "Opera/", 6)==0 ) return 1;
407 if( memcmp(zAgent, "Safari/", 7)==0 ) return 1;
408 if( memcmp(zAgent, "Lynx/", 5)==0 ) return 1;
409 if( memcmp(zAgent, "NetSurf/", 8)==0 ) return 1;
410 return 0;
411 }
412
413 /*
414 ** COMMAND: test-ishuman
@@ -565,11 +566,11 @@
566 style_header("Login/Logout");
567 @ %s(zErrMsg)
568 if( zGoto && P("anon")==0 ){
569 @ <p>A login is required for <a href="%h(zGoto)">%h(zGoto)</a>.</p>
570 }
571 form_begin(0, "%R/login");
572 if( zGoto ){
573 @ <input type="hidden" name="g" value="%h(zGoto)" />
574 }
575 @ <table class="login_out">
576 @ <tr>
@@ -631,11 +632,11 @@
632
633 @ <p><input type="hidden" name="cs" value="%u(uSeed)" />
634 @ Visitors may enter <b>anonymous</b> as the user-ID with
635 @ the 8-character hexadecimal password shown below:</p>
636 @ <div class="captcha"><table class="captcha"><tr><td><pre>
637 @ %h(zCaptcha)
638 @ </pre></td></tr></table>
639 if( bAutoCaptcha ) {
640 @ <input type="button" value="Fill out captcha"
641 @ onclick="gebi('u').value='anonymous'; gebi('p').value='%s(zDecoded)';" />
642 }
@@ -652,11 +653,11 @@
653 if( g.perm.Password ){
654 @ <hr />
655 @ <p>To change your password, enter your old password and your
656 @ new password twice below then press the "Change Password"
657 @ button.</p>
658 form_begin(0, "%R/login");
659 @ <table>
660 @ <tr><td class="login_out_label">Old Password:</td>
661 @ <td><input type="password" name="p" size="30" /></td></tr>
662 @ <tr><td class="login_out_label">New Password:</td>
663 @ <td><input type="password" name="n1" size="30" /></td></tr>
@@ -1260,11 +1261,11 @@
1261 uSeed = captcha_seed();
1262 zDecoded = captcha_decode(uSeed);
1263 zCaptcha = captcha_render(zDecoded);
1264
1265 /* Print out the registration form. */
1266 form_begin(0, "%R/register");
1267 if( P("g") ){
1268 @ <input type="hidden" name="g" value="%h(P("g"))" />
1269 }
1270 @ <p><input type="hidden" name="cs" value="%u(uSeed)" />
1271 @ <table class="login_out">
@@ -1290,11 +1291,11 @@
1291 @ </tr>
1292 @ <tr><td></td>
1293 @ <td><input type="submit" name="new" value="Register" /></td></tr>
1294 @ </table>
1295 @ <div class="captcha"><table class="captcha"><tr><td><pre>
1296 @ %h(zCaptcha)
1297 @ </pre></td></tr></table>
1298 @ </form>
1299 style_footer();
1300
1301 free(zCaptcha);
1302
+4 -1
--- src/main.c
+++ src/main.c
@@ -119,10 +119,11 @@
119119
int configOpen; /* True if the config database is open */
120120
sqlite3_int64 now; /* Seconds since 1970 */
121121
int repositoryOpen; /* True if the main repository database is open */
122122
char *zRepositoryName; /* Name of the repository database */
123123
const char *zMainDbType;/* "configdb", "localdb", or "repository" */
124
+ const char *zConfigDbType; /* "configdb", "localdb", or "repository" */
124125
const char *zHome; /* Name of user home directory */
125126
int localOpen; /* True if the local database is open */
126127
char *zLocalRoot; /* The directory holding the local database */
127128
int minPrefix; /* Number of digits needed for a distinct UUID */
128129
int fSqlTrace; /* True if --sqltrace flag is present */
@@ -130,11 +131,11 @@
130131
int fSqlPrint; /* True if -sqlprint flag is present */
131132
int fQuiet; /* True if -quiet flag is present */
132133
int fHttpTrace; /* Trace outbound HTTP requests */
133134
int fSystemTrace; /* Trace calls to fossil_system(), --systemtrace */
134135
int fSshTrace; /* Trace the SSH setup traffic */
135
- int fNoSync; /* Do not do an autosync even. --nosync */
136
+ int fNoSync; /* Do not do an autosync ever. --nosync */
136137
char *zPath; /* Name of webpage being served */
137138
char *zExtra; /* Extra path information past the webpage name */
138139
char *zBaseURL; /* Full text of the URL being served */
139140
char *zTop; /* Parent directory of zPath */
140141
const char *zContentType; /* The content type of the input HTTP request */
@@ -144,17 +145,19 @@
144145
Blob cgiIn; /* Input to an xfer www method */
145146
int cgiOutput; /* Write error and status messages to CGI */
146147
int xferPanic; /* Write error messages in XFER protocol */
147148
int fullHttpReply; /* True for full HTTP reply. False for CGI reply */
148149
Th_Interp *interp; /* The TH1 interpreter */
150
+ char *th1Setup; /* The TH1 post-creation setup script, if any */
149151
FILE *httpIn; /* Accept HTTP input from here */
150152
FILE *httpOut; /* Send HTTP output here */
151153
int xlinkClusterOnly; /* Set when cloning. Only process clusters */
152154
int fTimeFormat; /* 1 for UTC. 2 for localtime. 0 not yet selected */
153155
int *aCommitFile; /* Array of files to be committed */
154156
int markPrivate; /* All new artifacts are private if true */
155157
int clockSkewSeen; /* True if clocks on client and server out of sync */
158
+ int wikiFlags; /* Wiki conversion flags applied to %w and %W */
156159
char isHTTP; /* True if server/CGI modes, else assume CLI. */
157160
char javascriptHyperlink; /* If true, set href= using script, not HTML */
158161
159162
int urlIsFile; /* True if a "file:" url */
160163
int urlIsHttps; /* True if a "https:" url */
161164
--- src/main.c
+++ src/main.c
@@ -119,10 +119,11 @@
119 int configOpen; /* True if the config database is open */
120 sqlite3_int64 now; /* Seconds since 1970 */
121 int repositoryOpen; /* True if the main repository database is open */
122 char *zRepositoryName; /* Name of the repository database */
123 const char *zMainDbType;/* "configdb", "localdb", or "repository" */
 
124 const char *zHome; /* Name of user home directory */
125 int localOpen; /* True if the local database is open */
126 char *zLocalRoot; /* The directory holding the local database */
127 int minPrefix; /* Number of digits needed for a distinct UUID */
128 int fSqlTrace; /* True if --sqltrace flag is present */
@@ -130,11 +131,11 @@
130 int fSqlPrint; /* True if -sqlprint flag is present */
131 int fQuiet; /* True if -quiet flag is present */
132 int fHttpTrace; /* Trace outbound HTTP requests */
133 int fSystemTrace; /* Trace calls to fossil_system(), --systemtrace */
134 int fSshTrace; /* Trace the SSH setup traffic */
135 int fNoSync; /* Do not do an autosync even. --nosync */
136 char *zPath; /* Name of webpage being served */
137 char *zExtra; /* Extra path information past the webpage name */
138 char *zBaseURL; /* Full text of the URL being served */
139 char *zTop; /* Parent directory of zPath */
140 const char *zContentType; /* The content type of the input HTTP request */
@@ -144,17 +145,19 @@
144 Blob cgiIn; /* Input to an xfer www method */
145 int cgiOutput; /* Write error and status messages to CGI */
146 int xferPanic; /* Write error messages in XFER protocol */
147 int fullHttpReply; /* True for full HTTP reply. False for CGI reply */
148 Th_Interp *interp; /* The TH1 interpreter */
 
149 FILE *httpIn; /* Accept HTTP input from here */
150 FILE *httpOut; /* Send HTTP output here */
151 int xlinkClusterOnly; /* Set when cloning. Only process clusters */
152 int fTimeFormat; /* 1 for UTC. 2 for localtime. 0 not yet selected */
153 int *aCommitFile; /* Array of files to be committed */
154 int markPrivate; /* All new artifacts are private if true */
155 int clockSkewSeen; /* True if clocks on client and server out of sync */
 
156 char isHTTP; /* True if server/CGI modes, else assume CLI. */
157 char javascriptHyperlink; /* If true, set href= using script, not HTML */
158
159 int urlIsFile; /* True if a "file:" url */
160 int urlIsHttps; /* True if a "https:" url */
161
--- src/main.c
+++ src/main.c
@@ -119,10 +119,11 @@
119 int configOpen; /* True if the config database is open */
120 sqlite3_int64 now; /* Seconds since 1970 */
121 int repositoryOpen; /* True if the main repository database is open */
122 char *zRepositoryName; /* Name of the repository database */
123 const char *zMainDbType;/* "configdb", "localdb", or "repository" */
124 const char *zConfigDbType; /* "configdb", "localdb", or "repository" */
125 const char *zHome; /* Name of user home directory */
126 int localOpen; /* True if the local database is open */
127 char *zLocalRoot; /* The directory holding the local database */
128 int minPrefix; /* Number of digits needed for a distinct UUID */
129 int fSqlTrace; /* True if --sqltrace flag is present */
@@ -130,11 +131,11 @@
131 int fSqlPrint; /* True if -sqlprint flag is present */
132 int fQuiet; /* True if -quiet flag is present */
133 int fHttpTrace; /* Trace outbound HTTP requests */
134 int fSystemTrace; /* Trace calls to fossil_system(), --systemtrace */
135 int fSshTrace; /* Trace the SSH setup traffic */
136 int fNoSync; /* Do not do an autosync ever. --nosync */
137 char *zPath; /* Name of webpage being served */
138 char *zExtra; /* Extra path information past the webpage name */
139 char *zBaseURL; /* Full text of the URL being served */
140 char *zTop; /* Parent directory of zPath */
141 const char *zContentType; /* The content type of the input HTTP request */
@@ -144,17 +145,19 @@
145 Blob cgiIn; /* Input to an xfer www method */
146 int cgiOutput; /* Write error and status messages to CGI */
147 int xferPanic; /* Write error messages in XFER protocol */
148 int fullHttpReply; /* True for full HTTP reply. False for CGI reply */
149 Th_Interp *interp; /* The TH1 interpreter */
150 char *th1Setup; /* The TH1 post-creation setup script, if any */
151 FILE *httpIn; /* Accept HTTP input from here */
152 FILE *httpOut; /* Send HTTP output here */
153 int xlinkClusterOnly; /* Set when cloning. Only process clusters */
154 int fTimeFormat; /* 1 for UTC. 2 for localtime. 0 not yet selected */
155 int *aCommitFile; /* Array of files to be committed */
156 int markPrivate; /* All new artifacts are private if true */
157 int clockSkewSeen; /* True if clocks on client and server out of sync */
158 int wikiFlags; /* Wiki conversion flags applied to %w and %W */
159 char isHTTP; /* True if server/CGI modes, else assume CLI. */
160 char javascriptHyperlink; /* If true, set href= using script, not HTML */
161
162 int urlIsFile; /* True if a "file:" url */
163 int urlIsHttps; /* True if a "https:" url */
164
--- src/makemake.tcl
+++ src/makemake.tcl
@@ -364,10 +364,14 @@
364364
# will run on the platform that is doing the build. This is used
365365
# to compile code-generator programs as part of the build process.
366366
# See TCC below for the C compiler for building the finished binary.
367367
#
368368
BCC = gcc
369
+
370
+#### Enable compiling with debug symbols (much larger binary)
371
+#
372
+# FOSSIL_ENABLE_SYMBOLS = 1
369373
370374
#### Enable JSON (http://www.json.org) support using "cson"
371375
#
372376
# FOSSIL_ENABLE_JSON = 1
373377
@@ -442,10 +446,17 @@
442446
# as BCC, unless you are cross-compiling. This C compiler builds
443447
# the finished binary for fossil. The BCC compiler above is used
444448
# for building intermediate code-generator tools.
445449
#
446450
TCC = $(PREFIX)gcc -Os -Wall -L$(ZLIBDIR) -I$(ZINCDIR)
451
+
452
+#### Add the necessary command line options to build with debugging
453
+# symbols, if enabled.
454
+#
455
+ifdef FOSSIL_ENABLE_SYMBOLS
456
+TCC += -g
457
+endif
447458
448459
#### Compile resources for use in building executables that will run
449460
# on the target platform.
450461
#
451462
RCC = $(PREFIX)windres -I$(SRCDIR) -I$(ZINCDIR)
452463
--- src/makemake.tcl
+++ src/makemake.tcl
@@ -364,10 +364,14 @@
364 # will run on the platform that is doing the build. This is used
365 # to compile code-generator programs as part of the build process.
366 # See TCC below for the C compiler for building the finished binary.
367 #
368 BCC = gcc
 
 
 
 
369
370 #### Enable JSON (http://www.json.org) support using "cson"
371 #
372 # FOSSIL_ENABLE_JSON = 1
373
@@ -442,10 +446,17 @@
442 # as BCC, unless you are cross-compiling. This C compiler builds
443 # the finished binary for fossil. The BCC compiler above is used
444 # for building intermediate code-generator tools.
445 #
446 TCC = $(PREFIX)gcc -Os -Wall -L$(ZLIBDIR) -I$(ZINCDIR)
 
 
 
 
 
 
 
447
448 #### Compile resources for use in building executables that will run
449 # on the target platform.
450 #
451 RCC = $(PREFIX)windres -I$(SRCDIR) -I$(ZINCDIR)
452
--- src/makemake.tcl
+++ src/makemake.tcl
@@ -364,10 +364,14 @@
364 # will run on the platform that is doing the build. This is used
365 # to compile code-generator programs as part of the build process.
366 # See TCC below for the C compiler for building the finished binary.
367 #
368 BCC = gcc
369
370 #### Enable compiling with debug symbols (much larger binary)
371 #
372 # FOSSIL_ENABLE_SYMBOLS = 1
373
374 #### Enable JSON (http://www.json.org) support using "cson"
375 #
376 # FOSSIL_ENABLE_JSON = 1
377
@@ -442,10 +446,17 @@
446 # as BCC, unless you are cross-compiling. This C compiler builds
447 # the finished binary for fossil. The BCC compiler above is used
448 # for building intermediate code-generator tools.
449 #
450 TCC = $(PREFIX)gcc -Os -Wall -L$(ZLIBDIR) -I$(ZINCDIR)
451
452 #### Add the necessary command line options to build with debugging
453 # symbols, if enabled.
454 #
455 ifdef FOSSIL_ENABLE_SYMBOLS
456 TCC += -g
457 endif
458
459 #### Compile resources for use in building executables that will run
460 # on the target platform.
461 #
462 RCC = $(PREFIX)windres -I$(SRCDIR) -I$(ZINCDIR)
463
+1 -1
--- src/manifest.c
+++ src/manifest.c
@@ -833,11 +833,11 @@
833833
default: {
834834
SYNTAX("unrecognized card");
835835
}
836836
}
837837
}
838
- if( x.z<x.zEnd ) SYNTAX("card in the wrong order");
838
+ if( x.z<x.zEnd ) SYNTAX("extra characters at end of card");
839839
840840
if( p->nFile>0 || p->zRepoCksum!=0 || p->zBaseline ){
841841
if( p->nCChild>0 ) SYNTAX("M-card in check-in");
842842
if( p->rDate<=0.0 ) SYNTAX("missing date for check-in");
843843
if( p->nField>0 ) SYNTAX("J-card in check-in");
844844
--- src/manifest.c
+++ src/manifest.c
@@ -833,11 +833,11 @@
833 default: {
834 SYNTAX("unrecognized card");
835 }
836 }
837 }
838 if( x.z<x.zEnd ) SYNTAX("card in the wrong order");
839
840 if( p->nFile>0 || p->zRepoCksum!=0 || p->zBaseline ){
841 if( p->nCChild>0 ) SYNTAX("M-card in check-in");
842 if( p->rDate<=0.0 ) SYNTAX("missing date for check-in");
843 if( p->nField>0 ) SYNTAX("J-card in check-in");
844
--- src/manifest.c
+++ src/manifest.c
@@ -833,11 +833,11 @@
833 default: {
834 SYNTAX("unrecognized card");
835 }
836 }
837 }
838 if( x.z<x.zEnd ) SYNTAX("extra characters at end of card");
839
840 if( p->nFile>0 || p->zRepoCksum!=0 || p->zBaseline ){
841 if( p->nCChild>0 ) SYNTAX("M-card in check-in");
842 if( p->rDate<=0.0 ) SYNTAX("missing date for check-in");
843 if( p->nField>0 ) SYNTAX("J-card in check-in");
844
+23 -10
--- src/printf.c
+++ src/printf.c
@@ -44,12 +44,11 @@
4444
#define etHTMLIZE 16 /* Make text safe for HTML */
4545
#define etHTTPIZE 17 /* Make text safe for HTTP. "/" encoded as %2f */
4646
#define etURLIZE 18 /* Make text safe for HTTP. "/" not encoded */
4747
#define etFOSSILIZE 19 /* The fossil header encoding format. */
4848
#define etPATH 20 /* Path type */
49
-#define etWIKISTR 21 /* Wiki text rendered from a char*: %w */
50
-#define etWIKIBLOB 22 /* Wiki text rendered from a Blob*: %W */
49
+#define etWIKISTR 21 /* Timeline comment text rendered from a char*: %w */
5150
#define etSTRINGID 23 /* String with length limit for a UUID prefix: %S */
5251
#define etROOT 24 /* String value of g.zTop: % */
5352
5453
5554
/*
@@ -92,11 +91,10 @@
9291
{ 'q', 0, 4, etSQLESCAPE, 0, 0 },
9392
{ 'Q', 0, 4, etSQLESCAPE2, 0, 0 },
9493
{ 'b', 0, 2, etBLOB, 0, 0 },
9594
{ 'B', 0, 2, etBLOBSQL, 0, 0 },
9695
{ 'w', 0, 2, etWIKISTR, 0, 0 },
97
- { 'W', 0, 2, etWIKIBLOB, 0, 0 },
9896
{ 'h', 0, 4, etHTMLIZE, 0, 0 },
9997
{ 'R', 0, 0, etROOT, 0, 0 },
10098
{ 't', 0, 4, etHTTPIZE, 0, 0 }, /* "/" -> "%2F" */
10199
{ 'T', 0, 4, etURLIZE, 0, 0 }, /* "/" unchanged */
102100
{ 'F', 0, 4, etFOSSILIZE, 0, 0 },
@@ -156,10 +154,31 @@
156154
static int StrNLen32(const char *z, int N){
157155
int n = 0;
158156
while( (N-- != 0) && *(z++)!=0 ){ n++; }
159157
return n;
160158
}
159
+
160
+/*
161
+** Return an appropriate set of flags for wiki_convert() for displaying
162
+** comments on a timeline. These flag settings are determined by
163
+** configuration parameters.
164
+*/
165
+static int wiki_convert_flags(void){
166
+ static int wikiFlags = 0;
167
+ if( wikiFlags==0 ){
168
+ if( db_get_boolean("timeline-block-markup", 0) ){
169
+ wikiFlags = WIKI_INLINE | WIKI_NOBADLINKS;
170
+ }else{
171
+ wikiFlags = WIKI_INLINE | WIKI_NOBLOCK | WIKI_NOBADLINKS;
172
+ }
173
+ if( db_get_boolean("timeline-plaintext", 0) ){
174
+ wikiFlags |= WIKI_LINKSONLY;
175
+ }
176
+ }
177
+ return wikiFlags;
178
+}
179
+
161180
162181
163182
/*
164183
** The root program. All variations call this core.
165184
**
@@ -698,21 +717,15 @@
698717
case etWIKISTR: {
699718
int limit = flag_alternateform ? va_arg(ap,int) : -1;
700719
char *zWiki = va_arg(ap, char*);
701720
Blob wiki;
702721
blob_init(&wiki, zWiki, limit);
703
- wiki_convert(&wiki, pBlob, WIKI_INLINE);
722
+ wiki_convert(&wiki, pBlob, wiki_convert_flags());
704723
blob_reset(&wiki);
705724
length = width = 0;
706725
break;
707726
}
708
- case etWIKIBLOB: {
709
- Blob *pWiki = va_arg(ap, Blob*);
710
- wiki_convert(pWiki, pBlob, WIKI_INLINE);
711
- length = width = 0;
712
- break;
713
- }
714727
case etERROR:
715728
buf[0] = '%';
716729
buf[1] = c;
717730
errorflag = 0;
718731
idx = 1+(c!=0);
719732
--- src/printf.c
+++ src/printf.c
@@ -44,12 +44,11 @@
44 #define etHTMLIZE 16 /* Make text safe for HTML */
45 #define etHTTPIZE 17 /* Make text safe for HTTP. "/" encoded as %2f */
46 #define etURLIZE 18 /* Make text safe for HTTP. "/" not encoded */
47 #define etFOSSILIZE 19 /* The fossil header encoding format. */
48 #define etPATH 20 /* Path type */
49 #define etWIKISTR 21 /* Wiki text rendered from a char*: %w */
50 #define etWIKIBLOB 22 /* Wiki text rendered from a Blob*: %W */
51 #define etSTRINGID 23 /* String with length limit for a UUID prefix: %S */
52 #define etROOT 24 /* String value of g.zTop: % */
53
54
55 /*
@@ -92,11 +91,10 @@
92 { 'q', 0, 4, etSQLESCAPE, 0, 0 },
93 { 'Q', 0, 4, etSQLESCAPE2, 0, 0 },
94 { 'b', 0, 2, etBLOB, 0, 0 },
95 { 'B', 0, 2, etBLOBSQL, 0, 0 },
96 { 'w', 0, 2, etWIKISTR, 0, 0 },
97 { 'W', 0, 2, etWIKIBLOB, 0, 0 },
98 { 'h', 0, 4, etHTMLIZE, 0, 0 },
99 { 'R', 0, 0, etROOT, 0, 0 },
100 { 't', 0, 4, etHTTPIZE, 0, 0 }, /* "/" -> "%2F" */
101 { 'T', 0, 4, etURLIZE, 0, 0 }, /* "/" unchanged */
102 { 'F', 0, 4, etFOSSILIZE, 0, 0 },
@@ -156,10 +154,31 @@
156 static int StrNLen32(const char *z, int N){
157 int n = 0;
158 while( (N-- != 0) && *(z++)!=0 ){ n++; }
159 return n;
160 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
161
162
163 /*
164 ** The root program. All variations call this core.
165 **
@@ -698,21 +717,15 @@
698 case etWIKISTR: {
699 int limit = flag_alternateform ? va_arg(ap,int) : -1;
700 char *zWiki = va_arg(ap, char*);
701 Blob wiki;
702 blob_init(&wiki, zWiki, limit);
703 wiki_convert(&wiki, pBlob, WIKI_INLINE);
704 blob_reset(&wiki);
705 length = width = 0;
706 break;
707 }
708 case etWIKIBLOB: {
709 Blob *pWiki = va_arg(ap, Blob*);
710 wiki_convert(pWiki, pBlob, WIKI_INLINE);
711 length = width = 0;
712 break;
713 }
714 case etERROR:
715 buf[0] = '%';
716 buf[1] = c;
717 errorflag = 0;
718 idx = 1+(c!=0);
719
--- src/printf.c
+++ src/printf.c
@@ -44,12 +44,11 @@
44 #define etHTMLIZE 16 /* Make text safe for HTML */
45 #define etHTTPIZE 17 /* Make text safe for HTTP. "/" encoded as %2f */
46 #define etURLIZE 18 /* Make text safe for HTTP. "/" not encoded */
47 #define etFOSSILIZE 19 /* The fossil header encoding format. */
48 #define etPATH 20 /* Path type */
49 #define etWIKISTR 21 /* Timeline comment text rendered from a char*: %w */
 
50 #define etSTRINGID 23 /* String with length limit for a UUID prefix: %S */
51 #define etROOT 24 /* String value of g.zTop: % */
52
53
54 /*
@@ -92,11 +91,10 @@
91 { 'q', 0, 4, etSQLESCAPE, 0, 0 },
92 { 'Q', 0, 4, etSQLESCAPE2, 0, 0 },
93 { 'b', 0, 2, etBLOB, 0, 0 },
94 { 'B', 0, 2, etBLOBSQL, 0, 0 },
95 { 'w', 0, 2, etWIKISTR, 0, 0 },
 
96 { 'h', 0, 4, etHTMLIZE, 0, 0 },
97 { 'R', 0, 0, etROOT, 0, 0 },
98 { 't', 0, 4, etHTTPIZE, 0, 0 }, /* "/" -> "%2F" */
99 { 'T', 0, 4, etURLIZE, 0, 0 }, /* "/" unchanged */
100 { 'F', 0, 4, etFOSSILIZE, 0, 0 },
@@ -156,10 +154,31 @@
154 static int StrNLen32(const char *z, int N){
155 int n = 0;
156 while( (N-- != 0) && *(z++)!=0 ){ n++; }
157 return n;
158 }
159
160 /*
161 ** Return an appropriate set of flags for wiki_convert() for displaying
162 ** comments on a timeline. These flag settings are determined by
163 ** configuration parameters.
164 */
165 static int wiki_convert_flags(void){
166 static int wikiFlags = 0;
167 if( wikiFlags==0 ){
168 if( db_get_boolean("timeline-block-markup", 0) ){
169 wikiFlags = WIKI_INLINE | WIKI_NOBADLINKS;
170 }else{
171 wikiFlags = WIKI_INLINE | WIKI_NOBLOCK | WIKI_NOBADLINKS;
172 }
173 if( db_get_boolean("timeline-plaintext", 0) ){
174 wikiFlags |= WIKI_LINKSONLY;
175 }
176 }
177 return wikiFlags;
178 }
179
180
181
182 /*
183 ** The root program. All variations call this core.
184 **
@@ -698,21 +717,15 @@
717 case etWIKISTR: {
718 int limit = flag_alternateform ? va_arg(ap,int) : -1;
719 char *zWiki = va_arg(ap, char*);
720 Blob wiki;
721 blob_init(&wiki, zWiki, limit);
722 wiki_convert(&wiki, pBlob, wiki_convert_flags());
723 blob_reset(&wiki);
724 length = width = 0;
725 break;
726 }
 
 
 
 
 
 
727 case etERROR:
728 buf[0] = '%';
729 buf[1] = c;
730 errorflag = 0;
731 idx = 1+(c!=0);
732
+1 -1
--- src/report.c
+++ src/report.c
@@ -730,11 +730,11 @@
730730
}
731731
if( zData[0] ){
732732
Blob content;
733733
@ </tr><tr style="background-color:%h(zBg)"><td colspan=%d(pState->nCol)>
734734
blob_init(&content, zData, -1);
735
- wiki_convert(&content, 0, 0);
735
+ wiki_convert(&content, 0, WIKI_NOBADLINKS);
736736
blob_reset(&content);
737737
}
738738
}else if( azName[i][0]=='#' ){
739739
zTid = zData;
740740
@ <td valign="top">%z(href("%R/tktview?name=%h",zData))%h(zData)</a></td>
741741
--- src/report.c
+++ src/report.c
@@ -730,11 +730,11 @@
730 }
731 if( zData[0] ){
732 Blob content;
733 @ </tr><tr style="background-color:%h(zBg)"><td colspan=%d(pState->nCol)>
734 blob_init(&content, zData, -1);
735 wiki_convert(&content, 0, 0);
736 blob_reset(&content);
737 }
738 }else if( azName[i][0]=='#' ){
739 zTid = zData;
740 @ <td valign="top">%z(href("%R/tktview?name=%h",zData))%h(zData)</a></td>
741
--- src/report.c
+++ src/report.c
@@ -730,11 +730,11 @@
730 }
731 if( zData[0] ){
732 Blob content;
733 @ </tr><tr style="background-color:%h(zBg)"><td colspan=%d(pState->nCol)>
734 blob_init(&content, zData, -1);
735 wiki_convert(&content, 0, WIKI_NOBADLINKS);
736 blob_reset(&content);
737 }
738 }else if( azName[i][0]=='#' ){
739 zTid = zData;
740 @ <td valign="top">%z(href("%R/tktview?name=%h",zData))%h(zData)</a></td>
741
+11 -5
--- src/setup.c
+++ src/setup.c
@@ -934,10 +934,17 @@
934934
@ if it does, your server will end up computing diffs and annotations for
935935
@ every historical version of every file and creating ZIPs and tarballs of
936936
@ every historical check-in, which can use a lot of CPU and bandwidth
937937
@ even for relatively small projects.</p>
938938
939
+ @ <hr />
940
+ onoff_attribute("Require a CAPTCHA if not logged in",
941
+ "require-captcha", "reqcapt", 1);
942
+ @ <p>Require a CAPTCHA for edit operations (appending, creating, or
943
+ @ editing wiki or tickets or adding attachments to wiki or tickets)
944
+ @ for users who are not logged in.</p>
945
+
939946
@ <hr />
940947
entry_attribute("Public pages", 30, "public-pages",
941948
"pubpage", "");
942949
@ <p>A comma-separated list of glob patterns for pages that are accessible
943950
@ without needing a login and using the privileges given by the
@@ -944,11 +951,10 @@
944951
@ "Default privileges" setting below. Example use case: Set this field
945952
@ to "/doc/trunk/www/*" to give anonymous users read-only permission to the
946953
@ latest version of the embedded documentation in the www/ folder without
947954
@ allowing them to see the rest of the source code.
948955
@ </p>
949
-
950956
951957
@ <hr />
952958
onoff_attribute("Allow users to register themselves",
953959
"self-register", "selfregister", 0);
954960
@ <p>Allow users to register themselves through the HTTP UI.
@@ -1018,21 +1024,21 @@
10181024
@ is not currently part of any login-group.
10191025
@ To join a login group, fill out the form below.</p>
10201026
@
10211027
@ <form action="%s(g.zTop)/setup_login_group" method="post"><div>
10221028
login_insert_csrf_secret();
1023
- @ <blockquote><table broder="0">
1029
+ @ <blockquote><table border="0">
10241030
@
10251031
@ <tr><td align="right"><b>Repository filename in group to join:</b></td>
10261032
@ <td width="5"></td><td>
10271033
@ <input type="text" size="50" value="%h(zRepo)" name="repo"></td></tr>
10281034
@
1029
- @ <td align="right"><b>Login on the above repo:</b></td>
1035
+ @ <tr><td align="right"><b>Login on the above repo:</b></td>
10301036
@ <td width="5"></td><td>
10311037
@ <input type="text" size="20" value="%h(zLogin)" name="login"></td></tr>
10321038
@
1033
- @ <td align="right"><b>Password:</b></td>
1039
+ @ <tr><td align="right"><b>Password:</b></td>
10341040
@ <td width="5"></td><td>
10351041
@ <input type="password" size="20" name="pw"></td></tr>
10361042
@
10371043
@ <tr><td align="right"><b>Name of login-group:</b></td>
10381044
@ <td width="5"></td><td>
@@ -1039,11 +1045,11 @@
10391045
@ <input type="text" size="30" value="%h(zNewName)" name="newname">
10401046
@ (only used if creating a new login-group).</td></tr>
10411047
@
10421048
@ <tr><td colspan="3" align="center">
10431049
@ <input type="submit" value="Join" name="join"></td></tr>
1044
- @ </table>
1050
+ @ </table></blockquote></div></form>
10451051
}else{
10461052
Stmt q;
10471053
int n = 0;
10481054
@ <p>This repository (in the file "%h(zSelfRepo)")
10491055
@ is currently part of the "<b>%h(zGroup)</b>" login group.
10501056
--- src/setup.c
+++ src/setup.c
@@ -934,10 +934,17 @@
934 @ if it does, your server will end up computing diffs and annotations for
935 @ every historical version of every file and creating ZIPs and tarballs of
936 @ every historical check-in, which can use a lot of CPU and bandwidth
937 @ even for relatively small projects.</p>
938
 
 
 
 
 
 
 
939 @ <hr />
940 entry_attribute("Public pages", 30, "public-pages",
941 "pubpage", "");
942 @ <p>A comma-separated list of glob patterns for pages that are accessible
943 @ without needing a login and using the privileges given by the
@@ -944,11 +951,10 @@
944 @ "Default privileges" setting below. Example use case: Set this field
945 @ to "/doc/trunk/www/*" to give anonymous users read-only permission to the
946 @ latest version of the embedded documentation in the www/ folder without
947 @ allowing them to see the rest of the source code.
948 @ </p>
949
950
951 @ <hr />
952 onoff_attribute("Allow users to register themselves",
953 "self-register", "selfregister", 0);
954 @ <p>Allow users to register themselves through the HTTP UI.
@@ -1018,21 +1024,21 @@
1018 @ is not currently part of any login-group.
1019 @ To join a login group, fill out the form below.</p>
1020 @
1021 @ <form action="%s(g.zTop)/setup_login_group" method="post"><div>
1022 login_insert_csrf_secret();
1023 @ <blockquote><table broder="0">
1024 @
1025 @ <tr><td align="right"><b>Repository filename in group to join:</b></td>
1026 @ <td width="5"></td><td>
1027 @ <input type="text" size="50" value="%h(zRepo)" name="repo"></td></tr>
1028 @
1029 @ <td align="right"><b>Login on the above repo:</b></td>
1030 @ <td width="5"></td><td>
1031 @ <input type="text" size="20" value="%h(zLogin)" name="login"></td></tr>
1032 @
1033 @ <td align="right"><b>Password:</b></td>
1034 @ <td width="5"></td><td>
1035 @ <input type="password" size="20" name="pw"></td></tr>
1036 @
1037 @ <tr><td align="right"><b>Name of login-group:</b></td>
1038 @ <td width="5"></td><td>
@@ -1039,11 +1045,11 @@
1039 @ <input type="text" size="30" value="%h(zNewName)" name="newname">
1040 @ (only used if creating a new login-group).</td></tr>
1041 @
1042 @ <tr><td colspan="3" align="center">
1043 @ <input type="submit" value="Join" name="join"></td></tr>
1044 @ </table>
1045 }else{
1046 Stmt q;
1047 int n = 0;
1048 @ <p>This repository (in the file "%h(zSelfRepo)")
1049 @ is currently part of the "<b>%h(zGroup)</b>" login group.
1050
--- src/setup.c
+++ src/setup.c
@@ -934,10 +934,17 @@
934 @ if it does, your server will end up computing diffs and annotations for
935 @ every historical version of every file and creating ZIPs and tarballs of
936 @ every historical check-in, which can use a lot of CPU and bandwidth
937 @ even for relatively small projects.</p>
938
939 @ <hr />
940 onoff_attribute("Require a CAPTCHA if not logged in",
941 "require-captcha", "reqcapt", 1);
942 @ <p>Require a CAPTCHA for edit operations (appending, creating, or
943 @ editing wiki or tickets or adding attachments to wiki or tickets)
944 @ for users who are not logged in.</p>
945
946 @ <hr />
947 entry_attribute("Public pages", 30, "public-pages",
948 "pubpage", "");
949 @ <p>A comma-separated list of glob patterns for pages that are accessible
950 @ without needing a login and using the privileges given by the
@@ -944,11 +951,10 @@
951 @ "Default privileges" setting below. Example use case: Set this field
952 @ to "/doc/trunk/www/*" to give anonymous users read-only permission to the
953 @ latest version of the embedded documentation in the www/ folder without
954 @ allowing them to see the rest of the source code.
955 @ </p>
 
956
957 @ <hr />
958 onoff_attribute("Allow users to register themselves",
959 "self-register", "selfregister", 0);
960 @ <p>Allow users to register themselves through the HTTP UI.
@@ -1018,21 +1024,21 @@
1024 @ is not currently part of any login-group.
1025 @ To join a login group, fill out the form below.</p>
1026 @
1027 @ <form action="%s(g.zTop)/setup_login_group" method="post"><div>
1028 login_insert_csrf_secret();
1029 @ <blockquote><table border="0">
1030 @
1031 @ <tr><td align="right"><b>Repository filename in group to join:</b></td>
1032 @ <td width="5"></td><td>
1033 @ <input type="text" size="50" value="%h(zRepo)" name="repo"></td></tr>
1034 @
1035 @ <tr><td align="right"><b>Login on the above repo:</b></td>
1036 @ <td width="5"></td><td>
1037 @ <input type="text" size="20" value="%h(zLogin)" name="login"></td></tr>
1038 @
1039 @ <tr><td align="right"><b>Password:</b></td>
1040 @ <td width="5"></td><td>
1041 @ <input type="password" size="20" name="pw"></td></tr>
1042 @
1043 @ <tr><td align="right"><b>Name of login-group:</b></td>
1044 @ <td width="5"></td><td>
@@ -1039,11 +1045,11 @@
1045 @ <input type="text" size="30" value="%h(zNewName)" name="newname">
1046 @ (only used if creating a new login-group).</td></tr>
1047 @
1048 @ <tr><td colspan="3" align="center">
1049 @ <input type="submit" value="Join" name="join"></td></tr>
1050 @ </table></blockquote></div></form>
1051 }else{
1052 Stmt q;
1053 int n = 0;
1054 @ <p>This repository (in the file "%h(zSelfRepo)")
1055 @ is currently part of the "<b>%h(zGroup)</b>" login group.
1056
+75 -75
--- src/skins.c
+++ src/skins.c
@@ -24,20 +24,20 @@
2424
/* @-comment: ## */
2525
/*
2626
** A black-and-white theme with the project title in a bar across the top
2727
** and no logo image.
2828
*/
29
-static const char zBuiltinSkin1[] =
29
+static const char zBuiltinSkin1[] =
3030
@ REPLACE INTO config(name,mtime,value)
3131
@ VALUES('css',now(),'/* General settings for the entire page */
3232
@ body {
3333
@ margin: 0ex 1ex;
3434
@ padding: 0px;
3535
@ background-color: white;
3636
@ font-family: sans-serif;
3737
@ }
38
-@
38
+@
3939
@ /* The project logo in the upper left-hand corner of each page */
4040
@ div.logo {
4141
@ display: table-row;
4242
@ text-align: center;
4343
@ /* vertical-align: bottom;*/
@@ -46,11 +46,11 @@
4646
@ background-color: #707070;
4747
@ color: #ffffff;
4848
@ min-width: 200px;
4949
@ white-space: nowrap;
5050
@ }
51
-@
51
+@
5252
@ /* The page title centered at the top of each page */
5353
@ div.title {
5454
@ display: table-cell;
5555
@ font-size: 1.5em;
5656
@ font-weight: bold;
@@ -58,11 +58,11 @@
5858
@ padding: 0 0 0 10px;
5959
@ color: #404040;
6060
@ vertical-align: bottom;
6161
@ width: 100%;
6262
@ }
63
-@
63
+@
6464
@ /* The login status message in the top right-hand corner */
6565
@ div.status {
6666
@ display: table-cell;
6767
@ text-align: right;
6868
@ vertical-align: bottom;
@@ -70,17 +70,17 @@
7070
@ font-size: 0.8em;
7171
@ font-weight: bold;
7272
@ min-width: 200px;
7373
@ white-space: nowrap;
7474
@ }
75
-@
75
+@
7676
@ /* The header across the top of the page */
7777
@ div.header {
7878
@ display: table;
7979
@ width: 100%;
8080
@ }
81
-@
81
+@
8282
@ /* The main menu bar that appears at the top of the page beneath
8383
@ ** the header */
8484
@ div.mainmenu {
8585
@ padding: 5px 10px 5px 10px;
8686
@ font-size: 0.9em;
@@ -117,11 +117,11 @@
117117
@ }
118118
@ /* Hyperlink colors */
119119
@ div.content a { color: #604000; }
120120
@ div.content a:link { color: #604000;}
121121
@ div.content a:visited { color: #600000; }
122
-@
122
+@
123123
@ /* Some pages have section dividers */
124124
@ div.section {
125125
@ margin-bottom: 0px;
126126
@ margin-top: 1em;
127127
@ padding: 1px 1px 1px 1px;
@@ -129,11 +129,11 @@
129129
@ font-weight: bold;
130130
@ background-color: #404040;
131131
@ color: white;
132132
@ white-space: nowrap;
133133
@ }
134
-@
134
+@
135135
@ /* The "Date" that occurs on the left hand side of timelines */
136136
@ div.divider {
137137
@ background: #a0a0a0;
138138
@ border: 2px #505050 solid;
139139
@ font-size: 1em; font-weight: normal;
@@ -141,21 +141,21 @@
141141
@ margin: .2em 0 .2em 0;
142142
@ float: left;
143143
@ clear: left;
144144
@ white-space: nowrap;
145145
@ }
146
-@
146
+@
147147
@ /* The footer at the very bottom of the page */
148148
@ div.footer {
149149
@ font-size: 0.8em;
150150
@ margin-top: 12px;
151151
@ padding: 5px 10px 5px 10px;
152152
@ text-align: right;
153153
@ background-color: #404040;
154154
@ color: white;
155155
@ }
156
-@
156
+@
157157
@ /* The label/value pairs on (for example) the vinfo page */
158158
@ table.label-value th {
159159
@ vertical-align: top;
160160
@ text-align: right;
161161
@ padding: 0.2ex 2ex;
@@ -211,30 +211,30 @@
211211
@ }
212212
@ </th1></div>
213213
@ ');
214214
@ REPLACE INTO config(name,mtime,value)
215215
@ VALUES('footer',now(),'<div class="footer">
216
-@ Fossil version $manifest_version $manifest_date
216
+@ Fossil version $manifest_version $manifest_date
217217
@ </div>
218218
@ </body></html>
219219
@ ');
220220
;
221221
222222
/*
223223
** A tan theme with the project title above the user identification
224224
** and no logo image.
225225
*/
226
-static const char zBuiltinSkin2[] =
226
+static const char zBuiltinSkin2[] =
227227
@ REPLACE INTO config(name,mtime,value)
228228
@ VALUES('css',now(),'/* General settings for the entire page */
229229
@ body {
230230
@ margin: 0ex 0ex;
231231
@ padding: 0px;
232232
@ background-color: #fef3bc;
233233
@ font-family: sans-serif;
234234
@ }
235
-@
235
+@
236236
@ /* The project logo in the upper left-hand corner of each page */
237237
@ div.logo {
238238
@ display: inline;
239239
@ text-align: center;
240240
@ vertical-align: bottom;
@@ -241,11 +241,11 @@
241241
@ font-weight: bold;
242242
@ font-size: 2.5em;
243243
@ color: #a09048;
244244
@ white-space: nowrap;
245245
@ }
246
-@
246
+@
247247
@ /* The page title centered at the top of each page */
248248
@ div.title {
249249
@ display: table-cell;
250250
@ font-size: 2em;
251251
@ font-weight: bold;
@@ -253,11 +253,11 @@
253253
@ padding: 0 0 0 5px;
254254
@ color: #a09048;
255255
@ vertical-align: bottom;
256256
@ width: 100%;
257257
@ }
258
-@
258
+@
259259
@ /* The login status message in the top right-hand corner */
260260
@ div.status {
261261
@ display: table-cell;
262262
@ text-align: right;
263263
@ vertical-align: bottom;
@@ -265,17 +265,17 @@
265265
@ padding: 5px 5px 0 0;
266266
@ font-size: 0.8em;
267267
@ font-weight: bold;
268268
@ white-space: nowrap;
269269
@ }
270
-@
270
+@
271271
@ /* The header across the top of the page */
272272
@ div.header {
273273
@ display: table;
274274
@ width: 100%;
275275
@ }
276
-@
276
+@
277277
@ /* The main menu bar that appears at the top of the page beneath
278278
@ ** the header */
279279
@ div.mainmenu {
280280
@ padding: 5px 10px 5px 10px;
281281
@ font-size: 0.9em;
@@ -283,11 +283,11 @@
283283
@ text-align: center;
284284
@ letter-spacing: 1px;
285285
@ background-color: #a09048;
286286
@ color: black;
287287
@ }
288
-@
288
+@
289289
@ /* The submenu bar that *sometimes* appears below the main menu */
290290
@ div.submenu, div.sectionmenu {
291291
@ padding: 3px 10px 3px 0px;
292292
@ font-size: 0.9em;
293293
@ text-align: center;
@@ -302,21 +302,21 @@
302302
@ }
303303
@ div.mainmenu a:hover, div.submenu a:hover, div.sectionmenu>a.button:hover {
304304
@ color: #a09048;
305305
@ background-color: white;
306306
@ }
307
-@
307
+@
308308
@ /* All page content from the bottom of the menu or submenu down to
309309
@ ** the footer */
310310
@ div.content {
311311
@ padding: 1ex 5px;
312312
@ }
313313
@ div.content a { color: #706532; }
314314
@ div.content a:link { color: #706532; }
315315
@ div.content a:visited { color: #704032; }
316316
@ div.content a:hover { background-color: white; color: #706532; }
317
-@
317
+@
318318
@ /* Some pages have section dividers */
319319
@ div.section {
320320
@ margin-bottom: 0px;
321321
@ margin-top: 1em;
322322
@ padding: 3px 3px 0 3px;
@@ -324,11 +324,11 @@
324324
@ font-weight: bold;
325325
@ background-color: #a09048;
326326
@ color: white;
327327
@ white-space: nowrap;
328328
@ }
329
-@
329
+@
330330
@ /* The "Date" that occurs on the left hand side of timelines */
331331
@ div.divider {
332332
@ background: #e1d498;
333333
@ border: 2px #a09048 solid;
334334
@ font-size: 1em; font-weight: normal;
@@ -336,33 +336,33 @@
336336
@ margin: .2em 0 .2em 0;
337337
@ float: left;
338338
@ clear: left;
339339
@ white-space: nowrap;
340340
@ }
341
-@
341
+@
342342
@ /* The footer at the very bottom of the page */
343343
@ div.footer {
344344
@ font-size: 0.8em;
345345
@ margin-top: 12px;
346346
@ padding: 5px 10px 5px 10px;
347347
@ text-align: right;
348348
@ background-color: #a09048;
349349
@ color: white;
350350
@ }
351
-@
351
+@
352352
@ /* Hyperlink colors */
353353
@ div.footer a { color: white; }
354354
@ div.footer a:link { color: white; }
355355
@ div.footer a:visited { color: white; }
356356
@ div.footer a:hover { background-color: white; color: #558195; }
357
-@
357
+@
358358
@ /* <verbatim> blocks */
359359
@ pre.verbatim {
360360
@ background-color: #f5f5f5;
361361
@ padding: 0.5em;
362362
@ }
363
-@
363
+@
364364
@ /* The label/value pairs on (for example) the ci page */
365365
@ table.label-value th {
366366
@ vertical-align: top;
367367
@ text-align: right;
368368
@ padding: 0.2ex 2ex;
@@ -430,39 +430,39 @@
430430
431431
/*
432432
** Black letters on a white or cream background with the main menu
433433
** stuck on the left-hand side.
434434
*/
435
-static const char zBuiltinSkin3[] =
435
+static const char zBuiltinSkin3[] =
436436
@ REPLACE INTO config(name,mtime,value)
437437
@ VALUES('css',now(),'/* General settings for the entire page */
438438
@ body {
439439
@ margin:0px 0px 0px 0px;
440440
@ padding:0px;
441441
@ font-family:verdana, arial, helvetica, "sans serif";
442442
@ color:#333;
443443
@ background-color:white;
444444
@ }
445
-@
445
+@
446446
@ /* consistent colours */
447447
@ h2 {
448448
@ color: #333;
449449
@ }
450450
@ h3 {
451451
@ color: #333;
452452
@ }
453
-@
453
+@
454454
@ /* The project logo in the upper left-hand corner of each page */
455455
@ div.logo {
456456
@ display: table-cell;
457457
@ text-align: left;
458458
@ vertical-align: bottom;
459459
@ font-weight: bold;
460460
@ color: #333;
461461
@ white-space: nowrap;
462462
@ }
463
-@
463
+@
464464
@ /* The page title centered at the top of each page */
465465
@ div.title {
466466
@ display: table-cell;
467467
@ font-size: 2em;
468468
@ font-weight: bold;
@@ -469,11 +469,11 @@
469469
@ text-align: center;
470470
@ color: #333;
471471
@ vertical-align: bottom;
472472
@ width: 100%;
473473
@ }
474
-@
474
+@
475475
@ /* The login status message in the top right-hand corner */
476476
@ div.status {
477477
@ display: table-cell;
478478
@ padding-right: 10px;
479479
@ text-align: right;
@@ -482,21 +482,21 @@
482482
@ color: #333;
483483
@ font-size: 0.8em;
484484
@ font-weight: bold;
485485
@ white-space: nowrap;
486486
@ }
487
-@
487
+@
488488
@ /* The header across the top of the page */
489489
@ div.header {
490490
@ margin:10px 0px 10px 0px;
491491
@ padding:1px 0px 0px 20px;
492492
@ border-style:solid;
493493
@ border-color:black;
494494
@ border-width:1px 0px;
495495
@ background-color:#eee;
496496
@ }
497
-@
497
+@
498498
@ /* The main menu bar that appears at the top left of the page beneath
499499
@ ** the header. Width must be co-ordinated with the container below */
500500
@ div.mainmenu {
501501
@ float: left;
502502
@ margin-left: 10px;
@@ -506,11 +506,11 @@
506506
@ padding:5px;
507507
@ background-color:#eee;
508508
@ border:1px solid #999;
509509
@ width:8em;
510510
@ }
511
-@
511
+@
512512
@ /* Main menu is now a list */
513513
@ div.mainmenu ul {
514514
@ padding: 0;
515515
@ list-style:none;
516516
@ }
@@ -521,17 +521,17 @@
521521
@ }
522522
@ div.mainmenu a:hover {
523523
@ color: #eee;
524524
@ background-color: #333;
525525
@ }
526
-@
526
+@
527527
@ /* Container for the sub-menu and content so they don''t spread
528528
@ ** out underneath the main menu */
529529
@ #container {
530530
@ padding-left: 9em;
531531
@ }
532
-@
532
+@
533533
@ /* The submenu bar that *sometimes* appears below the main menu */
534534
@ div.submenu, div.sectionmenu {
535535
@ padding: 3px 10px 3px 10px;
536536
@ font-size: 0.9em;
537537
@ text-align: center;
@@ -548,17 +548,17 @@
548548
@ }
549549
@ div.submenu a:hover, div.sectionmenu>a.button:hover {
550550
@ color: #eee;
551551
@ background-color: #333;
552552
@ }
553
-@
553
+@
554554
@ /* All page content from the bottom of the menu or submenu down to
555555
@ ** the footer */
556556
@ div.content {
557557
@ padding: 2ex 1ex 0ex 2ex;
558558
@ }
559
-@
559
+@
560560
@ /* Some pages have section dividers */
561561
@ div.section {
562562
@ margin-bottom: 0px;
563563
@ margin-top: 1em;
564564
@ padding: 1px 1px 1px 1px;
@@ -569,11 +569,11 @@
569569
@ border-width:1px 0px;
570570
@ background-color: #eee;
571571
@ color: #333;
572572
@ white-space: nowrap;
573573
@ }
574
-@
574
+@
575575
@ /* The "Date" that occurs on the left hand side of timelines */
576576
@ div.divider {
577577
@ background: #eee;
578578
@ border: 2px #999 solid;
579579
@ font-size: 1em; font-weight: normal;
@@ -582,27 +582,27 @@
582582
@ float: left;
583583
@ clear: left;
584584
@ color: #333;
585585
@ white-space: nowrap;
586586
@ }
587
-@
587
+@
588588
@ /* The footer at the very bottom of the page */
589589
@ div.footer {
590590
@ font-size: 0.8em;
591591
@ margin-top: 12px;
592592
@ padding: 5px 10px 5px 10px;
593593
@ text-align: right;
594594
@ background-color: #eee;
595595
@ color: #555;
596596
@ }
597
-@
597
+@
598598
@ /* <verbatim> blocks */
599599
@ pre.verbatim {
600600
@ background-color: #f5f5f5;
601601
@ padding: 0.5em;
602602
@ }
603
-@
603
+@
604604
@ /* The label/value pairs on (for example) the ci page */
605605
@ table.label-value th {
606606
@ vertical-align: top;
607607
@ text-align: right;
608608
@ padding: 0.2ex 2ex;
@@ -673,11 +673,11 @@
673673
674674
675675
/*
676676
** Shadow boxes and rounded corners.
677677
*/
678
-static const char zBuiltinSkin4[] =
678
+static const char zBuiltinSkin4[] =
679679
@ REPLACE INTO config(name,mtime,value)
680680
@ VALUES('css',now(),'/* General settings for the entire page */
681681
@ html {
682682
@ min-height: 100%;
683683
@ }
@@ -687,28 +687,28 @@
687687
@ background-color: white;
688688
@ color: #333;
689689
@ font-family: Verdana, sans-serif;
690690
@ font-size: 0.8em;
691691
@ }
692
-@
692
+@
693693
@ /* The project logo in the upper left-hand corner of each page */
694694
@ div.logo {
695695
@ display: table-cell;
696696
@ text-align: right;
697697
@ vertical-align: bottom;
698698
@ font-weight: normal;
699699
@ white-space: nowrap;
700700
@ }
701
-@
701
+@
702702
@ /* Widths */
703703
@ div.header, div.mainmenu, div.submenu, div.content, div.footer {
704704
@ max-width: 900px;
705705
@ margin: auto;
706706
@ padding: 3px 20px 3px 20px;
707707
@ clear: both;
708708
@ }
709
-@
709
+@
710710
@ /* The page title at the top of each page */
711711
@ div.title {
712712
@ display: table-cell;
713713
@ padding-left: 10px;
714714
@ font-size: 2em;
@@ -719,21 +719,21 @@
719719
@ font-family: Verdana, sans-serif;
720720
@ font-weight: bold;
721721
@ color: #558195;
722722
@ text-shadow: 0px 2px 2px #999999;
723723
@ }
724
-@
724
+@
725725
@ /* The login status message in the top right-hand corner */
726726
@ div.status {
727727
@ display: table-cell;
728728
@ text-align: right;
729729
@ vertical-align: bottom;
730730
@ color: #333;
731731
@ margin-right: -20px;
732732
@ white-space: nowrap;
733733
@ }
734
-@
734
+@
735735
@ /* The main menu bar that appears at the top of the page beneath
736736
@ ** the header */
737737
@ div.mainmenu {
738738
@ text-align: center;
739739
@ color: white;
@@ -743,11 +743,11 @@
743743
@ padding-top: 8px;
744744
@ padding-bottom: 8px;
745745
@ background-color: #446979;
746746
@ box-shadow: 0px 3px 4px #333333;
747747
@ }
748
-@
748
+@
749749
@ /* The submenu bar that *sometimes* appears below the main menu */
750750
@ div.submenu {
751751
@ padding-top:10px;
752752
@ padding-bottom:0;
753753
@ text-align: right;
@@ -768,24 +768,24 @@
768768
@ color: #000;
769769
@ font-family: Arial;
770770
@ text-decoration: none;
771771
@ margin:auto;
772772
@ border-radius: 5px;
773
-@ background-color: #e0e0e0 ;
773
+@ background-color: #e0e0e0;
774774
@ text-shadow: 0px -1px 0px #eee;
775775
@ border: 1px solid #000;
776776
@ }
777
-@
777
+@
778778
@ div.mainmenu a:hover {
779779
@ color: #000;
780780
@ background-color: white;
781781
@ }
782
-@
782
+@
783783
@ div.submenu a:hover, div.sectionmenu>a.button:hover {
784
-@ background-color: #c0c0c0 ;
784
+@ background-color: #c0c0c0;
785785
@ }
786
-@
786
+@
787787
@ /* All page content from the bottom of the menu or submenu down to
788788
@ ** the footer */
789789
@ div.content {
790790
@ background-color: #fff;
791791
@ box-shadow: 0px 3px 4px #999;
@@ -792,12 +792,12 @@
792792
@ border-bottom-right-radius: 5px;
793793
@ border-bottom-left-radius: 5px;
794794
@ padding-bottom: 1em;
795795
@ min-height:40%;
796796
@ }
797
-@
798
-@
797
+@
798
+@
799799
@ /* Some pages have section dividers */
800800
@ div.section {
801801
@ margin-bottom: 0.5em;
802802
@ margin-top: 1em;
803803
@ margin-right: auto;
@@ -809,69 +809,69 @@
809809
@ border-radius: 5px;
810810
@ background-color: #446979;
811811
@ box-shadow: 0px 3px 4px #333333;
812812
@ white-space: nowrap;
813813
@ }
814
-@
814
+@
815815
@ /* The "Date" that occurs on the left hand side of timelines */
816816
@ div.divider {
817
-@ font-size: 1.2em;
817
+@ font-size: 1.2em;
818818
@ font-family: Georgia, serif;
819819
@ font-weight: bold;
820820
@ margin-top: 1em;
821821
@ white-space: nowrap;
822822
@ }
823
-@
823
+@
824824
@ /* The footer at the very bottom of the page */
825825
@ div.footer {
826826
@ font-size: 0.9em;
827827
@ text-align: right;
828828
@ margin-bottom: 1em;
829829
@ color: #666;
830830
@ }
831
-@
831
+@
832832
@ /* Hyperlink colors in the footer */
833833
@ div.footer a { color: white; }
834834
@ div.footer a:link { color: white; }
835835
@ div.footer a:visited { color: white; }
836836
@ div.footer a:hover { background-color: white; color: #558195; }
837
-@
837
+@
838838
@ /* <verbatim> blocks */
839839
@ pre.verbatim, blockquote pre {
840840
@ font-family: Dejavu Sans Mono, Monaco, Lucida Console, monospace;
841841
@ background-color: #f3f3f3;
842842
@ padding: 0.5em;
843843
@ white-space: pre-wrap;
844844
@ }
845
-@
845
+@
846846
@ blockquote pre {
847847
@ border: 1px #000 dashed;
848848
@ }
849
-@
849
+@
850850
@ /* The label/value pairs on (for example) the ci page */
851851
@ table.label-value th {
852852
@ vertical-align: top;
853853
@ text-align: right;
854854
@ padding: 0.2ex 2ex;
855855
@ }
856
-@
857
-@
856
+@
857
+@
858858
@ table.report {
859859
@ border-collapse:collapse;
860860
@ border: 1px solid #999;
861861
@ margin: 1em 0 1em 0;
862862
@ }
863
-@
863
+@
864864
@ table.report tr th {
865865
@ padding: 3px 5px;
866
-@ text-transform : capitalize;
866
+@ text-transform: capitalize;
867867
@ }
868
-@
868
+@
869869
@ table.report tr td {
870870
@ padding: 3px 5px;
871871
@ }
872
-@
872
+@
873873
@ textarea {
874874
@ font-size: 1em;
875875
@ }');
876876
@ REPLACE INTO config(name,mtime,value) VALUES('header',now(),'<html>
877877
@ <head>
@@ -952,11 +952,11 @@
952952
** Fossil repository. Additionally, if the Tcl integration feature is
953953
** enabled, the loaded version of Tcl is included, with a hyperlink to the
954954
** official Tcl/Tk web site. The footer also contains a TH1 script block
955955
** to help accomplish these tasks.
956956
*/
957
-static const char zBuiltinSkin5[] =
957
+static const char zBuiltinSkin5[] =
958958
@ REPLACE INTO config(name,mtime,value)
959959
@ VALUES('css',now(),'/* General settings for the entire page */
960960
@ body {
961961
@ margin: 0ex 1ex;
962962
@ padding: 0px;
@@ -982,11 +982,11 @@
982982
@ font-weight: bold;
983983
@ text-align: center;
984984
@ padding: 0 0 0 1em;
985985
@ color: #558195;
986986
@ vertical-align: bottom;
987
-@ width: 100% ;
987
+@ width: 100%;
988988
@ }
989989
@
990990
@ /* The login status message in the top right-hand corner */
991991
@ div.status {
992992
@ display: table-cell;
@@ -1000,11 +1000,11 @@
10001000
@ }
10011001
@
10021002
@ /* The header across the top of the page */
10031003
@ div.header {
10041004
@ display: table;
1005
-@ width: 100% ;
1005
+@ width: 100%;
10061006
@ }
10071007
@
10081008
@ /* The main menu bar that appears at the top of the page beneath
10091009
@ ** the header */
10101010
@ div.mainmenu {
@@ -1085,11 +1085,11 @@
10851085
@ /* Hyperlink colors in the footer */
10861086
@ div.footer a { color: white; }
10871087
@ div.footer a:link { color: white; }
10881088
@ div.footer a:visited { color: white; }
10891089
@ div.footer a:hover { background-color: white; color: #558195; }
1090
-@
1090
+@
10911091
@ /* verbatim blocks */
10921092
@ pre.verbatim {
10931093
@ background-color: #f5f5f5;
10941094
@ padding: 0.5em;
10951095
@}
@@ -1397,11 +1397,11 @@
13971397
style_header("Skins");
13981398
if( zErr ){
13991399
@ <p><font color="red">%h(zErr)</font></p>
14001400
}
14011401
@ <p>A "skin" is a combination of
1402
- @ <a href="setup_editcss">CSS</a>,
1402
+ @ <a href="setup_editcss">CSS</a>,
14031403
@ <a href="setup_header">Header</a>,
14041404
@ <a href="setup_footer">Footer</a>, and
14051405
@ <a href="setup_logo">Logo</a> that determines the look and feel
14061406
@ of the web interface.</p>
14071407
@
@@ -1411,11 +1411,11 @@
14111411
z = aBuiltinSkin[i].zName;
14121412
if( fossil_strcmp(aBuiltinSkin[i].zValue, zCurrent)==0 ){
14131413
@ <li><p>%h(z).&nbsp;&nbsp; <b>Currently In Use</b></p>
14141414
}else{
14151415
@ <li><form action="%s(g.zTop)/setup_skin" method="post"><div>
1416
- @ %h(z).&nbsp;&nbsp;
1416
+ @ %h(z).&nbsp;&nbsp;
14171417
@ <input type="hidden" name="sn" value="%h(z)" />
14181418
@ <input type="submit" name="load" value="Use This Skin" />
14191419
@ </div></form></li>
14201420
}
14211421
}
@@ -1429,11 +1429,11 @@
14291429
const char *zV = db_column_text(&q, 1);
14301430
if( fossil_strcmp(zV, zCurrent)==0 ){
14311431
@ <li><p>%h(zN).&nbsp;&nbsp; <b>Currently In Use</b></p>
14321432
}else{
14331433
@ <li><form action="%s(g.zTop)/setup_skin" method="post">
1434
- @ %h(zN).&nbsp;&nbsp;
1434
+ @ %h(zN).&nbsp;&nbsp;
14351435
@ <input type="hidden" name="sn" value="%h(zN)">
14361436
@ <input type="submit" name="load" value="Use This Skin">
14371437
@ <input type="submit" name="del1" value="Delete This Skin">
14381438
@ </form></li>
14391439
}
14401440
--- src/skins.c
+++ src/skins.c
@@ -24,20 +24,20 @@
24 /* @-comment: ## */
25 /*
26 ** A black-and-white theme with the project title in a bar across the top
27 ** and no logo image.
28 */
29 static const char zBuiltinSkin1[] =
30 @ REPLACE INTO config(name,mtime,value)
31 @ VALUES('css',now(),'/* General settings for the entire page */
32 @ body {
33 @ margin: 0ex 1ex;
34 @ padding: 0px;
35 @ background-color: white;
36 @ font-family: sans-serif;
37 @ }
38 @
39 @ /* The project logo in the upper left-hand corner of each page */
40 @ div.logo {
41 @ display: table-row;
42 @ text-align: center;
43 @ /* vertical-align: bottom;*/
@@ -46,11 +46,11 @@
46 @ background-color: #707070;
47 @ color: #ffffff;
48 @ min-width: 200px;
49 @ white-space: nowrap;
50 @ }
51 @
52 @ /* The page title centered at the top of each page */
53 @ div.title {
54 @ display: table-cell;
55 @ font-size: 1.5em;
56 @ font-weight: bold;
@@ -58,11 +58,11 @@
58 @ padding: 0 0 0 10px;
59 @ color: #404040;
60 @ vertical-align: bottom;
61 @ width: 100%;
62 @ }
63 @
64 @ /* The login status message in the top right-hand corner */
65 @ div.status {
66 @ display: table-cell;
67 @ text-align: right;
68 @ vertical-align: bottom;
@@ -70,17 +70,17 @@
70 @ font-size: 0.8em;
71 @ font-weight: bold;
72 @ min-width: 200px;
73 @ white-space: nowrap;
74 @ }
75 @
76 @ /* The header across the top of the page */
77 @ div.header {
78 @ display: table;
79 @ width: 100%;
80 @ }
81 @
82 @ /* The main menu bar that appears at the top of the page beneath
83 @ ** the header */
84 @ div.mainmenu {
85 @ padding: 5px 10px 5px 10px;
86 @ font-size: 0.9em;
@@ -117,11 +117,11 @@
117 @ }
118 @ /* Hyperlink colors */
119 @ div.content a { color: #604000; }
120 @ div.content a:link { color: #604000;}
121 @ div.content a:visited { color: #600000; }
122 @
123 @ /* Some pages have section dividers */
124 @ div.section {
125 @ margin-bottom: 0px;
126 @ margin-top: 1em;
127 @ padding: 1px 1px 1px 1px;
@@ -129,11 +129,11 @@
129 @ font-weight: bold;
130 @ background-color: #404040;
131 @ color: white;
132 @ white-space: nowrap;
133 @ }
134 @
135 @ /* The "Date" that occurs on the left hand side of timelines */
136 @ div.divider {
137 @ background: #a0a0a0;
138 @ border: 2px #505050 solid;
139 @ font-size: 1em; font-weight: normal;
@@ -141,21 +141,21 @@
141 @ margin: .2em 0 .2em 0;
142 @ float: left;
143 @ clear: left;
144 @ white-space: nowrap;
145 @ }
146 @
147 @ /* The footer at the very bottom of the page */
148 @ div.footer {
149 @ font-size: 0.8em;
150 @ margin-top: 12px;
151 @ padding: 5px 10px 5px 10px;
152 @ text-align: right;
153 @ background-color: #404040;
154 @ color: white;
155 @ }
156 @
157 @ /* The label/value pairs on (for example) the vinfo page */
158 @ table.label-value th {
159 @ vertical-align: top;
160 @ text-align: right;
161 @ padding: 0.2ex 2ex;
@@ -211,30 +211,30 @@
211 @ }
212 @ </th1></div>
213 @ ');
214 @ REPLACE INTO config(name,mtime,value)
215 @ VALUES('footer',now(),'<div class="footer">
216 @ Fossil version $manifest_version $manifest_date
217 @ </div>
218 @ </body></html>
219 @ ');
220 ;
221
222 /*
223 ** A tan theme with the project title above the user identification
224 ** and no logo image.
225 */
226 static const char zBuiltinSkin2[] =
227 @ REPLACE INTO config(name,mtime,value)
228 @ VALUES('css',now(),'/* General settings for the entire page */
229 @ body {
230 @ margin: 0ex 0ex;
231 @ padding: 0px;
232 @ background-color: #fef3bc;
233 @ font-family: sans-serif;
234 @ }
235 @
236 @ /* The project logo in the upper left-hand corner of each page */
237 @ div.logo {
238 @ display: inline;
239 @ text-align: center;
240 @ vertical-align: bottom;
@@ -241,11 +241,11 @@
241 @ font-weight: bold;
242 @ font-size: 2.5em;
243 @ color: #a09048;
244 @ white-space: nowrap;
245 @ }
246 @
247 @ /* The page title centered at the top of each page */
248 @ div.title {
249 @ display: table-cell;
250 @ font-size: 2em;
251 @ font-weight: bold;
@@ -253,11 +253,11 @@
253 @ padding: 0 0 0 5px;
254 @ color: #a09048;
255 @ vertical-align: bottom;
256 @ width: 100%;
257 @ }
258 @
259 @ /* The login status message in the top right-hand corner */
260 @ div.status {
261 @ display: table-cell;
262 @ text-align: right;
263 @ vertical-align: bottom;
@@ -265,17 +265,17 @@
265 @ padding: 5px 5px 0 0;
266 @ font-size: 0.8em;
267 @ font-weight: bold;
268 @ white-space: nowrap;
269 @ }
270 @
271 @ /* The header across the top of the page */
272 @ div.header {
273 @ display: table;
274 @ width: 100%;
275 @ }
276 @
277 @ /* The main menu bar that appears at the top of the page beneath
278 @ ** the header */
279 @ div.mainmenu {
280 @ padding: 5px 10px 5px 10px;
281 @ font-size: 0.9em;
@@ -283,11 +283,11 @@
283 @ text-align: center;
284 @ letter-spacing: 1px;
285 @ background-color: #a09048;
286 @ color: black;
287 @ }
288 @
289 @ /* The submenu bar that *sometimes* appears below the main menu */
290 @ div.submenu, div.sectionmenu {
291 @ padding: 3px 10px 3px 0px;
292 @ font-size: 0.9em;
293 @ text-align: center;
@@ -302,21 +302,21 @@
302 @ }
303 @ div.mainmenu a:hover, div.submenu a:hover, div.sectionmenu>a.button:hover {
304 @ color: #a09048;
305 @ background-color: white;
306 @ }
307 @
308 @ /* All page content from the bottom of the menu or submenu down to
309 @ ** the footer */
310 @ div.content {
311 @ padding: 1ex 5px;
312 @ }
313 @ div.content a { color: #706532; }
314 @ div.content a:link { color: #706532; }
315 @ div.content a:visited { color: #704032; }
316 @ div.content a:hover { background-color: white; color: #706532; }
317 @
318 @ /* Some pages have section dividers */
319 @ div.section {
320 @ margin-bottom: 0px;
321 @ margin-top: 1em;
322 @ padding: 3px 3px 0 3px;
@@ -324,11 +324,11 @@
324 @ font-weight: bold;
325 @ background-color: #a09048;
326 @ color: white;
327 @ white-space: nowrap;
328 @ }
329 @
330 @ /* The "Date" that occurs on the left hand side of timelines */
331 @ div.divider {
332 @ background: #e1d498;
333 @ border: 2px #a09048 solid;
334 @ font-size: 1em; font-weight: normal;
@@ -336,33 +336,33 @@
336 @ margin: .2em 0 .2em 0;
337 @ float: left;
338 @ clear: left;
339 @ white-space: nowrap;
340 @ }
341 @
342 @ /* The footer at the very bottom of the page */
343 @ div.footer {
344 @ font-size: 0.8em;
345 @ margin-top: 12px;
346 @ padding: 5px 10px 5px 10px;
347 @ text-align: right;
348 @ background-color: #a09048;
349 @ color: white;
350 @ }
351 @
352 @ /* Hyperlink colors */
353 @ div.footer a { color: white; }
354 @ div.footer a:link { color: white; }
355 @ div.footer a:visited { color: white; }
356 @ div.footer a:hover { background-color: white; color: #558195; }
357 @
358 @ /* <verbatim> blocks */
359 @ pre.verbatim {
360 @ background-color: #f5f5f5;
361 @ padding: 0.5em;
362 @ }
363 @
364 @ /* The label/value pairs on (for example) the ci page */
365 @ table.label-value th {
366 @ vertical-align: top;
367 @ text-align: right;
368 @ padding: 0.2ex 2ex;
@@ -430,39 +430,39 @@
430
431 /*
432 ** Black letters on a white or cream background with the main menu
433 ** stuck on the left-hand side.
434 */
435 static const char zBuiltinSkin3[] =
436 @ REPLACE INTO config(name,mtime,value)
437 @ VALUES('css',now(),'/* General settings for the entire page */
438 @ body {
439 @ margin:0px 0px 0px 0px;
440 @ padding:0px;
441 @ font-family:verdana, arial, helvetica, "sans serif";
442 @ color:#333;
443 @ background-color:white;
444 @ }
445 @
446 @ /* consistent colours */
447 @ h2 {
448 @ color: #333;
449 @ }
450 @ h3 {
451 @ color: #333;
452 @ }
453 @
454 @ /* The project logo in the upper left-hand corner of each page */
455 @ div.logo {
456 @ display: table-cell;
457 @ text-align: left;
458 @ vertical-align: bottom;
459 @ font-weight: bold;
460 @ color: #333;
461 @ white-space: nowrap;
462 @ }
463 @
464 @ /* The page title centered at the top of each page */
465 @ div.title {
466 @ display: table-cell;
467 @ font-size: 2em;
468 @ font-weight: bold;
@@ -469,11 +469,11 @@
469 @ text-align: center;
470 @ color: #333;
471 @ vertical-align: bottom;
472 @ width: 100%;
473 @ }
474 @
475 @ /* The login status message in the top right-hand corner */
476 @ div.status {
477 @ display: table-cell;
478 @ padding-right: 10px;
479 @ text-align: right;
@@ -482,21 +482,21 @@
482 @ color: #333;
483 @ font-size: 0.8em;
484 @ font-weight: bold;
485 @ white-space: nowrap;
486 @ }
487 @
488 @ /* The header across the top of the page */
489 @ div.header {
490 @ margin:10px 0px 10px 0px;
491 @ padding:1px 0px 0px 20px;
492 @ border-style:solid;
493 @ border-color:black;
494 @ border-width:1px 0px;
495 @ background-color:#eee;
496 @ }
497 @
498 @ /* The main menu bar that appears at the top left of the page beneath
499 @ ** the header. Width must be co-ordinated with the container below */
500 @ div.mainmenu {
501 @ float: left;
502 @ margin-left: 10px;
@@ -506,11 +506,11 @@
506 @ padding:5px;
507 @ background-color:#eee;
508 @ border:1px solid #999;
509 @ width:8em;
510 @ }
511 @
512 @ /* Main menu is now a list */
513 @ div.mainmenu ul {
514 @ padding: 0;
515 @ list-style:none;
516 @ }
@@ -521,17 +521,17 @@
521 @ }
522 @ div.mainmenu a:hover {
523 @ color: #eee;
524 @ background-color: #333;
525 @ }
526 @
527 @ /* Container for the sub-menu and content so they don''t spread
528 @ ** out underneath the main menu */
529 @ #container {
530 @ padding-left: 9em;
531 @ }
532 @
533 @ /* The submenu bar that *sometimes* appears below the main menu */
534 @ div.submenu, div.sectionmenu {
535 @ padding: 3px 10px 3px 10px;
536 @ font-size: 0.9em;
537 @ text-align: center;
@@ -548,17 +548,17 @@
548 @ }
549 @ div.submenu a:hover, div.sectionmenu>a.button:hover {
550 @ color: #eee;
551 @ background-color: #333;
552 @ }
553 @
554 @ /* All page content from the bottom of the menu or submenu down to
555 @ ** the footer */
556 @ div.content {
557 @ padding: 2ex 1ex 0ex 2ex;
558 @ }
559 @
560 @ /* Some pages have section dividers */
561 @ div.section {
562 @ margin-bottom: 0px;
563 @ margin-top: 1em;
564 @ padding: 1px 1px 1px 1px;
@@ -569,11 +569,11 @@
569 @ border-width:1px 0px;
570 @ background-color: #eee;
571 @ color: #333;
572 @ white-space: nowrap;
573 @ }
574 @
575 @ /* The "Date" that occurs on the left hand side of timelines */
576 @ div.divider {
577 @ background: #eee;
578 @ border: 2px #999 solid;
579 @ font-size: 1em; font-weight: normal;
@@ -582,27 +582,27 @@
582 @ float: left;
583 @ clear: left;
584 @ color: #333;
585 @ white-space: nowrap;
586 @ }
587 @
588 @ /* The footer at the very bottom of the page */
589 @ div.footer {
590 @ font-size: 0.8em;
591 @ margin-top: 12px;
592 @ padding: 5px 10px 5px 10px;
593 @ text-align: right;
594 @ background-color: #eee;
595 @ color: #555;
596 @ }
597 @
598 @ /* <verbatim> blocks */
599 @ pre.verbatim {
600 @ background-color: #f5f5f5;
601 @ padding: 0.5em;
602 @ }
603 @
604 @ /* The label/value pairs on (for example) the ci page */
605 @ table.label-value th {
606 @ vertical-align: top;
607 @ text-align: right;
608 @ padding: 0.2ex 2ex;
@@ -673,11 +673,11 @@
673
674
675 /*
676 ** Shadow boxes and rounded corners.
677 */
678 static const char zBuiltinSkin4[] =
679 @ REPLACE INTO config(name,mtime,value)
680 @ VALUES('css',now(),'/* General settings for the entire page */
681 @ html {
682 @ min-height: 100%;
683 @ }
@@ -687,28 +687,28 @@
687 @ background-color: white;
688 @ color: #333;
689 @ font-family: Verdana, sans-serif;
690 @ font-size: 0.8em;
691 @ }
692 @
693 @ /* The project logo in the upper left-hand corner of each page */
694 @ div.logo {
695 @ display: table-cell;
696 @ text-align: right;
697 @ vertical-align: bottom;
698 @ font-weight: normal;
699 @ white-space: nowrap;
700 @ }
701 @
702 @ /* Widths */
703 @ div.header, div.mainmenu, div.submenu, div.content, div.footer {
704 @ max-width: 900px;
705 @ margin: auto;
706 @ padding: 3px 20px 3px 20px;
707 @ clear: both;
708 @ }
709 @
710 @ /* The page title at the top of each page */
711 @ div.title {
712 @ display: table-cell;
713 @ padding-left: 10px;
714 @ font-size: 2em;
@@ -719,21 +719,21 @@
719 @ font-family: Verdana, sans-serif;
720 @ font-weight: bold;
721 @ color: #558195;
722 @ text-shadow: 0px 2px 2px #999999;
723 @ }
724 @
725 @ /* The login status message in the top right-hand corner */
726 @ div.status {
727 @ display: table-cell;
728 @ text-align: right;
729 @ vertical-align: bottom;
730 @ color: #333;
731 @ margin-right: -20px;
732 @ white-space: nowrap;
733 @ }
734 @
735 @ /* The main menu bar that appears at the top of the page beneath
736 @ ** the header */
737 @ div.mainmenu {
738 @ text-align: center;
739 @ color: white;
@@ -743,11 +743,11 @@
743 @ padding-top: 8px;
744 @ padding-bottom: 8px;
745 @ background-color: #446979;
746 @ box-shadow: 0px 3px 4px #333333;
747 @ }
748 @
749 @ /* The submenu bar that *sometimes* appears below the main menu */
750 @ div.submenu {
751 @ padding-top:10px;
752 @ padding-bottom:0;
753 @ text-align: right;
@@ -768,24 +768,24 @@
768 @ color: #000;
769 @ font-family: Arial;
770 @ text-decoration: none;
771 @ margin:auto;
772 @ border-radius: 5px;
773 @ background-color: #e0e0e0 ;
774 @ text-shadow: 0px -1px 0px #eee;
775 @ border: 1px solid #000;
776 @ }
777 @
778 @ div.mainmenu a:hover {
779 @ color: #000;
780 @ background-color: white;
781 @ }
782 @
783 @ div.submenu a:hover, div.sectionmenu>a.button:hover {
784 @ background-color: #c0c0c0 ;
785 @ }
786 @
787 @ /* All page content from the bottom of the menu or submenu down to
788 @ ** the footer */
789 @ div.content {
790 @ background-color: #fff;
791 @ box-shadow: 0px 3px 4px #999;
@@ -792,12 +792,12 @@
792 @ border-bottom-right-radius: 5px;
793 @ border-bottom-left-radius: 5px;
794 @ padding-bottom: 1em;
795 @ min-height:40%;
796 @ }
797 @
798 @
799 @ /* Some pages have section dividers */
800 @ div.section {
801 @ margin-bottom: 0.5em;
802 @ margin-top: 1em;
803 @ margin-right: auto;
@@ -809,69 +809,69 @@
809 @ border-radius: 5px;
810 @ background-color: #446979;
811 @ box-shadow: 0px 3px 4px #333333;
812 @ white-space: nowrap;
813 @ }
814 @
815 @ /* The "Date" that occurs on the left hand side of timelines */
816 @ div.divider {
817 @ font-size: 1.2em;
818 @ font-family: Georgia, serif;
819 @ font-weight: bold;
820 @ margin-top: 1em;
821 @ white-space: nowrap;
822 @ }
823 @
824 @ /* The footer at the very bottom of the page */
825 @ div.footer {
826 @ font-size: 0.9em;
827 @ text-align: right;
828 @ margin-bottom: 1em;
829 @ color: #666;
830 @ }
831 @
832 @ /* Hyperlink colors in the footer */
833 @ div.footer a { color: white; }
834 @ div.footer a:link { color: white; }
835 @ div.footer a:visited { color: white; }
836 @ div.footer a:hover { background-color: white; color: #558195; }
837 @
838 @ /* <verbatim> blocks */
839 @ pre.verbatim, blockquote pre {
840 @ font-family: Dejavu Sans Mono, Monaco, Lucida Console, monospace;
841 @ background-color: #f3f3f3;
842 @ padding: 0.5em;
843 @ white-space: pre-wrap;
844 @ }
845 @
846 @ blockquote pre {
847 @ border: 1px #000 dashed;
848 @ }
849 @
850 @ /* The label/value pairs on (for example) the ci page */
851 @ table.label-value th {
852 @ vertical-align: top;
853 @ text-align: right;
854 @ padding: 0.2ex 2ex;
855 @ }
856 @
857 @
858 @ table.report {
859 @ border-collapse:collapse;
860 @ border: 1px solid #999;
861 @ margin: 1em 0 1em 0;
862 @ }
863 @
864 @ table.report tr th {
865 @ padding: 3px 5px;
866 @ text-transform : capitalize;
867 @ }
868 @
869 @ table.report tr td {
870 @ padding: 3px 5px;
871 @ }
872 @
873 @ textarea {
874 @ font-size: 1em;
875 @ }');
876 @ REPLACE INTO config(name,mtime,value) VALUES('header',now(),'<html>
877 @ <head>
@@ -952,11 +952,11 @@
952 ** Fossil repository. Additionally, if the Tcl integration feature is
953 ** enabled, the loaded version of Tcl is included, with a hyperlink to the
954 ** official Tcl/Tk web site. The footer also contains a TH1 script block
955 ** to help accomplish these tasks.
956 */
957 static const char zBuiltinSkin5[] =
958 @ REPLACE INTO config(name,mtime,value)
959 @ VALUES('css',now(),'/* General settings for the entire page */
960 @ body {
961 @ margin: 0ex 1ex;
962 @ padding: 0px;
@@ -982,11 +982,11 @@
982 @ font-weight: bold;
983 @ text-align: center;
984 @ padding: 0 0 0 1em;
985 @ color: #558195;
986 @ vertical-align: bottom;
987 @ width: 100% ;
988 @ }
989 @
990 @ /* The login status message in the top right-hand corner */
991 @ div.status {
992 @ display: table-cell;
@@ -1000,11 +1000,11 @@
1000 @ }
1001 @
1002 @ /* The header across the top of the page */
1003 @ div.header {
1004 @ display: table;
1005 @ width: 100% ;
1006 @ }
1007 @
1008 @ /* The main menu bar that appears at the top of the page beneath
1009 @ ** the header */
1010 @ div.mainmenu {
@@ -1085,11 +1085,11 @@
1085 @ /* Hyperlink colors in the footer */
1086 @ div.footer a { color: white; }
1087 @ div.footer a:link { color: white; }
1088 @ div.footer a:visited { color: white; }
1089 @ div.footer a:hover { background-color: white; color: #558195; }
1090 @
1091 @ /* verbatim blocks */
1092 @ pre.verbatim {
1093 @ background-color: #f5f5f5;
1094 @ padding: 0.5em;
1095 @}
@@ -1397,11 +1397,11 @@
1397 style_header("Skins");
1398 if( zErr ){
1399 @ <p><font color="red">%h(zErr)</font></p>
1400 }
1401 @ <p>A "skin" is a combination of
1402 @ <a href="setup_editcss">CSS</a>,
1403 @ <a href="setup_header">Header</a>,
1404 @ <a href="setup_footer">Footer</a>, and
1405 @ <a href="setup_logo">Logo</a> that determines the look and feel
1406 @ of the web interface.</p>
1407 @
@@ -1411,11 +1411,11 @@
1411 z = aBuiltinSkin[i].zName;
1412 if( fossil_strcmp(aBuiltinSkin[i].zValue, zCurrent)==0 ){
1413 @ <li><p>%h(z).&nbsp;&nbsp; <b>Currently In Use</b></p>
1414 }else{
1415 @ <li><form action="%s(g.zTop)/setup_skin" method="post"><div>
1416 @ %h(z).&nbsp;&nbsp;
1417 @ <input type="hidden" name="sn" value="%h(z)" />
1418 @ <input type="submit" name="load" value="Use This Skin" />
1419 @ </div></form></li>
1420 }
1421 }
@@ -1429,11 +1429,11 @@
1429 const char *zV = db_column_text(&q, 1);
1430 if( fossil_strcmp(zV, zCurrent)==0 ){
1431 @ <li><p>%h(zN).&nbsp;&nbsp; <b>Currently In Use</b></p>
1432 }else{
1433 @ <li><form action="%s(g.zTop)/setup_skin" method="post">
1434 @ %h(zN).&nbsp;&nbsp;
1435 @ <input type="hidden" name="sn" value="%h(zN)">
1436 @ <input type="submit" name="load" value="Use This Skin">
1437 @ <input type="submit" name="del1" value="Delete This Skin">
1438 @ </form></li>
1439 }
1440
--- src/skins.c
+++ src/skins.c
@@ -24,20 +24,20 @@
24 /* @-comment: ## */
25 /*
26 ** A black-and-white theme with the project title in a bar across the top
27 ** and no logo image.
28 */
29 static const char zBuiltinSkin1[] =
30 @ REPLACE INTO config(name,mtime,value)
31 @ VALUES('css',now(),'/* General settings for the entire page */
32 @ body {
33 @ margin: 0ex 1ex;
34 @ padding: 0px;
35 @ background-color: white;
36 @ font-family: sans-serif;
37 @ }
38 @
39 @ /* The project logo in the upper left-hand corner of each page */
40 @ div.logo {
41 @ display: table-row;
42 @ text-align: center;
43 @ /* vertical-align: bottom;*/
@@ -46,11 +46,11 @@
46 @ background-color: #707070;
47 @ color: #ffffff;
48 @ min-width: 200px;
49 @ white-space: nowrap;
50 @ }
51 @
52 @ /* The page title centered at the top of each page */
53 @ div.title {
54 @ display: table-cell;
55 @ font-size: 1.5em;
56 @ font-weight: bold;
@@ -58,11 +58,11 @@
58 @ padding: 0 0 0 10px;
59 @ color: #404040;
60 @ vertical-align: bottom;
61 @ width: 100%;
62 @ }
63 @
64 @ /* The login status message in the top right-hand corner */
65 @ div.status {
66 @ display: table-cell;
67 @ text-align: right;
68 @ vertical-align: bottom;
@@ -70,17 +70,17 @@
70 @ font-size: 0.8em;
71 @ font-weight: bold;
72 @ min-width: 200px;
73 @ white-space: nowrap;
74 @ }
75 @
76 @ /* The header across the top of the page */
77 @ div.header {
78 @ display: table;
79 @ width: 100%;
80 @ }
81 @
82 @ /* The main menu bar that appears at the top of the page beneath
83 @ ** the header */
84 @ div.mainmenu {
85 @ padding: 5px 10px 5px 10px;
86 @ font-size: 0.9em;
@@ -117,11 +117,11 @@
117 @ }
118 @ /* Hyperlink colors */
119 @ div.content a { color: #604000; }
120 @ div.content a:link { color: #604000;}
121 @ div.content a:visited { color: #600000; }
122 @
123 @ /* Some pages have section dividers */
124 @ div.section {
125 @ margin-bottom: 0px;
126 @ margin-top: 1em;
127 @ padding: 1px 1px 1px 1px;
@@ -129,11 +129,11 @@
129 @ font-weight: bold;
130 @ background-color: #404040;
131 @ color: white;
132 @ white-space: nowrap;
133 @ }
134 @
135 @ /* The "Date" that occurs on the left hand side of timelines */
136 @ div.divider {
137 @ background: #a0a0a0;
138 @ border: 2px #505050 solid;
139 @ font-size: 1em; font-weight: normal;
@@ -141,21 +141,21 @@
141 @ margin: .2em 0 .2em 0;
142 @ float: left;
143 @ clear: left;
144 @ white-space: nowrap;
145 @ }
146 @
147 @ /* The footer at the very bottom of the page */
148 @ div.footer {
149 @ font-size: 0.8em;
150 @ margin-top: 12px;
151 @ padding: 5px 10px 5px 10px;
152 @ text-align: right;
153 @ background-color: #404040;
154 @ color: white;
155 @ }
156 @
157 @ /* The label/value pairs on (for example) the vinfo page */
158 @ table.label-value th {
159 @ vertical-align: top;
160 @ text-align: right;
161 @ padding: 0.2ex 2ex;
@@ -211,30 +211,30 @@
211 @ }
212 @ </th1></div>
213 @ ');
214 @ REPLACE INTO config(name,mtime,value)
215 @ VALUES('footer',now(),'<div class="footer">
216 @ Fossil version $manifest_version $manifest_date
217 @ </div>
218 @ </body></html>
219 @ ');
220 ;
221
222 /*
223 ** A tan theme with the project title above the user identification
224 ** and no logo image.
225 */
226 static const char zBuiltinSkin2[] =
227 @ REPLACE INTO config(name,mtime,value)
228 @ VALUES('css',now(),'/* General settings for the entire page */
229 @ body {
230 @ margin: 0ex 0ex;
231 @ padding: 0px;
232 @ background-color: #fef3bc;
233 @ font-family: sans-serif;
234 @ }
235 @
236 @ /* The project logo in the upper left-hand corner of each page */
237 @ div.logo {
238 @ display: inline;
239 @ text-align: center;
240 @ vertical-align: bottom;
@@ -241,11 +241,11 @@
241 @ font-weight: bold;
242 @ font-size: 2.5em;
243 @ color: #a09048;
244 @ white-space: nowrap;
245 @ }
246 @
247 @ /* The page title centered at the top of each page */
248 @ div.title {
249 @ display: table-cell;
250 @ font-size: 2em;
251 @ font-weight: bold;
@@ -253,11 +253,11 @@
253 @ padding: 0 0 0 5px;
254 @ color: #a09048;
255 @ vertical-align: bottom;
256 @ width: 100%;
257 @ }
258 @
259 @ /* The login status message in the top right-hand corner */
260 @ div.status {
261 @ display: table-cell;
262 @ text-align: right;
263 @ vertical-align: bottom;
@@ -265,17 +265,17 @@
265 @ padding: 5px 5px 0 0;
266 @ font-size: 0.8em;
267 @ font-weight: bold;
268 @ white-space: nowrap;
269 @ }
270 @
271 @ /* The header across the top of the page */
272 @ div.header {
273 @ display: table;
274 @ width: 100%;
275 @ }
276 @
277 @ /* The main menu bar that appears at the top of the page beneath
278 @ ** the header */
279 @ div.mainmenu {
280 @ padding: 5px 10px 5px 10px;
281 @ font-size: 0.9em;
@@ -283,11 +283,11 @@
283 @ text-align: center;
284 @ letter-spacing: 1px;
285 @ background-color: #a09048;
286 @ color: black;
287 @ }
288 @
289 @ /* The submenu bar that *sometimes* appears below the main menu */
290 @ div.submenu, div.sectionmenu {
291 @ padding: 3px 10px 3px 0px;
292 @ font-size: 0.9em;
293 @ text-align: center;
@@ -302,21 +302,21 @@
302 @ }
303 @ div.mainmenu a:hover, div.submenu a:hover, div.sectionmenu>a.button:hover {
304 @ color: #a09048;
305 @ background-color: white;
306 @ }
307 @
308 @ /* All page content from the bottom of the menu or submenu down to
309 @ ** the footer */
310 @ div.content {
311 @ padding: 1ex 5px;
312 @ }
313 @ div.content a { color: #706532; }
314 @ div.content a:link { color: #706532; }
315 @ div.content a:visited { color: #704032; }
316 @ div.content a:hover { background-color: white; color: #706532; }
317 @
318 @ /* Some pages have section dividers */
319 @ div.section {
320 @ margin-bottom: 0px;
321 @ margin-top: 1em;
322 @ padding: 3px 3px 0 3px;
@@ -324,11 +324,11 @@
324 @ font-weight: bold;
325 @ background-color: #a09048;
326 @ color: white;
327 @ white-space: nowrap;
328 @ }
329 @
330 @ /* The "Date" that occurs on the left hand side of timelines */
331 @ div.divider {
332 @ background: #e1d498;
333 @ border: 2px #a09048 solid;
334 @ font-size: 1em; font-weight: normal;
@@ -336,33 +336,33 @@
336 @ margin: .2em 0 .2em 0;
337 @ float: left;
338 @ clear: left;
339 @ white-space: nowrap;
340 @ }
341 @
342 @ /* The footer at the very bottom of the page */
343 @ div.footer {
344 @ font-size: 0.8em;
345 @ margin-top: 12px;
346 @ padding: 5px 10px 5px 10px;
347 @ text-align: right;
348 @ background-color: #a09048;
349 @ color: white;
350 @ }
351 @
352 @ /* Hyperlink colors */
353 @ div.footer a { color: white; }
354 @ div.footer a:link { color: white; }
355 @ div.footer a:visited { color: white; }
356 @ div.footer a:hover { background-color: white; color: #558195; }
357 @
358 @ /* <verbatim> blocks */
359 @ pre.verbatim {
360 @ background-color: #f5f5f5;
361 @ padding: 0.5em;
362 @ }
363 @
364 @ /* The label/value pairs on (for example) the ci page */
365 @ table.label-value th {
366 @ vertical-align: top;
367 @ text-align: right;
368 @ padding: 0.2ex 2ex;
@@ -430,39 +430,39 @@
430
431 /*
432 ** Black letters on a white or cream background with the main menu
433 ** stuck on the left-hand side.
434 */
435 static const char zBuiltinSkin3[] =
436 @ REPLACE INTO config(name,mtime,value)
437 @ VALUES('css',now(),'/* General settings for the entire page */
438 @ body {
439 @ margin:0px 0px 0px 0px;
440 @ padding:0px;
441 @ font-family:verdana, arial, helvetica, "sans serif";
442 @ color:#333;
443 @ background-color:white;
444 @ }
445 @
446 @ /* consistent colours */
447 @ h2 {
448 @ color: #333;
449 @ }
450 @ h3 {
451 @ color: #333;
452 @ }
453 @
454 @ /* The project logo in the upper left-hand corner of each page */
455 @ div.logo {
456 @ display: table-cell;
457 @ text-align: left;
458 @ vertical-align: bottom;
459 @ font-weight: bold;
460 @ color: #333;
461 @ white-space: nowrap;
462 @ }
463 @
464 @ /* The page title centered at the top of each page */
465 @ div.title {
466 @ display: table-cell;
467 @ font-size: 2em;
468 @ font-weight: bold;
@@ -469,11 +469,11 @@
469 @ text-align: center;
470 @ color: #333;
471 @ vertical-align: bottom;
472 @ width: 100%;
473 @ }
474 @
475 @ /* The login status message in the top right-hand corner */
476 @ div.status {
477 @ display: table-cell;
478 @ padding-right: 10px;
479 @ text-align: right;
@@ -482,21 +482,21 @@
482 @ color: #333;
483 @ font-size: 0.8em;
484 @ font-weight: bold;
485 @ white-space: nowrap;
486 @ }
487 @
488 @ /* The header across the top of the page */
489 @ div.header {
490 @ margin:10px 0px 10px 0px;
491 @ padding:1px 0px 0px 20px;
492 @ border-style:solid;
493 @ border-color:black;
494 @ border-width:1px 0px;
495 @ background-color:#eee;
496 @ }
497 @
498 @ /* The main menu bar that appears at the top left of the page beneath
499 @ ** the header. Width must be co-ordinated with the container below */
500 @ div.mainmenu {
501 @ float: left;
502 @ margin-left: 10px;
@@ -506,11 +506,11 @@
506 @ padding:5px;
507 @ background-color:#eee;
508 @ border:1px solid #999;
509 @ width:8em;
510 @ }
511 @
512 @ /* Main menu is now a list */
513 @ div.mainmenu ul {
514 @ padding: 0;
515 @ list-style:none;
516 @ }
@@ -521,17 +521,17 @@
521 @ }
522 @ div.mainmenu a:hover {
523 @ color: #eee;
524 @ background-color: #333;
525 @ }
526 @
527 @ /* Container for the sub-menu and content so they don''t spread
528 @ ** out underneath the main menu */
529 @ #container {
530 @ padding-left: 9em;
531 @ }
532 @
533 @ /* The submenu bar that *sometimes* appears below the main menu */
534 @ div.submenu, div.sectionmenu {
535 @ padding: 3px 10px 3px 10px;
536 @ font-size: 0.9em;
537 @ text-align: center;
@@ -548,17 +548,17 @@
548 @ }
549 @ div.submenu a:hover, div.sectionmenu>a.button:hover {
550 @ color: #eee;
551 @ background-color: #333;
552 @ }
553 @
554 @ /* All page content from the bottom of the menu or submenu down to
555 @ ** the footer */
556 @ div.content {
557 @ padding: 2ex 1ex 0ex 2ex;
558 @ }
559 @
560 @ /* Some pages have section dividers */
561 @ div.section {
562 @ margin-bottom: 0px;
563 @ margin-top: 1em;
564 @ padding: 1px 1px 1px 1px;
@@ -569,11 +569,11 @@
569 @ border-width:1px 0px;
570 @ background-color: #eee;
571 @ color: #333;
572 @ white-space: nowrap;
573 @ }
574 @
575 @ /* The "Date" that occurs on the left hand side of timelines */
576 @ div.divider {
577 @ background: #eee;
578 @ border: 2px #999 solid;
579 @ font-size: 1em; font-weight: normal;
@@ -582,27 +582,27 @@
582 @ float: left;
583 @ clear: left;
584 @ color: #333;
585 @ white-space: nowrap;
586 @ }
587 @
588 @ /* The footer at the very bottom of the page */
589 @ div.footer {
590 @ font-size: 0.8em;
591 @ margin-top: 12px;
592 @ padding: 5px 10px 5px 10px;
593 @ text-align: right;
594 @ background-color: #eee;
595 @ color: #555;
596 @ }
597 @
598 @ /* <verbatim> blocks */
599 @ pre.verbatim {
600 @ background-color: #f5f5f5;
601 @ padding: 0.5em;
602 @ }
603 @
604 @ /* The label/value pairs on (for example) the ci page */
605 @ table.label-value th {
606 @ vertical-align: top;
607 @ text-align: right;
608 @ padding: 0.2ex 2ex;
@@ -673,11 +673,11 @@
673
674
675 /*
676 ** Shadow boxes and rounded corners.
677 */
678 static const char zBuiltinSkin4[] =
679 @ REPLACE INTO config(name,mtime,value)
680 @ VALUES('css',now(),'/* General settings for the entire page */
681 @ html {
682 @ min-height: 100%;
683 @ }
@@ -687,28 +687,28 @@
687 @ background-color: white;
688 @ color: #333;
689 @ font-family: Verdana, sans-serif;
690 @ font-size: 0.8em;
691 @ }
692 @
693 @ /* The project logo in the upper left-hand corner of each page */
694 @ div.logo {
695 @ display: table-cell;
696 @ text-align: right;
697 @ vertical-align: bottom;
698 @ font-weight: normal;
699 @ white-space: nowrap;
700 @ }
701 @
702 @ /* Widths */
703 @ div.header, div.mainmenu, div.submenu, div.content, div.footer {
704 @ max-width: 900px;
705 @ margin: auto;
706 @ padding: 3px 20px 3px 20px;
707 @ clear: both;
708 @ }
709 @
710 @ /* The page title at the top of each page */
711 @ div.title {
712 @ display: table-cell;
713 @ padding-left: 10px;
714 @ font-size: 2em;
@@ -719,21 +719,21 @@
719 @ font-family: Verdana, sans-serif;
720 @ font-weight: bold;
721 @ color: #558195;
722 @ text-shadow: 0px 2px 2px #999999;
723 @ }
724 @
725 @ /* The login status message in the top right-hand corner */
726 @ div.status {
727 @ display: table-cell;
728 @ text-align: right;
729 @ vertical-align: bottom;
730 @ color: #333;
731 @ margin-right: -20px;
732 @ white-space: nowrap;
733 @ }
734 @
735 @ /* The main menu bar that appears at the top of the page beneath
736 @ ** the header */
737 @ div.mainmenu {
738 @ text-align: center;
739 @ color: white;
@@ -743,11 +743,11 @@
743 @ padding-top: 8px;
744 @ padding-bottom: 8px;
745 @ background-color: #446979;
746 @ box-shadow: 0px 3px 4px #333333;
747 @ }
748 @
749 @ /* The submenu bar that *sometimes* appears below the main menu */
750 @ div.submenu {
751 @ padding-top:10px;
752 @ padding-bottom:0;
753 @ text-align: right;
@@ -768,24 +768,24 @@
768 @ color: #000;
769 @ font-family: Arial;
770 @ text-decoration: none;
771 @ margin:auto;
772 @ border-radius: 5px;
773 @ background-color: #e0e0e0;
774 @ text-shadow: 0px -1px 0px #eee;
775 @ border: 1px solid #000;
776 @ }
777 @
778 @ div.mainmenu a:hover {
779 @ color: #000;
780 @ background-color: white;
781 @ }
782 @
783 @ div.submenu a:hover, div.sectionmenu>a.button:hover {
784 @ background-color: #c0c0c0;
785 @ }
786 @
787 @ /* All page content from the bottom of the menu or submenu down to
788 @ ** the footer */
789 @ div.content {
790 @ background-color: #fff;
791 @ box-shadow: 0px 3px 4px #999;
@@ -792,12 +792,12 @@
792 @ border-bottom-right-radius: 5px;
793 @ border-bottom-left-radius: 5px;
794 @ padding-bottom: 1em;
795 @ min-height:40%;
796 @ }
797 @
798 @
799 @ /* Some pages have section dividers */
800 @ div.section {
801 @ margin-bottom: 0.5em;
802 @ margin-top: 1em;
803 @ margin-right: auto;
@@ -809,69 +809,69 @@
809 @ border-radius: 5px;
810 @ background-color: #446979;
811 @ box-shadow: 0px 3px 4px #333333;
812 @ white-space: nowrap;
813 @ }
814 @
815 @ /* The "Date" that occurs on the left hand side of timelines */
816 @ div.divider {
817 @ font-size: 1.2em;
818 @ font-family: Georgia, serif;
819 @ font-weight: bold;
820 @ margin-top: 1em;
821 @ white-space: nowrap;
822 @ }
823 @
824 @ /* The footer at the very bottom of the page */
825 @ div.footer {
826 @ font-size: 0.9em;
827 @ text-align: right;
828 @ margin-bottom: 1em;
829 @ color: #666;
830 @ }
831 @
832 @ /* Hyperlink colors in the footer */
833 @ div.footer a { color: white; }
834 @ div.footer a:link { color: white; }
835 @ div.footer a:visited { color: white; }
836 @ div.footer a:hover { background-color: white; color: #558195; }
837 @
838 @ /* <verbatim> blocks */
839 @ pre.verbatim, blockquote pre {
840 @ font-family: Dejavu Sans Mono, Monaco, Lucida Console, monospace;
841 @ background-color: #f3f3f3;
842 @ padding: 0.5em;
843 @ white-space: pre-wrap;
844 @ }
845 @
846 @ blockquote pre {
847 @ border: 1px #000 dashed;
848 @ }
849 @
850 @ /* The label/value pairs on (for example) the ci page */
851 @ table.label-value th {
852 @ vertical-align: top;
853 @ text-align: right;
854 @ padding: 0.2ex 2ex;
855 @ }
856 @
857 @
858 @ table.report {
859 @ border-collapse:collapse;
860 @ border: 1px solid #999;
861 @ margin: 1em 0 1em 0;
862 @ }
863 @
864 @ table.report tr th {
865 @ padding: 3px 5px;
866 @ text-transform: capitalize;
867 @ }
868 @
869 @ table.report tr td {
870 @ padding: 3px 5px;
871 @ }
872 @
873 @ textarea {
874 @ font-size: 1em;
875 @ }');
876 @ REPLACE INTO config(name,mtime,value) VALUES('header',now(),'<html>
877 @ <head>
@@ -952,11 +952,11 @@
952 ** Fossil repository. Additionally, if the Tcl integration feature is
953 ** enabled, the loaded version of Tcl is included, with a hyperlink to the
954 ** official Tcl/Tk web site. The footer also contains a TH1 script block
955 ** to help accomplish these tasks.
956 */
957 static const char zBuiltinSkin5[] =
958 @ REPLACE INTO config(name,mtime,value)
959 @ VALUES('css',now(),'/* General settings for the entire page */
960 @ body {
961 @ margin: 0ex 1ex;
962 @ padding: 0px;
@@ -982,11 +982,11 @@
982 @ font-weight: bold;
983 @ text-align: center;
984 @ padding: 0 0 0 1em;
985 @ color: #558195;
986 @ vertical-align: bottom;
987 @ width: 100%;
988 @ }
989 @
990 @ /* The login status message in the top right-hand corner */
991 @ div.status {
992 @ display: table-cell;
@@ -1000,11 +1000,11 @@
1000 @ }
1001 @
1002 @ /* The header across the top of the page */
1003 @ div.header {
1004 @ display: table;
1005 @ width: 100%;
1006 @ }
1007 @
1008 @ /* The main menu bar that appears at the top of the page beneath
1009 @ ** the header */
1010 @ div.mainmenu {
@@ -1085,11 +1085,11 @@
1085 @ /* Hyperlink colors in the footer */
1086 @ div.footer a { color: white; }
1087 @ div.footer a:link { color: white; }
1088 @ div.footer a:visited { color: white; }
1089 @ div.footer a:hover { background-color: white; color: #558195; }
1090 @
1091 @ /* verbatim blocks */
1092 @ pre.verbatim {
1093 @ background-color: #f5f5f5;
1094 @ padding: 0.5em;
1095 @}
@@ -1397,11 +1397,11 @@
1397 style_header("Skins");
1398 if( zErr ){
1399 @ <p><font color="red">%h(zErr)</font></p>
1400 }
1401 @ <p>A "skin" is a combination of
1402 @ <a href="setup_editcss">CSS</a>,
1403 @ <a href="setup_header">Header</a>,
1404 @ <a href="setup_footer">Footer</a>, and
1405 @ <a href="setup_logo">Logo</a> that determines the look and feel
1406 @ of the web interface.</p>
1407 @
@@ -1411,11 +1411,11 @@
1411 z = aBuiltinSkin[i].zName;
1412 if( fossil_strcmp(aBuiltinSkin[i].zValue, zCurrent)==0 ){
1413 @ <li><p>%h(z).&nbsp;&nbsp; <b>Currently In Use</b></p>
1414 }else{
1415 @ <li><form action="%s(g.zTop)/setup_skin" method="post"><div>
1416 @ %h(z).&nbsp;&nbsp;
1417 @ <input type="hidden" name="sn" value="%h(z)" />
1418 @ <input type="submit" name="load" value="Use This Skin" />
1419 @ </div></form></li>
1420 }
1421 }
@@ -1429,11 +1429,11 @@
1429 const char *zV = db_column_text(&q, 1);
1430 if( fossil_strcmp(zV, zCurrent)==0 ){
1431 @ <li><p>%h(zN).&nbsp;&nbsp; <b>Currently In Use</b></p>
1432 }else{
1433 @ <li><form action="%s(g.zTop)/setup_skin" method="post">
1434 @ %h(zN).&nbsp;&nbsp;
1435 @ <input type="hidden" name="sn" value="%h(zN)">
1436 @ <input type="submit" name="load" value="Use This Skin">
1437 @ <input type="submit" name="del1" value="Delete This Skin">
1438 @ </form></li>
1439 }
1440
+45 -16
--- src/style.c
+++ src/style.c
@@ -47,16 +47,18 @@
4747
*/
4848
static int sideboxUsed = 0;
4949
5050
5151
/*
52
-** List of hyperlinks that need to be resolved by javascript in
52
+** List of hyperlinks and forms that need to be resolved by javascript in
5353
** the footer.
5454
*/
5555
char **aHref = 0;
5656
int nHref = 0;
5757
int nHrefAlloc = 0;
58
+char **aFormAction = 0;
59
+int nFormAction = 0;
5860
5961
/*
6062
** Generate and return a anchor tag like this:
6163
**
6264
** <a href="URL">
@@ -64,11 +66,11 @@
6466
**
6567
** The form of the anchor tag is determined by the g.javascriptHyperlink
6668
** variable. The href="URL" form is used if g.javascriptHyperlink is false.
6769
** If g.javascriptHyperlink is true then the
6870
** id="ID" form is used and javascript is generated in the footer to cause
69
-** href values to be inserted after the page has loaded. If
71
+** href values to be inserted after the page has loaded. If
7072
** g.perm.History is false, then the <a id="ID"> form is still
7173
** generated but the javascript is not generated so the links never
7274
** activate.
7375
**
7476
** Filling in the href="URL" using javascript is a defense against bots.
@@ -119,23 +121,49 @@
119121
aHref = fossil_realloc(aHref, nHrefAlloc*sizeof(aHref[0]));
120122
}
121123
aHref[nHref++] = zUrl;
122124
return mprintf("<a id=%d>", nHref);
123125
}
126
+
127
+/*
128
+** Generate <form method="post" action=ARG>. The ARG value is inserted
129
+** by javascript.
130
+*/
131
+void form_begin(const char *zOtherArgs, const char *zAction, ...){
132
+ char *zLink;
133
+ va_list ap;
134
+ if( zOtherArgs==0 ) zOtherArgs = "";
135
+ va_start(ap, zAction);
136
+ zLink = vmprintf(zAction, ap);
137
+ va_end(ap);
138
+ if( g.perm.Hyperlink && !g.javascriptHyperlink ){
139
+ @ <form method="POST" action="%z(zLink)" %s(zOtherArgs)>
140
+ }else{
141
+ int n;
142
+ aFormAction = fossil_realloc(aFormAction, (nFormAction+1)*sizeof(char*));
143
+ aFormAction[nFormAction++] = zLink;
144
+ n = nFormAction;
145
+ @ <form id="form%d(n)" method="POST" action='%R/login' %s(zOtherArgs)>
146
+ }
147
+}
124148
125149
/*
126150
** Generate javascript that will set the href= attribute on all anchors.
127151
*/
128152
void style_resolve_href(void){
129153
int i;
130
- if( !g.perm.Hyperlink || !g.javascriptHyperlink || nHref==0 ) return;
154
+ if( !g.perm.Hyperlink || !g.javascriptHyperlink ) return;
155
+ if( nHref==0 && nFormAction==0 ) return;
131156
@ <script type="text/JavaScript">
132157
@ /* <![CDATA[ */
133158
@ function u(i,h){gebi(i).href=h;}
134159
for(i=0; i<nHref; i++){
135160
@ u(%d(i+1),"%s(aHref[i])");
136161
}
162
+ for(i=0; i<nFormAction; i++){
163
+ @ gebi("form%d(i+1)").action="%s(aFormAction[i])";
164
+ }
137165
@ /* ]]> */
138166
@ </script>
139167
}
140168
141169
/*
@@ -190,21 +218,21 @@
190218
** Draw the header.
191219
*/
192220
void style_header(const char *zTitleFormat, ...){
193221
va_list ap;
194222
char *zTitle;
195
- const char *zHeader = db_get("header", (char*)zDefaultHeader);
223
+ const char *zHeader = db_get("header", (char*)zDefaultHeader);
196224
login_check_credentials();
197225
198226
va_start(ap, zTitleFormat);
199227
zTitle = vmprintf(zTitleFormat, ap);
200228
va_end(ap);
201
-
229
+
202230
cgi_destination(CGI_HEADER);
203231
204232
@ <!DOCTYPE html>
205
-
233
+
206234
if( g.thTrace ) Th_Trace("BEGIN_HEADER<br />\n", -1);
207235
208236
/* Generate the header up through the main menu */
209237
Th_Store("project_name", db_get("project-name","Unnamed Fossil Project"));
210238
Th_Store("title", zTitle);
@@ -267,11 +295,11 @@
267295
*/
268296
void style_footer(void){
269297
const char *zFooter;
270298
271299
if( !headerHasBeenGenerated ) return;
272
-
300
+
273301
/* Go back and put the submenu at the top of the page. We delay the
274302
** creation of the submenu until the end so that we can add elements
275303
** to the submenu while generating page text.
276304
*/
277305
cgi_destination(CGI_HEADER);
@@ -308,11 +336,11 @@
308336
309337
zFooter = db_get("footer", (char*)zDefaultFooter);
310338
if( g.thTrace ) Th_Trace("BEGIN_FOOTER<br />\n", -1);
311339
Th_Render(zFooter);
312340
if( g.thTrace ) Th_Trace("END_FOOTER<br />\n", -1);
313
-
341
+
314342
/* Render trace log if TH1 tracing is enabled. */
315343
if( g.thTrace ){
316344
cgi_append_content("<span class=\"thTrace\"><hr />\n", -1);
317345
cgi_append_content(blob_str(&g.thLog), blob_size(&g.thLog));
318346
cgi_append_content("</span>\n", -1);
@@ -338,11 +366,11 @@
338366
339367
/* @-comment: // */
340368
/*
341369
** The default page header.
342370
*/
343
-const char zDefaultHeader[] =
371
+const char zDefaultHeader[] =
344372
@ <html>
345373
@ <head>
346374
@ <base href="$baseurl/$current_page" />
347375
@ <title>$<project_name>: $<title></title>
348376
@ <link rel="alternate" type="application/rss+xml" title="RSS Feed"
@@ -397,11 +425,11 @@
397425
;
398426
399427
/*
400428
** The default page footer
401429
*/
402
-const char zDefaultFooter[] =
430
+const char zDefaultFooter[] =
403431
@ <div class="footer">
404432
@ Fossil version $release_version $manifest_version $manifest_date
405433
@ </div>
406434
@ </body></html>
407435
;
@@ -411,11 +439,11 @@
411439
** It's assembled by different strings for each class.
412440
** The default css conatains all definitions.
413441
** The style sheet, send to the client only contains the ones,
414442
** not defined in the user defined css.
415443
*/
416
-const char zDefaultCSS[] =
444
+const char zDefaultCSS[] =
417445
@ /* General settings for the entire page */
418446
@ body {
419447
@ margin: 0ex 1ex;
420448
@ padding: 0px;
421449
@ background-color: white;
@@ -440,11 +468,11 @@
440468
@ font-weight: bold;
441469
@ text-align: center;
442470
@ padding: 0 0 0 1em;
443471
@ color: #558195;
444472
@ vertical-align: bottom;
445
-@ width: 100% ;
473
+@ width: 100%;
446474
@ }
447475
@
448476
@ /* The login status message in the top right-hand corner */
449477
@ div.status {
450478
@ display: table-cell;
@@ -458,11 +486,11 @@
458486
@ }
459487
@
460488
@ /* The header across the top of the page */
461489
@ div.header {
462490
@ display: table;
463
-@ width: 100% ;
491
+@ width: 100%;
464492
@ }
465493
@
466494
@ /* The main menu bar that appears at the top of the page beneath
467495
@ ** the header */
468496
@ div.mainmenu {
@@ -543,11 +571,11 @@
543571
@ /* Hyperlink colors in the footer */
544572
@ div.footer a { color: white; }
545573
@ div.footer a:link { color: white; }
546574
@ div.footer a:visited { color: white; }
547575
@ div.footer a:hover { background-color: white; color: #558195; }
548
-@
576
+@
549577
@ /* verbatim blocks */
550578
@ pre.verbatim {
551579
@ background-color: #f5f5f5;
552580
@ padding: 0.5em;
553581
@}
@@ -660,16 +688,16 @@
660688
@ text-decoration: line-through;
661689
},
662690
{ "table.browser",
663691
"format for the file display table",
664692
@ /* the format for wiki errors */
665
- @ width: 100% ;
693
+ @ width: 100%;
666694
@ border: 0;
667695
},
668696
{ "td.browser",
669697
"format for cells in the file browser",
670
- @ width: 24% ;
698
+ @ width: 24%;
671699
@ vertical-align: top;
672700
},
673701
{ "ul.browser",
674702
"format for the list in the file browser",
675703
@ margin-left: 0.5em;
@@ -684,10 +712,11 @@
684712
@ margin-top: 10px;
685713
},
686714
{ "div.captcha",
687715
"captcha display options",
688716
@ text-align: center;
717
+ @ padding: 1ex;
689718
},
690719
{ "table.captcha",
691720
"format for the layout table, used for the captcha display",
692721
@ margin: auto;
693722
@ padding: 10px;
694723
--- src/style.c
+++ src/style.c
@@ -47,16 +47,18 @@
47 */
48 static int sideboxUsed = 0;
49
50
51 /*
52 ** List of hyperlinks that need to be resolved by javascript in
53 ** the footer.
54 */
55 char **aHref = 0;
56 int nHref = 0;
57 int nHrefAlloc = 0;
 
 
58
59 /*
60 ** Generate and return a anchor tag like this:
61 **
62 ** <a href="URL">
@@ -64,11 +66,11 @@
64 **
65 ** The form of the anchor tag is determined by the g.javascriptHyperlink
66 ** variable. The href="URL" form is used if g.javascriptHyperlink is false.
67 ** If g.javascriptHyperlink is true then the
68 ** id="ID" form is used and javascript is generated in the footer to cause
69 ** href values to be inserted after the page has loaded. If
70 ** g.perm.History is false, then the <a id="ID"> form is still
71 ** generated but the javascript is not generated so the links never
72 ** activate.
73 **
74 ** Filling in the href="URL" using javascript is a defense against bots.
@@ -119,23 +121,49 @@
119 aHref = fossil_realloc(aHref, nHrefAlloc*sizeof(aHref[0]));
120 }
121 aHref[nHref++] = zUrl;
122 return mprintf("<a id=%d>", nHref);
123 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
124
125 /*
126 ** Generate javascript that will set the href= attribute on all anchors.
127 */
128 void style_resolve_href(void){
129 int i;
130 if( !g.perm.Hyperlink || !g.javascriptHyperlink || nHref==0 ) return;
 
131 @ <script type="text/JavaScript">
132 @ /* <![CDATA[ */
133 @ function u(i,h){gebi(i).href=h;}
134 for(i=0; i<nHref; i++){
135 @ u(%d(i+1),"%s(aHref[i])");
136 }
 
 
 
137 @ /* ]]> */
138 @ </script>
139 }
140
141 /*
@@ -190,21 +218,21 @@
190 ** Draw the header.
191 */
192 void style_header(const char *zTitleFormat, ...){
193 va_list ap;
194 char *zTitle;
195 const char *zHeader = db_get("header", (char*)zDefaultHeader);
196 login_check_credentials();
197
198 va_start(ap, zTitleFormat);
199 zTitle = vmprintf(zTitleFormat, ap);
200 va_end(ap);
201
202 cgi_destination(CGI_HEADER);
203
204 @ <!DOCTYPE html>
205
206 if( g.thTrace ) Th_Trace("BEGIN_HEADER<br />\n", -1);
207
208 /* Generate the header up through the main menu */
209 Th_Store("project_name", db_get("project-name","Unnamed Fossil Project"));
210 Th_Store("title", zTitle);
@@ -267,11 +295,11 @@
267 */
268 void style_footer(void){
269 const char *zFooter;
270
271 if( !headerHasBeenGenerated ) return;
272
273 /* Go back and put the submenu at the top of the page. We delay the
274 ** creation of the submenu until the end so that we can add elements
275 ** to the submenu while generating page text.
276 */
277 cgi_destination(CGI_HEADER);
@@ -308,11 +336,11 @@
308
309 zFooter = db_get("footer", (char*)zDefaultFooter);
310 if( g.thTrace ) Th_Trace("BEGIN_FOOTER<br />\n", -1);
311 Th_Render(zFooter);
312 if( g.thTrace ) Th_Trace("END_FOOTER<br />\n", -1);
313
314 /* Render trace log if TH1 tracing is enabled. */
315 if( g.thTrace ){
316 cgi_append_content("<span class=\"thTrace\"><hr />\n", -1);
317 cgi_append_content(blob_str(&g.thLog), blob_size(&g.thLog));
318 cgi_append_content("</span>\n", -1);
@@ -338,11 +366,11 @@
338
339 /* @-comment: // */
340 /*
341 ** The default page header.
342 */
343 const char zDefaultHeader[] =
344 @ <html>
345 @ <head>
346 @ <base href="$baseurl/$current_page" />
347 @ <title>$<project_name>: $<title></title>
348 @ <link rel="alternate" type="application/rss+xml" title="RSS Feed"
@@ -397,11 +425,11 @@
397 ;
398
399 /*
400 ** The default page footer
401 */
402 const char zDefaultFooter[] =
403 @ <div class="footer">
404 @ Fossil version $release_version $manifest_version $manifest_date
405 @ </div>
406 @ </body></html>
407 ;
@@ -411,11 +439,11 @@
411 ** It's assembled by different strings for each class.
412 ** The default css conatains all definitions.
413 ** The style sheet, send to the client only contains the ones,
414 ** not defined in the user defined css.
415 */
416 const char zDefaultCSS[] =
417 @ /* General settings for the entire page */
418 @ body {
419 @ margin: 0ex 1ex;
420 @ padding: 0px;
421 @ background-color: white;
@@ -440,11 +468,11 @@
440 @ font-weight: bold;
441 @ text-align: center;
442 @ padding: 0 0 0 1em;
443 @ color: #558195;
444 @ vertical-align: bottom;
445 @ width: 100% ;
446 @ }
447 @
448 @ /* The login status message in the top right-hand corner */
449 @ div.status {
450 @ display: table-cell;
@@ -458,11 +486,11 @@
458 @ }
459 @
460 @ /* The header across the top of the page */
461 @ div.header {
462 @ display: table;
463 @ width: 100% ;
464 @ }
465 @
466 @ /* The main menu bar that appears at the top of the page beneath
467 @ ** the header */
468 @ div.mainmenu {
@@ -543,11 +571,11 @@
543 @ /* Hyperlink colors in the footer */
544 @ div.footer a { color: white; }
545 @ div.footer a:link { color: white; }
546 @ div.footer a:visited { color: white; }
547 @ div.footer a:hover { background-color: white; color: #558195; }
548 @
549 @ /* verbatim blocks */
550 @ pre.verbatim {
551 @ background-color: #f5f5f5;
552 @ padding: 0.5em;
553 @}
@@ -660,16 +688,16 @@
660 @ text-decoration: line-through;
661 },
662 { "table.browser",
663 "format for the file display table",
664 @ /* the format for wiki errors */
665 @ width: 100% ;
666 @ border: 0;
667 },
668 { "td.browser",
669 "format for cells in the file browser",
670 @ width: 24% ;
671 @ vertical-align: top;
672 },
673 { "ul.browser",
674 "format for the list in the file browser",
675 @ margin-left: 0.5em;
@@ -684,10 +712,11 @@
684 @ margin-top: 10px;
685 },
686 { "div.captcha",
687 "captcha display options",
688 @ text-align: center;
 
689 },
690 { "table.captcha",
691 "format for the layout table, used for the captcha display",
692 @ margin: auto;
693 @ padding: 10px;
694
--- src/style.c
+++ src/style.c
@@ -47,16 +47,18 @@
47 */
48 static int sideboxUsed = 0;
49
50
51 /*
52 ** List of hyperlinks and forms that need to be resolved by javascript in
53 ** the footer.
54 */
55 char **aHref = 0;
56 int nHref = 0;
57 int nHrefAlloc = 0;
58 char **aFormAction = 0;
59 int nFormAction = 0;
60
61 /*
62 ** Generate and return a anchor tag like this:
63 **
64 ** <a href="URL">
@@ -64,11 +66,11 @@
66 **
67 ** The form of the anchor tag is determined by the g.javascriptHyperlink
68 ** variable. The href="URL" form is used if g.javascriptHyperlink is false.
69 ** If g.javascriptHyperlink is true then the
70 ** id="ID" form is used and javascript is generated in the footer to cause
71 ** href values to be inserted after the page has loaded. If
72 ** g.perm.History is false, then the <a id="ID"> form is still
73 ** generated but the javascript is not generated so the links never
74 ** activate.
75 **
76 ** Filling in the href="URL" using javascript is a defense against bots.
@@ -119,23 +121,49 @@
121 aHref = fossil_realloc(aHref, nHrefAlloc*sizeof(aHref[0]));
122 }
123 aHref[nHref++] = zUrl;
124 return mprintf("<a id=%d>", nHref);
125 }
126
127 /*
128 ** Generate <form method="post" action=ARG>. The ARG value is inserted
129 ** by javascript.
130 */
131 void form_begin(const char *zOtherArgs, const char *zAction, ...){
132 char *zLink;
133 va_list ap;
134 if( zOtherArgs==0 ) zOtherArgs = "";
135 va_start(ap, zAction);
136 zLink = vmprintf(zAction, ap);
137 va_end(ap);
138 if( g.perm.Hyperlink && !g.javascriptHyperlink ){
139 @ <form method="POST" action="%z(zLink)" %s(zOtherArgs)>
140 }else{
141 int n;
142 aFormAction = fossil_realloc(aFormAction, (nFormAction+1)*sizeof(char*));
143 aFormAction[nFormAction++] = zLink;
144 n = nFormAction;
145 @ <form id="form%d(n)" method="POST" action='%R/login' %s(zOtherArgs)>
146 }
147 }
148
149 /*
150 ** Generate javascript that will set the href= attribute on all anchors.
151 */
152 void style_resolve_href(void){
153 int i;
154 if( !g.perm.Hyperlink || !g.javascriptHyperlink ) return;
155 if( nHref==0 && nFormAction==0 ) return;
156 @ <script type="text/JavaScript">
157 @ /* <![CDATA[ */
158 @ function u(i,h){gebi(i).href=h;}
159 for(i=0; i<nHref; i++){
160 @ u(%d(i+1),"%s(aHref[i])");
161 }
162 for(i=0; i<nFormAction; i++){
163 @ gebi("form%d(i+1)").action="%s(aFormAction[i])";
164 }
165 @ /* ]]> */
166 @ </script>
167 }
168
169 /*
@@ -190,21 +218,21 @@
218 ** Draw the header.
219 */
220 void style_header(const char *zTitleFormat, ...){
221 va_list ap;
222 char *zTitle;
223 const char *zHeader = db_get("header", (char*)zDefaultHeader);
224 login_check_credentials();
225
226 va_start(ap, zTitleFormat);
227 zTitle = vmprintf(zTitleFormat, ap);
228 va_end(ap);
229
230 cgi_destination(CGI_HEADER);
231
232 @ <!DOCTYPE html>
233
234 if( g.thTrace ) Th_Trace("BEGIN_HEADER<br />\n", -1);
235
236 /* Generate the header up through the main menu */
237 Th_Store("project_name", db_get("project-name","Unnamed Fossil Project"));
238 Th_Store("title", zTitle);
@@ -267,11 +295,11 @@
295 */
296 void style_footer(void){
297 const char *zFooter;
298
299 if( !headerHasBeenGenerated ) return;
300
301 /* Go back and put the submenu at the top of the page. We delay the
302 ** creation of the submenu until the end so that we can add elements
303 ** to the submenu while generating page text.
304 */
305 cgi_destination(CGI_HEADER);
@@ -308,11 +336,11 @@
336
337 zFooter = db_get("footer", (char*)zDefaultFooter);
338 if( g.thTrace ) Th_Trace("BEGIN_FOOTER<br />\n", -1);
339 Th_Render(zFooter);
340 if( g.thTrace ) Th_Trace("END_FOOTER<br />\n", -1);
341
342 /* Render trace log if TH1 tracing is enabled. */
343 if( g.thTrace ){
344 cgi_append_content("<span class=\"thTrace\"><hr />\n", -1);
345 cgi_append_content(blob_str(&g.thLog), blob_size(&g.thLog));
346 cgi_append_content("</span>\n", -1);
@@ -338,11 +366,11 @@
366
367 /* @-comment: // */
368 /*
369 ** The default page header.
370 */
371 const char zDefaultHeader[] =
372 @ <html>
373 @ <head>
374 @ <base href="$baseurl/$current_page" />
375 @ <title>$<project_name>: $<title></title>
376 @ <link rel="alternate" type="application/rss+xml" title="RSS Feed"
@@ -397,11 +425,11 @@
425 ;
426
427 /*
428 ** The default page footer
429 */
430 const char zDefaultFooter[] =
431 @ <div class="footer">
432 @ Fossil version $release_version $manifest_version $manifest_date
433 @ </div>
434 @ </body></html>
435 ;
@@ -411,11 +439,11 @@
439 ** It's assembled by different strings for each class.
440 ** The default css conatains all definitions.
441 ** The style sheet, send to the client only contains the ones,
442 ** not defined in the user defined css.
443 */
444 const char zDefaultCSS[] =
445 @ /* General settings for the entire page */
446 @ body {
447 @ margin: 0ex 1ex;
448 @ padding: 0px;
449 @ background-color: white;
@@ -440,11 +468,11 @@
468 @ font-weight: bold;
469 @ text-align: center;
470 @ padding: 0 0 0 1em;
471 @ color: #558195;
472 @ vertical-align: bottom;
473 @ width: 100%;
474 @ }
475 @
476 @ /* The login status message in the top right-hand corner */
477 @ div.status {
478 @ display: table-cell;
@@ -458,11 +486,11 @@
486 @ }
487 @
488 @ /* The header across the top of the page */
489 @ div.header {
490 @ display: table;
491 @ width: 100%;
492 @ }
493 @
494 @ /* The main menu bar that appears at the top of the page beneath
495 @ ** the header */
496 @ div.mainmenu {
@@ -543,11 +571,11 @@
571 @ /* Hyperlink colors in the footer */
572 @ div.footer a { color: white; }
573 @ div.footer a:link { color: white; }
574 @ div.footer a:visited { color: white; }
575 @ div.footer a:hover { background-color: white; color: #558195; }
576 @
577 @ /* verbatim blocks */
578 @ pre.verbatim {
579 @ background-color: #f5f5f5;
580 @ padding: 0.5em;
581 @}
@@ -660,16 +688,16 @@
688 @ text-decoration: line-through;
689 },
690 { "table.browser",
691 "format for the file display table",
692 @ /* the format for wiki errors */
693 @ width: 100%;
694 @ border: 0;
695 },
696 { "td.browser",
697 "format for cells in the file browser",
698 @ width: 24%;
699 @ vertical-align: top;
700 },
701 { "ul.browser",
702 "format for the list in the file browser",
703 @ margin-left: 0.5em;
@@ -684,10 +712,11 @@
712 @ margin-top: 10px;
713 },
714 { "div.captcha",
715 "captcha display options",
716 @ text-align: center;
717 @ padding: 1ex;
718 },
719 { "table.captcha",
720 "format for the layout table, used for the captcha display",
721 @ margin: auto;
722 @ padding: 10px;
723
+34 -32
--- src/sync.c
+++ src/sync.c
@@ -19,19 +19,10 @@
1919
*/
2020
#include "config.h"
2121
#include "sync.h"
2222
#include <assert.h>
2323
24
-#if INTERFACE
25
-/*
26
-** Flags used to determine which direction(s) an autosync goes in.
27
-*/
28
-#define AUTOSYNC_PUSH 1
29
-#define AUTOSYNC_PULL 2
30
-
31
-#endif /* INTERFACE */
32
-
3324
/*
3425
** If the repository is configured for autosyncing, then do an
3526
** autosync. This will be a pull if the argument is true or a push
3627
** if the argument is false.
3728
**
@@ -44,16 +35,16 @@
4435
int rc;
4536
int configSync = 0; /* configuration changes transferred */
4637
if( g.fNoSync ){
4738
return 0;
4839
}
49
- if( flags==AUTOSYNC_PUSH && db_get_boolean("dont-push",0) ){
40
+ if( flags==SYNC_PUSH && db_get_boolean("dont-push",0) ){
5041
return 0;
5142
}
5243
zAutosync = db_get("autosync", 0);
5344
if( zAutosync ){
54
- if( (flags & AUTOSYNC_PUSH)!=0 && memcmp(zAutosync,"pull",4)==0 ){
45
+ if( (flags & SYNC_PUSH)!=0 && memcmp(zAutosync,"pull",4)==0 ){
5546
return 0; /* Do not auto-push when autosync=pullonly */
5647
}
5748
if( is_false(zAutosync) ){
5849
return 0; /* Autosync is completely off */
5950
}
@@ -79,13 +70,14 @@
7970
** autosync, or something?
8071
*/
8172
configSync = CONFIGSET_SHUN;
8273
}
8374
#endif
75
+ if( find_option("verbose","v",0)!=0 ) flags |= SYNC_VERBOSE;
8476
fossil_print("Autosync: %s\n", g.urlCanonical);
8577
url_enable_proxy("via proxy: ");
86
- rc = client_sync((flags & AUTOSYNC_PUSH)!=0, 1, 0, 0, configSync, 0);
78
+ rc = client_sync(flags, configSync, 0);
8779
if( rc ) fossil_warning("Autosync failed");
8880
return rc;
8981
}
9082
9183
/*
@@ -92,17 +84,22 @@
9284
** This routine processes the command-line argument for push, pull,
9385
** and sync. If a command-line argument is given, that is the URL
9486
** of a server to sync against. If no argument is given, use the
9587
** most recently synced URL. Remember the current URL for next time.
9688
*/
97
-static void process_sync_args(int *pConfigSync, int *pPrivate){
89
+static void process_sync_args(unsigned *pConfigFlags, unsigned *pSyncFlags){
9890
const char *zUrl = 0;
9991
const char *zPw = 0;
100
- int configSync = 0;
92
+ unsigned configSync = 0;
10193
int urlOptional = find_option("autourl",0,0)!=0;
10294
g.dontKeepUrl = find_option("once",0,0)!=0;
103
- *pPrivate = find_option("private",0,0)!=0;
95
+ if( find_option("private",0,0)!=0 ){
96
+ *pSyncFlags |= SYNC_PRIVATE;
97
+ }
98
+ if( find_option("verbose","v",0)!=0 ){
99
+ *pSyncFlags |= SYNC_VERBOSE;
100
+ }
104101
url_proxy_options();
105102
db_find_and_open_repository(0, 0);
106103
db_open_config(0);
107104
if( g.argc==2 ){
108105
zUrl = db_get("last-sync-url", 0);
@@ -127,14 +124,20 @@
127124
db_set("last-sync-url", g.urlCanonical, 0);
128125
if( g.urlPasswd ) db_set("last-sync-pw", obscure(g.urlPasswd), 0);
129126
}
130127
user_select();
131128
if( g.argc==2 ){
132
- fossil_print("Server: %s\n", g.urlCanonical);
129
+ if( ((*pSyncFlags) & (SYNC_PUSH|SYNC_PULL))==(SYNC_PUSH|SYNC_PULL) ){
130
+ fossil_print("Sync with %s\n", g.urlCanonical);
131
+ }else if( (*pSyncFlags) & SYNC_PUSH ){
132
+ fossil_print("Push to %s\n", g.urlCanonical);
133
+ }else if( (*pSyncFlags) & SYNC_PULL ){
134
+ fossil_print("Pull from %s\n", g.urlCanonical);
135
+ }
133136
}
134137
url_enable_proxy("via proxy: ");
135
- *pConfigSync = configSync;
138
+ *pConfigFlags |= configSync;
136139
}
137140
138141
/*
139142
** COMMAND: pull
140143
**
@@ -156,14 +159,14 @@
156159
** remote repository.
157160
**
158161
** See also: clone, push, sync, remote-url
159162
*/
160163
void pull_cmd(void){
161
- int syncFlags;
162
- int bPrivate;
163
- process_sync_args(&syncFlags, &bPrivate);
164
- client_sync(0,1,0,bPrivate,syncFlags,0);
164
+ unsigned configFlags = 0;
165
+ unsigned syncFlags = SYNC_PULL;
166
+ process_sync_args(&configFlags, &syncFlags);
167
+ client_sync(syncFlags, configFlags, 0);
165168
}
166169
167170
/*
168171
** COMMAND: push
169172
**
@@ -185,17 +188,17 @@
185188
** remote repository.
186189
**
187190
** See also: clone, pull, sync, remote-url
188191
*/
189192
void push_cmd(void){
190
- int syncFlags;
191
- int bPrivate;
192
- process_sync_args(&syncFlags, &bPrivate);
193
+ unsigned configFlags = 0;
194
+ unsigned syncFlags = SYNC_PUSH;
195
+ process_sync_args(&configFlags, &syncFlags);
193196
if( db_get_boolean("dont-push",0) ){
194197
fossil_fatal("pushing is prohibited: the 'dont-push' option is set");
195198
}
196
- client_sync(1,0,0,bPrivate,0,0);
199
+ client_sync(syncFlags, 0, 0);
197200
}
198201
199202
200203
/*
201204
** COMMAND: sync
@@ -223,17 +226,16 @@
223226
** remote repository.
224227
**
225228
** See also: clone, push, pull, remote-url
226229
*/
227230
void sync_cmd(void){
228
- int syncFlags;
229
- int bPrivate;
230
- int pushFlag = 1;
231
- process_sync_args(&syncFlags, &bPrivate);
232
- if( db_get_boolean("dont-push",0) ) pushFlag = 0;
233
- client_sync(pushFlag,1,0,bPrivate,syncFlags,0);
234
- if( pushFlag==0 ){
231
+ unsigned configFlags = 0;
232
+ unsigned syncFlags = SYNC_PUSH|SYNC_PULL;
233
+ process_sync_args(&configFlags, &syncFlags);
234
+ if( db_get_boolean("dont-push",0) ) syncFlags &= ~SYNC_PUSH;
235
+ client_sync(syncFlags, configFlags, 0);
236
+ if( (syncFlags & SYNC_PUSH)==0 ){
235237
fossil_warning("pull only: the 'dont-push' option is set");
236238
}
237239
}
238240
239241
/*
240242
--- src/sync.c
+++ src/sync.c
@@ -19,19 +19,10 @@
19 */
20 #include "config.h"
21 #include "sync.h"
22 #include <assert.h>
23
24 #if INTERFACE
25 /*
26 ** Flags used to determine which direction(s) an autosync goes in.
27 */
28 #define AUTOSYNC_PUSH 1
29 #define AUTOSYNC_PULL 2
30
31 #endif /* INTERFACE */
32
33 /*
34 ** If the repository is configured for autosyncing, then do an
35 ** autosync. This will be a pull if the argument is true or a push
36 ** if the argument is false.
37 **
@@ -44,16 +35,16 @@
44 int rc;
45 int configSync = 0; /* configuration changes transferred */
46 if( g.fNoSync ){
47 return 0;
48 }
49 if( flags==AUTOSYNC_PUSH && db_get_boolean("dont-push",0) ){
50 return 0;
51 }
52 zAutosync = db_get("autosync", 0);
53 if( zAutosync ){
54 if( (flags & AUTOSYNC_PUSH)!=0 && memcmp(zAutosync,"pull",4)==0 ){
55 return 0; /* Do not auto-push when autosync=pullonly */
56 }
57 if( is_false(zAutosync) ){
58 return 0; /* Autosync is completely off */
59 }
@@ -79,13 +70,14 @@
79 ** autosync, or something?
80 */
81 configSync = CONFIGSET_SHUN;
82 }
83 #endif
 
84 fossil_print("Autosync: %s\n", g.urlCanonical);
85 url_enable_proxy("via proxy: ");
86 rc = client_sync((flags & AUTOSYNC_PUSH)!=0, 1, 0, 0, configSync, 0);
87 if( rc ) fossil_warning("Autosync failed");
88 return rc;
89 }
90
91 /*
@@ -92,17 +84,22 @@
92 ** This routine processes the command-line argument for push, pull,
93 ** and sync. If a command-line argument is given, that is the URL
94 ** of a server to sync against. If no argument is given, use the
95 ** most recently synced URL. Remember the current URL for next time.
96 */
97 static void process_sync_args(int *pConfigSync, int *pPrivate){
98 const char *zUrl = 0;
99 const char *zPw = 0;
100 int configSync = 0;
101 int urlOptional = find_option("autourl",0,0)!=0;
102 g.dontKeepUrl = find_option("once",0,0)!=0;
103 *pPrivate = find_option("private",0,0)!=0;
 
 
 
 
 
104 url_proxy_options();
105 db_find_and_open_repository(0, 0);
106 db_open_config(0);
107 if( g.argc==2 ){
108 zUrl = db_get("last-sync-url", 0);
@@ -127,14 +124,20 @@
127 db_set("last-sync-url", g.urlCanonical, 0);
128 if( g.urlPasswd ) db_set("last-sync-pw", obscure(g.urlPasswd), 0);
129 }
130 user_select();
131 if( g.argc==2 ){
132 fossil_print("Server: %s\n", g.urlCanonical);
 
 
 
 
 
 
133 }
134 url_enable_proxy("via proxy: ");
135 *pConfigSync = configSync;
136 }
137
138 /*
139 ** COMMAND: pull
140 **
@@ -156,14 +159,14 @@
156 ** remote repository.
157 **
158 ** See also: clone, push, sync, remote-url
159 */
160 void pull_cmd(void){
161 int syncFlags;
162 int bPrivate;
163 process_sync_args(&syncFlags, &bPrivate);
164 client_sync(0,1,0,bPrivate,syncFlags,0);
165 }
166
167 /*
168 ** COMMAND: push
169 **
@@ -185,17 +188,17 @@
185 ** remote repository.
186 **
187 ** See also: clone, pull, sync, remote-url
188 */
189 void push_cmd(void){
190 int syncFlags;
191 int bPrivate;
192 process_sync_args(&syncFlags, &bPrivate);
193 if( db_get_boolean("dont-push",0) ){
194 fossil_fatal("pushing is prohibited: the 'dont-push' option is set");
195 }
196 client_sync(1,0,0,bPrivate,0,0);
197 }
198
199
200 /*
201 ** COMMAND: sync
@@ -223,17 +226,16 @@
223 ** remote repository.
224 **
225 ** See also: clone, push, pull, remote-url
226 */
227 void sync_cmd(void){
228 int syncFlags;
229 int bPrivate;
230 int pushFlag = 1;
231 process_sync_args(&syncFlags, &bPrivate);
232 if( db_get_boolean("dont-push",0) ) pushFlag = 0;
233 client_sync(pushFlag,1,0,bPrivate,syncFlags,0);
234 if( pushFlag==0 ){
235 fossil_warning("pull only: the 'dont-push' option is set");
236 }
237 }
238
239 /*
240
--- src/sync.c
+++ src/sync.c
@@ -19,19 +19,10 @@
19 */
20 #include "config.h"
21 #include "sync.h"
22 #include <assert.h>
23
 
 
 
 
 
 
 
 
 
24 /*
25 ** If the repository is configured for autosyncing, then do an
26 ** autosync. This will be a pull if the argument is true or a push
27 ** if the argument is false.
28 **
@@ -44,16 +35,16 @@
35 int rc;
36 int configSync = 0; /* configuration changes transferred */
37 if( g.fNoSync ){
38 return 0;
39 }
40 if( flags==SYNC_PUSH && db_get_boolean("dont-push",0) ){
41 return 0;
42 }
43 zAutosync = db_get("autosync", 0);
44 if( zAutosync ){
45 if( (flags & SYNC_PUSH)!=0 && memcmp(zAutosync,"pull",4)==0 ){
46 return 0; /* Do not auto-push when autosync=pullonly */
47 }
48 if( is_false(zAutosync) ){
49 return 0; /* Autosync is completely off */
50 }
@@ -79,13 +70,14 @@
70 ** autosync, or something?
71 */
72 configSync = CONFIGSET_SHUN;
73 }
74 #endif
75 if( find_option("verbose","v",0)!=0 ) flags |= SYNC_VERBOSE;
76 fossil_print("Autosync: %s\n", g.urlCanonical);
77 url_enable_proxy("via proxy: ");
78 rc = client_sync(flags, configSync, 0);
79 if( rc ) fossil_warning("Autosync failed");
80 return rc;
81 }
82
83 /*
@@ -92,17 +84,22 @@
84 ** This routine processes the command-line argument for push, pull,
85 ** and sync. If a command-line argument is given, that is the URL
86 ** of a server to sync against. If no argument is given, use the
87 ** most recently synced URL. Remember the current URL for next time.
88 */
89 static void process_sync_args(unsigned *pConfigFlags, unsigned *pSyncFlags){
90 const char *zUrl = 0;
91 const char *zPw = 0;
92 unsigned configSync = 0;
93 int urlOptional = find_option("autourl",0,0)!=0;
94 g.dontKeepUrl = find_option("once",0,0)!=0;
95 if( find_option("private",0,0)!=0 ){
96 *pSyncFlags |= SYNC_PRIVATE;
97 }
98 if( find_option("verbose","v",0)!=0 ){
99 *pSyncFlags |= SYNC_VERBOSE;
100 }
101 url_proxy_options();
102 db_find_and_open_repository(0, 0);
103 db_open_config(0);
104 if( g.argc==2 ){
105 zUrl = db_get("last-sync-url", 0);
@@ -127,14 +124,20 @@
124 db_set("last-sync-url", g.urlCanonical, 0);
125 if( g.urlPasswd ) db_set("last-sync-pw", obscure(g.urlPasswd), 0);
126 }
127 user_select();
128 if( g.argc==2 ){
129 if( ((*pSyncFlags) & (SYNC_PUSH|SYNC_PULL))==(SYNC_PUSH|SYNC_PULL) ){
130 fossil_print("Sync with %s\n", g.urlCanonical);
131 }else if( (*pSyncFlags) & SYNC_PUSH ){
132 fossil_print("Push to %s\n", g.urlCanonical);
133 }else if( (*pSyncFlags) & SYNC_PULL ){
134 fossil_print("Pull from %s\n", g.urlCanonical);
135 }
136 }
137 url_enable_proxy("via proxy: ");
138 *pConfigFlags |= configSync;
139 }
140
141 /*
142 ** COMMAND: pull
143 **
@@ -156,14 +159,14 @@
159 ** remote repository.
160 **
161 ** See also: clone, push, sync, remote-url
162 */
163 void pull_cmd(void){
164 unsigned configFlags = 0;
165 unsigned syncFlags = SYNC_PULL;
166 process_sync_args(&configFlags, &syncFlags);
167 client_sync(syncFlags, configFlags, 0);
168 }
169
170 /*
171 ** COMMAND: push
172 **
@@ -185,17 +188,17 @@
188 ** remote repository.
189 **
190 ** See also: clone, pull, sync, remote-url
191 */
192 void push_cmd(void){
193 unsigned configFlags = 0;
194 unsigned syncFlags = SYNC_PUSH;
195 process_sync_args(&configFlags, &syncFlags);
196 if( db_get_boolean("dont-push",0) ){
197 fossil_fatal("pushing is prohibited: the 'dont-push' option is set");
198 }
199 client_sync(syncFlags, 0, 0);
200 }
201
202
203 /*
204 ** COMMAND: sync
@@ -223,17 +226,16 @@
226 ** remote repository.
227 **
228 ** See also: clone, push, pull, remote-url
229 */
230 void sync_cmd(void){
231 unsigned configFlags = 0;
232 unsigned syncFlags = SYNC_PUSH|SYNC_PULL;
233 process_sync_args(&configFlags, &syncFlags);
234 if( db_get_boolean("dont-push",0) ) syncFlags &= ~SYNC_PUSH;
235 client_sync(syncFlags, configFlags, 0);
236 if( (syncFlags & SYNC_PUSH)==0 ){
 
237 fossil_warning("pull only: the 'dont-push' option is set");
238 }
239 }
240
241 /*
242
+133 -18
--- src/th_main.c
+++ src/th_main.c
@@ -77,14 +77,33 @@
7777
if( argc!=2 ){
7878
return Th_WrongNumArgs(interp, "enable_output BOOLEAN");
7979
}
8080
return Th_ToInt(interp, argv[1], argl[1], &enableOutput);
8181
}
82
+
83
+/*
84
+** Return a name for a TH1 return code.
85
+*/
86
+const char *Th_ReturnCodeName(int rc){
87
+ static char zRc[32];
88
+ switch( rc ){
89
+ case TH_OK: return "TH_OK";
90
+ case TH_ERROR: return "TH_ERROR";
91
+ case TH_BREAK: return "TH_BREAK";
92
+ case TH_RETURN: return "TH_RETURN";
93
+ case TH_CONTINUE: return "TH_CONTINUE";
94
+ default: {
95
+ sqlite3_snprintf(sizeof(zRc),zRc,"return code %d",rc);
96
+ }
97
+ }
98
+ return zRc;
99
+}
82100
83101
/*
84102
** Send text to the appropriate output: Either to the console
85
-** or to the CGI reply buffer.
103
+** or to the CGI reply buffer. Escape all characters with special
104
+** meaning to HTML if the encode parameter is true.
86105
*/
87106
static void sendText(const char *z, int n, int encode){
88107
if( enableOutput && n ){
89108
if( n<0 ) n = strlen(z);
90109
if( encode ){
@@ -98,16 +117,25 @@
98117
fflush(stdout);
99118
}
100119
if( encode ) free((char*)z);
101120
}
102121
}
122
+
123
+static void sendError(const char *z, int n, int forceCgi){
124
+ if( forceCgi || g.cgiOutput ){
125
+ sendText("<hr><p class=\"thmainError\">", -1, 0);
126
+ }
127
+ sendText("ERROR: ", -1, 0);
128
+ sendText((char*)z, n, 1);
129
+ sendText(forceCgi || g.cgiOutput ? "</p>" : "\n", -1, 0);
130
+}
103131
104132
/*
105133
** TH command: puts STRING
106134
** TH command: html STRING
107135
**
108
-** Output STRING as HTML (html) or unchanged (puts).
136
+** Output STRING escaped for HTML (html) or unchanged (puts).
109137
*/
110138
static int putsCmd(
111139
Th_Interp *interp,
112140
void *pConvert,
113141
int argc,
@@ -115,11 +143,11 @@
115143
int *argl
116144
){
117145
if( argc!=2 ){
118146
return Th_WrongNumArgs(interp, "puts STRING");
119147
}
120
- sendText((char*)argv[1], argl[1], pConvert!=0);
148
+ sendText((char*)argv[1], argl[1], *(unsigned int*)pConvert);
121149
return TH_OK;
122150
}
123151
124152
/*
125153
** TH command: wiki STRING
@@ -131,17 +159,18 @@
131159
void *p,
132160
int argc,
133161
const char **argv,
134162
int *argl
135163
){
164
+ int flags = WIKI_INLINE | WIKI_NOBADLINKS | *(unsigned int*)p;
136165
if( argc!=2 ){
137166
return Th_WrongNumArgs(interp, "wiki STRING");
138167
}
139168
if( enableOutput ){
140169
Blob src;
141170
blob_init(&src, (char*)argv[1], argl[1]);
142
- wiki_convert(&src, 0, WIKI_INLINE);
171
+ wiki_convert(&src, 0, flags);
143172
blob_reset(&src);
144173
}
145174
return TH_OK;
146175
}
147176
@@ -503,69 +532,157 @@
503532
sqlite3_snprintf(sizeof(zUTime), zUTime, "%llu", x);
504533
Th_SetResult(interp, zUTime, -1);
505534
return TH_OK;
506535
}
507536
537
+
538
+/*
539
+** TH1 command: randhex N
540
+**
541
+** Return N*2 random hexadecimal digits with N<50. If N is omitted,
542
+** use a value of 10.
543
+*/
544
+static int randhexCmd(
545
+ Th_Interp *interp,
546
+ void *p,
547
+ int argc,
548
+ const char **argv,
549
+ int *argl
550
+){
551
+ int n;
552
+ unsigned char aRand[50];
553
+ unsigned char zOut[100];
554
+ if( argc!=1 && argc!=2 ){
555
+ return Th_WrongNumArgs(interp, "repository ?BOOLEAN?");
556
+ }
557
+ if( argc==2 ){
558
+ if( Th_ToInt(interp, argv[1], argl[1], &n) ){
559
+ return TH_ERROR;
560
+ }
561
+ if( n<1 ) n = 1;
562
+ if( n>sizeof(aRand) ) n = sizeof(aRand);
563
+ }else{
564
+ n = 10;
565
+ }
566
+ sqlite3_randomness(n, aRand);
567
+ encode16(aRand, zOut, n);
568
+ Th_SetResult(interp, (const char *)zOut, -1);
569
+ return TH_OK;
570
+}
571
+
508572
509573
/*
510574
** Make sure the interpreter has been initialized. Initialize it if
511575
** it has not been already.
512576
**
513577
** The interpreter is stored in the g.interp global variable.
514578
*/
515
-void Th_FossilInit(void){
579
+void Th_FossilInit(int needConfig, int forceSetup){
580
+ int wasInit = 0;
581
+ static unsigned int aFlags[] = { 0, 1, WIKI_LINKSONLY };
516582
static struct _Command {
517583
const char *zName;
518584
Th_CommandProc xProc;
519585
void *pContext;
520586
} aCommand[] = {
521587
{"anycap", anycapCmd, 0},
522588
{"combobox", comboboxCmd, 0},
589
+ {"date", dateCmd, 0},
590
+ {"decorate", wikiCmd, (void*)&aFlags[2]},
523591
{"enable_output", enableOutputCmd, 0},
524
- {"linecount", linecntCmd, 0},
525592
{"hascap", hascapCmd, 0},
526593
{"hasfeature", hasfeatureCmd, 0},
594
+ {"html", putsCmd, (void*)&aFlags[0]},
527595
{"htmlize", htmlizeCmd, 0},
528
- {"date", dateCmd, 0},
529
- {"html", putsCmd, 0},
530
- {"puts", putsCmd, (void*)1},
531
- {"wiki", wikiCmd, 0},
596
+ {"linecount", linecntCmd, 0},
597
+ {"puts", putsCmd, (void*)&aFlags[1]},
598
+ {"randhex", randhexCmd, 0},
532599
{"repository", repositoryCmd, 0},
533
- {"utime", utimeCmd, 0},
534600
{"stime", stimeCmd, 0},
601
+ {"utime", utimeCmd, 0},
602
+ {"wiki", wikiCmd, (void*)&aFlags[0]},
535603
{0, 0, 0}
536604
};
605
+ if( needConfig ){
606
+ /*
607
+ ** This function uses several settings which may be defined in the
608
+ ** repository and/or the global configuration. Since the caller
609
+ ** passed a non-zero value for the needConfig parameter, make sure
610
+ ** the necessary database connections are open prior to continuing.
611
+ */
612
+ db_find_and_open_repository(OPEN_ANY_SCHEMA | OPEN_OK_NOT_FOUND, 0);
613
+ db_open_config(0);
614
+ }
537615
if( g.interp==0 ){
538616
int i;
539617
g.interp = Th_CreateInterp(&vtab);
540618
th_register_language(g.interp); /* Basic scripting commands. */
541619
#ifdef FOSSIL_ENABLE_TCL
542620
if( getenv("TH1_ENABLE_TCL")!=0 || db_get_boolean("tcl", 0) ){
543
- g.tcl.setup = db_get("tcl-setup", 0); /* Grab optional setup script. */
621
+ if( !g.tcl.setup ){
622
+ g.tcl.setup = db_get("tcl-setup", 0); /* Grab Tcl setup script. */
623
+ }
544624
th_register_tcl(g.interp, &g.tcl); /* Tcl integration commands. */
545625
}
546626
#endif
547627
for(i=0; i<sizeof(aCommand)/sizeof(aCommand[0]); i++){
548628
if ( !aCommand[i].zName || !aCommand[i].xProc ) continue;
549629
Th_CreateCommand(g.interp, aCommand[i].zName, aCommand[i].xProc,
550630
aCommand[i].pContext, 0);
551631
}
632
+ }else{
633
+ wasInit = 1;
634
+ }
635
+ if( forceSetup || !wasInit ){
636
+ int rc = TH_OK;
637
+ if( !g.th1Setup ){
638
+ g.th1Setup = db_get("th1-setup", 0); /* Grab TH1 setup script. */
639
+ }
640
+ if( g.th1Setup ){
641
+ rc = Th_Eval(g.interp, 0, g.th1Setup, -1);
642
+ if( rc==TH_ERROR ){
643
+ int nResult = 0;
644
+ char *zResult = (char*)Th_GetResult(g.interp, &nResult);
645
+ sendError(zResult, nResult, 0);
646
+ }
647
+ }
648
+ if( g.thTrace ){
649
+ Th_Trace("th1-setup {%h} => %h<br />\n", g.th1Setup,
650
+ Th_ReturnCodeName(rc));
651
+ }
552652
}
553653
}
554654
555655
/*
556656
** Store a string value in a variable in the interpreter.
557657
*/
558658
void Th_Store(const char *zName, const char *zValue){
559
- Th_FossilInit();
659
+ Th_FossilInit(0, 0);
560660
if( zValue ){
561661
if( g.thTrace ){
562662
Th_Trace("set %h {%h}<br />\n", zName, zValue);
563663
}
564664
Th_SetVar(g.interp, zName, -1, zValue, strlen(zValue));
565665
}
566666
}
667
+
668
+/*
669
+** Store an integer value in a variable in the interpreter.
670
+*/
671
+void Th_StoreInt(const char *zName, int iValue){
672
+ Blob value;
673
+ char *zValue;
674
+ Th_FossilInit(0, 0);
675
+ blob_zero(&value);
676
+ blob_appendf(&value, "%d", iValue);
677
+ zValue = blob_str(&value);
678
+ if( g.thTrace ){
679
+ Th_Trace("set %h {%h}<br />\n", zName, zValue);
680
+ }
681
+ Th_SetVar(g.interp, zName, -1, zValue, strlen(zValue));
682
+ blob_reset(&value);
683
+}
567684
568685
/*
569686
** Unset a variable.
570687
*/
571688
void Th_Unstore(const char *zName){
@@ -578,11 +695,11 @@
578695
** Retrieve a string value from the interpreter. If no such
579696
** variable exists, return NULL.
580697
*/
581698
char *Th_Fetch(const char *zName, int *pSize){
582699
int rc;
583
- Th_FossilInit();
700
+ Th_FossilInit(0, 0);
584701
rc = Th_GetVar(g.interp, (char*)zName, -1);
585702
if( rc==TH_OK ){
586703
return (char*)Th_GetResult(g.interp, pSize);
587704
}else{
588705
return 0;
@@ -658,11 +775,11 @@
658775
int Th_Render(const char *z){
659776
int i = 0;
660777
int n;
661778
int rc = TH_OK;
662779
char *zResult;
663
- Th_FossilInit();
780
+ Th_FossilInit(0, 0);
664781
while( z[i] ){
665782
if( z[i]=='$' && (n = validVarName(&z[i+1]))>0 ){
666783
const char *zVar;
667784
int nVar;
668785
int encode = 1;
@@ -694,14 +811,12 @@
694811
}else{
695812
i++;
696813
}
697814
}
698815
if( rc==TH_ERROR ){
699
- sendText("<hr><p class=\"thmainError\">ERROR: ", -1, 0);
700816
zResult = (char*)Th_GetResult(g.interp, &n);
701
- sendText((char*)zResult, n, 1);
702
- sendText("</p>", -1, 0);
817
+ sendError(zResult, n, 1);
703818
}else{
704819
sendText(z, i, 0);
705820
}
706821
return rc;
707822
}
708823
--- src/th_main.c
+++ src/th_main.c
@@ -77,14 +77,33 @@
77 if( argc!=2 ){
78 return Th_WrongNumArgs(interp, "enable_output BOOLEAN");
79 }
80 return Th_ToInt(interp, argv[1], argl[1], &enableOutput);
81 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
82
83 /*
84 ** Send text to the appropriate output: Either to the console
85 ** or to the CGI reply buffer.
 
86 */
87 static void sendText(const char *z, int n, int encode){
88 if( enableOutput && n ){
89 if( n<0 ) n = strlen(z);
90 if( encode ){
@@ -98,16 +117,25 @@
98 fflush(stdout);
99 }
100 if( encode ) free((char*)z);
101 }
102 }
 
 
 
 
 
 
 
 
 
103
104 /*
105 ** TH command: puts STRING
106 ** TH command: html STRING
107 **
108 ** Output STRING as HTML (html) or unchanged (puts).
109 */
110 static int putsCmd(
111 Th_Interp *interp,
112 void *pConvert,
113 int argc,
@@ -115,11 +143,11 @@
115 int *argl
116 ){
117 if( argc!=2 ){
118 return Th_WrongNumArgs(interp, "puts STRING");
119 }
120 sendText((char*)argv[1], argl[1], pConvert!=0);
121 return TH_OK;
122 }
123
124 /*
125 ** TH command: wiki STRING
@@ -131,17 +159,18 @@
131 void *p,
132 int argc,
133 const char **argv,
134 int *argl
135 ){
 
136 if( argc!=2 ){
137 return Th_WrongNumArgs(interp, "wiki STRING");
138 }
139 if( enableOutput ){
140 Blob src;
141 blob_init(&src, (char*)argv[1], argl[1]);
142 wiki_convert(&src, 0, WIKI_INLINE);
143 blob_reset(&src);
144 }
145 return TH_OK;
146 }
147
@@ -503,69 +532,157 @@
503 sqlite3_snprintf(sizeof(zUTime), zUTime, "%llu", x);
504 Th_SetResult(interp, zUTime, -1);
505 return TH_OK;
506 }
507
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
508
509 /*
510 ** Make sure the interpreter has been initialized. Initialize it if
511 ** it has not been already.
512 **
513 ** The interpreter is stored in the g.interp global variable.
514 */
515 void Th_FossilInit(void){
 
 
516 static struct _Command {
517 const char *zName;
518 Th_CommandProc xProc;
519 void *pContext;
520 } aCommand[] = {
521 {"anycap", anycapCmd, 0},
522 {"combobox", comboboxCmd, 0},
 
 
523 {"enable_output", enableOutputCmd, 0},
524 {"linecount", linecntCmd, 0},
525 {"hascap", hascapCmd, 0},
526 {"hasfeature", hasfeatureCmd, 0},
 
527 {"htmlize", htmlizeCmd, 0},
528 {"date", dateCmd, 0},
529 {"html", putsCmd, 0},
530 {"puts", putsCmd, (void*)1},
531 {"wiki", wikiCmd, 0},
532 {"repository", repositoryCmd, 0},
533 {"utime", utimeCmd, 0},
534 {"stime", stimeCmd, 0},
 
 
535 {0, 0, 0}
536 };
 
 
 
 
 
 
 
 
 
 
537 if( g.interp==0 ){
538 int i;
539 g.interp = Th_CreateInterp(&vtab);
540 th_register_language(g.interp); /* Basic scripting commands. */
541 #ifdef FOSSIL_ENABLE_TCL
542 if( getenv("TH1_ENABLE_TCL")!=0 || db_get_boolean("tcl", 0) ){
543 g.tcl.setup = db_get("tcl-setup", 0); /* Grab optional setup script. */
 
 
544 th_register_tcl(g.interp, &g.tcl); /* Tcl integration commands. */
545 }
546 #endif
547 for(i=0; i<sizeof(aCommand)/sizeof(aCommand[0]); i++){
548 if ( !aCommand[i].zName || !aCommand[i].xProc ) continue;
549 Th_CreateCommand(g.interp, aCommand[i].zName, aCommand[i].xProc,
550 aCommand[i].pContext, 0);
551 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
552 }
553 }
554
555 /*
556 ** Store a string value in a variable in the interpreter.
557 */
558 void Th_Store(const char *zName, const char *zValue){
559 Th_FossilInit();
560 if( zValue ){
561 if( g.thTrace ){
562 Th_Trace("set %h {%h}<br />\n", zName, zValue);
563 }
564 Th_SetVar(g.interp, zName, -1, zValue, strlen(zValue));
565 }
566 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
567
568 /*
569 ** Unset a variable.
570 */
571 void Th_Unstore(const char *zName){
@@ -578,11 +695,11 @@
578 ** Retrieve a string value from the interpreter. If no such
579 ** variable exists, return NULL.
580 */
581 char *Th_Fetch(const char *zName, int *pSize){
582 int rc;
583 Th_FossilInit();
584 rc = Th_GetVar(g.interp, (char*)zName, -1);
585 if( rc==TH_OK ){
586 return (char*)Th_GetResult(g.interp, pSize);
587 }else{
588 return 0;
@@ -658,11 +775,11 @@
658 int Th_Render(const char *z){
659 int i = 0;
660 int n;
661 int rc = TH_OK;
662 char *zResult;
663 Th_FossilInit();
664 while( z[i] ){
665 if( z[i]=='$' && (n = validVarName(&z[i+1]))>0 ){
666 const char *zVar;
667 int nVar;
668 int encode = 1;
@@ -694,14 +811,12 @@
694 }else{
695 i++;
696 }
697 }
698 if( rc==TH_ERROR ){
699 sendText("<hr><p class=\"thmainError\">ERROR: ", -1, 0);
700 zResult = (char*)Th_GetResult(g.interp, &n);
701 sendText((char*)zResult, n, 1);
702 sendText("</p>", -1, 0);
703 }else{
704 sendText(z, i, 0);
705 }
706 return rc;
707 }
708
--- src/th_main.c
+++ src/th_main.c
@@ -77,14 +77,33 @@
77 if( argc!=2 ){
78 return Th_WrongNumArgs(interp, "enable_output BOOLEAN");
79 }
80 return Th_ToInt(interp, argv[1], argl[1], &enableOutput);
81 }
82
83 /*
84 ** Return a name for a TH1 return code.
85 */
86 const char *Th_ReturnCodeName(int rc){
87 static char zRc[32];
88 switch( rc ){
89 case TH_OK: return "TH_OK";
90 case TH_ERROR: return "TH_ERROR";
91 case TH_BREAK: return "TH_BREAK";
92 case TH_RETURN: return "TH_RETURN";
93 case TH_CONTINUE: return "TH_CONTINUE";
94 default: {
95 sqlite3_snprintf(sizeof(zRc),zRc,"return code %d",rc);
96 }
97 }
98 return zRc;
99 }
100
101 /*
102 ** Send text to the appropriate output: Either to the console
103 ** or to the CGI reply buffer. Escape all characters with special
104 ** meaning to HTML if the encode parameter is true.
105 */
106 static void sendText(const char *z, int n, int encode){
107 if( enableOutput && n ){
108 if( n<0 ) n = strlen(z);
109 if( encode ){
@@ -98,16 +117,25 @@
117 fflush(stdout);
118 }
119 if( encode ) free((char*)z);
120 }
121 }
122
123 static void sendError(const char *z, int n, int forceCgi){
124 if( forceCgi || g.cgiOutput ){
125 sendText("<hr><p class=\"thmainError\">", -1, 0);
126 }
127 sendText("ERROR: ", -1, 0);
128 sendText((char*)z, n, 1);
129 sendText(forceCgi || g.cgiOutput ? "</p>" : "\n", -1, 0);
130 }
131
132 /*
133 ** TH command: puts STRING
134 ** TH command: html STRING
135 **
136 ** Output STRING escaped for HTML (html) or unchanged (puts).
137 */
138 static int putsCmd(
139 Th_Interp *interp,
140 void *pConvert,
141 int argc,
@@ -115,11 +143,11 @@
143 int *argl
144 ){
145 if( argc!=2 ){
146 return Th_WrongNumArgs(interp, "puts STRING");
147 }
148 sendText((char*)argv[1], argl[1], *(unsigned int*)pConvert);
149 return TH_OK;
150 }
151
152 /*
153 ** TH command: wiki STRING
@@ -131,17 +159,18 @@
159 void *p,
160 int argc,
161 const char **argv,
162 int *argl
163 ){
164 int flags = WIKI_INLINE | WIKI_NOBADLINKS | *(unsigned int*)p;
165 if( argc!=2 ){
166 return Th_WrongNumArgs(interp, "wiki STRING");
167 }
168 if( enableOutput ){
169 Blob src;
170 blob_init(&src, (char*)argv[1], argl[1]);
171 wiki_convert(&src, 0, flags);
172 blob_reset(&src);
173 }
174 return TH_OK;
175 }
176
@@ -503,69 +532,157 @@
532 sqlite3_snprintf(sizeof(zUTime), zUTime, "%llu", x);
533 Th_SetResult(interp, zUTime, -1);
534 return TH_OK;
535 }
536
537
538 /*
539 ** TH1 command: randhex N
540 **
541 ** Return N*2 random hexadecimal digits with N<50. If N is omitted,
542 ** use a value of 10.
543 */
544 static int randhexCmd(
545 Th_Interp *interp,
546 void *p,
547 int argc,
548 const char **argv,
549 int *argl
550 ){
551 int n;
552 unsigned char aRand[50];
553 unsigned char zOut[100];
554 if( argc!=1 && argc!=2 ){
555 return Th_WrongNumArgs(interp, "repository ?BOOLEAN?");
556 }
557 if( argc==2 ){
558 if( Th_ToInt(interp, argv[1], argl[1], &n) ){
559 return TH_ERROR;
560 }
561 if( n<1 ) n = 1;
562 if( n>sizeof(aRand) ) n = sizeof(aRand);
563 }else{
564 n = 10;
565 }
566 sqlite3_randomness(n, aRand);
567 encode16(aRand, zOut, n);
568 Th_SetResult(interp, (const char *)zOut, -1);
569 return TH_OK;
570 }
571
572
573 /*
574 ** Make sure the interpreter has been initialized. Initialize it if
575 ** it has not been already.
576 **
577 ** The interpreter is stored in the g.interp global variable.
578 */
579 void Th_FossilInit(int needConfig, int forceSetup){
580 int wasInit = 0;
581 static unsigned int aFlags[] = { 0, 1, WIKI_LINKSONLY };
582 static struct _Command {
583 const char *zName;
584 Th_CommandProc xProc;
585 void *pContext;
586 } aCommand[] = {
587 {"anycap", anycapCmd, 0},
588 {"combobox", comboboxCmd, 0},
589 {"date", dateCmd, 0},
590 {"decorate", wikiCmd, (void*)&aFlags[2]},
591 {"enable_output", enableOutputCmd, 0},
 
592 {"hascap", hascapCmd, 0},
593 {"hasfeature", hasfeatureCmd, 0},
594 {"html", putsCmd, (void*)&aFlags[0]},
595 {"htmlize", htmlizeCmd, 0},
596 {"linecount", linecntCmd, 0},
597 {"puts", putsCmd, (void*)&aFlags[1]},
598 {"randhex", randhexCmd, 0},
 
599 {"repository", repositoryCmd, 0},
 
600 {"stime", stimeCmd, 0},
601 {"utime", utimeCmd, 0},
602 {"wiki", wikiCmd, (void*)&aFlags[0]},
603 {0, 0, 0}
604 };
605 if( needConfig ){
606 /*
607 ** This function uses several settings which may be defined in the
608 ** repository and/or the global configuration. Since the caller
609 ** passed a non-zero value for the needConfig parameter, make sure
610 ** the necessary database connections are open prior to continuing.
611 */
612 db_find_and_open_repository(OPEN_ANY_SCHEMA | OPEN_OK_NOT_FOUND, 0);
613 db_open_config(0);
614 }
615 if( g.interp==0 ){
616 int i;
617 g.interp = Th_CreateInterp(&vtab);
618 th_register_language(g.interp); /* Basic scripting commands. */
619 #ifdef FOSSIL_ENABLE_TCL
620 if( getenv("TH1_ENABLE_TCL")!=0 || db_get_boolean("tcl", 0) ){
621 if( !g.tcl.setup ){
622 g.tcl.setup = db_get("tcl-setup", 0); /* Grab Tcl setup script. */
623 }
624 th_register_tcl(g.interp, &g.tcl); /* Tcl integration commands. */
625 }
626 #endif
627 for(i=0; i<sizeof(aCommand)/sizeof(aCommand[0]); i++){
628 if ( !aCommand[i].zName || !aCommand[i].xProc ) continue;
629 Th_CreateCommand(g.interp, aCommand[i].zName, aCommand[i].xProc,
630 aCommand[i].pContext, 0);
631 }
632 }else{
633 wasInit = 1;
634 }
635 if( forceSetup || !wasInit ){
636 int rc = TH_OK;
637 if( !g.th1Setup ){
638 g.th1Setup = db_get("th1-setup", 0); /* Grab TH1 setup script. */
639 }
640 if( g.th1Setup ){
641 rc = Th_Eval(g.interp, 0, g.th1Setup, -1);
642 if( rc==TH_ERROR ){
643 int nResult = 0;
644 char *zResult = (char*)Th_GetResult(g.interp, &nResult);
645 sendError(zResult, nResult, 0);
646 }
647 }
648 if( g.thTrace ){
649 Th_Trace("th1-setup {%h} => %h<br />\n", g.th1Setup,
650 Th_ReturnCodeName(rc));
651 }
652 }
653 }
654
655 /*
656 ** Store a string value in a variable in the interpreter.
657 */
658 void Th_Store(const char *zName, const char *zValue){
659 Th_FossilInit(0, 0);
660 if( zValue ){
661 if( g.thTrace ){
662 Th_Trace("set %h {%h}<br />\n", zName, zValue);
663 }
664 Th_SetVar(g.interp, zName, -1, zValue, strlen(zValue));
665 }
666 }
667
668 /*
669 ** Store an integer value in a variable in the interpreter.
670 */
671 void Th_StoreInt(const char *zName, int iValue){
672 Blob value;
673 char *zValue;
674 Th_FossilInit(0, 0);
675 blob_zero(&value);
676 blob_appendf(&value, "%d", iValue);
677 zValue = blob_str(&value);
678 if( g.thTrace ){
679 Th_Trace("set %h {%h}<br />\n", zName, zValue);
680 }
681 Th_SetVar(g.interp, zName, -1, zValue, strlen(zValue));
682 blob_reset(&value);
683 }
684
685 /*
686 ** Unset a variable.
687 */
688 void Th_Unstore(const char *zName){
@@ -578,11 +695,11 @@
695 ** Retrieve a string value from the interpreter. If no such
696 ** variable exists, return NULL.
697 */
698 char *Th_Fetch(const char *zName, int *pSize){
699 int rc;
700 Th_FossilInit(0, 0);
701 rc = Th_GetVar(g.interp, (char*)zName, -1);
702 if( rc==TH_OK ){
703 return (char*)Th_GetResult(g.interp, pSize);
704 }else{
705 return 0;
@@ -658,11 +775,11 @@
775 int Th_Render(const char *z){
776 int i = 0;
777 int n;
778 int rc = TH_OK;
779 char *zResult;
780 Th_FossilInit(0, 0);
781 while( z[i] ){
782 if( z[i]=='$' && (n = validVarName(&z[i+1]))>0 ){
783 const char *zVar;
784 int nVar;
785 int encode = 1;
@@ -694,14 +811,12 @@
811 }else{
812 i++;
813 }
814 }
815 if( rc==TH_ERROR ){
 
816 zResult = (char*)Th_GetResult(g.interp, &n);
817 sendError(zResult, n, 1);
 
818 }else{
819 sendText(z, i, 0);
820 }
821 return rc;
822 }
823
+8 -20
--- src/timeline.c
+++ src/timeline.c
@@ -85,10 +85,11 @@
8585
** Generate a hyperlink to a user. This will link to a timeline showing
8686
** events by that user. If the date+time is specified, then the timeline
8787
** is centered on that date+time.
8888
*/
8989
void hyperlink_to_user(const char *zU, const char *zD, const char *zSuf){
90
+ if( zU==0 || zU[0]==0 ) zU = "anonymous";
9091
if( zSuf==0 ) zSuf = "";
9192
if( g.perm.Hyperlink ){
9293
if( zD && zD[0] ){
9394
@ %z(href("%R/timeline?c=%T&u=%T",zD,zU))%h(zU)</a>%s(zSuf)
9495
}else{
@@ -191,12 +192,10 @@
191192
int tmFlags, /* Flags controlling display behavior */
192193
const char *zThisUser, /* Suppress links to this user */
193194
const char *zThisTag, /* Suppress links to this tag */
194195
void (*xExtra)(int) /* Routine to call on each line of display */
195196
){
196
- int wikiFlags;
197
- int plainText;
198197
int mxWikiLen;
199198
Blob comment;
200199
int prevTagid = 0;
201200
int suppressCnt = 0;
202201
char zPrevDate[20];
@@ -206,17 +205,11 @@
206205
Stmt fchngQuery; /* Query for file changes on check-ins */
207206
static Stmt qbranch;
208207
int pendingEndTr = 0; /* True if a </td></tr> is needed */
209208
210209
zPrevDate[0] = 0;
211
- plainText = db_get_int("timeline-plaintext", 0);
212210
mxWikiLen = db_get_int("timeline-max-comment", 0);
213
- if( db_get_boolean("timeline-block-markup", 0) ){
214
- wikiFlags = WIKI_INLINE;
215
- }else{
216
- wikiFlags = WIKI_INLINE | WIKI_NOBLOCK;
217
- }
218211
if( tmFlags & TIMELINE_GRAPH ){
219212
pGraph = graph_init();
220213
/* style is not moved to css, because this is
221214
** a technical div for the timeline graph
222215
*/
@@ -237,10 +230,11 @@
237230
const char *zDate = db_column_text(pQuery, 2);
238231
const char *zType = db_column_text(pQuery, 7);
239232
const char *zUser = db_column_text(pQuery, 4);
240233
const char *zTagList = db_column_text(pQuery, 8);
241234
int tagid = db_column_int(pQuery, 9);
235
+ const char *zDispUser = zUser && zUser[0] ? zUser : "anonymous";
242236
const char *zBr = 0; /* Branch */
243237
int commentColumn = 3; /* Column containing comment text */
244238
int modPending; /* Pending moderation */
245239
char zTime[8];
246240
@@ -355,32 +349,26 @@
355349
if( mxWikiLen>0 && blob_size(&comment)>mxWikiLen ){
356350
Blob truncated;
357351
blob_zero(&truncated);
358352
blob_append(&truncated, blob_buffer(&comment), mxWikiLen);
359353
blob_append(&truncated, "...", 3);
360
- if( plainText ){
361
- @ %h(blob_str(&truncated))
362
- }else{
363
- wiki_convert(&truncated, 0, wikiFlags);
364
- }
354
+ @ %w(blob_str(&truncated))
365355
blob_reset(&truncated);
366
- }else if( plainText ){
367
- @ %h(blob_str(&comment));
368356
}else{
369
- wiki_convert(&comment, 0, wikiFlags);
357
+ @ %w(blob_str(&comment))
370358
}
371359
blob_reset(&comment);
372360
373361
/* Generate the "user: USERNAME" at the end of the comment, together
374362
** with a hyperlink to another timeline for that user.
375363
*/
376364
if( zTagList && zTagList[0]==0 ) zTagList = 0;
377
- if( g.perm.Hyperlink && fossil_strcmp(zUser, zThisUser)!=0 ){
378
- char *zLink = mprintf("%R/timeline?u=%h&c=%t&nd", zUser, zDate);
379
- @ (user: %z(href("%z",zLink))%h(zUser)</a>%s(zTagList?",":"\051")
365
+ if( g.perm.Hyperlink && fossil_strcmp(zDispUser, zThisUser)!=0 ){
366
+ char *zLink = mprintf("%R/timeline?u=%h&c=%t&nd", zDispUser, zDate);
367
+ @ (user: %z(href("%z",zLink))%h(zDispUser)</a>%s(zTagList?",":"\051")
380368
}else{
381
- @ (user: %h(zUser)%s(zTagList?",":"\051")
369
+ @ (user: %h(zDispUser)%s(zTagList?",":"\051")
382370
}
383371
384372
/* Generate a "detail" link for tags. */
385373
if( (zType[0]=='g' || zType[0]=='w' || zType[0]=='t') && g.perm.Hyperlink ){
386374
@ [%z(href("%R/info/%S",zUuid))details</a>]
387375
--- src/timeline.c
+++ src/timeline.c
@@ -85,10 +85,11 @@
85 ** Generate a hyperlink to a user. This will link to a timeline showing
86 ** events by that user. If the date+time is specified, then the timeline
87 ** is centered on that date+time.
88 */
89 void hyperlink_to_user(const char *zU, const char *zD, const char *zSuf){
 
90 if( zSuf==0 ) zSuf = "";
91 if( g.perm.Hyperlink ){
92 if( zD && zD[0] ){
93 @ %z(href("%R/timeline?c=%T&u=%T",zD,zU))%h(zU)</a>%s(zSuf)
94 }else{
@@ -191,12 +192,10 @@
191 int tmFlags, /* Flags controlling display behavior */
192 const char *zThisUser, /* Suppress links to this user */
193 const char *zThisTag, /* Suppress links to this tag */
194 void (*xExtra)(int) /* Routine to call on each line of display */
195 ){
196 int wikiFlags;
197 int plainText;
198 int mxWikiLen;
199 Blob comment;
200 int prevTagid = 0;
201 int suppressCnt = 0;
202 char zPrevDate[20];
@@ -206,17 +205,11 @@
206 Stmt fchngQuery; /* Query for file changes on check-ins */
207 static Stmt qbranch;
208 int pendingEndTr = 0; /* True if a </td></tr> is needed */
209
210 zPrevDate[0] = 0;
211 plainText = db_get_int("timeline-plaintext", 0);
212 mxWikiLen = db_get_int("timeline-max-comment", 0);
213 if( db_get_boolean("timeline-block-markup", 0) ){
214 wikiFlags = WIKI_INLINE;
215 }else{
216 wikiFlags = WIKI_INLINE | WIKI_NOBLOCK;
217 }
218 if( tmFlags & TIMELINE_GRAPH ){
219 pGraph = graph_init();
220 /* style is not moved to css, because this is
221 ** a technical div for the timeline graph
222 */
@@ -237,10 +230,11 @@
237 const char *zDate = db_column_text(pQuery, 2);
238 const char *zType = db_column_text(pQuery, 7);
239 const char *zUser = db_column_text(pQuery, 4);
240 const char *zTagList = db_column_text(pQuery, 8);
241 int tagid = db_column_int(pQuery, 9);
 
242 const char *zBr = 0; /* Branch */
243 int commentColumn = 3; /* Column containing comment text */
244 int modPending; /* Pending moderation */
245 char zTime[8];
246
@@ -355,32 +349,26 @@
355 if( mxWikiLen>0 && blob_size(&comment)>mxWikiLen ){
356 Blob truncated;
357 blob_zero(&truncated);
358 blob_append(&truncated, blob_buffer(&comment), mxWikiLen);
359 blob_append(&truncated, "...", 3);
360 if( plainText ){
361 @ %h(blob_str(&truncated))
362 }else{
363 wiki_convert(&truncated, 0, wikiFlags);
364 }
365 blob_reset(&truncated);
366 }else if( plainText ){
367 @ %h(blob_str(&comment));
368 }else{
369 wiki_convert(&comment, 0, wikiFlags);
370 }
371 blob_reset(&comment);
372
373 /* Generate the "user: USERNAME" at the end of the comment, together
374 ** with a hyperlink to another timeline for that user.
375 */
376 if( zTagList && zTagList[0]==0 ) zTagList = 0;
377 if( g.perm.Hyperlink && fossil_strcmp(zUser, zThisUser)!=0 ){
378 char *zLink = mprintf("%R/timeline?u=%h&c=%t&nd", zUser, zDate);
379 @ (user: %z(href("%z",zLink))%h(zUser)</a>%s(zTagList?",":"\051")
380 }else{
381 @ (user: %h(zUser)%s(zTagList?",":"\051")
382 }
383
384 /* Generate a "detail" link for tags. */
385 if( (zType[0]=='g' || zType[0]=='w' || zType[0]=='t') && g.perm.Hyperlink ){
386 @ [%z(href("%R/info/%S",zUuid))details</a>]
387
--- src/timeline.c
+++ src/timeline.c
@@ -85,10 +85,11 @@
85 ** Generate a hyperlink to a user. This will link to a timeline showing
86 ** events by that user. If the date+time is specified, then the timeline
87 ** is centered on that date+time.
88 */
89 void hyperlink_to_user(const char *zU, const char *zD, const char *zSuf){
90 if( zU==0 || zU[0]==0 ) zU = "anonymous";
91 if( zSuf==0 ) zSuf = "";
92 if( g.perm.Hyperlink ){
93 if( zD && zD[0] ){
94 @ %z(href("%R/timeline?c=%T&u=%T",zD,zU))%h(zU)</a>%s(zSuf)
95 }else{
@@ -191,12 +192,10 @@
192 int tmFlags, /* Flags controlling display behavior */
193 const char *zThisUser, /* Suppress links to this user */
194 const char *zThisTag, /* Suppress links to this tag */
195 void (*xExtra)(int) /* Routine to call on each line of display */
196 ){
 
 
197 int mxWikiLen;
198 Blob comment;
199 int prevTagid = 0;
200 int suppressCnt = 0;
201 char zPrevDate[20];
@@ -206,17 +205,11 @@
205 Stmt fchngQuery; /* Query for file changes on check-ins */
206 static Stmt qbranch;
207 int pendingEndTr = 0; /* True if a </td></tr> is needed */
208
209 zPrevDate[0] = 0;
 
210 mxWikiLen = db_get_int("timeline-max-comment", 0);
 
 
 
 
 
211 if( tmFlags & TIMELINE_GRAPH ){
212 pGraph = graph_init();
213 /* style is not moved to css, because this is
214 ** a technical div for the timeline graph
215 */
@@ -237,10 +230,11 @@
230 const char *zDate = db_column_text(pQuery, 2);
231 const char *zType = db_column_text(pQuery, 7);
232 const char *zUser = db_column_text(pQuery, 4);
233 const char *zTagList = db_column_text(pQuery, 8);
234 int tagid = db_column_int(pQuery, 9);
235 const char *zDispUser = zUser && zUser[0] ? zUser : "anonymous";
236 const char *zBr = 0; /* Branch */
237 int commentColumn = 3; /* Column containing comment text */
238 int modPending; /* Pending moderation */
239 char zTime[8];
240
@@ -355,32 +349,26 @@
349 if( mxWikiLen>0 && blob_size(&comment)>mxWikiLen ){
350 Blob truncated;
351 blob_zero(&truncated);
352 blob_append(&truncated, blob_buffer(&comment), mxWikiLen);
353 blob_append(&truncated, "...", 3);
354 @ %w(blob_str(&truncated))
 
 
 
 
355 blob_reset(&truncated);
 
 
356 }else{
357 @ %w(blob_str(&comment))
358 }
359 blob_reset(&comment);
360
361 /* Generate the "user: USERNAME" at the end of the comment, together
362 ** with a hyperlink to another timeline for that user.
363 */
364 if( zTagList && zTagList[0]==0 ) zTagList = 0;
365 if( g.perm.Hyperlink && fossil_strcmp(zDispUser, zThisUser)!=0 ){
366 char *zLink = mprintf("%R/timeline?u=%h&c=%t&nd", zDispUser, zDate);
367 @ (user: %z(href("%z",zLink))%h(zDispUser)</a>%s(zTagList?",":"\051")
368 }else{
369 @ (user: %h(zDispUser)%s(zTagList?",":"\051")
370 }
371
372 /* Generate a "detail" link for tags. */
373 if( (zType[0]=='g' || zType[0]=='w' || zType[0]=='t') && g.perm.Hyperlink ){
374 @ [%z(href("%R/info/%S",zUuid))details</a>]
375
+15 -9
--- src/tkt.c
+++ src/tkt.c
@@ -238,21 +238,21 @@
238238
/*
239239
** Create the subscript interpreter and load the "common" code.
240240
*/
241241
void ticket_init(void){
242242
const char *zConfig;
243
- Th_FossilInit();
243
+ Th_FossilInit(0, 0);
244244
zConfig = ticket_common_code();
245245
Th_Eval(g.interp, 0, zConfig, -1);
246246
}
247247
248248
/*
249249
** Create the subscript interpreter and load the "change" code.
250250
*/
251251
int ticket_change(void){
252252
const char *zConfig;
253
- Th_FossilInit();
253
+ Th_FossilInit(0, 0);
254254
zConfig = ticket_change_code();
255255
return Th_Eval(g.interp, 0, zConfig, -1);
256256
}
257257
258258
/*
@@ -430,10 +430,14 @@
430430
int i;
431431
int nJ = 0;
432432
Blob tktchng, cksum;
433433
434434
login_verify_csrf_secret();
435
+ if( !captcha_is_correct() ){
436
+ @ <p class="generalError">Error: Incorrect security code.</p>
437
+ return TH_OK;
438
+ }
435439
zUuid = (const char *)pUuid;
436440
blob_zero(&tktchng);
437441
zDate = date_in_standard_format("now");
438442
blob_appendf(&tktchng, "D %s\n", zDate);
439443
free(zDate);
@@ -522,26 +526,27 @@
522526
if( g.thTrace ) Th_Trace("BEGIN_TKTNEW<br />\n", -1);
523527
ticket_init();
524528
getAllTicketFields();
525529
initializeVariablesFromDb();
526530
initializeVariablesFromCGI();
527
- @ <form method="post" action="%s(g.zTop)/%s(g.zPath)"><p>
531
+ form_begin(0, "%R/%s", g.zPath);
528532
login_insert_csrf_secret();
529533
if( P("date_override") && g.perm.Setup ){
530534
@ <input type="hidden" name="date_override" value="%h(P("date_override"))">
531535
}
532536
@ </p>
533537
zScript = ticket_newpage_code();
534
- Th_Store("login", g.zLogin);
538
+ Th_Store("login", g.zLogin ? g.zLogin : "nobody");
535539
Th_Store("date", db_text(0, "SELECT datetime('now')"));
536540
Th_CreateCommand(g.interp, "submit_ticket", submitTicketCmd,
537541
(void*)&zNewUuid, 0);
538542
if( g.thTrace ) Th_Trace("BEGIN_TKTNEW_SCRIPT<br />\n", -1);
539543
if( Th_Render(zScript)==TH_RETURN && !g.thTrace && zNewUuid ){
540544
cgi_redirect(mprintf("%s/tktview/%s", g.zTop, zNewUuid));
541545
return;
542546
}
547
+ captcha_generate();
543548
@ </form>
544549
if( g.thTrace ) Th_Trace("END_TKTVIEW<br />\n", -1);
545550
style_footer();
546551
}
547552
@@ -591,24 +596,25 @@
591596
if( g.thTrace ) Th_Trace("BEGIN_TKTEDIT<br />\n", -1);
592597
ticket_init();
593598
getAllTicketFields();
594599
initializeVariablesFromCGI();
595600
initializeVariablesFromDb();
596
- @ <form method="post" action="%s(g.zTop)/%s(g.zPath)"><p>
601
+ form_begin(0, "%R/%s", g.zPath);
597602
@ <input type="hidden" name="name" value="%s(zName)" />
598603
login_insert_csrf_secret();
599604
@ </p>
600605
zScript = ticket_editpage_code();
601
- Th_Store("login", g.zLogin);
606
+ Th_Store("login", g.zLogin ? g.zLogin : "nobody");
602607
Th_Store("date", db_text(0, "SELECT datetime('now')"));
603608
Th_CreateCommand(g.interp, "append_field", appendRemarkCmd, 0, 0);
604609
Th_CreateCommand(g.interp, "submit_ticket", submitTicketCmd, (void*)&zName,0);
605610
if( g.thTrace ) Th_Trace("BEGIN_TKTEDIT_SCRIPT<br />\n", -1);
606611
if( Th_Render(zScript)==TH_RETURN && !g.thTrace && zName ){
607612
cgi_redirect(mprintf("%s/tktview/%s", g.zTop, zName));
608613
return;
609614
}
615
+ captcha_generate();
610616
@ </form>
611617
if( g.thTrace ) Th_Trace("BEGIN_TKTEDIT<br />\n", -1);
612618
style_footer();
613619
}
614620
@@ -829,15 +835,15 @@
829835
const char *z;
830836
z = pTkt->aField[i].zName;
831837
blob_set(&val, pTkt->aField[i].zValue);
832838
if( z[0]=='+' ){
833839
@ <li>Appended to %h(&z[1]):<blockquote>
834
- wiki_convert(&val, 0, 0);
840
+ wiki_convert(&val, 0, WIKI_NOBADLINKS);
835841
@ </blockquote></li>
836842
}else if( blob_size(&val)<=50 && contains_newline(&val) ){
837843
@ <li>Change %h(z) to:<blockquote>
838
- wiki_convert(&val, 0, 0);
844
+ wiki_convert(&val, 0, WIKI_NOBADLINKS);
839845
@ </blockquote></li>
840846
}else{
841847
@ <li>Change %h(z) to "%h(blob_str(&val))"</li>
842848
}
843849
blob_reset(&val);
@@ -1006,11 +1012,11 @@
10061012
eCmd = history;
10071013
}else{
10081014
eCmd = set;
10091015
}
10101016
if( g.argc==3 ){
1011
- usage("set TICKETUUID");
1017
+ usage("set|change|history TICKETUUID");
10121018
}
10131019
zTktUuid = db_text(0,
10141020
"SELECT tkt_uuid FROM ticket WHERE tkt_uuid GLOB '%s*'", g.argv[3]
10151021
);
10161022
if( !zTktUuid ){
10171023
--- src/tkt.c
+++ src/tkt.c
@@ -238,21 +238,21 @@
238 /*
239 ** Create the subscript interpreter and load the "common" code.
240 */
241 void ticket_init(void){
242 const char *zConfig;
243 Th_FossilInit();
244 zConfig = ticket_common_code();
245 Th_Eval(g.interp, 0, zConfig, -1);
246 }
247
248 /*
249 ** Create the subscript interpreter and load the "change" code.
250 */
251 int ticket_change(void){
252 const char *zConfig;
253 Th_FossilInit();
254 zConfig = ticket_change_code();
255 return Th_Eval(g.interp, 0, zConfig, -1);
256 }
257
258 /*
@@ -430,10 +430,14 @@
430 int i;
431 int nJ = 0;
432 Blob tktchng, cksum;
433
434 login_verify_csrf_secret();
 
 
 
 
435 zUuid = (const char *)pUuid;
436 blob_zero(&tktchng);
437 zDate = date_in_standard_format("now");
438 blob_appendf(&tktchng, "D %s\n", zDate);
439 free(zDate);
@@ -522,26 +526,27 @@
522 if( g.thTrace ) Th_Trace("BEGIN_TKTNEW<br />\n", -1);
523 ticket_init();
524 getAllTicketFields();
525 initializeVariablesFromDb();
526 initializeVariablesFromCGI();
527 @ <form method="post" action="%s(g.zTop)/%s(g.zPath)"><p>
528 login_insert_csrf_secret();
529 if( P("date_override") && g.perm.Setup ){
530 @ <input type="hidden" name="date_override" value="%h(P("date_override"))">
531 }
532 @ </p>
533 zScript = ticket_newpage_code();
534 Th_Store("login", g.zLogin);
535 Th_Store("date", db_text(0, "SELECT datetime('now')"));
536 Th_CreateCommand(g.interp, "submit_ticket", submitTicketCmd,
537 (void*)&zNewUuid, 0);
538 if( g.thTrace ) Th_Trace("BEGIN_TKTNEW_SCRIPT<br />\n", -1);
539 if( Th_Render(zScript)==TH_RETURN && !g.thTrace && zNewUuid ){
540 cgi_redirect(mprintf("%s/tktview/%s", g.zTop, zNewUuid));
541 return;
542 }
 
543 @ </form>
544 if( g.thTrace ) Th_Trace("END_TKTVIEW<br />\n", -1);
545 style_footer();
546 }
547
@@ -591,24 +596,25 @@
591 if( g.thTrace ) Th_Trace("BEGIN_TKTEDIT<br />\n", -1);
592 ticket_init();
593 getAllTicketFields();
594 initializeVariablesFromCGI();
595 initializeVariablesFromDb();
596 @ <form method="post" action="%s(g.zTop)/%s(g.zPath)"><p>
597 @ <input type="hidden" name="name" value="%s(zName)" />
598 login_insert_csrf_secret();
599 @ </p>
600 zScript = ticket_editpage_code();
601 Th_Store("login", g.zLogin);
602 Th_Store("date", db_text(0, "SELECT datetime('now')"));
603 Th_CreateCommand(g.interp, "append_field", appendRemarkCmd, 0, 0);
604 Th_CreateCommand(g.interp, "submit_ticket", submitTicketCmd, (void*)&zName,0);
605 if( g.thTrace ) Th_Trace("BEGIN_TKTEDIT_SCRIPT<br />\n", -1);
606 if( Th_Render(zScript)==TH_RETURN && !g.thTrace && zName ){
607 cgi_redirect(mprintf("%s/tktview/%s", g.zTop, zName));
608 return;
609 }
 
610 @ </form>
611 if( g.thTrace ) Th_Trace("BEGIN_TKTEDIT<br />\n", -1);
612 style_footer();
613 }
614
@@ -829,15 +835,15 @@
829 const char *z;
830 z = pTkt->aField[i].zName;
831 blob_set(&val, pTkt->aField[i].zValue);
832 if( z[0]=='+' ){
833 @ <li>Appended to %h(&z[1]):<blockquote>
834 wiki_convert(&val, 0, 0);
835 @ </blockquote></li>
836 }else if( blob_size(&val)<=50 && contains_newline(&val) ){
837 @ <li>Change %h(z) to:<blockquote>
838 wiki_convert(&val, 0, 0);
839 @ </blockquote></li>
840 }else{
841 @ <li>Change %h(z) to "%h(blob_str(&val))"</li>
842 }
843 blob_reset(&val);
@@ -1006,11 +1012,11 @@
1006 eCmd = history;
1007 }else{
1008 eCmd = set;
1009 }
1010 if( g.argc==3 ){
1011 usage("set TICKETUUID");
1012 }
1013 zTktUuid = db_text(0,
1014 "SELECT tkt_uuid FROM ticket WHERE tkt_uuid GLOB '%s*'", g.argv[3]
1015 );
1016 if( !zTktUuid ){
1017
--- src/tkt.c
+++ src/tkt.c
@@ -238,21 +238,21 @@
238 /*
239 ** Create the subscript interpreter and load the "common" code.
240 */
241 void ticket_init(void){
242 const char *zConfig;
243 Th_FossilInit(0, 0);
244 zConfig = ticket_common_code();
245 Th_Eval(g.interp, 0, zConfig, -1);
246 }
247
248 /*
249 ** Create the subscript interpreter and load the "change" code.
250 */
251 int ticket_change(void){
252 const char *zConfig;
253 Th_FossilInit(0, 0);
254 zConfig = ticket_change_code();
255 return Th_Eval(g.interp, 0, zConfig, -1);
256 }
257
258 /*
@@ -430,10 +430,14 @@
430 int i;
431 int nJ = 0;
432 Blob tktchng, cksum;
433
434 login_verify_csrf_secret();
435 if( !captcha_is_correct() ){
436 @ <p class="generalError">Error: Incorrect security code.</p>
437 return TH_OK;
438 }
439 zUuid = (const char *)pUuid;
440 blob_zero(&tktchng);
441 zDate = date_in_standard_format("now");
442 blob_appendf(&tktchng, "D %s\n", zDate);
443 free(zDate);
@@ -522,26 +526,27 @@
526 if( g.thTrace ) Th_Trace("BEGIN_TKTNEW<br />\n", -1);
527 ticket_init();
528 getAllTicketFields();
529 initializeVariablesFromDb();
530 initializeVariablesFromCGI();
531 form_begin(0, "%R/%s", g.zPath);
532 login_insert_csrf_secret();
533 if( P("date_override") && g.perm.Setup ){
534 @ <input type="hidden" name="date_override" value="%h(P("date_override"))">
535 }
536 @ </p>
537 zScript = ticket_newpage_code();
538 Th_Store("login", g.zLogin ? g.zLogin : "nobody");
539 Th_Store("date", db_text(0, "SELECT datetime('now')"));
540 Th_CreateCommand(g.interp, "submit_ticket", submitTicketCmd,
541 (void*)&zNewUuid, 0);
542 if( g.thTrace ) Th_Trace("BEGIN_TKTNEW_SCRIPT<br />\n", -1);
543 if( Th_Render(zScript)==TH_RETURN && !g.thTrace && zNewUuid ){
544 cgi_redirect(mprintf("%s/tktview/%s", g.zTop, zNewUuid));
545 return;
546 }
547 captcha_generate();
548 @ </form>
549 if( g.thTrace ) Th_Trace("END_TKTVIEW<br />\n", -1);
550 style_footer();
551 }
552
@@ -591,24 +596,25 @@
596 if( g.thTrace ) Th_Trace("BEGIN_TKTEDIT<br />\n", -1);
597 ticket_init();
598 getAllTicketFields();
599 initializeVariablesFromCGI();
600 initializeVariablesFromDb();
601 form_begin(0, "%R/%s", g.zPath);
602 @ <input type="hidden" name="name" value="%s(zName)" />
603 login_insert_csrf_secret();
604 @ </p>
605 zScript = ticket_editpage_code();
606 Th_Store("login", g.zLogin ? g.zLogin : "nobody");
607 Th_Store("date", db_text(0, "SELECT datetime('now')"));
608 Th_CreateCommand(g.interp, "append_field", appendRemarkCmd, 0, 0);
609 Th_CreateCommand(g.interp, "submit_ticket", submitTicketCmd, (void*)&zName,0);
610 if( g.thTrace ) Th_Trace("BEGIN_TKTEDIT_SCRIPT<br />\n", -1);
611 if( Th_Render(zScript)==TH_RETURN && !g.thTrace && zName ){
612 cgi_redirect(mprintf("%s/tktview/%s", g.zTop, zName));
613 return;
614 }
615 captcha_generate();
616 @ </form>
617 if( g.thTrace ) Th_Trace("BEGIN_TKTEDIT<br />\n", -1);
618 style_footer();
619 }
620
@@ -829,15 +835,15 @@
835 const char *z;
836 z = pTkt->aField[i].zName;
837 blob_set(&val, pTkt->aField[i].zValue);
838 if( z[0]=='+' ){
839 @ <li>Appended to %h(&z[1]):<blockquote>
840 wiki_convert(&val, 0, WIKI_NOBADLINKS);
841 @ </blockquote></li>
842 }else if( blob_size(&val)<=50 && contains_newline(&val) ){
843 @ <li>Change %h(z) to:<blockquote>
844 wiki_convert(&val, 0, WIKI_NOBADLINKS);
845 @ </blockquote></li>
846 }else{
847 @ <li>Change %h(z) to "%h(blob_str(&val))"</li>
848 }
849 blob_reset(&val);
@@ -1006,11 +1012,11 @@
1012 eCmd = history;
1013 }else{
1014 eCmd = set;
1015 }
1016 if( g.argc==3 ){
1017 usage("set|change|history TICKETUUID");
1018 }
1019 zTktUuid = db_text(0,
1020 "SELECT tkt_uuid FROM ticket WHERE tkt_uuid GLOB '%s*'", g.argv[3]
1021 );
1022 if( !zTktUuid ){
1023
+3 -1
--- src/update.c
+++ src/update.c
@@ -123,11 +123,13 @@
123123
db_must_be_within_tree();
124124
vid = db_lget_int("checkout", 0);
125125
if( vid==0 ){
126126
fossil_fatal("cannot find current version");
127127
}
128
- if( !nochangeFlag && !internalUpdate ) autosync(AUTOSYNC_PULL);
128
+ if( !nochangeFlag && !internalUpdate ){
129
+ autosync(SYNC_PULL + SYNC_VERBOSE*verboseFlag);
130
+ }
129131
130132
/* Create any empty directories now, as well as after the update,
131133
** so changes in settings are reflected now */
132134
if( !nochangeFlag ) ensure_empty_dirs_created();
133135
134136
--- src/update.c
+++ src/update.c
@@ -123,11 +123,13 @@
123 db_must_be_within_tree();
124 vid = db_lget_int("checkout", 0);
125 if( vid==0 ){
126 fossil_fatal("cannot find current version");
127 }
128 if( !nochangeFlag && !internalUpdate ) autosync(AUTOSYNC_PULL);
 
 
129
130 /* Create any empty directories now, as well as after the update,
131 ** so changes in settings are reflected now */
132 if( !nochangeFlag ) ensure_empty_dirs_created();
133
134
--- src/update.c
+++ src/update.c
@@ -123,11 +123,13 @@
123 db_must_be_within_tree();
124 vid = db_lget_int("checkout", 0);
125 if( vid==0 ){
126 fossil_fatal("cannot find current version");
127 }
128 if( !nochangeFlag && !internalUpdate ){
129 autosync(SYNC_PULL + SYNC_VERBOSE*verboseFlag);
130 }
131
132 /* Create any empty directories now, as well as after the update,
133 ** so changes in settings are reflected now */
134 if( !nochangeFlag ) ensure_empty_dirs_created();
135
136
+37 -11
--- src/wiki.c
+++ src/wiki.c
@@ -127,10 +127,11 @@
127127
*/
128128
void wiki_page(void){
129129
char *zTag;
130130
int rid = 0;
131131
int isSandbox;
132
+ char *zUuid;
132133
Blob wiki;
133134
Manifest *pWiki = 0;
134135
const char *zPageName;
135136
char *zBody = mprintf("%s","<i>Empty Page</i>");
136137
@@ -159,12 +160,13 @@
159160
@ <li> %z(href("%R/wcontent"))List of All Wiki Pages</a>
160161
@ available on this server.</li>
161162
if( g.perm.ModWiki ){
162163
@ <li> %z(href("%R/modreq"))Tend to pending moderation requests</a></li>
163164
}
164
- @ <li> <form method="get" action="%s(g.zTop)/wfind"><div>
165
- @ Search wiki titles: <input type="text" name="title"/>
165
+ @ <li>
166
+ form_begin(0, "%R/wfind");
167
+ @ <div>Search wiki titles: <input type="text" name="title"/>
166168
@ &nbsp; <input type="submit" /></div></form>
167169
@ </li>
168170
@ </ul>
169171
style_footer();
170172
return;
@@ -171,10 +173,11 @@
171173
}
172174
if( check_name(zPageName) ) return;
173175
isSandbox = is_sandbox(zPageName);
174176
if( isSandbox ){
175177
zBody = db_get("sandbox",zBody);
178
+ rid = 0;
176179
}else{
177180
zTag = mprintf("wiki-%s", zPageName);
178181
rid = db_int(0,
179182
"SELECT rid FROM tagxref"
180183
" WHERE tagid=(SELECT tagid FROM tag WHERE tagname=%Q)"
@@ -185,10 +188,17 @@
185188
if( pWiki ){
186189
zBody = pWiki->zWiki;
187190
}
188191
}
189192
if( !g.isHome ){
193
+ if( rid ){
194
+ style_submenu_element("Diff", "Last change",
195
+ "%R/wdiff?name=%T&a=%d", zPageName, rid);
196
+ zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
197
+ style_submenu_element("Details", "Details",
198
+ "%R/info/%S", zUuid);
199
+ }
190200
if( (rid && g.perm.WrWiki) || (!rid && g.perm.NewWiki) ){
191201
if( db_get_boolean("wysiwyg-wiki", 0) ){
192202
style_submenu_element("Edit", "Edit Wiki Page",
193203
"%s/wikiedit?name=%T&wysiwyg=1",
194204
g.zTop, zPageName);
@@ -253,10 +263,11 @@
253263
const char *zPageName;
254264
int n;
255265
const char *z;
256266
char *zBody = (char*)P("w");
257267
int isWysiwyg = P("wysiwyg")!=0;
268
+ int goodCaptcha = 1;
258269
259270
if( P("edit-wysiwyg")!=0 ){ isWysiwyg = 1; zBody = 0; }
260271
if( P("edit-markup")!=0 ){ isWysiwyg = 0; zBody = 0; }
261272
if( zBody ){
262273
if( isWysiwyg ){
@@ -294,11 +305,13 @@
294305
}
295306
if( zBody==0 && (pWiki = manifest_get(rid, CFTYPE_WIKI))!=0 ){
296307
zBody = pWiki->zWiki;
297308
}
298309
}
299
- if( P("submit")!=0 && zBody!=0 ){
310
+ if( P("submit")!=0 && zBody!=0
311
+ && (goodCaptcha = captcha_is_correct())
312
+ ){
300313
char *zDate;
301314
Blob cksum;
302315
blob_zero(&wiki);
303316
db_begin_transaction();
304317
if( isSandbox ){
@@ -333,10 +346,13 @@
333346
if( zBody==0 ){
334347
zBody = mprintf("<i>Empty Page</i>");
335348
}
336349
style_set_current_page("%s?name=%T", g.zPath, zPageName);
337350
style_header("Edit: %s", zPageName);
351
+ if( !goodCaptcha ){
352
+ @ <p class="generalError">Error: Incorrect security code.</p>
353
+ }
338354
blob_zero(&wiki);
339355
blob_append(&wiki, zBody, -1);
340356
if( P("preview")!=0 ){
341357
@ Preview:<hr />
342358
wiki_convert(&wiki, 0, 0);
@@ -348,11 +364,12 @@
348364
}
349365
if( n<20 ) n = 20;
350366
if( n>30 ) n = 30;
351367
if( !isWysiwyg ){
352368
/* Traditional markup-only editing */
353
- @ <form method="post" action="%s(g.zTop)/wikiedit"><div>
369
+ form_begin(0, "%R/wikiedit");
370
+ @ <div>
354371
@ <textarea name="w" class="wikiedit" cols="80"
355372
@ rows="%d(n)" wrap="virtual">%h(zBody)</textarea>
356373
@ <br />
357374
if( db_get_boolean("wysiwyg-wiki", 0) ){
358375
@ <input type="submit" name="edit-wysiwyg" value="Wysiwyg Editor"
@@ -360,12 +377,12 @@
360377
}
361378
@ <input type="submit" name="preview" value="Preview Your Changes" />
362379
}else{
363380
/* Wysiwyg editing */
364381
Blob html, temp;
365
- @ <form method="post" action="%s(g.zTop)/wikiedit"
366
- @ onsubmit="wysiwygSubmit()"><div>
382
+ form_begin("onsubmit='wysiwygSubmit()'", "%R/wikiedit");
383
+ @ <div>
367384
@ <input type="hidden" name="wysiwyg" value="1" />
368385
blob_zero(&temp);
369386
wiki_convert(&wiki, &temp, 0);
370387
blob_zero(&html);
371388
htmlTidy(blob_str(&temp), &html);
@@ -374,16 +391,18 @@
374391
blob_reset(&html);
375392
@ <br />
376393
@ <input type="submit" name="edit-markup" value="Markup Editor"
377394
@ onclick='return confirm("Switching to markup-mode\nwill erase your WYSIWYG\nedits. Continue?")' />
378395
}
379
- @ <input type="submit" name="submit" value="Apply These Changes" />
380396
login_insert_csrf_secret();
397
+ @ <input type="submit" name="submit" value="Apply These Changes" />
381398
@ <input type="hidden" name="name" value="%h(zPageName)" />
382399
@ <input type="submit" name="cancel" value="Cancel"
383400
@ onclick='confirm("Abandon your changes?")' />
384
- @ </div></form>
401
+ @ </div>
402
+ captcha_generate();
403
+ @ </form>
385404
manifest_destroy(pWiki);
386405
blob_reset(&wiki);
387406
style_footer();
388407
}
389408
@@ -410,11 +429,11 @@
410429
}
411430
}
412431
style_header("Create A New Wiki Page");
413432
@ <p>Rules for wiki page names:</p>
414433
well_formed_wiki_name_rules();
415
- @ <form method="post" action="%s(g.zTop)/wikinew">
434
+ form_begin(0, "%R/wikinew");
416435
@ <p>Name of new wiki page:
417436
@ <input style="width: 35;" type="text" name="name" value="%h(zName)" />
418437
@ <input type="submit" value="Create" />
419438
@ </p></form>
420439
if( zName[0] ){
@@ -455,10 +474,11 @@
455474
char *zTag;
456475
int rid = 0;
457476
int isSandbox;
458477
const char *zPageName;
459478
const char *zUser;
479
+ int goodCaptcha = 1;
460480
461481
login_check_credentials();
462482
zPageName = PD("name","");
463483
if( check_name(zPageName) ) return;
464484
isSandbox = is_sandbox(zPageName);
@@ -477,11 +497,13 @@
477497
}
478498
if( !g.perm.ApndWiki ){
479499
login_needed();
480500
return;
481501
}
482
- if( P("submit")!=0 && P("r")!=0 && P("u")!=0 ){
502
+ if( P("submit")!=0 && P("r")!=0 && P("u")!=0
503
+ && (goodCaptcha = captcha_is_correct())
504
+ ){
483505
char *zDate;
484506
Blob cksum;
485507
Blob body;
486508
Blob wiki;
487509
Manifest *pWiki = 0;
@@ -525,10 +547,13 @@
525547
cgi_redirectf("wiki?name=%T", zPageName);
526548
return;
527549
}
528550
style_set_current_page("%s?name=%T", g.zPath, zPageName);
529551
style_header("Append Comment To: %s", zPageName);
552
+ if( !goodCaptcha ){
553
+ @ <p class="generalError">Error: Incorrect security code.</p>
554
+ }
530555
if( P("preview")!=0 ){
531556
Blob preview;
532557
blob_zero(&preview);
533558
appendRemark(&preview);
534559
@ Preview:<hr>
@@ -535,11 +560,11 @@
535560
wiki_convert(&preview, 0, 0);
536561
@ <hr>
537562
blob_reset(&preview);
538563
}
539564
zUser = PD("u", g.zLogin);
540
- @ <form method="post" action="%s(g.zTop)/wikiappend">
565
+ form_begin(0, "%R/wikiappend");
541566
login_insert_csrf_secret();
542567
@ <input type="hidden" name="name" value="%h(zPageName)" />
543568
@ Your Name:
544569
@ <input type="text" name="u" size="20" value="%h(zUser)" /><br />
545570
@ Comment to append:<br />
@@ -547,10 +572,11 @@
547572
@ rows="10" wrap="virtual">%h(PD("r",""))</textarea>
548573
@ <br />
549574
@ <input type="submit" name="preview" value="Preview Your Comment" />
550575
@ <input type="submit" name="submit" value="Append Your Changes" />
551576
@ <input type="submit" name="cancel" value="Cancel" />
577
+ captcha_generate();
552578
@ </form>
553579
style_footer();
554580
}
555581
556582
/*
557583
--- src/wiki.c
+++ src/wiki.c
@@ -127,10 +127,11 @@
127 */
128 void wiki_page(void){
129 char *zTag;
130 int rid = 0;
131 int isSandbox;
 
132 Blob wiki;
133 Manifest *pWiki = 0;
134 const char *zPageName;
135 char *zBody = mprintf("%s","<i>Empty Page</i>");
136
@@ -159,12 +160,13 @@
159 @ <li> %z(href("%R/wcontent"))List of All Wiki Pages</a>
160 @ available on this server.</li>
161 if( g.perm.ModWiki ){
162 @ <li> %z(href("%R/modreq"))Tend to pending moderation requests</a></li>
163 }
164 @ <li> <form method="get" action="%s(g.zTop)/wfind"><div>
165 @ Search wiki titles: <input type="text" name="title"/>
 
166 @ &nbsp; <input type="submit" /></div></form>
167 @ </li>
168 @ </ul>
169 style_footer();
170 return;
@@ -171,10 +173,11 @@
171 }
172 if( check_name(zPageName) ) return;
173 isSandbox = is_sandbox(zPageName);
174 if( isSandbox ){
175 zBody = db_get("sandbox",zBody);
 
176 }else{
177 zTag = mprintf("wiki-%s", zPageName);
178 rid = db_int(0,
179 "SELECT rid FROM tagxref"
180 " WHERE tagid=(SELECT tagid FROM tag WHERE tagname=%Q)"
@@ -185,10 +188,17 @@
185 if( pWiki ){
186 zBody = pWiki->zWiki;
187 }
188 }
189 if( !g.isHome ){
 
 
 
 
 
 
 
190 if( (rid && g.perm.WrWiki) || (!rid && g.perm.NewWiki) ){
191 if( db_get_boolean("wysiwyg-wiki", 0) ){
192 style_submenu_element("Edit", "Edit Wiki Page",
193 "%s/wikiedit?name=%T&wysiwyg=1",
194 g.zTop, zPageName);
@@ -253,10 +263,11 @@
253 const char *zPageName;
254 int n;
255 const char *z;
256 char *zBody = (char*)P("w");
257 int isWysiwyg = P("wysiwyg")!=0;
 
258
259 if( P("edit-wysiwyg")!=0 ){ isWysiwyg = 1; zBody = 0; }
260 if( P("edit-markup")!=0 ){ isWysiwyg = 0; zBody = 0; }
261 if( zBody ){
262 if( isWysiwyg ){
@@ -294,11 +305,13 @@
294 }
295 if( zBody==0 && (pWiki = manifest_get(rid, CFTYPE_WIKI))!=0 ){
296 zBody = pWiki->zWiki;
297 }
298 }
299 if( P("submit")!=0 && zBody!=0 ){
 
 
300 char *zDate;
301 Blob cksum;
302 blob_zero(&wiki);
303 db_begin_transaction();
304 if( isSandbox ){
@@ -333,10 +346,13 @@
333 if( zBody==0 ){
334 zBody = mprintf("<i>Empty Page</i>");
335 }
336 style_set_current_page("%s?name=%T", g.zPath, zPageName);
337 style_header("Edit: %s", zPageName);
 
 
 
338 blob_zero(&wiki);
339 blob_append(&wiki, zBody, -1);
340 if( P("preview")!=0 ){
341 @ Preview:<hr />
342 wiki_convert(&wiki, 0, 0);
@@ -348,11 +364,12 @@
348 }
349 if( n<20 ) n = 20;
350 if( n>30 ) n = 30;
351 if( !isWysiwyg ){
352 /* Traditional markup-only editing */
353 @ <form method="post" action="%s(g.zTop)/wikiedit"><div>
 
354 @ <textarea name="w" class="wikiedit" cols="80"
355 @ rows="%d(n)" wrap="virtual">%h(zBody)</textarea>
356 @ <br />
357 if( db_get_boolean("wysiwyg-wiki", 0) ){
358 @ <input type="submit" name="edit-wysiwyg" value="Wysiwyg Editor"
@@ -360,12 +377,12 @@
360 }
361 @ <input type="submit" name="preview" value="Preview Your Changes" />
362 }else{
363 /* Wysiwyg editing */
364 Blob html, temp;
365 @ <form method="post" action="%s(g.zTop)/wikiedit"
366 @ onsubmit="wysiwygSubmit()"><div>
367 @ <input type="hidden" name="wysiwyg" value="1" />
368 blob_zero(&temp);
369 wiki_convert(&wiki, &temp, 0);
370 blob_zero(&html);
371 htmlTidy(blob_str(&temp), &html);
@@ -374,16 +391,18 @@
374 blob_reset(&html);
375 @ <br />
376 @ <input type="submit" name="edit-markup" value="Markup Editor"
377 @ onclick='return confirm("Switching to markup-mode\nwill erase your WYSIWYG\nedits. Continue?")' />
378 }
379 @ <input type="submit" name="submit" value="Apply These Changes" />
380 login_insert_csrf_secret();
 
381 @ <input type="hidden" name="name" value="%h(zPageName)" />
382 @ <input type="submit" name="cancel" value="Cancel"
383 @ onclick='confirm("Abandon your changes?")' />
384 @ </div></form>
 
 
385 manifest_destroy(pWiki);
386 blob_reset(&wiki);
387 style_footer();
388 }
389
@@ -410,11 +429,11 @@
410 }
411 }
412 style_header("Create A New Wiki Page");
413 @ <p>Rules for wiki page names:</p>
414 well_formed_wiki_name_rules();
415 @ <form method="post" action="%s(g.zTop)/wikinew">
416 @ <p>Name of new wiki page:
417 @ <input style="width: 35;" type="text" name="name" value="%h(zName)" />
418 @ <input type="submit" value="Create" />
419 @ </p></form>
420 if( zName[0] ){
@@ -455,10 +474,11 @@
455 char *zTag;
456 int rid = 0;
457 int isSandbox;
458 const char *zPageName;
459 const char *zUser;
 
460
461 login_check_credentials();
462 zPageName = PD("name","");
463 if( check_name(zPageName) ) return;
464 isSandbox = is_sandbox(zPageName);
@@ -477,11 +497,13 @@
477 }
478 if( !g.perm.ApndWiki ){
479 login_needed();
480 return;
481 }
482 if( P("submit")!=0 && P("r")!=0 && P("u")!=0 ){
 
 
483 char *zDate;
484 Blob cksum;
485 Blob body;
486 Blob wiki;
487 Manifest *pWiki = 0;
@@ -525,10 +547,13 @@
525 cgi_redirectf("wiki?name=%T", zPageName);
526 return;
527 }
528 style_set_current_page("%s?name=%T", g.zPath, zPageName);
529 style_header("Append Comment To: %s", zPageName);
 
 
 
530 if( P("preview")!=0 ){
531 Blob preview;
532 blob_zero(&preview);
533 appendRemark(&preview);
534 @ Preview:<hr>
@@ -535,11 +560,11 @@
535 wiki_convert(&preview, 0, 0);
536 @ <hr>
537 blob_reset(&preview);
538 }
539 zUser = PD("u", g.zLogin);
540 @ <form method="post" action="%s(g.zTop)/wikiappend">
541 login_insert_csrf_secret();
542 @ <input type="hidden" name="name" value="%h(zPageName)" />
543 @ Your Name:
544 @ <input type="text" name="u" size="20" value="%h(zUser)" /><br />
545 @ Comment to append:<br />
@@ -547,10 +572,11 @@
547 @ rows="10" wrap="virtual">%h(PD("r",""))</textarea>
548 @ <br />
549 @ <input type="submit" name="preview" value="Preview Your Comment" />
550 @ <input type="submit" name="submit" value="Append Your Changes" />
551 @ <input type="submit" name="cancel" value="Cancel" />
 
552 @ </form>
553 style_footer();
554 }
555
556 /*
557
--- src/wiki.c
+++ src/wiki.c
@@ -127,10 +127,11 @@
127 */
128 void wiki_page(void){
129 char *zTag;
130 int rid = 0;
131 int isSandbox;
132 char *zUuid;
133 Blob wiki;
134 Manifest *pWiki = 0;
135 const char *zPageName;
136 char *zBody = mprintf("%s","<i>Empty Page</i>");
137
@@ -159,12 +160,13 @@
160 @ <li> %z(href("%R/wcontent"))List of All Wiki Pages</a>
161 @ available on this server.</li>
162 if( g.perm.ModWiki ){
163 @ <li> %z(href("%R/modreq"))Tend to pending moderation requests</a></li>
164 }
165 @ <li>
166 form_begin(0, "%R/wfind");
167 @ <div>Search wiki titles: <input type="text" name="title"/>
168 @ &nbsp; <input type="submit" /></div></form>
169 @ </li>
170 @ </ul>
171 style_footer();
172 return;
@@ -171,10 +173,11 @@
173 }
174 if( check_name(zPageName) ) return;
175 isSandbox = is_sandbox(zPageName);
176 if( isSandbox ){
177 zBody = db_get("sandbox",zBody);
178 rid = 0;
179 }else{
180 zTag = mprintf("wiki-%s", zPageName);
181 rid = db_int(0,
182 "SELECT rid FROM tagxref"
183 " WHERE tagid=(SELECT tagid FROM tag WHERE tagname=%Q)"
@@ -185,10 +188,17 @@
188 if( pWiki ){
189 zBody = pWiki->zWiki;
190 }
191 }
192 if( !g.isHome ){
193 if( rid ){
194 style_submenu_element("Diff", "Last change",
195 "%R/wdiff?name=%T&a=%d", zPageName, rid);
196 zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
197 style_submenu_element("Details", "Details",
198 "%R/info/%S", zUuid);
199 }
200 if( (rid && g.perm.WrWiki) || (!rid && g.perm.NewWiki) ){
201 if( db_get_boolean("wysiwyg-wiki", 0) ){
202 style_submenu_element("Edit", "Edit Wiki Page",
203 "%s/wikiedit?name=%T&wysiwyg=1",
204 g.zTop, zPageName);
@@ -253,10 +263,11 @@
263 const char *zPageName;
264 int n;
265 const char *z;
266 char *zBody = (char*)P("w");
267 int isWysiwyg = P("wysiwyg")!=0;
268 int goodCaptcha = 1;
269
270 if( P("edit-wysiwyg")!=0 ){ isWysiwyg = 1; zBody = 0; }
271 if( P("edit-markup")!=0 ){ isWysiwyg = 0; zBody = 0; }
272 if( zBody ){
273 if( isWysiwyg ){
@@ -294,11 +305,13 @@
305 }
306 if( zBody==0 && (pWiki = manifest_get(rid, CFTYPE_WIKI))!=0 ){
307 zBody = pWiki->zWiki;
308 }
309 }
310 if( P("submit")!=0 && zBody!=0
311 && (goodCaptcha = captcha_is_correct())
312 ){
313 char *zDate;
314 Blob cksum;
315 blob_zero(&wiki);
316 db_begin_transaction();
317 if( isSandbox ){
@@ -333,10 +346,13 @@
346 if( zBody==0 ){
347 zBody = mprintf("<i>Empty Page</i>");
348 }
349 style_set_current_page("%s?name=%T", g.zPath, zPageName);
350 style_header("Edit: %s", zPageName);
351 if( !goodCaptcha ){
352 @ <p class="generalError">Error: Incorrect security code.</p>
353 }
354 blob_zero(&wiki);
355 blob_append(&wiki, zBody, -1);
356 if( P("preview")!=0 ){
357 @ Preview:<hr />
358 wiki_convert(&wiki, 0, 0);
@@ -348,11 +364,12 @@
364 }
365 if( n<20 ) n = 20;
366 if( n>30 ) n = 30;
367 if( !isWysiwyg ){
368 /* Traditional markup-only editing */
369 form_begin(0, "%R/wikiedit");
370 @ <div>
371 @ <textarea name="w" class="wikiedit" cols="80"
372 @ rows="%d(n)" wrap="virtual">%h(zBody)</textarea>
373 @ <br />
374 if( db_get_boolean("wysiwyg-wiki", 0) ){
375 @ <input type="submit" name="edit-wysiwyg" value="Wysiwyg Editor"
@@ -360,12 +377,12 @@
377 }
378 @ <input type="submit" name="preview" value="Preview Your Changes" />
379 }else{
380 /* Wysiwyg editing */
381 Blob html, temp;
382 form_begin("onsubmit='wysiwygSubmit()'", "%R/wikiedit");
383 @ <div>
384 @ <input type="hidden" name="wysiwyg" value="1" />
385 blob_zero(&temp);
386 wiki_convert(&wiki, &temp, 0);
387 blob_zero(&html);
388 htmlTidy(blob_str(&temp), &html);
@@ -374,16 +391,18 @@
391 blob_reset(&html);
392 @ <br />
393 @ <input type="submit" name="edit-markup" value="Markup Editor"
394 @ onclick='return confirm("Switching to markup-mode\nwill erase your WYSIWYG\nedits. Continue?")' />
395 }
 
396 login_insert_csrf_secret();
397 @ <input type="submit" name="submit" value="Apply These Changes" />
398 @ <input type="hidden" name="name" value="%h(zPageName)" />
399 @ <input type="submit" name="cancel" value="Cancel"
400 @ onclick='confirm("Abandon your changes?")' />
401 @ </div>
402 captcha_generate();
403 @ </form>
404 manifest_destroy(pWiki);
405 blob_reset(&wiki);
406 style_footer();
407 }
408
@@ -410,11 +429,11 @@
429 }
430 }
431 style_header("Create A New Wiki Page");
432 @ <p>Rules for wiki page names:</p>
433 well_formed_wiki_name_rules();
434 form_begin(0, "%R/wikinew");
435 @ <p>Name of new wiki page:
436 @ <input style="width: 35;" type="text" name="name" value="%h(zName)" />
437 @ <input type="submit" value="Create" />
438 @ </p></form>
439 if( zName[0] ){
@@ -455,10 +474,11 @@
474 char *zTag;
475 int rid = 0;
476 int isSandbox;
477 const char *zPageName;
478 const char *zUser;
479 int goodCaptcha = 1;
480
481 login_check_credentials();
482 zPageName = PD("name","");
483 if( check_name(zPageName) ) return;
484 isSandbox = is_sandbox(zPageName);
@@ -477,11 +497,13 @@
497 }
498 if( !g.perm.ApndWiki ){
499 login_needed();
500 return;
501 }
502 if( P("submit")!=0 && P("r")!=0 && P("u")!=0
503 && (goodCaptcha = captcha_is_correct())
504 ){
505 char *zDate;
506 Blob cksum;
507 Blob body;
508 Blob wiki;
509 Manifest *pWiki = 0;
@@ -525,10 +547,13 @@
547 cgi_redirectf("wiki?name=%T", zPageName);
548 return;
549 }
550 style_set_current_page("%s?name=%T", g.zPath, zPageName);
551 style_header("Append Comment To: %s", zPageName);
552 if( !goodCaptcha ){
553 @ <p class="generalError">Error: Incorrect security code.</p>
554 }
555 if( P("preview")!=0 ){
556 Blob preview;
557 blob_zero(&preview);
558 appendRemark(&preview);
559 @ Preview:<hr>
@@ -535,11 +560,11 @@
560 wiki_convert(&preview, 0, 0);
561 @ <hr>
562 blob_reset(&preview);
563 }
564 zUser = PD("u", g.zLogin);
565 form_begin(0, "%R/wikiappend");
566 login_insert_csrf_secret();
567 @ <input type="hidden" name="name" value="%h(zPageName)" />
568 @ Your Name:
569 @ <input type="text" name="u" size="20" value="%h(zUser)" /><br />
570 @ Comment to append:<br />
@@ -547,10 +572,11 @@
572 @ rows="10" wrap="virtual">%h(PD("r",""))</textarea>
573 @ <br />
574 @ <input type="submit" name="preview" value="Preview Your Comment" />
575 @ <input type="submit" name="submit" value="Append Your Changes" />
576 @ <input type="submit" name="cancel" value="Cancel" />
577 captcha_generate();
578 @ </form>
579 style_footer();
580 }
581
582 /*
583
+138 -59
--- src/wikiformat.c
+++ src/wikiformat.c
@@ -23,15 +23,16 @@
2323
2424
#if INTERFACE
2525
/*
2626
** Allowed wiki transformation operations
2727
*/
28
-#define WIKI_NOFOLLOW 0x001
29
-#define WIKI_HTML 0x002
30
-#define WIKI_INLINE 0x004 /* Do not surround with <p>..</p> */
31
-#define WIKI_NOBLOCK 0x008 /* No block markup of any kind */
32
-#define WIKI_BUTTONS 0x010 /* Allow sub-menu buttons */
28
+#define WIKI_HTMLONLY 0x001 /* HTML markup only. No wiki */
29
+#define WIKI_INLINE 0x002 /* Do not surround with <p>..</p> */
30
+#define WIKI_NOBLOCK 0x004 /* No block markup of any kind */
31
+#define WIKI_BUTTONS 0x008 /* Allow sub-menu buttons */
32
+#define WIKI_NOBADLINKS 0x010 /* Ignore broken hyperlinks */
33
+#define WIKI_LINKSONLY 0x020 /* No markup. Only decorate links */
3334
#endif
3435
3536
3637
/*
3738
** These are the only markup attributes allowed.
@@ -384,22 +385,23 @@
384385
** State flags. Save the lower 16 bits for the WIKI_* flags.
385386
*/
386387
#define AT_NEWLINE 0x0010000 /* At start of a line */
387388
#define AT_PARAGRAPH 0x0020000 /* At start of a paragraph */
388389
#define ALLOW_WIKI 0x0040000 /* Allow wiki markup */
389
-#define FONT_MARKUP_ONLY 0x0080000 /* Only allow MUTYPE_FONT markup */
390
-#define INLINE_MARKUP_ONLY 0x0100000 /* Allow only "inline" markup */
391
-#define IN_LIST 0x0200000 /* Within wiki <ul> or <ol> */
392
-#define WIKI_USE_HTML 0x0400000 /* wiki-use-html option = on */
390
+#define ALLOW_LINKS 0x0080000 /* Allow [...] hyperlinks */
391
+#define FONT_MARKUP_ONLY 0x0100000 /* Only allow MUTYPE_FONT markup */
392
+#define INLINE_MARKUP_ONLY 0x0200000 /* Allow only "inline" markup */
393
+#define IN_LIST 0x0400000 /* Within wiki <ul> or <ol> */
393394
394395
/*
395396
** Current state of the rendering engine
396397
*/
397398
typedef struct Renderer Renderer;
398399
struct Renderer {
399400
Blob *pOut; /* Output appended to this blob */
400401
int state; /* Flag that govern rendering */
402
+ unsigned renderFlags; /* Flags from the client */
401403
int wikiList; /* Current wiki list type */
402404
int inVerbatim; /* True in <verbatim> mode */
403405
int preVerbState; /* Value of state prior to verbatim */
404406
int wantAutoParagraph; /* True if a <p> is desired */
405407
int inAutoParagraph; /* True if within an automatic paragraph */
@@ -484,18 +486,27 @@
484486
** <
485487
** &
486488
** \n
487489
** [
488490
**
489
-** The "[" and "\n" are only considered interesting if the "useWiki"
490
-** flag is set.
491
+** The "[" is only considered if flags contain ALLOW_LINKS or ALLOW_WIKI.
492
+** The "\n" is only considered interesting if the flags constains ALLOW_WIKI.
491493
*/
492
-static int textLength(const char *z, int useWiki){
494
+static int textLength(const char *z, int flags){
493495
int n = 0;
494
- int c;
495
- while( (c = z[0])!=0 && c!='<' && c!='&' &&
496
- (useWiki==0 || (c!='[' && c!='\n')) ){
496
+ int c, x1, x2;
497
+
498
+ if( flags & ALLOW_WIKI ){
499
+ x1 = '[';
500
+ x2 = '\n';
501
+ }else if( flags & ALLOW_LINKS ){
502
+ x1 = '[';
503
+ x2 = 0;
504
+ }else{
505
+ x1 = x2 = 0;
506
+ }
507
+ while( (c = z[0])!=0 && c!='<' && c!='&' && c!=x1 && c!=x2 ){
497508
n++;
498509
z++;
499510
}
500511
return n;
501512
}
@@ -668,13 +679,16 @@
668679
}
669680
if( z[0]=='[' && (n = linkLength(z))>0 ){
670681
*pTokenType = TOKEN_LINK;
671682
return n;
672683
}
684
+ }else if( (p->state & ALLOW_LINKS)!=0 && z[0]=='[' && (n = linkLength(z))>0 ){
685
+ *pTokenType = TOKEN_LINK;
686
+ return n;
673687
}
674688
*pTokenType = TOKEN_TEXT;
675
- return 1 + textLength(z+1, p->state & ALLOW_WIKI);
689
+ return 1 + textLength(z+1, p->state);
676690
}
677691
678692
/*
679693
** Parse only Wiki links, return everything else as TOKEN_RAW.
680694
**
@@ -982,10 +996,11 @@
982996
/*
983997
** Begin a new paragraph if that something that is needed.
984998
*/
985999
static void startAutoParagraph(Renderer *p){
9861000
if( p->wantAutoParagraph==0 ) return;
1001
+ if( p->state & WIKI_LINKSONLY ) return;
9871002
if( p->wikiList==MARKUP_OL || p->wikiList==MARKUP_UL ) return;
9881003
blob_appendf(p->pOut, "<p>", -1);
9891004
pushStack(p, MARKUP_P);
9901005
p->wantAutoParagraph = 0;
9911006
p->inAutoParagraph = 1;
@@ -1075,16 +1090,39 @@
10751090
rc = 0;
10761091
}
10771092
db_reset(&q);
10781093
return rc;
10791094
}
1095
+
1096
+/*
1097
+** Return a pointer to the name part of zTarget (skipping the "wiki:" prefix
1098
+** if there is one) if zTarget is a valid wiki page name. Return NULL if
1099
+** zTarget names a page that does not exist.
1100
+*/
1101
+static const char *validWikiPageName(Renderer *p, const char *zTarget){
1102
+ if( strncmp(zTarget, "wiki:", 5)==0
1103
+ && wiki_name_is_wellformed((const unsigned char*)zTarget) ){
1104
+ return zTarget+5;
1105
+ }
1106
+ if( strcmp(zTarget, "Sandbox")==0 ) return zTarget;
1107
+ if( wiki_name_is_wellformed((const unsigned char *)zTarget)
1108
+ && ((p->state & WIKI_NOBADLINKS)==0 ||
1109
+ db_exists("SELECT 1 FROM tag WHERE tagname GLOB 'wiki-%q'", zTarget))
1110
+ ){
1111
+ return zTarget;
1112
+ }
1113
+ return 0;
1114
+}
10801115
10811116
/*
10821117
** Resolve a hyperlink. The zTarget argument is the content of the [...]
10831118
** in the wiki. Append to the output string whatever text is appropriate
10841119
** for opening the hyperlink. Write into zClose[0...nClose-1] text that will
10851120
** close the markup.
1121
+**
1122
+** If this routine determines that no hyperlink should be generated, then
1123
+** set zClose[0] to 0.
10861124
**
10871125
** Actually, this routine might or might not append the hyperlink, depending
10881126
** on current rendering rules: specifically does the current user have
10891127
** "History" permission.
10901128
**
@@ -1112,27 +1150,23 @@
11121150
char *zClose, /* Write hyperlink closing text here */
11131151
int nClose, /* Bytes available in zClose[] */
11141152
const char *zOrig /* Complete document text */
11151153
){
11161154
const char *zTerm = "</a>";
1117
- assert( nClose>=20 );
1155
+ const char *z;
11181156
1157
+ assert( nClose>=20 );
11191158
if( strncmp(zTarget, "http:", 5)==0
11201159
|| strncmp(zTarget, "https:", 6)==0
11211160
|| strncmp(zTarget, "ftp:", 4)==0
11221161
|| strncmp(zTarget, "mailto:", 7)==0
11231162
){
11241163
blob_appendf(p->pOut, "<a href=\"%s\">", zTarget);
1125
- /* zTerm = "&#x27FE;</a>"; // doesn't work on windows */
11261164
}else if( zTarget[0]=='/' ){
11271165
blob_appendf(p->pOut, "<a href=\"%s%h\">", g.zTop, zTarget);
11281166
}else if( zTarget[0]=='.' || zTarget[0]=='#' ){
1129
- if( 1 ){
1130
- blob_appendf(p->pOut, "<a href=\"%h\">", zTarget);
1131
- }else{
1132
- zTerm = "";
1133
- }
1167
+ blob_appendf(p->pOut, "<a href=\"%h\">", zTarget);
11341168
}else if( is_valid_uuid(zTarget) ){
11351169
int isClosed = 0;
11361170
if( is_ticket(zTarget, &isClosed) ){
11371171
/* Special display processing for tickets. Display the hyperlink
11381172
** as crossed out if the ticket is closed.
@@ -1156,32 +1190,33 @@
11561190
blob_appendf(p->pOut, "[");
11571191
zTerm = "]";
11581192
}
11591193
}
11601194
}else if( !in_this_repo(zTarget) ){
1161
- blob_appendf(p->pOut, "<span class=\"brokenlink\">[", zTarget);
1162
- zTerm = "]</span>";
1195
+ if( (p->state & (WIKI_LINKSONLY|WIKI_NOBADLINKS))!=0 ){
1196
+ zTerm = "";
1197
+ }else{
1198
+ blob_appendf(p->pOut, "<span class=\"brokenlink\">[", zTarget);
1199
+ zTerm = "]</span>";
1200
+ }
11631201
}else if( g.perm.Hyperlink ){
11641202
blob_appendf(p->pOut, "%z[",href("%R/info/%s", zTarget));
11651203
zTerm = "]</a>";
11661204
}
11671205
}else if( strlen(zTarget)>=10 && fossil_isdigit(zTarget[0]) && zTarget[4]=='-'
11681206
&& db_int(0, "SELECT datetime(%Q) NOT NULL", zTarget) ){
11691207
blob_appendf(p->pOut, "<a href=\"%R/timeline?c=%T\">", zTarget);
1170
- }else if( strncmp(zTarget, "wiki:", 5)==0
1171
- && wiki_name_is_wellformed((const unsigned char*)zTarget) ){
1172
- zTarget += 5;
1173
- blob_appendf(p->pOut, "<a href=\"%R/wiki?name=%T\">", zTarget);
1174
- }else if( wiki_name_is_wellformed((const unsigned char *)zTarget) ){
1175
- blob_appendf(p->pOut, "<a href=\"%R/wiki?name=%T\">", zTarget);
1208
+ }else if( (z = validWikiPageName(p, zTarget))!=0 ){
1209
+ blob_appendf(p->pOut, "<a href=\"%R/wiki?name=%T\">", z);
11761210
}else if( zTarget>=&zOrig[2] && !fossil_isspace(zTarget[-2]) ){
11771211
/* Probably an array subscript in code */
1178
- blob_appendf(p->pOut, "[");
1179
- zTerm = "]";
1212
+ zTerm = "";
1213
+ }else if( (p->state & (WIKI_NOBADLINKS|WIKI_LINKSONLY))!=0 ){
1214
+ zTerm = "";
11801215
}else{
1181
- blob_appendf(p->pOut, "<span class=\"brokenlink\">[%h]</span>", zTarget);
1182
- zTerm = "";
1216
+ blob_appendf(p->pOut, "<span class=\"brokenlink\">[%h]", zTarget);
1217
+ zTerm = "</span>";
11831218
}
11841219
assert( strlen(zTerm)<nClose );
11851220
sqlite3_snprintf(nClose, zClose, "%s", zTerm);
11861221
}
11871222
@@ -1217,19 +1252,20 @@
12171252
static void wiki_render(Renderer *p, char *z){
12181253
int tokenType;
12191254
ParsedMarkup markup;
12201255
int n;
12211256
int inlineOnly = (p->state & INLINE_MARKUP_ONLY)!=0;
1222
- int wikiUseHtml = (p->state & WIKI_USE_HTML)!=0;
1257
+ int wikiHtmlOnly = (p->state & (WIKI_HTMLONLY | WIKI_LINKSONLY))!=0;
1258
+ int linksOnly = (p->state & WIKI_LINKSONLY)!=0;
12231259
char *zOrig = z;
12241260
12251261
/* Make sure the attribute constants and names still align
12261262
** following changes in the attribute list. */
12271263
assert( fossil_strcmp(aAttribute[ATTR_WIDTH].zName, "width")==0 );
12281264
12291265
while( z[0] ){
1230
- if( wikiUseHtml ){
1266
+ if( wikiHtmlOnly ){
12311267
n = nextRawToken(z, p, &tokenType);
12321268
}else{
12331269
n = nextWikiToken(z, p, &tokenType);
12341270
}
12351271
p->state &= ~(AT_NEWLINE|AT_PARAGRAPH);
@@ -1338,33 +1374,46 @@
13381374
char *zTarget;
13391375
char *zDisplay = 0;
13401376
int i, j;
13411377
int savedState;
13421378
char zClose[20];
1379
+ char cS1 = 0;
1380
+ int iS1 = 0;
13431381
13441382
startAutoParagraph(p);
13451383
zTarget = &z[1];
13461384
for(i=1; z[i] && z[i]!=']'; i++){
13471385
if( z[i]=='|' && zDisplay==0 ){
13481386
zDisplay = &z[i+1];
1349
- z[i] = 0;
1350
- for(j=i-1; j>0 && fossil_isspace(z[j]); j--){ z[j] = 0; }
1387
+ for(j=i; j>0 && fossil_isspace(z[j-1]); j--){}
1388
+ iS1 = j;
1389
+ cS1 = z[j];
1390
+ z[j] = 0;
13511391
}
13521392
}
13531393
z[i] = 0;
13541394
if( zDisplay==0 ){
13551395
zDisplay = zTarget;
13561396
}else{
13571397
while( fossil_isspace(*zDisplay) ) zDisplay++;
13581398
}
13591399
openHyperlink(p, zTarget, zClose, sizeof(zClose), zOrig);
1360
- savedState = p->state;
1361
- p->state &= ~ALLOW_WIKI;
1362
- p->state |= FONT_MARKUP_ONLY;
1363
- wiki_render(p, zDisplay);
1364
- p->state = savedState;
1365
- blob_append(p->pOut, zClose, -1);
1400
+ if( linksOnly || zClose[0]==0 || p->inVerbatim ){
1401
+ if( cS1 ) z[iS1] = cS1;
1402
+ if( zClose[0]!=']' ){
1403
+ blob_appendf(p->pOut, "[%h]%s", zTarget, zClose);
1404
+ }else{
1405
+ blob_appendf(p->pOut, "%h%s", zTarget, zClose);
1406
+ }
1407
+ }else{
1408
+ savedState = p->state;
1409
+ p->state &= ~ALLOW_WIKI;
1410
+ p->state |= FONT_MARKUP_ONLY;
1411
+ wiki_render(p, zDisplay);
1412
+ p->state = savedState;
1413
+ blob_append(p->pOut, zClose, -1);
1414
+ }
13661415
break;
13671416
}
13681417
case TOKEN_TEXT: {
13691418
int i;
13701419
for(i=0; i<n && fossil_isspace(z[i]); i++){}
@@ -1371,11 +1420,15 @@
13711420
if( i<n ) startAutoParagraph(p);
13721421
blob_append(p->pOut, z, n);
13731422
break;
13741423
}
13751424
case TOKEN_RAW: {
1376
- blob_append(p->pOut, z, n);
1425
+ if( linksOnly ){
1426
+ htmlize_to_blob(p->pOut, z, n);
1427
+ }else{
1428
+ blob_append(p->pOut, z, n);
1429
+ }
13771430
break;
13781431
}
13791432
case TOKEN_MARKUP: {
13801433
const char *zId;
13811434
int iDiv;
@@ -1466,22 +1519,26 @@
14661519
/* Enter <verbatim> processing. With verbatim enabled, all other
14671520
** markup other than the corresponding end-tag with the same ID is
14681521
** ignored.
14691522
*/
14701523
if( markup.iCode==MARKUP_VERBATIM ){
1471
- int vAttrIdx, vAttrDidAppend=0;
1524
+ int ii, vAttrDidAppend=0;
14721525
p->zVerbatimId = 0;
14731526
p->inVerbatim = 1;
14741527
p->preVerbState = p->state;
14751528
p->state &= ~ALLOW_WIKI;
1476
- for (vAttrIdx = 0; vAttrIdx < markup.nAttr; vAttrIdx++){
1477
- if( markup.aAttr[vAttrIdx].iACode == ATTR_ID ){
1478
- p->zVerbatimId = markup.aAttr[0].zValue;
1479
- }else if( markup.aAttr[vAttrIdx].iACode == ATTR_TYPE ){
1480
- blob_appendf(p->pOut, "<pre name='code' class='%s'>",
1481
- markup.aAttr[vAttrIdx].zValue);
1482
- vAttrDidAppend=1;
1529
+ for(ii=0; ii<markup.nAttr; ii++){
1530
+ if( markup.aAttr[ii].iACode == ATTR_ID ){
1531
+ p->zVerbatimId = markup.aAttr[ii].zValue;
1532
+ }else if( markup.aAttr[ii].iACode == ATTR_TYPE ){
1533
+ if( fossil_stricmp(markup.aAttr[ii].zValue, "allow-links")==0 ){
1534
+ p->state |= ALLOW_LINKS;
1535
+ }else{
1536
+ blob_appendf(p->pOut, "<pre name='code' class='%s'>",
1537
+ markup.aAttr[ii].zValue);
1538
+ vAttrDidAppend=1;
1539
+ }
14831540
}
14841541
}
14851542
if( !vAttrDidAppend ) {
14861543
endAutoParagraph(p);
14871544
blob_append(p->pOut, "<pre class='verbatim'>",-1);
@@ -1558,10 +1615,11 @@
15581615
*/
15591616
void wiki_convert(Blob *pIn, Blob *pOut, int flags){
15601617
Renderer renderer;
15611618
15621619
memset(&renderer, 0, sizeof(renderer));
1620
+ renderer.renderFlags = flags;
15631621
renderer.state = ALLOW_WIKI|AT_NEWLINE|AT_PARAGRAPH|flags;
15641622
if( flags & WIKI_NOBLOCK ){
15651623
renderer.state |= INLINE_MARKUP_ONLY;
15661624
}
15671625
if( flags & WIKI_INLINE ){
@@ -1568,11 +1626,11 @@
15681626
renderer.wantAutoParagraph = 0;
15691627
}else{
15701628
renderer.wantAutoParagraph = 1;
15711629
}
15721630
if( wikiUsesHtml() ){
1573
- renderer.state |= WIKI_USE_HTML;
1631
+ renderer.state |= WIKI_HTMLONLY;
15741632
}
15751633
if( pOut ){
15761634
renderer.pOut = pOut;
15771635
}else{
15781636
renderer.pOut = cgi_output_blob();
@@ -1585,23 +1643,44 @@
15851643
popStack(&renderer);
15861644
}
15871645
blob_append(renderer.pOut, "\n", 1);
15881646
free(renderer.aStack);
15891647
}
1648
+
1649
+/*
1650
+** Send a string as wiki to CGI output.
1651
+*/
1652
+void wiki_write(const char *zIn, int flags){
1653
+ Blob in;
1654
+ blob_init(&in, zIn, -1);
1655
+ wiki_convert(&in, 0, flags);
1656
+ blob_reset(&in);
1657
+}
15901658
15911659
/*
15921660
** COMMAND: test-wiki-render
15931661
**
15941662
** %fossil test-wiki-render FILE [OPTIONS]
15951663
**
15961664
** Options:
15971665
** --buttons Set the WIKI_BUTTONS flag
1666
+** --htmlonly Set the WIKI_HTMLONLY flag
1667
+** --linksonly Set the WIKI_LINKSONLY flag
1668
+** --nobadlinks Set the WIKI_NOBADLINKS flag
1669
+** --inline Set the WIKI_INLINE flag
1670
+** --noblock Set the WIKI_NOBLOCK flag
15981671
*/
15991672
void test_wiki_render(void){
16001673
Blob in, out;
16011674
int flags = 0;
16021675
if( find_option("buttons",0,0)!=0 ) flags |= WIKI_BUTTONS;
1676
+ if( find_option("htmlonly",0,0)!=0 ) flags |= WIKI_HTMLONLY;
1677
+ if( find_option("linksonly",0,0)!=0 ) flags |= WIKI_LINKSONLY;
1678
+ if( find_option("nobadlinks",0,0)!=0 ) flags |= WIKI_NOBADLINKS;
1679
+ if( find_option("inline",0,0)!=0 ) flags |= WIKI_INLINE;
1680
+ if( find_option("noblock",0,0)!=0 ) flags |= WIKI_NOBLOCK;
1681
+ db_find_and_open_repository(0,0);
16031682
verify_all_options();
16041683
if( g.argc!=3 ) usage("FILE");
16051684
blob_zero(&out);
16061685
blob_read_from_file(&in, g.argv[2]);
16071686
wiki_convert(&in, &out, flags);
@@ -1656,29 +1735,29 @@
16561735
Renderer renderer;
16571736
int tokenType;
16581737
ParsedMarkup markup;
16591738
int n;
16601739
int inlineOnly;
1661
- int wikiUseHtml = 0;
1740
+ int wikiHtmlOnly = 0;
16621741
16631742
memset(&renderer, 0, sizeof(renderer));
16641743
renderer.state = ALLOW_WIKI|AT_NEWLINE|AT_PARAGRAPH;
16651744
if( flags & WIKI_NOBLOCK ){
16661745
renderer.state |= INLINE_MARKUP_ONLY;
16671746
}
16681747
if( wikiUsesHtml() ){
1669
- renderer.state |= WIKI_USE_HTML;
1670
- wikiUseHtml = 1;
1748
+ renderer.state |= WIKI_HTMLONLY;
1749
+ wikiHtmlOnly = 1;
16711750
}
16721751
inlineOnly = (renderer.state & INLINE_MARKUP_ONLY)!=0;
16731752
if( replaceFlag ){
16741753
db_multi_exec("DELETE FROM backlink WHERE srctype=%d AND srcid=%d",
16751754
srctype, srcid);
16761755
}
16771756
16781757
while( z[0] ){
1679
- if( wikiUseHtml ){
1758
+ if( wikiHtmlOnly ){
16801759
n = nextRawToken(z, &renderer, &tokenType);
16811760
}else{
16821761
n = nextWikiToken(z, &renderer, &tokenType);
16831762
}
16841763
switch( tokenType ){
16851764
--- src/wikiformat.c
+++ src/wikiformat.c
@@ -23,15 +23,16 @@
23
24 #if INTERFACE
25 /*
26 ** Allowed wiki transformation operations
27 */
28 #define WIKI_NOFOLLOW 0x001
29 #define WIKI_HTML 0x002
30 #define WIKI_INLINE 0x004 /* Do not surround with <p>..</p> */
31 #define WIKI_NOBLOCK 0x008 /* No block markup of any kind */
32 #define WIKI_BUTTONS 0x010 /* Allow sub-menu buttons */
 
33 #endif
34
35
36 /*
37 ** These are the only markup attributes allowed.
@@ -384,22 +385,23 @@
384 ** State flags. Save the lower 16 bits for the WIKI_* flags.
385 */
386 #define AT_NEWLINE 0x0010000 /* At start of a line */
387 #define AT_PARAGRAPH 0x0020000 /* At start of a paragraph */
388 #define ALLOW_WIKI 0x0040000 /* Allow wiki markup */
389 #define FONT_MARKUP_ONLY 0x0080000 /* Only allow MUTYPE_FONT markup */
390 #define INLINE_MARKUP_ONLY 0x0100000 /* Allow only "inline" markup */
391 #define IN_LIST 0x0200000 /* Within wiki <ul> or <ol> */
392 #define WIKI_USE_HTML 0x0400000 /* wiki-use-html option = on */
393
394 /*
395 ** Current state of the rendering engine
396 */
397 typedef struct Renderer Renderer;
398 struct Renderer {
399 Blob *pOut; /* Output appended to this blob */
400 int state; /* Flag that govern rendering */
 
401 int wikiList; /* Current wiki list type */
402 int inVerbatim; /* True in <verbatim> mode */
403 int preVerbState; /* Value of state prior to verbatim */
404 int wantAutoParagraph; /* True if a <p> is desired */
405 int inAutoParagraph; /* True if within an automatic paragraph */
@@ -484,18 +486,27 @@
484 ** <
485 ** &
486 ** \n
487 ** [
488 **
489 ** The "[" and "\n" are only considered interesting if the "useWiki"
490 ** flag is set.
491 */
492 static int textLength(const char *z, int useWiki){
493 int n = 0;
494 int c;
495 while( (c = z[0])!=0 && c!='<' && c!='&' &&
496 (useWiki==0 || (c!='[' && c!='\n')) ){
 
 
 
 
 
 
 
 
 
497 n++;
498 z++;
499 }
500 return n;
501 }
@@ -668,13 +679,16 @@
668 }
669 if( z[0]=='[' && (n = linkLength(z))>0 ){
670 *pTokenType = TOKEN_LINK;
671 return n;
672 }
 
 
 
673 }
674 *pTokenType = TOKEN_TEXT;
675 return 1 + textLength(z+1, p->state & ALLOW_WIKI);
676 }
677
678 /*
679 ** Parse only Wiki links, return everything else as TOKEN_RAW.
680 **
@@ -982,10 +996,11 @@
982 /*
983 ** Begin a new paragraph if that something that is needed.
984 */
985 static void startAutoParagraph(Renderer *p){
986 if( p->wantAutoParagraph==0 ) return;
 
987 if( p->wikiList==MARKUP_OL || p->wikiList==MARKUP_UL ) return;
988 blob_appendf(p->pOut, "<p>", -1);
989 pushStack(p, MARKUP_P);
990 p->wantAutoParagraph = 0;
991 p->inAutoParagraph = 1;
@@ -1075,16 +1090,39 @@
1075 rc = 0;
1076 }
1077 db_reset(&q);
1078 return rc;
1079 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1080
1081 /*
1082 ** Resolve a hyperlink. The zTarget argument is the content of the [...]
1083 ** in the wiki. Append to the output string whatever text is appropriate
1084 ** for opening the hyperlink. Write into zClose[0...nClose-1] text that will
1085 ** close the markup.
 
 
 
1086 **
1087 ** Actually, this routine might or might not append the hyperlink, depending
1088 ** on current rendering rules: specifically does the current user have
1089 ** "History" permission.
1090 **
@@ -1112,27 +1150,23 @@
1112 char *zClose, /* Write hyperlink closing text here */
1113 int nClose, /* Bytes available in zClose[] */
1114 const char *zOrig /* Complete document text */
1115 ){
1116 const char *zTerm = "</a>";
1117 assert( nClose>=20 );
1118
 
1119 if( strncmp(zTarget, "http:", 5)==0
1120 || strncmp(zTarget, "https:", 6)==0
1121 || strncmp(zTarget, "ftp:", 4)==0
1122 || strncmp(zTarget, "mailto:", 7)==0
1123 ){
1124 blob_appendf(p->pOut, "<a href=\"%s\">", zTarget);
1125 /* zTerm = "&#x27FE;</a>"; // doesn't work on windows */
1126 }else if( zTarget[0]=='/' ){
1127 blob_appendf(p->pOut, "<a href=\"%s%h\">", g.zTop, zTarget);
1128 }else if( zTarget[0]=='.' || zTarget[0]=='#' ){
1129 if( 1 ){
1130 blob_appendf(p->pOut, "<a href=\"%h\">", zTarget);
1131 }else{
1132 zTerm = "";
1133 }
1134 }else if( is_valid_uuid(zTarget) ){
1135 int isClosed = 0;
1136 if( is_ticket(zTarget, &isClosed) ){
1137 /* Special display processing for tickets. Display the hyperlink
1138 ** as crossed out if the ticket is closed.
@@ -1156,32 +1190,33 @@
1156 blob_appendf(p->pOut, "[");
1157 zTerm = "]";
1158 }
1159 }
1160 }else if( !in_this_repo(zTarget) ){
1161 blob_appendf(p->pOut, "<span class=\"brokenlink\">[", zTarget);
1162 zTerm = "]</span>";
 
 
 
 
1163 }else if( g.perm.Hyperlink ){
1164 blob_appendf(p->pOut, "%z[",href("%R/info/%s", zTarget));
1165 zTerm = "]</a>";
1166 }
1167 }else if( strlen(zTarget)>=10 && fossil_isdigit(zTarget[0]) && zTarget[4]=='-'
1168 && db_int(0, "SELECT datetime(%Q) NOT NULL", zTarget) ){
1169 blob_appendf(p->pOut, "<a href=\"%R/timeline?c=%T\">", zTarget);
1170 }else if( strncmp(zTarget, "wiki:", 5)==0
1171 && wiki_name_is_wellformed((const unsigned char*)zTarget) ){
1172 zTarget += 5;
1173 blob_appendf(p->pOut, "<a href=\"%R/wiki?name=%T\">", zTarget);
1174 }else if( wiki_name_is_wellformed((const unsigned char *)zTarget) ){
1175 blob_appendf(p->pOut, "<a href=\"%R/wiki?name=%T\">", zTarget);
1176 }else if( zTarget>=&zOrig[2] && !fossil_isspace(zTarget[-2]) ){
1177 /* Probably an array subscript in code */
1178 blob_appendf(p->pOut, "[");
1179 zTerm = "]";
 
1180 }else{
1181 blob_appendf(p->pOut, "<span class=\"brokenlink\">[%h]</span>", zTarget);
1182 zTerm = "";
1183 }
1184 assert( strlen(zTerm)<nClose );
1185 sqlite3_snprintf(nClose, zClose, "%s", zTerm);
1186 }
1187
@@ -1217,19 +1252,20 @@
1217 static void wiki_render(Renderer *p, char *z){
1218 int tokenType;
1219 ParsedMarkup markup;
1220 int n;
1221 int inlineOnly = (p->state & INLINE_MARKUP_ONLY)!=0;
1222 int wikiUseHtml = (p->state & WIKI_USE_HTML)!=0;
 
1223 char *zOrig = z;
1224
1225 /* Make sure the attribute constants and names still align
1226 ** following changes in the attribute list. */
1227 assert( fossil_strcmp(aAttribute[ATTR_WIDTH].zName, "width")==0 );
1228
1229 while( z[0] ){
1230 if( wikiUseHtml ){
1231 n = nextRawToken(z, p, &tokenType);
1232 }else{
1233 n = nextWikiToken(z, p, &tokenType);
1234 }
1235 p->state &= ~(AT_NEWLINE|AT_PARAGRAPH);
@@ -1338,33 +1374,46 @@
1338 char *zTarget;
1339 char *zDisplay = 0;
1340 int i, j;
1341 int savedState;
1342 char zClose[20];
 
 
1343
1344 startAutoParagraph(p);
1345 zTarget = &z[1];
1346 for(i=1; z[i] && z[i]!=']'; i++){
1347 if( z[i]=='|' && zDisplay==0 ){
1348 zDisplay = &z[i+1];
1349 z[i] = 0;
1350 for(j=i-1; j>0 && fossil_isspace(z[j]); j--){ z[j] = 0; }
 
 
1351 }
1352 }
1353 z[i] = 0;
1354 if( zDisplay==0 ){
1355 zDisplay = zTarget;
1356 }else{
1357 while( fossil_isspace(*zDisplay) ) zDisplay++;
1358 }
1359 openHyperlink(p, zTarget, zClose, sizeof(zClose), zOrig);
1360 savedState = p->state;
1361 p->state &= ~ALLOW_WIKI;
1362 p->state |= FONT_MARKUP_ONLY;
1363 wiki_render(p, zDisplay);
1364 p->state = savedState;
1365 blob_append(p->pOut, zClose, -1);
 
 
 
 
 
 
 
 
 
1366 break;
1367 }
1368 case TOKEN_TEXT: {
1369 int i;
1370 for(i=0; i<n && fossil_isspace(z[i]); i++){}
@@ -1371,11 +1420,15 @@
1371 if( i<n ) startAutoParagraph(p);
1372 blob_append(p->pOut, z, n);
1373 break;
1374 }
1375 case TOKEN_RAW: {
1376 blob_append(p->pOut, z, n);
 
 
 
 
1377 break;
1378 }
1379 case TOKEN_MARKUP: {
1380 const char *zId;
1381 int iDiv;
@@ -1466,22 +1519,26 @@
1466 /* Enter <verbatim> processing. With verbatim enabled, all other
1467 ** markup other than the corresponding end-tag with the same ID is
1468 ** ignored.
1469 */
1470 if( markup.iCode==MARKUP_VERBATIM ){
1471 int vAttrIdx, vAttrDidAppend=0;
1472 p->zVerbatimId = 0;
1473 p->inVerbatim = 1;
1474 p->preVerbState = p->state;
1475 p->state &= ~ALLOW_WIKI;
1476 for (vAttrIdx = 0; vAttrIdx < markup.nAttr; vAttrIdx++){
1477 if( markup.aAttr[vAttrIdx].iACode == ATTR_ID ){
1478 p->zVerbatimId = markup.aAttr[0].zValue;
1479 }else if( markup.aAttr[vAttrIdx].iACode == ATTR_TYPE ){
1480 blob_appendf(p->pOut, "<pre name='code' class='%s'>",
1481 markup.aAttr[vAttrIdx].zValue);
1482 vAttrDidAppend=1;
 
 
 
 
1483 }
1484 }
1485 if( !vAttrDidAppend ) {
1486 endAutoParagraph(p);
1487 blob_append(p->pOut, "<pre class='verbatim'>",-1);
@@ -1558,10 +1615,11 @@
1558 */
1559 void wiki_convert(Blob *pIn, Blob *pOut, int flags){
1560 Renderer renderer;
1561
1562 memset(&renderer, 0, sizeof(renderer));
 
1563 renderer.state = ALLOW_WIKI|AT_NEWLINE|AT_PARAGRAPH|flags;
1564 if( flags & WIKI_NOBLOCK ){
1565 renderer.state |= INLINE_MARKUP_ONLY;
1566 }
1567 if( flags & WIKI_INLINE ){
@@ -1568,11 +1626,11 @@
1568 renderer.wantAutoParagraph = 0;
1569 }else{
1570 renderer.wantAutoParagraph = 1;
1571 }
1572 if( wikiUsesHtml() ){
1573 renderer.state |= WIKI_USE_HTML;
1574 }
1575 if( pOut ){
1576 renderer.pOut = pOut;
1577 }else{
1578 renderer.pOut = cgi_output_blob();
@@ -1585,23 +1643,44 @@
1585 popStack(&renderer);
1586 }
1587 blob_append(renderer.pOut, "\n", 1);
1588 free(renderer.aStack);
1589 }
 
 
 
 
 
 
 
 
 
 
1590
1591 /*
1592 ** COMMAND: test-wiki-render
1593 **
1594 ** %fossil test-wiki-render FILE [OPTIONS]
1595 **
1596 ** Options:
1597 ** --buttons Set the WIKI_BUTTONS flag
 
 
 
 
 
1598 */
1599 void test_wiki_render(void){
1600 Blob in, out;
1601 int flags = 0;
1602 if( find_option("buttons",0,0)!=0 ) flags |= WIKI_BUTTONS;
 
 
 
 
 
 
1603 verify_all_options();
1604 if( g.argc!=3 ) usage("FILE");
1605 blob_zero(&out);
1606 blob_read_from_file(&in, g.argv[2]);
1607 wiki_convert(&in, &out, flags);
@@ -1656,29 +1735,29 @@
1656 Renderer renderer;
1657 int tokenType;
1658 ParsedMarkup markup;
1659 int n;
1660 int inlineOnly;
1661 int wikiUseHtml = 0;
1662
1663 memset(&renderer, 0, sizeof(renderer));
1664 renderer.state = ALLOW_WIKI|AT_NEWLINE|AT_PARAGRAPH;
1665 if( flags & WIKI_NOBLOCK ){
1666 renderer.state |= INLINE_MARKUP_ONLY;
1667 }
1668 if( wikiUsesHtml() ){
1669 renderer.state |= WIKI_USE_HTML;
1670 wikiUseHtml = 1;
1671 }
1672 inlineOnly = (renderer.state & INLINE_MARKUP_ONLY)!=0;
1673 if( replaceFlag ){
1674 db_multi_exec("DELETE FROM backlink WHERE srctype=%d AND srcid=%d",
1675 srctype, srcid);
1676 }
1677
1678 while( z[0] ){
1679 if( wikiUseHtml ){
1680 n = nextRawToken(z, &renderer, &tokenType);
1681 }else{
1682 n = nextWikiToken(z, &renderer, &tokenType);
1683 }
1684 switch( tokenType ){
1685
--- src/wikiformat.c
+++ src/wikiformat.c
@@ -23,15 +23,16 @@
23
24 #if INTERFACE
25 /*
26 ** Allowed wiki transformation operations
27 */
28 #define WIKI_HTMLONLY 0x001 /* HTML markup only. No wiki */
29 #define WIKI_INLINE 0x002 /* Do not surround with <p>..</p> */
30 #define WIKI_NOBLOCK 0x004 /* No block markup of any kind */
31 #define WIKI_BUTTONS 0x008 /* Allow sub-menu buttons */
32 #define WIKI_NOBADLINKS 0x010 /* Ignore broken hyperlinks */
33 #define WIKI_LINKSONLY 0x020 /* No markup. Only decorate links */
34 #endif
35
36
37 /*
38 ** These are the only markup attributes allowed.
@@ -384,22 +385,23 @@
385 ** State flags. Save the lower 16 bits for the WIKI_* flags.
386 */
387 #define AT_NEWLINE 0x0010000 /* At start of a line */
388 #define AT_PARAGRAPH 0x0020000 /* At start of a paragraph */
389 #define ALLOW_WIKI 0x0040000 /* Allow wiki markup */
390 #define ALLOW_LINKS 0x0080000 /* Allow [...] hyperlinks */
391 #define FONT_MARKUP_ONLY 0x0100000 /* Only allow MUTYPE_FONT markup */
392 #define INLINE_MARKUP_ONLY 0x0200000 /* Allow only "inline" markup */
393 #define IN_LIST 0x0400000 /* Within wiki <ul> or <ol> */
394
395 /*
396 ** Current state of the rendering engine
397 */
398 typedef struct Renderer Renderer;
399 struct Renderer {
400 Blob *pOut; /* Output appended to this blob */
401 int state; /* Flag that govern rendering */
402 unsigned renderFlags; /* Flags from the client */
403 int wikiList; /* Current wiki list type */
404 int inVerbatim; /* True in <verbatim> mode */
405 int preVerbState; /* Value of state prior to verbatim */
406 int wantAutoParagraph; /* True if a <p> is desired */
407 int inAutoParagraph; /* True if within an automatic paragraph */
@@ -484,18 +486,27 @@
486 ** <
487 ** &
488 ** \n
489 ** [
490 **
491 ** The "[" is only considered if flags contain ALLOW_LINKS or ALLOW_WIKI.
492 ** The "\n" is only considered interesting if the flags constains ALLOW_WIKI.
493 */
494 static int textLength(const char *z, int flags){
495 int n = 0;
496 int c, x1, x2;
497
498 if( flags & ALLOW_WIKI ){
499 x1 = '[';
500 x2 = '\n';
501 }else if( flags & ALLOW_LINKS ){
502 x1 = '[';
503 x2 = 0;
504 }else{
505 x1 = x2 = 0;
506 }
507 while( (c = z[0])!=0 && c!='<' && c!='&' && c!=x1 && c!=x2 ){
508 n++;
509 z++;
510 }
511 return n;
512 }
@@ -668,13 +679,16 @@
679 }
680 if( z[0]=='[' && (n = linkLength(z))>0 ){
681 *pTokenType = TOKEN_LINK;
682 return n;
683 }
684 }else if( (p->state & ALLOW_LINKS)!=0 && z[0]=='[' && (n = linkLength(z))>0 ){
685 *pTokenType = TOKEN_LINK;
686 return n;
687 }
688 *pTokenType = TOKEN_TEXT;
689 return 1 + textLength(z+1, p->state);
690 }
691
692 /*
693 ** Parse only Wiki links, return everything else as TOKEN_RAW.
694 **
@@ -982,10 +996,11 @@
996 /*
997 ** Begin a new paragraph if that something that is needed.
998 */
999 static void startAutoParagraph(Renderer *p){
1000 if( p->wantAutoParagraph==0 ) return;
1001 if( p->state & WIKI_LINKSONLY ) return;
1002 if( p->wikiList==MARKUP_OL || p->wikiList==MARKUP_UL ) return;
1003 blob_appendf(p->pOut, "<p>", -1);
1004 pushStack(p, MARKUP_P);
1005 p->wantAutoParagraph = 0;
1006 p->inAutoParagraph = 1;
@@ -1075,16 +1090,39 @@
1090 rc = 0;
1091 }
1092 db_reset(&q);
1093 return rc;
1094 }
1095
1096 /*
1097 ** Return a pointer to the name part of zTarget (skipping the "wiki:" prefix
1098 ** if there is one) if zTarget is a valid wiki page name. Return NULL if
1099 ** zTarget names a page that does not exist.
1100 */
1101 static const char *validWikiPageName(Renderer *p, const char *zTarget){
1102 if( strncmp(zTarget, "wiki:", 5)==0
1103 && wiki_name_is_wellformed((const unsigned char*)zTarget) ){
1104 return zTarget+5;
1105 }
1106 if( strcmp(zTarget, "Sandbox")==0 ) return zTarget;
1107 if( wiki_name_is_wellformed((const unsigned char *)zTarget)
1108 && ((p->state & WIKI_NOBADLINKS)==0 ||
1109 db_exists("SELECT 1 FROM tag WHERE tagname GLOB 'wiki-%q'", zTarget))
1110 ){
1111 return zTarget;
1112 }
1113 return 0;
1114 }
1115
1116 /*
1117 ** Resolve a hyperlink. The zTarget argument is the content of the [...]
1118 ** in the wiki. Append to the output string whatever text is appropriate
1119 ** for opening the hyperlink. Write into zClose[0...nClose-1] text that will
1120 ** close the markup.
1121 **
1122 ** If this routine determines that no hyperlink should be generated, then
1123 ** set zClose[0] to 0.
1124 **
1125 ** Actually, this routine might or might not append the hyperlink, depending
1126 ** on current rendering rules: specifically does the current user have
1127 ** "History" permission.
1128 **
@@ -1112,27 +1150,23 @@
1150 char *zClose, /* Write hyperlink closing text here */
1151 int nClose, /* Bytes available in zClose[] */
1152 const char *zOrig /* Complete document text */
1153 ){
1154 const char *zTerm = "</a>";
1155 const char *z;
1156
1157 assert( nClose>=20 );
1158 if( strncmp(zTarget, "http:", 5)==0
1159 || strncmp(zTarget, "https:", 6)==0
1160 || strncmp(zTarget, "ftp:", 4)==0
1161 || strncmp(zTarget, "mailto:", 7)==0
1162 ){
1163 blob_appendf(p->pOut, "<a href=\"%s\">", zTarget);
 
1164 }else if( zTarget[0]=='/' ){
1165 blob_appendf(p->pOut, "<a href=\"%s%h\">", g.zTop, zTarget);
1166 }else if( zTarget[0]=='.' || zTarget[0]=='#' ){
1167 blob_appendf(p->pOut, "<a href=\"%h\">", zTarget);
 
 
 
 
1168 }else if( is_valid_uuid(zTarget) ){
1169 int isClosed = 0;
1170 if( is_ticket(zTarget, &isClosed) ){
1171 /* Special display processing for tickets. Display the hyperlink
1172 ** as crossed out if the ticket is closed.
@@ -1156,32 +1190,33 @@
1190 blob_appendf(p->pOut, "[");
1191 zTerm = "]";
1192 }
1193 }
1194 }else if( !in_this_repo(zTarget) ){
1195 if( (p->state & (WIKI_LINKSONLY|WIKI_NOBADLINKS))!=0 ){
1196 zTerm = "";
1197 }else{
1198 blob_appendf(p->pOut, "<span class=\"brokenlink\">[", zTarget);
1199 zTerm = "]</span>";
1200 }
1201 }else if( g.perm.Hyperlink ){
1202 blob_appendf(p->pOut, "%z[",href("%R/info/%s", zTarget));
1203 zTerm = "]</a>";
1204 }
1205 }else if( strlen(zTarget)>=10 && fossil_isdigit(zTarget[0]) && zTarget[4]=='-'
1206 && db_int(0, "SELECT datetime(%Q) NOT NULL", zTarget) ){
1207 blob_appendf(p->pOut, "<a href=\"%R/timeline?c=%T\">", zTarget);
1208 }else if( (z = validWikiPageName(p, zTarget))!=0 ){
1209 blob_appendf(p->pOut, "<a href=\"%R/wiki?name=%T\">", z);
 
 
 
 
1210 }else if( zTarget>=&zOrig[2] && !fossil_isspace(zTarget[-2]) ){
1211 /* Probably an array subscript in code */
1212 zTerm = "";
1213 }else if( (p->state & (WIKI_NOBADLINKS|WIKI_LINKSONLY))!=0 ){
1214 zTerm = "";
1215 }else{
1216 blob_appendf(p->pOut, "<span class=\"brokenlink\">[%h]", zTarget);
1217 zTerm = "</span>";
1218 }
1219 assert( strlen(zTerm)<nClose );
1220 sqlite3_snprintf(nClose, zClose, "%s", zTerm);
1221 }
1222
@@ -1217,19 +1252,20 @@
1252 static void wiki_render(Renderer *p, char *z){
1253 int tokenType;
1254 ParsedMarkup markup;
1255 int n;
1256 int inlineOnly = (p->state & INLINE_MARKUP_ONLY)!=0;
1257 int wikiHtmlOnly = (p->state & (WIKI_HTMLONLY | WIKI_LINKSONLY))!=0;
1258 int linksOnly = (p->state & WIKI_LINKSONLY)!=0;
1259 char *zOrig = z;
1260
1261 /* Make sure the attribute constants and names still align
1262 ** following changes in the attribute list. */
1263 assert( fossil_strcmp(aAttribute[ATTR_WIDTH].zName, "width")==0 );
1264
1265 while( z[0] ){
1266 if( wikiHtmlOnly ){
1267 n = nextRawToken(z, p, &tokenType);
1268 }else{
1269 n = nextWikiToken(z, p, &tokenType);
1270 }
1271 p->state &= ~(AT_NEWLINE|AT_PARAGRAPH);
@@ -1338,33 +1374,46 @@
1374 char *zTarget;
1375 char *zDisplay = 0;
1376 int i, j;
1377 int savedState;
1378 char zClose[20];
1379 char cS1 = 0;
1380 int iS1 = 0;
1381
1382 startAutoParagraph(p);
1383 zTarget = &z[1];
1384 for(i=1; z[i] && z[i]!=']'; i++){
1385 if( z[i]=='|' && zDisplay==0 ){
1386 zDisplay = &z[i+1];
1387 for(j=i; j>0 && fossil_isspace(z[j-1]); j--){}
1388 iS1 = j;
1389 cS1 = z[j];
1390 z[j] = 0;
1391 }
1392 }
1393 z[i] = 0;
1394 if( zDisplay==0 ){
1395 zDisplay = zTarget;
1396 }else{
1397 while( fossil_isspace(*zDisplay) ) zDisplay++;
1398 }
1399 openHyperlink(p, zTarget, zClose, sizeof(zClose), zOrig);
1400 if( linksOnly || zClose[0]==0 || p->inVerbatim ){
1401 if( cS1 ) z[iS1] = cS1;
1402 if( zClose[0]!=']' ){
1403 blob_appendf(p->pOut, "[%h]%s", zTarget, zClose);
1404 }else{
1405 blob_appendf(p->pOut, "%h%s", zTarget, zClose);
1406 }
1407 }else{
1408 savedState = p->state;
1409 p->state &= ~ALLOW_WIKI;
1410 p->state |= FONT_MARKUP_ONLY;
1411 wiki_render(p, zDisplay);
1412 p->state = savedState;
1413 blob_append(p->pOut, zClose, -1);
1414 }
1415 break;
1416 }
1417 case TOKEN_TEXT: {
1418 int i;
1419 for(i=0; i<n && fossil_isspace(z[i]); i++){}
@@ -1371,11 +1420,15 @@
1420 if( i<n ) startAutoParagraph(p);
1421 blob_append(p->pOut, z, n);
1422 break;
1423 }
1424 case TOKEN_RAW: {
1425 if( linksOnly ){
1426 htmlize_to_blob(p->pOut, z, n);
1427 }else{
1428 blob_append(p->pOut, z, n);
1429 }
1430 break;
1431 }
1432 case TOKEN_MARKUP: {
1433 const char *zId;
1434 int iDiv;
@@ -1466,22 +1519,26 @@
1519 /* Enter <verbatim> processing. With verbatim enabled, all other
1520 ** markup other than the corresponding end-tag with the same ID is
1521 ** ignored.
1522 */
1523 if( markup.iCode==MARKUP_VERBATIM ){
1524 int ii, vAttrDidAppend=0;
1525 p->zVerbatimId = 0;
1526 p->inVerbatim = 1;
1527 p->preVerbState = p->state;
1528 p->state &= ~ALLOW_WIKI;
1529 for(ii=0; ii<markup.nAttr; ii++){
1530 if( markup.aAttr[ii].iACode == ATTR_ID ){
1531 p->zVerbatimId = markup.aAttr[ii].zValue;
1532 }else if( markup.aAttr[ii].iACode == ATTR_TYPE ){
1533 if( fossil_stricmp(markup.aAttr[ii].zValue, "allow-links")==0 ){
1534 p->state |= ALLOW_LINKS;
1535 }else{
1536 blob_appendf(p->pOut, "<pre name='code' class='%s'>",
1537 markup.aAttr[ii].zValue);
1538 vAttrDidAppend=1;
1539 }
1540 }
1541 }
1542 if( !vAttrDidAppend ) {
1543 endAutoParagraph(p);
1544 blob_append(p->pOut, "<pre class='verbatim'>",-1);
@@ -1558,10 +1615,11 @@
1615 */
1616 void wiki_convert(Blob *pIn, Blob *pOut, int flags){
1617 Renderer renderer;
1618
1619 memset(&renderer, 0, sizeof(renderer));
1620 renderer.renderFlags = flags;
1621 renderer.state = ALLOW_WIKI|AT_NEWLINE|AT_PARAGRAPH|flags;
1622 if( flags & WIKI_NOBLOCK ){
1623 renderer.state |= INLINE_MARKUP_ONLY;
1624 }
1625 if( flags & WIKI_INLINE ){
@@ -1568,11 +1626,11 @@
1626 renderer.wantAutoParagraph = 0;
1627 }else{
1628 renderer.wantAutoParagraph = 1;
1629 }
1630 if( wikiUsesHtml() ){
1631 renderer.state |= WIKI_HTMLONLY;
1632 }
1633 if( pOut ){
1634 renderer.pOut = pOut;
1635 }else{
1636 renderer.pOut = cgi_output_blob();
@@ -1585,23 +1643,44 @@
1643 popStack(&renderer);
1644 }
1645 blob_append(renderer.pOut, "\n", 1);
1646 free(renderer.aStack);
1647 }
1648
1649 /*
1650 ** Send a string as wiki to CGI output.
1651 */
1652 void wiki_write(const char *zIn, int flags){
1653 Blob in;
1654 blob_init(&in, zIn, -1);
1655 wiki_convert(&in, 0, flags);
1656 blob_reset(&in);
1657 }
1658
1659 /*
1660 ** COMMAND: test-wiki-render
1661 **
1662 ** %fossil test-wiki-render FILE [OPTIONS]
1663 **
1664 ** Options:
1665 ** --buttons Set the WIKI_BUTTONS flag
1666 ** --htmlonly Set the WIKI_HTMLONLY flag
1667 ** --linksonly Set the WIKI_LINKSONLY flag
1668 ** --nobadlinks Set the WIKI_NOBADLINKS flag
1669 ** --inline Set the WIKI_INLINE flag
1670 ** --noblock Set the WIKI_NOBLOCK flag
1671 */
1672 void test_wiki_render(void){
1673 Blob in, out;
1674 int flags = 0;
1675 if( find_option("buttons",0,0)!=0 ) flags |= WIKI_BUTTONS;
1676 if( find_option("htmlonly",0,0)!=0 ) flags |= WIKI_HTMLONLY;
1677 if( find_option("linksonly",0,0)!=0 ) flags |= WIKI_LINKSONLY;
1678 if( find_option("nobadlinks",0,0)!=0 ) flags |= WIKI_NOBADLINKS;
1679 if( find_option("inline",0,0)!=0 ) flags |= WIKI_INLINE;
1680 if( find_option("noblock",0,0)!=0 ) flags |= WIKI_NOBLOCK;
1681 db_find_and_open_repository(0,0);
1682 verify_all_options();
1683 if( g.argc!=3 ) usage("FILE");
1684 blob_zero(&out);
1685 blob_read_from_file(&in, g.argv[2]);
1686 wiki_convert(&in, &out, flags);
@@ -1656,29 +1735,29 @@
1735 Renderer renderer;
1736 int tokenType;
1737 ParsedMarkup markup;
1738 int n;
1739 int inlineOnly;
1740 int wikiHtmlOnly = 0;
1741
1742 memset(&renderer, 0, sizeof(renderer));
1743 renderer.state = ALLOW_WIKI|AT_NEWLINE|AT_PARAGRAPH;
1744 if( flags & WIKI_NOBLOCK ){
1745 renderer.state |= INLINE_MARKUP_ONLY;
1746 }
1747 if( wikiUsesHtml() ){
1748 renderer.state |= WIKI_HTMLONLY;
1749 wikiHtmlOnly = 1;
1750 }
1751 inlineOnly = (renderer.state & INLINE_MARKUP_ONLY)!=0;
1752 if( replaceFlag ){
1753 db_multi_exec("DELETE FROM backlink WHERE srctype=%d AND srcid=%d",
1754 srctype, srcid);
1755 }
1756
1757 while( z[0] ){
1758 if( wikiHtmlOnly ){
1759 n = nextRawToken(z, &renderer, &tokenType);
1760 }else{
1761 n = nextWikiToken(z, &renderer, &tokenType);
1762 }
1763 switch( tokenType ){
1764
+81 -44
--- src/xfer.c
+++ src/xfer.c
@@ -800,11 +800,11 @@
800800
*/
801801
static int run_script(const char *zScript){
802802
if( !zScript ){
803803
return TH_OK; /* No script, return success. */
804804
}
805
- Th_FossilInit(); /* Make sure TH1 is ready. */
805
+ Th_FossilInit(0, 0); /* Make sure TH1 is ready. */
806806
return Th_Eval(g.interp, 0, zScript, -1);
807807
}
808808
809809
/*
810810
** Run the pre-transfer TH1 script, if any, and returns the return code.
@@ -1266,11 +1266,23 @@
12661266
/*
12671267
** Format strings for progress reporting.
12681268
*/
12691269
static const char zLabelFormat[] = "%-10s %10s %10s %10s %10s\n";
12701270
static const char zValueFormat[] = "\r%-10s %10d %10d %10d %10d\n";
1271
+static const char zBriefFormat[] =
1272
+ "Round-trips: %d Artifacts sent: %d received: %d\r";
12711273
1274
+#if INTERFACE
1275
+/*
1276
+** Flag options for controlling client_sync()
1277
+*/
1278
+#define SYNC_PUSH 0x0001
1279
+#define SYNC_PULL 0x0002
1280
+#define SYNC_CLONE 0x0004
1281
+#define SYNC_PRIVATE 0x0008
1282
+#define SYNC_VERBOSE 0x0010
1283
+#endif
12721284
12731285
/*
12741286
** Sync to the host identified in g.urlName and g.urlPath. This
12751287
** routine is called by the client.
12761288
**
@@ -1277,16 +1289,13 @@
12771289
** Records are pushed to the server if pushFlag is true. Records
12781290
** are pulled if pullFlag is true. A full sync occurs if both are
12791291
** true.
12801292
*/
12811293
int client_sync(
1282
- int pushFlag, /* True to do a push (or a sync) */
1283
- int pullFlag, /* True to do a pull (or a sync) */
1284
- int cloneFlag, /* True if this is a clone */
1285
- int privateFlag, /* True to exchange private branches */
1286
- int configRcvMask, /* Receive these configuration items */
1287
- int configSendMask /* Send these configuration items */
1294
+ unsigned syncFlags, /* Mask of SYNC_* flags */
1295
+ unsigned configRcvMask, /* Receive these configuration items */
1296
+ unsigned configSendMask /* Send these configuration items */
12881297
){
12891298
int go = 1; /* Loop until zero */
12901299
int nCardSent = 0; /* Number of cards sent */
12911300
int nCardRcvd = 0; /* Number of cards received */
12921301
int nCycle = 0; /* Number of round trips to the server */
@@ -1304,27 +1313,30 @@
13041313
int lastPctDone = -1; /* Last displayed pctDone */
13051314
double rArrivalTime; /* Time at which a message arrived */
13061315
const char *zSCode = db_get("server-code", "x");
13071316
const char *zPCode = db_get("project-code", 0);
13081317
int nErr = 0; /* Number of errors */
1318
+ int nRoundtrip= 0; /* Number of HTTP requests */
1319
+ int nArtifactSent = 0; /* Total artifacts sent */
1320
+ int nArtifactRcvd = 0; /* Total artifacts received */
1321
+ const char *zOpType = 0;/* Push, Pull, Sync, Clone */
13091322
1310
- if( db_get_boolean("dont-push", 0) ) pushFlag = 0;
1311
- if( pushFlag + pullFlag + cloneFlag == 0
1323
+ if( db_get_boolean("dont-push", 0) ) syncFlags &= ~SYNC_PUSH;
1324
+ if( (syncFlags & (SYNC_PUSH|SYNC_PULL|SYNC_CLONE))==0
13121325
&& configRcvMask==0 && configSendMask==0 ) return 0;
13131326
13141327
transport_stats(0, 0, 1);
13151328
socket_global_init();
13161329
memset(&xfer, 0, sizeof(xfer));
13171330
xfer.pIn = &recv;
13181331
xfer.pOut = &send;
13191332
xfer.mxSend = db_get_int("max-upload", 250000);
1320
- if( privateFlag ){
1333
+ if( syncFlags & SYNC_PRIVATE ){
13211334
g.perm.Private = 1;
13221335
xfer.syncPrivate = 1;
13231336
}
13241337
1325
- assert( pushFlag | pullFlag | cloneFlag | configRcvMask | configSendMask );
13261338
db_begin_transaction();
13271339
db_record_repository_filename(0);
13281340
db_multi_exec(
13291341
"CREATE TEMP TABLE onremote(rid INTEGER PRIMARY KEY);"
13301342
);
@@ -1335,33 +1347,39 @@
13351347
blob_zero(&xfer.line);
13361348
origConfigRcvMask = 0;
13371349
13381350
13391351
/* Send the send-private pragma if we are trying to sync private data */
1340
- if( privateFlag ) blob_append(&send, "pragma send-private\n", -1);
1352
+ if( syncFlags & SYNC_PRIVATE ){
1353
+ blob_append(&send, "pragma send-private\n", -1);
1354
+ }
13411355
13421356
/*
13431357
** Always begin with a clone, pull, or push message
13441358
*/
1345
- if( cloneFlag ){
1359
+ if( syncFlags & SYNC_CLONE ){
13461360
blob_appendf(&send, "clone 3 %d\n", cloneSeqno);
1347
- pushFlag = 0;
1348
- pullFlag = 0;
1361
+ syncFlags &= ~(SYNC_PUSH|SYNC_PULL);
13491362
nCardSent++;
13501363
/* TBD: Request all transferable configuration values */
13511364
content_enable_dephantomize(0);
1352
- }else if( pullFlag ){
1365
+ zOpType = "Clone";
1366
+ }else if( syncFlags & SYNC_PULL ){
13531367
blob_appendf(&send, "pull %s %s\n", zSCode, zPCode);
13541368
nCardSent++;
1369
+ zOpType = "Pull";
13551370
}
1356
- if( pushFlag ){
1371
+ if( syncFlags & SYNC_PUSH ){
13571372
blob_appendf(&send, "push %s %s\n", zSCode, zPCode);
13581373
nCardSent++;
1374
+ if( (syncFlags & SYNC_PULL)==0 ) zOpType = "Push";
13591375
}
13601376
manifest_crosslink_begin();
13611377
transport_global_startup();
1362
- fossil_print(zLabelFormat, "", "Bytes", "Cards", "Artifacts", "Deltas");
1378
+ if( syncFlags & SYNC_VERBOSE ){
1379
+ fossil_print(zLabelFormat, "", "Bytes", "Cards", "Artifacts", "Deltas");
1380
+ }
13631381
13641382
while( go ){
13651383
int newPhantom = 0;
13661384
char *zRandomness;
13671385
@@ -1374,25 +1392,28 @@
13741392
}
13751393
13761394
/* Generate gimme cards for phantoms and leaf cards
13771395
** for all leaves.
13781396
*/
1379
- if( pullFlag || (cloneFlag && cloneSeqno==1) ){
1397
+ if( (syncFlags & SYNC_PULL)!=0
1398
+ || ((syncFlags & SYNC_CLONE)!=0 && cloneSeqno==1)
1399
+ ){
13801400
request_phantoms(&xfer, mxPhantomReq);
13811401
}
1382
- if( pushFlag ){
1402
+ if( syncFlags & SYNC_PUSH ){
13831403
send_unsent(&xfer);
13841404
nCardSent += send_unclustered(&xfer);
1385
- if( privateFlag ) send_private(&xfer);
1405
+ if( syncFlags & SYNC_PRIVATE ) send_private(&xfer);
13861406
}
13871407
13881408
/* Send configuration parameter requests. On a clone, delay sending
13891409
** this until the second cycle since the login card might fail on
13901410
** the first cycle.
13911411
*/
1392
- if( configRcvMask && (cloneFlag==0 || nCycle>0) ){
1412
+ if( configRcvMask && ((syncFlags & SYNC_CLONE)==0 || nCycle>0) ){
13931413
const char *zName;
1414
+ if( zOpType==0 ) zOpType = "Pull";
13941415
zName = configure_first_name(configRcvMask);
13951416
while( zName ){
13961417
blob_appendf(&send, "reqconfig %s\n", zName);
13971418
zName = configure_next_name(configRcvMask);
13981419
nCardSent++;
@@ -1407,10 +1428,11 @@
14071428
configRcvMask = 0;
14081429
}
14091430
14101431
/* Send configuration parameters being pushed */
14111432
if( configSendMask ){
1433
+ if( zOpType==0 ) zOpType = "Push";
14121434
if( configSendMask & CONFIGSET_OLDFORMAT ){
14131435
const char *zName;
14141436
zName = configure_first_name(configSendMask);
14151437
while( zName ){
14161438
send_legacy_config_card(&xfer, zName);
@@ -1430,42 +1452,50 @@
14301452
zRandomness = db_text(0, "SELECT hex(randomblob(20))");
14311453
blob_appendf(&send, "# %s\n", zRandomness);
14321454
free(zRandomness);
14331455
14341456
/* Exchange messages with the server */
1435
- fossil_print(zValueFormat, "Sent:",
1436
- blob_size(&send), nCardSent+xfer.nGimmeSent+xfer.nIGotSent,
1437
- xfer.nFileSent, xfer.nDeltaSent);
1457
+ if( syncFlags & SYNC_VERBOSE ){
1458
+ fossil_print(zValueFormat, "Sent:",
1459
+ blob_size(&send), nCardSent+xfer.nGimmeSent+xfer.nIGotSent,
1460
+ xfer.nFileSent, xfer.nDeltaSent);
1461
+ }else{
1462
+ nRoundtrip++;
1463
+ nArtifactSent += xfer.nFileSent + xfer.nDeltaSent;
1464
+ fossil_print(zBriefFormat, nRoundtrip, nArtifactSent, nArtifactRcvd);
1465
+ }
14381466
nCardSent = 0;
14391467
nCardRcvd = 0;
14401468
xfer.nFileSent = 0;
14411469
xfer.nDeltaSent = 0;
14421470
xfer.nGimmeSent = 0;
14431471
xfer.nIGotSent = 0;
1444
- if( !g.cgiOutput && !g.fQuiet ){
1472
+ if( syncFlags & SYNC_VERBOSE ){
14451473
fossil_print("waiting for server...");
14461474
}
14471475
fflush(stdout);
1448
- if( http_exchange(&send, &recv, cloneFlag==0 || nCycle>0) ){
1476
+ if( http_exchange(&send, &recv, (syncFlags & SYNC_CLONE)==0 || nCycle>0) ){
14491477
nErr++;
14501478
break;
14511479
}
14521480
lastPctDone = -1;
14531481
blob_reset(&send);
14541482
rArrivalTime = db_double(0.0, "SELECT julianday('now')");
14551483
14561484
/* Send the send-private pragma if we are trying to sync private data */
1457
- if( privateFlag ) blob_append(&send, "pragma send-private\n", -1);
1485
+ if( syncFlags & SYNC_PRIVATE ){
1486
+ blob_append(&send, "pragma send-private\n", -1);
1487
+ }
14581488
14591489
/* Begin constructing the next message (which might never be
14601490
** sent) by beginning with the pull or push cards
14611491
*/
1462
- if( pullFlag ){
1492
+ if( syncFlags & SYNC_PULL ){
14631493
blob_appendf(&send, "pull %s %s\n", zSCode, zPCode);
14641494
nCardSent++;
14651495
}
1466
- if( pushFlag ){
1496
+ if( syncFlags & SYNC_PUSH ){
14671497
blob_appendf(&send, "push %s %s\n", zSCode, zPCode);
14681498
nCardSent++;
14691499
}
14701500
go = 0;
14711501
@@ -1493,11 +1523,11 @@
14931523
nCardRcvd++;
14941524
continue;
14951525
}
14961526
xfer.nToken = blob_tokenize(&xfer.line, xfer.aToken, count(xfer.aToken));
14971527
nCardRcvd++;
1498
- if( !g.cgiOutput && !g.fQuiet && recv.nUsed>0 ){
1528
+ if( (syncFlags & SYNC_VERBOSE)!=0 && recv.nUsed>0 ){
14991529
pctDone = (recv.iCursor*100)/recv.nUsed;
15001530
if( pctDone!=lastPctDone ){
15011531
fossil_print("\rprocessed: %d%% ", pctDone);
15021532
lastPctDone = pctDone;
15031533
fflush(stdout);
@@ -1508,20 +1538,22 @@
15081538
** file UUID DELTASRC SIZE \n CONTENT
15091539
**
15101540
** Receive a file transmitted from the server.
15111541
*/
15121542
if( blob_eq(&xfer.aToken[0],"file") ){
1513
- xfer_accept_file(&xfer, cloneFlag);
1543
+ xfer_accept_file(&xfer, (syncFlags & SYNC_CLONE)!=0);
1544
+ nArtifactRcvd++;
15141545
}else
15151546
15161547
/* cfile UUID USIZE CSIZE \n CONTENT
15171548
** cfile UUID DELTASRC USIZE CSIZE \n CONTENT
15181549
**
15191550
** Receive a compressed file transmitted from the server.
15201551
*/
15211552
if( blob_eq(&xfer.aToken[0],"cfile") ){
15221553
xfer_accept_compressed_file(&xfer);
1554
+ nArtifactRcvd++;
15231555
}else
15241556
15251557
/* gimme UUID
15261558
**
15271559
** Server is requesting a file. If the file is a manifest, assume
@@ -1530,11 +1562,11 @@
15301562
*/
15311563
if( blob_eq(&xfer.aToken[0], "gimme")
15321564
&& xfer.nToken==2
15331565
&& blob_is_uuid(&xfer.aToken[1])
15341566
){
1535
- if( pushFlag ){
1567
+ if( syncFlags & SYNC_PUSH ){
15361568
int rid = rid_from_uuid(&xfer.aToken[1], 0, 0);
15371569
if( rid ) send_file(&xfer, rid, &xfer.aToken[1], 0);
15381570
}
15391571
}else
15401572
@@ -1559,11 +1591,11 @@
15591591
rid = rid_from_uuid(&xfer.aToken[1], 0, 0);
15601592
if( rid>0 ){
15611593
if( !isPriv ) content_make_public(rid);
15621594
}else if( isPriv && !g.perm.Private ){
15631595
/* ignore private files */
1564
- }else if( pullFlag || cloneFlag ){
1596
+ }else if( (syncFlags & (SYNC_PULL|SYNC_CLONE))!=0 ){
15651597
rid = content_new(blob_str(&xfer.aToken[1]), isPriv);
15661598
if( rid ) newPhantom = 1;
15671599
}
15681600
remote_has(rid);
15691601
}else
@@ -1574,11 +1606,11 @@
15741606
** Should only happen in response to a clone. This message tells
15751607
** the client what product to use for the new database.
15761608
*/
15771609
if( blob_eq(&xfer.aToken[0],"push")
15781610
&& xfer.nToken==3
1579
- && cloneFlag
1611
+ && (syncFlags & SYNC_CLONE)!=0
15801612
&& blob_is_uuid(&xfer.aToken[1])
15811613
&& blob_is_uuid(&xfer.aToken[2])
15821614
){
15831615
if( blob_eq_str(&xfer.aToken[1], zSCode, -1) ){
15841616
fossil_fatal("server loop");
@@ -1604,11 +1636,12 @@
16041636
Blob content;
16051637
blob_zero(&content);
16061638
blob_extract(xfer.pIn, size, &content);
16071639
g.perm.Admin = g.perm.RdAddr = 1;
16081640
configure_receive(zName, &content, origConfigRcvMask);
1609
- nCardSent++;
1641
+ nCardRcvd++;
1642
+ nArtifactRcvd++;
16101643
blob_reset(&content);
16111644
blob_seek(xfer.pIn, 1, BLOB_SEEK_CUR);
16121645
}else
16131646
16141647
@@ -1655,12 +1688,12 @@
16551688
** to the next cycle.
16561689
*/
16571690
if( blob_eq(&xfer.aToken[0],"message") && xfer.nToken==2 ){
16581691
char *zMsg = blob_terminate(&xfer.aToken[1]);
16591692
defossilize(zMsg);
1660
- if( pushFlag && zMsg && strglob("pull only *", zMsg) ){
1661
- pushFlag = 0;
1693
+ if( (syncFlags & SYNC_PUSH) && zMsg && strglob("pull only *", zMsg) ){
1694
+ syncFlags &= ~SYNC_PUSH;
16621695
zMsg = 0;
16631696
}
16641697
fossil_print("\rServer says: %s\n", zMsg);
16651698
}else
16661699
@@ -1683,11 +1716,11 @@
16831716
** is returned in the reply before the error card, so second and
16841717
** subsequent messages should be OK. Nevertheless, we need to ignore
16851718
** the error card on the first message of a clone.
16861719
*/
16871720
if( blob_eq(&xfer.aToken[0],"error") && xfer.nToken==2 ){
1688
- if( !cloneFlag || nCycle>0 ){
1721
+ if( (syncFlags & SYNC_CLONE)==0 || nCycle>0 ){
16891722
char *zMsg = blob_terminate(&xfer.aToken[1]);
16901723
defossilize(zMsg);
16911724
if( fossil_strcmp(zMsg, "login failed")==0 ){
16921725
if( nCycle<2 ){
16931726
if( !g.dontKeepUrl ) db_unset("last-sync-pw", 0);
@@ -1727,14 +1760,16 @@
17271760
&& (configRcvMask & CONFIGSET_OLDFORMAT)!=0
17281761
){
17291762
configure_finalize_receive();
17301763
}
17311764
origConfigRcvMask = 0;
1732
- if( nCardRcvd>0 ){
1765
+ if( nCardRcvd>0 && (syncFlags & SYNC_VERBOSE) ){
17331766
fossil_print(zValueFormat, "Received:",
17341767
blob_size(&recv), nCardRcvd,
17351768
xfer.nFileRcvd, xfer.nDeltaRcvd + xfer.nDanglingFile);
1769
+ }else{
1770
+ fossil_print(zBriefFormat, nRoundtrip, nArtifactSent, nArtifactRcvd);
17361771
}
17371772
blob_reset(&recv);
17381773
nCycle++;
17391774
17401775
/* If we received one or more files on the previous exchange but
@@ -1743,11 +1778,11 @@
17431778
nFileRecv = xfer.nFileRcvd + xfer.nDeltaRcvd + xfer.nDanglingFile;
17441779
if( (nFileRecv>0 || newPhantom) && db_exists("SELECT 1 FROM phantom") ){
17451780
go = 1;
17461781
mxPhantomReq = nFileRecv*2;
17471782
if( mxPhantomReq<200 ) mxPhantomReq = 200;
1748
- }else if( cloneFlag && nFileRecv>0 ){
1783
+ }else if( (syncFlags & SYNC_CLONE)!=0 && nFileRecv>0 ){
17491784
go = 1;
17501785
}
17511786
nCardRcvd = 0;
17521787
xfer.nFileRcvd = 0;
17531788
xfer.nDeltaRcvd = 0;
@@ -1759,25 +1794,27 @@
17591794
if( xfer.nFileSent+xfer.nDeltaSent>0 ){
17601795
go = 1;
17611796
}
17621797
17631798
/* If this is a clone, the go at least two rounds */
1764
- if( cloneFlag && nCycle==1 ) go = 1;
1799
+ if( (syncFlags & SYNC_CLONE)!=0 && nCycle==1 ) go = 1;
17651800
17661801
/* Stop the cycle if the server sends a "clone_seqno 0" card and
17671802
** we have gone at least two rounds. Always go at least two rounds
17681803
** on a clone in order to be sure to retrieve the configuration
17691804
** information which is only sent on the second round.
17701805
*/
17711806
if( cloneSeqno<=0 && nCycle>1 ) go = 0;
17721807
};
17731808
transport_stats(&nSent, &nRcvd, 1);
1774
- fossil_print("Total network traffic: %lld bytes sent, %lld bytes received\n",
1775
- nSent, nRcvd);
1809
+ if( (syncFlags & SYNC_VERBOSE)==0 ) fossil_print("\n");
1810
+ fossil_print(
1811
+ "%s finished with %lld bytes sent, %lld bytes received\n",
1812
+ zOpType, nSent, nRcvd);
17761813
transport_close();
17771814
transport_global_shutdown();
17781815
db_multi_exec("DROP TABLE onremote");
17791816
manifest_crosslink_end();
17801817
content_enable_dephantomize(1);
17811818
db_end_transaction(0);
17821819
return nErr;
17831820
}
17841821
--- src/xfer.c
+++ src/xfer.c
@@ -800,11 +800,11 @@
800 */
801 static int run_script(const char *zScript){
802 if( !zScript ){
803 return TH_OK; /* No script, return success. */
804 }
805 Th_FossilInit(); /* Make sure TH1 is ready. */
806 return Th_Eval(g.interp, 0, zScript, -1);
807 }
808
809 /*
810 ** Run the pre-transfer TH1 script, if any, and returns the return code.
@@ -1266,11 +1266,23 @@
1266 /*
1267 ** Format strings for progress reporting.
1268 */
1269 static const char zLabelFormat[] = "%-10s %10s %10s %10s %10s\n";
1270 static const char zValueFormat[] = "\r%-10s %10d %10d %10d %10d\n";
 
 
1271
 
 
 
 
 
 
 
 
 
 
1272
1273 /*
1274 ** Sync to the host identified in g.urlName and g.urlPath. This
1275 ** routine is called by the client.
1276 **
@@ -1277,16 +1289,13 @@
1277 ** Records are pushed to the server if pushFlag is true. Records
1278 ** are pulled if pullFlag is true. A full sync occurs if both are
1279 ** true.
1280 */
1281 int client_sync(
1282 int pushFlag, /* True to do a push (or a sync) */
1283 int pullFlag, /* True to do a pull (or a sync) */
1284 int cloneFlag, /* True if this is a clone */
1285 int privateFlag, /* True to exchange private branches */
1286 int configRcvMask, /* Receive these configuration items */
1287 int configSendMask /* Send these configuration items */
1288 ){
1289 int go = 1; /* Loop until zero */
1290 int nCardSent = 0; /* Number of cards sent */
1291 int nCardRcvd = 0; /* Number of cards received */
1292 int nCycle = 0; /* Number of round trips to the server */
@@ -1304,27 +1313,30 @@
1304 int lastPctDone = -1; /* Last displayed pctDone */
1305 double rArrivalTime; /* Time at which a message arrived */
1306 const char *zSCode = db_get("server-code", "x");
1307 const char *zPCode = db_get("project-code", 0);
1308 int nErr = 0; /* Number of errors */
 
 
 
 
1309
1310 if( db_get_boolean("dont-push", 0) ) pushFlag = 0;
1311 if( pushFlag + pullFlag + cloneFlag == 0
1312 && configRcvMask==0 && configSendMask==0 ) return 0;
1313
1314 transport_stats(0, 0, 1);
1315 socket_global_init();
1316 memset(&xfer, 0, sizeof(xfer));
1317 xfer.pIn = &recv;
1318 xfer.pOut = &send;
1319 xfer.mxSend = db_get_int("max-upload", 250000);
1320 if( privateFlag ){
1321 g.perm.Private = 1;
1322 xfer.syncPrivate = 1;
1323 }
1324
1325 assert( pushFlag | pullFlag | cloneFlag | configRcvMask | configSendMask );
1326 db_begin_transaction();
1327 db_record_repository_filename(0);
1328 db_multi_exec(
1329 "CREATE TEMP TABLE onremote(rid INTEGER PRIMARY KEY);"
1330 );
@@ -1335,33 +1347,39 @@
1335 blob_zero(&xfer.line);
1336 origConfigRcvMask = 0;
1337
1338
1339 /* Send the send-private pragma if we are trying to sync private data */
1340 if( privateFlag ) blob_append(&send, "pragma send-private\n", -1);
 
 
1341
1342 /*
1343 ** Always begin with a clone, pull, or push message
1344 */
1345 if( cloneFlag ){
1346 blob_appendf(&send, "clone 3 %d\n", cloneSeqno);
1347 pushFlag = 0;
1348 pullFlag = 0;
1349 nCardSent++;
1350 /* TBD: Request all transferable configuration values */
1351 content_enable_dephantomize(0);
1352 }else if( pullFlag ){
 
1353 blob_appendf(&send, "pull %s %s\n", zSCode, zPCode);
1354 nCardSent++;
 
1355 }
1356 if( pushFlag ){
1357 blob_appendf(&send, "push %s %s\n", zSCode, zPCode);
1358 nCardSent++;
 
1359 }
1360 manifest_crosslink_begin();
1361 transport_global_startup();
1362 fossil_print(zLabelFormat, "", "Bytes", "Cards", "Artifacts", "Deltas");
 
 
1363
1364 while( go ){
1365 int newPhantom = 0;
1366 char *zRandomness;
1367
@@ -1374,25 +1392,28 @@
1374 }
1375
1376 /* Generate gimme cards for phantoms and leaf cards
1377 ** for all leaves.
1378 */
1379 if( pullFlag || (cloneFlag && cloneSeqno==1) ){
 
 
1380 request_phantoms(&xfer, mxPhantomReq);
1381 }
1382 if( pushFlag ){
1383 send_unsent(&xfer);
1384 nCardSent += send_unclustered(&xfer);
1385 if( privateFlag ) send_private(&xfer);
1386 }
1387
1388 /* Send configuration parameter requests. On a clone, delay sending
1389 ** this until the second cycle since the login card might fail on
1390 ** the first cycle.
1391 */
1392 if( configRcvMask && (cloneFlag==0 || nCycle>0) ){
1393 const char *zName;
 
1394 zName = configure_first_name(configRcvMask);
1395 while( zName ){
1396 blob_appendf(&send, "reqconfig %s\n", zName);
1397 zName = configure_next_name(configRcvMask);
1398 nCardSent++;
@@ -1407,10 +1428,11 @@
1407 configRcvMask = 0;
1408 }
1409
1410 /* Send configuration parameters being pushed */
1411 if( configSendMask ){
 
1412 if( configSendMask & CONFIGSET_OLDFORMAT ){
1413 const char *zName;
1414 zName = configure_first_name(configSendMask);
1415 while( zName ){
1416 send_legacy_config_card(&xfer, zName);
@@ -1430,42 +1452,50 @@
1430 zRandomness = db_text(0, "SELECT hex(randomblob(20))");
1431 blob_appendf(&send, "# %s\n", zRandomness);
1432 free(zRandomness);
1433
1434 /* Exchange messages with the server */
1435 fossil_print(zValueFormat, "Sent:",
1436 blob_size(&send), nCardSent+xfer.nGimmeSent+xfer.nIGotSent,
1437 xfer.nFileSent, xfer.nDeltaSent);
 
 
 
 
 
 
1438 nCardSent = 0;
1439 nCardRcvd = 0;
1440 xfer.nFileSent = 0;
1441 xfer.nDeltaSent = 0;
1442 xfer.nGimmeSent = 0;
1443 xfer.nIGotSent = 0;
1444 if( !g.cgiOutput && !g.fQuiet ){
1445 fossil_print("waiting for server...");
1446 }
1447 fflush(stdout);
1448 if( http_exchange(&send, &recv, cloneFlag==0 || nCycle>0) ){
1449 nErr++;
1450 break;
1451 }
1452 lastPctDone = -1;
1453 blob_reset(&send);
1454 rArrivalTime = db_double(0.0, "SELECT julianday('now')");
1455
1456 /* Send the send-private pragma if we are trying to sync private data */
1457 if( privateFlag ) blob_append(&send, "pragma send-private\n", -1);
 
 
1458
1459 /* Begin constructing the next message (which might never be
1460 ** sent) by beginning with the pull or push cards
1461 */
1462 if( pullFlag ){
1463 blob_appendf(&send, "pull %s %s\n", zSCode, zPCode);
1464 nCardSent++;
1465 }
1466 if( pushFlag ){
1467 blob_appendf(&send, "push %s %s\n", zSCode, zPCode);
1468 nCardSent++;
1469 }
1470 go = 0;
1471
@@ -1493,11 +1523,11 @@
1493 nCardRcvd++;
1494 continue;
1495 }
1496 xfer.nToken = blob_tokenize(&xfer.line, xfer.aToken, count(xfer.aToken));
1497 nCardRcvd++;
1498 if( !g.cgiOutput && !g.fQuiet && recv.nUsed>0 ){
1499 pctDone = (recv.iCursor*100)/recv.nUsed;
1500 if( pctDone!=lastPctDone ){
1501 fossil_print("\rprocessed: %d%% ", pctDone);
1502 lastPctDone = pctDone;
1503 fflush(stdout);
@@ -1508,20 +1538,22 @@
1508 ** file UUID DELTASRC SIZE \n CONTENT
1509 **
1510 ** Receive a file transmitted from the server.
1511 */
1512 if( blob_eq(&xfer.aToken[0],"file") ){
1513 xfer_accept_file(&xfer, cloneFlag);
 
1514 }else
1515
1516 /* cfile UUID USIZE CSIZE \n CONTENT
1517 ** cfile UUID DELTASRC USIZE CSIZE \n CONTENT
1518 **
1519 ** Receive a compressed file transmitted from the server.
1520 */
1521 if( blob_eq(&xfer.aToken[0],"cfile") ){
1522 xfer_accept_compressed_file(&xfer);
 
1523 }else
1524
1525 /* gimme UUID
1526 **
1527 ** Server is requesting a file. If the file is a manifest, assume
@@ -1530,11 +1562,11 @@
1530 */
1531 if( blob_eq(&xfer.aToken[0], "gimme")
1532 && xfer.nToken==2
1533 && blob_is_uuid(&xfer.aToken[1])
1534 ){
1535 if( pushFlag ){
1536 int rid = rid_from_uuid(&xfer.aToken[1], 0, 0);
1537 if( rid ) send_file(&xfer, rid, &xfer.aToken[1], 0);
1538 }
1539 }else
1540
@@ -1559,11 +1591,11 @@
1559 rid = rid_from_uuid(&xfer.aToken[1], 0, 0);
1560 if( rid>0 ){
1561 if( !isPriv ) content_make_public(rid);
1562 }else if( isPriv && !g.perm.Private ){
1563 /* ignore private files */
1564 }else if( pullFlag || cloneFlag ){
1565 rid = content_new(blob_str(&xfer.aToken[1]), isPriv);
1566 if( rid ) newPhantom = 1;
1567 }
1568 remote_has(rid);
1569 }else
@@ -1574,11 +1606,11 @@
1574 ** Should only happen in response to a clone. This message tells
1575 ** the client what product to use for the new database.
1576 */
1577 if( blob_eq(&xfer.aToken[0],"push")
1578 && xfer.nToken==3
1579 && cloneFlag
1580 && blob_is_uuid(&xfer.aToken[1])
1581 && blob_is_uuid(&xfer.aToken[2])
1582 ){
1583 if( blob_eq_str(&xfer.aToken[1], zSCode, -1) ){
1584 fossil_fatal("server loop");
@@ -1604,11 +1636,12 @@
1604 Blob content;
1605 blob_zero(&content);
1606 blob_extract(xfer.pIn, size, &content);
1607 g.perm.Admin = g.perm.RdAddr = 1;
1608 configure_receive(zName, &content, origConfigRcvMask);
1609 nCardSent++;
 
1610 blob_reset(&content);
1611 blob_seek(xfer.pIn, 1, BLOB_SEEK_CUR);
1612 }else
1613
1614
@@ -1655,12 +1688,12 @@
1655 ** to the next cycle.
1656 */
1657 if( blob_eq(&xfer.aToken[0],"message") && xfer.nToken==2 ){
1658 char *zMsg = blob_terminate(&xfer.aToken[1]);
1659 defossilize(zMsg);
1660 if( pushFlag && zMsg && strglob("pull only *", zMsg) ){
1661 pushFlag = 0;
1662 zMsg = 0;
1663 }
1664 fossil_print("\rServer says: %s\n", zMsg);
1665 }else
1666
@@ -1683,11 +1716,11 @@
1683 ** is returned in the reply before the error card, so second and
1684 ** subsequent messages should be OK. Nevertheless, we need to ignore
1685 ** the error card on the first message of a clone.
1686 */
1687 if( blob_eq(&xfer.aToken[0],"error") && xfer.nToken==2 ){
1688 if( !cloneFlag || nCycle>0 ){
1689 char *zMsg = blob_terminate(&xfer.aToken[1]);
1690 defossilize(zMsg);
1691 if( fossil_strcmp(zMsg, "login failed")==0 ){
1692 if( nCycle<2 ){
1693 if( !g.dontKeepUrl ) db_unset("last-sync-pw", 0);
@@ -1727,14 +1760,16 @@
1727 && (configRcvMask & CONFIGSET_OLDFORMAT)!=0
1728 ){
1729 configure_finalize_receive();
1730 }
1731 origConfigRcvMask = 0;
1732 if( nCardRcvd>0 ){
1733 fossil_print(zValueFormat, "Received:",
1734 blob_size(&recv), nCardRcvd,
1735 xfer.nFileRcvd, xfer.nDeltaRcvd + xfer.nDanglingFile);
 
 
1736 }
1737 blob_reset(&recv);
1738 nCycle++;
1739
1740 /* If we received one or more files on the previous exchange but
@@ -1743,11 +1778,11 @@
1743 nFileRecv = xfer.nFileRcvd + xfer.nDeltaRcvd + xfer.nDanglingFile;
1744 if( (nFileRecv>0 || newPhantom) && db_exists("SELECT 1 FROM phantom") ){
1745 go = 1;
1746 mxPhantomReq = nFileRecv*2;
1747 if( mxPhantomReq<200 ) mxPhantomReq = 200;
1748 }else if( cloneFlag && nFileRecv>0 ){
1749 go = 1;
1750 }
1751 nCardRcvd = 0;
1752 xfer.nFileRcvd = 0;
1753 xfer.nDeltaRcvd = 0;
@@ -1759,25 +1794,27 @@
1759 if( xfer.nFileSent+xfer.nDeltaSent>0 ){
1760 go = 1;
1761 }
1762
1763 /* If this is a clone, the go at least two rounds */
1764 if( cloneFlag && nCycle==1 ) go = 1;
1765
1766 /* Stop the cycle if the server sends a "clone_seqno 0" card and
1767 ** we have gone at least two rounds. Always go at least two rounds
1768 ** on a clone in order to be sure to retrieve the configuration
1769 ** information which is only sent on the second round.
1770 */
1771 if( cloneSeqno<=0 && nCycle>1 ) go = 0;
1772 };
1773 transport_stats(&nSent, &nRcvd, 1);
1774 fossil_print("Total network traffic: %lld bytes sent, %lld bytes received\n",
1775 nSent, nRcvd);
 
 
1776 transport_close();
1777 transport_global_shutdown();
1778 db_multi_exec("DROP TABLE onremote");
1779 manifest_crosslink_end();
1780 content_enable_dephantomize(1);
1781 db_end_transaction(0);
1782 return nErr;
1783 }
1784
--- src/xfer.c
+++ src/xfer.c
@@ -800,11 +800,11 @@
800 */
801 static int run_script(const char *zScript){
802 if( !zScript ){
803 return TH_OK; /* No script, return success. */
804 }
805 Th_FossilInit(0, 0); /* Make sure TH1 is ready. */
806 return Th_Eval(g.interp, 0, zScript, -1);
807 }
808
809 /*
810 ** Run the pre-transfer TH1 script, if any, and returns the return code.
@@ -1266,11 +1266,23 @@
1266 /*
1267 ** Format strings for progress reporting.
1268 */
1269 static const char zLabelFormat[] = "%-10s %10s %10s %10s %10s\n";
1270 static const char zValueFormat[] = "\r%-10s %10d %10d %10d %10d\n";
1271 static const char zBriefFormat[] =
1272 "Round-trips: %d Artifacts sent: %d received: %d\r";
1273
1274 #if INTERFACE
1275 /*
1276 ** Flag options for controlling client_sync()
1277 */
1278 #define SYNC_PUSH 0x0001
1279 #define SYNC_PULL 0x0002
1280 #define SYNC_CLONE 0x0004
1281 #define SYNC_PRIVATE 0x0008
1282 #define SYNC_VERBOSE 0x0010
1283 #endif
1284
1285 /*
1286 ** Sync to the host identified in g.urlName and g.urlPath. This
1287 ** routine is called by the client.
1288 **
@@ -1277,16 +1289,13 @@
1289 ** Records are pushed to the server if pushFlag is true. Records
1290 ** are pulled if pullFlag is true. A full sync occurs if both are
1291 ** true.
1292 */
1293 int client_sync(
1294 unsigned syncFlags, /* Mask of SYNC_* flags */
1295 unsigned configRcvMask, /* Receive these configuration items */
1296 unsigned configSendMask /* Send these configuration items */
 
 
 
1297 ){
1298 int go = 1; /* Loop until zero */
1299 int nCardSent = 0; /* Number of cards sent */
1300 int nCardRcvd = 0; /* Number of cards received */
1301 int nCycle = 0; /* Number of round trips to the server */
@@ -1304,27 +1313,30 @@
1313 int lastPctDone = -1; /* Last displayed pctDone */
1314 double rArrivalTime; /* Time at which a message arrived */
1315 const char *zSCode = db_get("server-code", "x");
1316 const char *zPCode = db_get("project-code", 0);
1317 int nErr = 0; /* Number of errors */
1318 int nRoundtrip= 0; /* Number of HTTP requests */
1319 int nArtifactSent = 0; /* Total artifacts sent */
1320 int nArtifactRcvd = 0; /* Total artifacts received */
1321 const char *zOpType = 0;/* Push, Pull, Sync, Clone */
1322
1323 if( db_get_boolean("dont-push", 0) ) syncFlags &= ~SYNC_PUSH;
1324 if( (syncFlags & (SYNC_PUSH|SYNC_PULL|SYNC_CLONE))==0
1325 && configRcvMask==0 && configSendMask==0 ) return 0;
1326
1327 transport_stats(0, 0, 1);
1328 socket_global_init();
1329 memset(&xfer, 0, sizeof(xfer));
1330 xfer.pIn = &recv;
1331 xfer.pOut = &send;
1332 xfer.mxSend = db_get_int("max-upload", 250000);
1333 if( syncFlags & SYNC_PRIVATE ){
1334 g.perm.Private = 1;
1335 xfer.syncPrivate = 1;
1336 }
1337
 
1338 db_begin_transaction();
1339 db_record_repository_filename(0);
1340 db_multi_exec(
1341 "CREATE TEMP TABLE onremote(rid INTEGER PRIMARY KEY);"
1342 );
@@ -1335,33 +1347,39 @@
1347 blob_zero(&xfer.line);
1348 origConfigRcvMask = 0;
1349
1350
1351 /* Send the send-private pragma if we are trying to sync private data */
1352 if( syncFlags & SYNC_PRIVATE ){
1353 blob_append(&send, "pragma send-private\n", -1);
1354 }
1355
1356 /*
1357 ** Always begin with a clone, pull, or push message
1358 */
1359 if( syncFlags & SYNC_CLONE ){
1360 blob_appendf(&send, "clone 3 %d\n", cloneSeqno);
1361 syncFlags &= ~(SYNC_PUSH|SYNC_PULL);
 
1362 nCardSent++;
1363 /* TBD: Request all transferable configuration values */
1364 content_enable_dephantomize(0);
1365 zOpType = "Clone";
1366 }else if( syncFlags & SYNC_PULL ){
1367 blob_appendf(&send, "pull %s %s\n", zSCode, zPCode);
1368 nCardSent++;
1369 zOpType = "Pull";
1370 }
1371 if( syncFlags & SYNC_PUSH ){
1372 blob_appendf(&send, "push %s %s\n", zSCode, zPCode);
1373 nCardSent++;
1374 if( (syncFlags & SYNC_PULL)==0 ) zOpType = "Push";
1375 }
1376 manifest_crosslink_begin();
1377 transport_global_startup();
1378 if( syncFlags & SYNC_VERBOSE ){
1379 fossil_print(zLabelFormat, "", "Bytes", "Cards", "Artifacts", "Deltas");
1380 }
1381
1382 while( go ){
1383 int newPhantom = 0;
1384 char *zRandomness;
1385
@@ -1374,25 +1392,28 @@
1392 }
1393
1394 /* Generate gimme cards for phantoms and leaf cards
1395 ** for all leaves.
1396 */
1397 if( (syncFlags & SYNC_PULL)!=0
1398 || ((syncFlags & SYNC_CLONE)!=0 && cloneSeqno==1)
1399 ){
1400 request_phantoms(&xfer, mxPhantomReq);
1401 }
1402 if( syncFlags & SYNC_PUSH ){
1403 send_unsent(&xfer);
1404 nCardSent += send_unclustered(&xfer);
1405 if( syncFlags & SYNC_PRIVATE ) send_private(&xfer);
1406 }
1407
1408 /* Send configuration parameter requests. On a clone, delay sending
1409 ** this until the second cycle since the login card might fail on
1410 ** the first cycle.
1411 */
1412 if( configRcvMask && ((syncFlags & SYNC_CLONE)==0 || nCycle>0) ){
1413 const char *zName;
1414 if( zOpType==0 ) zOpType = "Pull";
1415 zName = configure_first_name(configRcvMask);
1416 while( zName ){
1417 blob_appendf(&send, "reqconfig %s\n", zName);
1418 zName = configure_next_name(configRcvMask);
1419 nCardSent++;
@@ -1407,10 +1428,11 @@
1428 configRcvMask = 0;
1429 }
1430
1431 /* Send configuration parameters being pushed */
1432 if( configSendMask ){
1433 if( zOpType==0 ) zOpType = "Push";
1434 if( configSendMask & CONFIGSET_OLDFORMAT ){
1435 const char *zName;
1436 zName = configure_first_name(configSendMask);
1437 while( zName ){
1438 send_legacy_config_card(&xfer, zName);
@@ -1430,42 +1452,50 @@
1452 zRandomness = db_text(0, "SELECT hex(randomblob(20))");
1453 blob_appendf(&send, "# %s\n", zRandomness);
1454 free(zRandomness);
1455
1456 /* Exchange messages with the server */
1457 if( syncFlags & SYNC_VERBOSE ){
1458 fossil_print(zValueFormat, "Sent:",
1459 blob_size(&send), nCardSent+xfer.nGimmeSent+xfer.nIGotSent,
1460 xfer.nFileSent, xfer.nDeltaSent);
1461 }else{
1462 nRoundtrip++;
1463 nArtifactSent += xfer.nFileSent + xfer.nDeltaSent;
1464 fossil_print(zBriefFormat, nRoundtrip, nArtifactSent, nArtifactRcvd);
1465 }
1466 nCardSent = 0;
1467 nCardRcvd = 0;
1468 xfer.nFileSent = 0;
1469 xfer.nDeltaSent = 0;
1470 xfer.nGimmeSent = 0;
1471 xfer.nIGotSent = 0;
1472 if( syncFlags & SYNC_VERBOSE ){
1473 fossil_print("waiting for server...");
1474 }
1475 fflush(stdout);
1476 if( http_exchange(&send, &recv, (syncFlags & SYNC_CLONE)==0 || nCycle>0) ){
1477 nErr++;
1478 break;
1479 }
1480 lastPctDone = -1;
1481 blob_reset(&send);
1482 rArrivalTime = db_double(0.0, "SELECT julianday('now')");
1483
1484 /* Send the send-private pragma if we are trying to sync private data */
1485 if( syncFlags & SYNC_PRIVATE ){
1486 blob_append(&send, "pragma send-private\n", -1);
1487 }
1488
1489 /* Begin constructing the next message (which might never be
1490 ** sent) by beginning with the pull or push cards
1491 */
1492 if( syncFlags & SYNC_PULL ){
1493 blob_appendf(&send, "pull %s %s\n", zSCode, zPCode);
1494 nCardSent++;
1495 }
1496 if( syncFlags & SYNC_PUSH ){
1497 blob_appendf(&send, "push %s %s\n", zSCode, zPCode);
1498 nCardSent++;
1499 }
1500 go = 0;
1501
@@ -1493,11 +1523,11 @@
1523 nCardRcvd++;
1524 continue;
1525 }
1526 xfer.nToken = blob_tokenize(&xfer.line, xfer.aToken, count(xfer.aToken));
1527 nCardRcvd++;
1528 if( (syncFlags & SYNC_VERBOSE)!=0 && recv.nUsed>0 ){
1529 pctDone = (recv.iCursor*100)/recv.nUsed;
1530 if( pctDone!=lastPctDone ){
1531 fossil_print("\rprocessed: %d%% ", pctDone);
1532 lastPctDone = pctDone;
1533 fflush(stdout);
@@ -1508,20 +1538,22 @@
1538 ** file UUID DELTASRC SIZE \n CONTENT
1539 **
1540 ** Receive a file transmitted from the server.
1541 */
1542 if( blob_eq(&xfer.aToken[0],"file") ){
1543 xfer_accept_file(&xfer, (syncFlags & SYNC_CLONE)!=0);
1544 nArtifactRcvd++;
1545 }else
1546
1547 /* cfile UUID USIZE CSIZE \n CONTENT
1548 ** cfile UUID DELTASRC USIZE CSIZE \n CONTENT
1549 **
1550 ** Receive a compressed file transmitted from the server.
1551 */
1552 if( blob_eq(&xfer.aToken[0],"cfile") ){
1553 xfer_accept_compressed_file(&xfer);
1554 nArtifactRcvd++;
1555 }else
1556
1557 /* gimme UUID
1558 **
1559 ** Server is requesting a file. If the file is a manifest, assume
@@ -1530,11 +1562,11 @@
1562 */
1563 if( blob_eq(&xfer.aToken[0], "gimme")
1564 && xfer.nToken==2
1565 && blob_is_uuid(&xfer.aToken[1])
1566 ){
1567 if( syncFlags & SYNC_PUSH ){
1568 int rid = rid_from_uuid(&xfer.aToken[1], 0, 0);
1569 if( rid ) send_file(&xfer, rid, &xfer.aToken[1], 0);
1570 }
1571 }else
1572
@@ -1559,11 +1591,11 @@
1591 rid = rid_from_uuid(&xfer.aToken[1], 0, 0);
1592 if( rid>0 ){
1593 if( !isPriv ) content_make_public(rid);
1594 }else if( isPriv && !g.perm.Private ){
1595 /* ignore private files */
1596 }else if( (syncFlags & (SYNC_PULL|SYNC_CLONE))!=0 ){
1597 rid = content_new(blob_str(&xfer.aToken[1]), isPriv);
1598 if( rid ) newPhantom = 1;
1599 }
1600 remote_has(rid);
1601 }else
@@ -1574,11 +1606,11 @@
1606 ** Should only happen in response to a clone. This message tells
1607 ** the client what product to use for the new database.
1608 */
1609 if( blob_eq(&xfer.aToken[0],"push")
1610 && xfer.nToken==3
1611 && (syncFlags & SYNC_CLONE)!=0
1612 && blob_is_uuid(&xfer.aToken[1])
1613 && blob_is_uuid(&xfer.aToken[2])
1614 ){
1615 if( blob_eq_str(&xfer.aToken[1], zSCode, -1) ){
1616 fossil_fatal("server loop");
@@ -1604,11 +1636,12 @@
1636 Blob content;
1637 blob_zero(&content);
1638 blob_extract(xfer.pIn, size, &content);
1639 g.perm.Admin = g.perm.RdAddr = 1;
1640 configure_receive(zName, &content, origConfigRcvMask);
1641 nCardRcvd++;
1642 nArtifactRcvd++;
1643 blob_reset(&content);
1644 blob_seek(xfer.pIn, 1, BLOB_SEEK_CUR);
1645 }else
1646
1647
@@ -1655,12 +1688,12 @@
1688 ** to the next cycle.
1689 */
1690 if( blob_eq(&xfer.aToken[0],"message") && xfer.nToken==2 ){
1691 char *zMsg = blob_terminate(&xfer.aToken[1]);
1692 defossilize(zMsg);
1693 if( (syncFlags & SYNC_PUSH) && zMsg && strglob("pull only *", zMsg) ){
1694 syncFlags &= ~SYNC_PUSH;
1695 zMsg = 0;
1696 }
1697 fossil_print("\rServer says: %s\n", zMsg);
1698 }else
1699
@@ -1683,11 +1716,11 @@
1716 ** is returned in the reply before the error card, so second and
1717 ** subsequent messages should be OK. Nevertheless, we need to ignore
1718 ** the error card on the first message of a clone.
1719 */
1720 if( blob_eq(&xfer.aToken[0],"error") && xfer.nToken==2 ){
1721 if( (syncFlags & SYNC_CLONE)==0 || nCycle>0 ){
1722 char *zMsg = blob_terminate(&xfer.aToken[1]);
1723 defossilize(zMsg);
1724 if( fossil_strcmp(zMsg, "login failed")==0 ){
1725 if( nCycle<2 ){
1726 if( !g.dontKeepUrl ) db_unset("last-sync-pw", 0);
@@ -1727,14 +1760,16 @@
1760 && (configRcvMask & CONFIGSET_OLDFORMAT)!=0
1761 ){
1762 configure_finalize_receive();
1763 }
1764 origConfigRcvMask = 0;
1765 if( nCardRcvd>0 && (syncFlags & SYNC_VERBOSE) ){
1766 fossil_print(zValueFormat, "Received:",
1767 blob_size(&recv), nCardRcvd,
1768 xfer.nFileRcvd, xfer.nDeltaRcvd + xfer.nDanglingFile);
1769 }else{
1770 fossil_print(zBriefFormat, nRoundtrip, nArtifactSent, nArtifactRcvd);
1771 }
1772 blob_reset(&recv);
1773 nCycle++;
1774
1775 /* If we received one or more files on the previous exchange but
@@ -1743,11 +1778,11 @@
1778 nFileRecv = xfer.nFileRcvd + xfer.nDeltaRcvd + xfer.nDanglingFile;
1779 if( (nFileRecv>0 || newPhantom) && db_exists("SELECT 1 FROM phantom") ){
1780 go = 1;
1781 mxPhantomReq = nFileRecv*2;
1782 if( mxPhantomReq<200 ) mxPhantomReq = 200;
1783 }else if( (syncFlags & SYNC_CLONE)!=0 && nFileRecv>0 ){
1784 go = 1;
1785 }
1786 nCardRcvd = 0;
1787 xfer.nFileRcvd = 0;
1788 xfer.nDeltaRcvd = 0;
@@ -1759,25 +1794,27 @@
1794 if( xfer.nFileSent+xfer.nDeltaSent>0 ){
1795 go = 1;
1796 }
1797
1798 /* If this is a clone, the go at least two rounds */
1799 if( (syncFlags & SYNC_CLONE)!=0 && nCycle==1 ) go = 1;
1800
1801 /* Stop the cycle if the server sends a "clone_seqno 0" card and
1802 ** we have gone at least two rounds. Always go at least two rounds
1803 ** on a clone in order to be sure to retrieve the configuration
1804 ** information which is only sent on the second round.
1805 */
1806 if( cloneSeqno<=0 && nCycle>1 ) go = 0;
1807 };
1808 transport_stats(&nSent, &nRcvd, 1);
1809 if( (syncFlags & SYNC_VERBOSE)==0 ) fossil_print("\n");
1810 fossil_print(
1811 "%s finished with %lld bytes sent, %lld bytes received\n",
1812 zOpType, nSent, nRcvd);
1813 transport_close();
1814 transport_global_shutdown();
1815 db_multi_exec("DROP TABLE onremote");
1816 manifest_crosslink_end();
1817 content_enable_dephantomize(1);
1818 db_end_transaction(0);
1819 return nErr;
1820 }
1821
--- win/Makefile.mingw
+++ win/Makefile.mingw
@@ -35,10 +35,14 @@
3535
# will run on the platform that is doing the build. This is used
3636
# to compile code-generator programs as part of the build process.
3737
# See TCC below for the C compiler for building the finished binary.
3838
#
3939
BCC = gcc
40
+
41
+#### Enable compiling with debug symbols (much larger binary)
42
+#
43
+# FOSSIL_ENABLE_SYMBOLS = 1
4044
4145
#### Enable JSON (http://www.json.org) support using "cson"
4246
#
4347
# FOSSIL_ENABLE_JSON = 1
4448
@@ -112,11 +116,18 @@
112116
# will run on the target platform. This is usually the same
113117
# as BCC, unless you are cross-compiling. This C compiler builds
114118
# the finished binary for fossil. The BCC compiler above is used
115119
# for building intermediate code-generator tools.
116120
#
117
-TCC = $(PREFIX)gcc -g -Os -Wall -L$(ZLIBDIR) -I$(ZINCDIR)
121
+TCC = $(PREFIX)gcc -Os -Wall -L$(ZLIBDIR) -I$(ZINCDIR)
122
+
123
+#### Add the necessary command line options to build with debugging
124
+# symbols, if enabled.
125
+#
126
+ifdef FOSSIL_ENABLE_SYMBOLS
127
+TCC += -g
128
+endif
118129
119130
#### Compile resources for use in building executables that will run
120131
# on the target platform.
121132
#
122133
RCC = $(PREFIX)windres -I$(SRCDIR) -I$(ZINCDIR)
123134
--- win/Makefile.mingw
+++ win/Makefile.mingw
@@ -35,10 +35,14 @@
35 # will run on the platform that is doing the build. This is used
36 # to compile code-generator programs as part of the build process.
37 # See TCC below for the C compiler for building the finished binary.
38 #
39 BCC = gcc
 
 
 
 
40
41 #### Enable JSON (http://www.json.org) support using "cson"
42 #
43 # FOSSIL_ENABLE_JSON = 1
44
@@ -112,11 +116,18 @@
112 # will run on the target platform. This is usually the same
113 # as BCC, unless you are cross-compiling. This C compiler builds
114 # the finished binary for fossil. The BCC compiler above is used
115 # for building intermediate code-generator tools.
116 #
117 TCC = $(PREFIX)gcc -g -Os -Wall -L$(ZLIBDIR) -I$(ZINCDIR)
 
 
 
 
 
 
 
118
119 #### Compile resources for use in building executables that will run
120 # on the target platform.
121 #
122 RCC = $(PREFIX)windres -I$(SRCDIR) -I$(ZINCDIR)
123
--- win/Makefile.mingw
+++ win/Makefile.mingw
@@ -35,10 +35,14 @@
35 # will run on the platform that is doing the build. This is used
36 # to compile code-generator programs as part of the build process.
37 # See TCC below for the C compiler for building the finished binary.
38 #
39 BCC = gcc
40
41 #### Enable compiling with debug symbols (much larger binary)
42 #
43 # FOSSIL_ENABLE_SYMBOLS = 1
44
45 #### Enable JSON (http://www.json.org) support using "cson"
46 #
47 # FOSSIL_ENABLE_JSON = 1
48
@@ -112,11 +116,18 @@
116 # will run on the target platform. This is usually the same
117 # as BCC, unless you are cross-compiling. This C compiler builds
118 # the finished binary for fossil. The BCC compiler above is used
119 # for building intermediate code-generator tools.
120 #
121 TCC = $(PREFIX)gcc -Os -Wall -L$(ZLIBDIR) -I$(ZINCDIR)
122
123 #### Add the necessary command line options to build with debugging
124 # symbols, if enabled.
125 #
126 ifdef FOSSIL_ENABLE_SYMBOLS
127 TCC += -g
128 endif
129
130 #### Compile resources for use in building executables that will run
131 # on the target platform.
132 #
133 RCC = $(PREFIX)windres -I$(SRCDIR) -I$(ZINCDIR)
134
--- win/Makefile.mingw.mistachkin
+++ win/Makefile.mingw.mistachkin
@@ -35,10 +35,14 @@
3535
# will run on the platform that is doing the build. This is used
3636
# to compile code-generator programs as part of the build process.
3737
# See TCC below for the C compiler for building the finished binary.
3838
#
3939
BCC = gcc
40
+
41
+#### Enable compiling with debug symbols (much larger binary)
42
+#
43
+# FOSSIL_ENABLE_SYMBOLS = 1
4044
4145
#### Enable JSON (http://www.json.org) support using "cson"
4246
#
4347
FOSSIL_ENABLE_JSON = 1
4448
@@ -112,11 +116,18 @@
112116
# will run on the target platform. This is usually the same
113117
# as BCC, unless you are cross-compiling. This C compiler builds
114118
# the finished binary for fossil. The BCC compiler above is used
115119
# for building intermediate code-generator tools.
116120
#
117
-TCC = $(PREFIX)gcc -g -Os -Wall -L$(ZLIBDIR) -I$(ZINCDIR)
121
+TCC = $(PREFIX)gcc -Os -Wall -L$(ZLIBDIR) -I$(ZINCDIR)
122
+
123
+#### Add the necessary command line options to build with debugging
124
+# symbols, if enabled.
125
+#
126
+ifdef FOSSIL_ENABLE_SYMBOLS
127
+TCC += -g
128
+endif
118129
119130
#### Compile resources for use in building executables that will run
120131
# on the target platform.
121132
#
122133
RCC = $(PREFIX)windres -I$(SRCDIR) -I$(ZINCDIR)
123134
--- win/Makefile.mingw.mistachkin
+++ win/Makefile.mingw.mistachkin
@@ -35,10 +35,14 @@
35 # will run on the platform that is doing the build. This is used
36 # to compile code-generator programs as part of the build process.
37 # See TCC below for the C compiler for building the finished binary.
38 #
39 BCC = gcc
 
 
 
 
40
41 #### Enable JSON (http://www.json.org) support using "cson"
42 #
43 FOSSIL_ENABLE_JSON = 1
44
@@ -112,11 +116,18 @@
112 # will run on the target platform. This is usually the same
113 # as BCC, unless you are cross-compiling. This C compiler builds
114 # the finished binary for fossil. The BCC compiler above is used
115 # for building intermediate code-generator tools.
116 #
117 TCC = $(PREFIX)gcc -g -Os -Wall -L$(ZLIBDIR) -I$(ZINCDIR)
 
 
 
 
 
 
 
118
119 #### Compile resources for use in building executables that will run
120 # on the target platform.
121 #
122 RCC = $(PREFIX)windres -I$(SRCDIR) -I$(ZINCDIR)
123
--- win/Makefile.mingw.mistachkin
+++ win/Makefile.mingw.mistachkin
@@ -35,10 +35,14 @@
35 # will run on the platform that is doing the build. This is used
36 # to compile code-generator programs as part of the build process.
37 # See TCC below for the C compiler for building the finished binary.
38 #
39 BCC = gcc
40
41 #### Enable compiling with debug symbols (much larger binary)
42 #
43 # FOSSIL_ENABLE_SYMBOLS = 1
44
45 #### Enable JSON (http://www.json.org) support using "cson"
46 #
47 FOSSIL_ENABLE_JSON = 1
48
@@ -112,11 +116,18 @@
116 # will run on the target platform. This is usually the same
117 # as BCC, unless you are cross-compiling. This C compiler builds
118 # the finished binary for fossil. The BCC compiler above is used
119 # for building intermediate code-generator tools.
120 #
121 TCC = $(PREFIX)gcc -Os -Wall -L$(ZLIBDIR) -I$(ZINCDIR)
122
123 #### Add the necessary command line options to build with debugging
124 # symbols, if enabled.
125 #
126 ifdef FOSSIL_ENABLE_SYMBOLS
127 TCC += -g
128 endif
129
130 #### Compile resources for use in building executables that will run
131 # on the target platform.
132 #
133 RCC = $(PREFIX)windres -I$(SRCDIR) -I$(ZINCDIR)
134

Keyboard Shortcuts

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