Fossil SCM

Merge the development of the Fossil chatroom onto trunk. This feature is well isolated from the rest of the system and so we can safely continue development on trunk, which is more convenient for testing.

drh 2020-12-23 18:27 trunk merge
Commit e8ba89b1682671c769d40055c6c9c7931dab0e5257f87e8abe1ccbbcd063425e
--- src/builtin.c
+++ src/builtin.c
@@ -636,10 +636,13 @@
636636
CX("isDark: %s"
637637
"/*true if the current skin has the 'white-foreground' detail*/",
638638
skin_detail_boolean("white-foreground") ? "true" : "false");
639639
CX("}\n"/*fossil.config.skin*/);
640640
CX("};\n"/* fossil.config */);
641
+ CX("window.fossil.user = {");
642
+ CX("name: %!j", (g.zLogin&&*g.zLogin) ? g.zLogin : "guest");
643
+ CX("};\n"/*fossil.user*/);
641644
CX("if(fossil.config.skin.isDark) "
642645
"document.body.classList.add('fossil-dark-style');\n");
643646
#if 0
644647
/* Is it safe to emit the CSRF token here? Some pages add it
645648
** as a hidden form field. */
646649
--- src/builtin.c
+++ src/builtin.c
@@ -636,10 +636,13 @@
636 CX("isDark: %s"
637 "/*true if the current skin has the 'white-foreground' detail*/",
638 skin_detail_boolean("white-foreground") ? "true" : "false");
639 CX("}\n"/*fossil.config.skin*/);
640 CX("};\n"/* fossil.config */);
 
 
 
641 CX("if(fossil.config.skin.isDark) "
642 "document.body.classList.add('fossil-dark-style');\n");
643 #if 0
644 /* Is it safe to emit the CSRF token here? Some pages add it
645 ** as a hidden form field. */
646
--- src/builtin.c
+++ src/builtin.c
@@ -636,10 +636,13 @@
636 CX("isDark: %s"
637 "/*true if the current skin has the 'white-foreground' detail*/",
638 skin_detail_boolean("white-foreground") ? "true" : "false");
639 CX("}\n"/*fossil.config.skin*/);
640 CX("};\n"/* fossil.config */);
641 CX("window.fossil.user = {");
642 CX("name: %!j", (g.zLogin&&*g.zLogin) ? g.zLogin : "guest");
643 CX("};\n"/*fossil.user*/);
644 CX("if(fossil.config.skin.isDark) "
645 "document.body.classList.add('fossil-dark-style');\n");
646 #if 0
647 /* Is it safe to emit the CSRF token here? Some pages add it
648 ** as a hidden form field. */
649
--- src/capabilities.c
+++ src/capabilities.c
@@ -304,10 +304,12 @@
304304
"Forum-Admin", "Grant capability '4' to other users" },
305305
{ '7', CAPCLASS_ALERT, 0,
306306
"Alerts", "Sign up for email alerts" },
307307
{ 'A', CAPCLASS_ALERT|CAPCLASS_SUPER, 0,
308308
"Announce", "Send announcements to all subscribers" },
309
+ { 'C', CAPCLASS_FORUM, 0,
310
+ "Chat", "Read and/or writes messages in the chatroom" },
309311
{ 'D', CAPCLASS_OTHER, 0,
310312
"Debug", "Enable debugging features" },
311313
};
312314
313315
/*
@@ -391,11 +393,11 @@
391393
" WHERE cap GLOB '*[as]*'"
392394
" ORDER BY 3 ASC",
393395
zSelfCap, hasPubPages, zSelfCap
394396
);
395397
@ <table id='capabilitySummary' cellpadding="0" cellspacing="0" border="1">
396
- @ <tr><th>&nbsp;<th>Code<th>Forum<th>Tickets<th>Wiki\
398
+ @ <tr><th>&nbsp;<th>Code<th>Forum<th>Tickets<th>Wiki<th>Chat\
397399
@ <th>Unversioned Content</th></tr>
398400
while( db_step(&q)==SQLITE_ROW ){
399401
const char *zId = db_column_text(&q, 0);
400402
const char *zCap = db_column_text(&q, 1);
401403
int n = db_column_int(&q, 3);
@@ -446,10 +448,18 @@
446448
/* Wiki */
447449
if( sqlite3_strglob("*[asdfklm]*",zCap)==0 ){
448450
eType = 2;
449451
}else if( sqlite3_strglob("*j*",zCap)==0 ){
450452
eType = 1;
453
+ }else{
454
+ eType = 0;
455
+ }
456
+ @ <td class="%s(azClass[eType])">%s(azType[eType])</td>
457
+
458
+ /* Chat */
459
+ if( sqlite3_strglob("*C*",zCap)==0 ){
460
+ eType = 2;
451461
}else{
452462
eType = 0;
453463
}
454464
@ <td class="%s(azClass[eType])">%s(azType[eType])</td>
455465
456466
457467
ADDED src/chat.c
458468
ADDED src/chat.js
--- src/capabilities.c
+++ src/capabilities.c
@@ -304,10 +304,12 @@
304 "Forum-Admin", "Grant capability '4' to other users" },
305 { '7', CAPCLASS_ALERT, 0,
306 "Alerts", "Sign up for email alerts" },
307 { 'A', CAPCLASS_ALERT|CAPCLASS_SUPER, 0,
308 "Announce", "Send announcements to all subscribers" },
 
 
309 { 'D', CAPCLASS_OTHER, 0,
310 "Debug", "Enable debugging features" },
311 };
312
313 /*
@@ -391,11 +393,11 @@
391 " WHERE cap GLOB '*[as]*'"
392 " ORDER BY 3 ASC",
393 zSelfCap, hasPubPages, zSelfCap
394 );
395 @ <table id='capabilitySummary' cellpadding="0" cellspacing="0" border="1">
396 @ <tr><th>&nbsp;<th>Code<th>Forum<th>Tickets<th>Wiki\
397 @ <th>Unversioned Content</th></tr>
398 while( db_step(&q)==SQLITE_ROW ){
399 const char *zId = db_column_text(&q, 0);
400 const char *zCap = db_column_text(&q, 1);
401 int n = db_column_int(&q, 3);
@@ -446,10 +448,18 @@
446 /* Wiki */
447 if( sqlite3_strglob("*[asdfklm]*",zCap)==0 ){
448 eType = 2;
449 }else if( sqlite3_strglob("*j*",zCap)==0 ){
450 eType = 1;
 
 
 
 
 
 
 
 
451 }else{
452 eType = 0;
453 }
454 @ <td class="%s(azClass[eType])">%s(azType[eType])</td>
455
456
457 DDED src/chat.c
458 DDED src/chat.js
--- src/capabilities.c
+++ src/capabilities.c
@@ -304,10 +304,12 @@
304 "Forum-Admin", "Grant capability '4' to other users" },
305 { '7', CAPCLASS_ALERT, 0,
306 "Alerts", "Sign up for email alerts" },
307 { 'A', CAPCLASS_ALERT|CAPCLASS_SUPER, 0,
308 "Announce", "Send announcements to all subscribers" },
309 { 'C', CAPCLASS_FORUM, 0,
310 "Chat", "Read and/or writes messages in the chatroom" },
311 { 'D', CAPCLASS_OTHER, 0,
312 "Debug", "Enable debugging features" },
313 };
314
315 /*
@@ -391,11 +393,11 @@
393 " WHERE cap GLOB '*[as]*'"
394 " ORDER BY 3 ASC",
395 zSelfCap, hasPubPages, zSelfCap
396 );
397 @ <table id='capabilitySummary' cellpadding="0" cellspacing="0" border="1">
398 @ <tr><th>&nbsp;<th>Code<th>Forum<th>Tickets<th>Wiki<th>Chat\
399 @ <th>Unversioned Content</th></tr>
400 while( db_step(&q)==SQLITE_ROW ){
401 const char *zId = db_column_text(&q, 0);
402 const char *zCap = db_column_text(&q, 1);
403 int n = db_column_int(&q, 3);
@@ -446,10 +448,18 @@
448 /* Wiki */
449 if( sqlite3_strglob("*[asdfklm]*",zCap)==0 ){
450 eType = 2;
451 }else if( sqlite3_strglob("*j*",zCap)==0 ){
452 eType = 1;
453 }else{
454 eType = 0;
455 }
456 @ <td class="%s(azClass[eType])">%s(azType[eType])</td>
457
458 /* Chat */
459 if( sqlite3_strglob("*C*",zCap)==0 ){
460 eType = 2;
461 }else{
462 eType = 0;
463 }
464 @ <td class="%s(azClass[eType])">%s(azType[eType])</td>
465
466
467 DDED src/chat.c
468 DDED src/chat.js
+80
--- a/src/chat.c
+++ b/src/chat.c
@@ -0,0 +1,80 @@
1
+0
2
+**
3
+** B of the default
4
+**;
5
+ const ch fossil_system(zCmd);
6
+}
7
+int iPingTcpiPingTcp = atoi(PD("ping","0"));
8
+ if( iPingTcp<1000 || iPingTcp>65535 ) iPingTcp = 0;
9
+ if( iPin\"fossil\""fossil""stgTcp = 0;
10
+ if( iPin\"fossil\""fossil""st0
11
+**
12
+** B of the default
13
+**;
14
+ const ch fossil_system(zCmd);
15
+}
16
+int iPingTcpiPingTcp = atoi(PD("ping","0"));
17
+ if( iPingTcp<1000 || iPingTcp>65535 ) iPingTcp = 0;
18
+ if( iPin\"fossil\""fossil""sttextarea'>form0
19
+**
20
+** B of the default
21
+**;
22
+nst ch fossil_systestyle>
23
+ @ #dialog {
24
+ @ width: 97%%;
25
+ @ }
26
+ @ #chat-input-area {
27
+ @ width: 100%%;
28
+ @ display: flex;
29
+ @ flex-direction: column;
30
+ @ }
31
+ @ #chat-input-line {
32
+ @ display: flex;
33
+ @ flex-direction: row;
34
+ @ margin-bottom: 1em;
35
+ @ align-items: center;
36
+ @ }
37
+ @ #chat-input-line > input[type=submit] {
38
+ @ flex: 1 5 auto;
39
+ @ max-width: 6em;
40
+ @ }
41
+ @ #chat-input-line > input[type=text] {
42
+ @ 5 1 auto;
43
+ @ }
44
+ @ #K@1GC,1Q: {
45
+ @ display: flex;
46
+ @ flex-direction: row;
47
+ @ align-items: center;
48
+ @ }
49
+ @ #K@1GC,Ba: > .help-buttonlet,
50
+ @ #chat-input-file {
51
+ @ align-self: flex-startput-file { during drop-targeting*/
52
+ @ border-radius: 0.25em;
53
+ @ }
54
+ @ #chat-input-file > input {
55
+ @ flex: 1 0 auto;
56
+ @ }
57
+ @ .chat-timestamp {
58
+ @ font-family: monospace;
59
+ @ font-size: 0.8em;
60
+ @ white-space: pre;
61
+ @ text-align: left;
62
+ @ opacity: 00.25em50%%;
63
+ @ }
64
+ @ </style1: 1px dashed green;
65
+ @ }
66
+ @ #chat-drop-details {
67
+ @ flex: 0 1 auto;
68
+ @ padding: 0.5em 1em;
69
+ @ margin-left: 0.5em;
70
+ @ white-space: pre;
71
+ @ font-family: monospace;
72
+ @ max-width: 50%%;
73
+ @ }
74
+ @ </sty1@15Y,K@16k,5:area'S@1Fw,5:line'N@1Ax,L@17Vow;
75
+ @ align-items: center;
76
+ @ }
77
+ @ #K@1GC,Ba: > .help-buttonlet,
78
+ @>
79
+ @{ during drop-targetiarea' font-family: monospace;
80
+ @
--- a/src/chat.c
+++ b/src/chat.c
@@ -0,0 +1,80 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
--- a/src/chat.c
+++ b/src/chat.c
@@ -0,0 +1,80 @@
1 0
2 **
3 ** B of the default
4 **;
5 const ch fossil_system(zCmd);
6 }
7 int iPingTcpiPingTcp = atoi(PD("ping","0"));
8 if( iPingTcp<1000 || iPingTcp>65535 ) iPingTcp = 0;
9 if( iPin\"fossil\""fossil""stgTcp = 0;
10 if( iPin\"fossil\""fossil""st0
11 **
12 ** B of the default
13 **;
14 const ch fossil_system(zCmd);
15 }
16 int iPingTcpiPingTcp = atoi(PD("ping","0"));
17 if( iPingTcp<1000 || iPingTcp>65535 ) iPingTcp = 0;
18 if( iPin\"fossil\""fossil""sttextarea'>form0
19 **
20 ** B of the default
21 **;
22 nst ch fossil_systestyle>
23 @ #dialog {
24 @ width: 97%%;
25 @ }
26 @ #chat-input-area {
27 @ width: 100%%;
28 @ display: flex;
29 @ flex-direction: column;
30 @ }
31 @ #chat-input-line {
32 @ display: flex;
33 @ flex-direction: row;
34 @ margin-bottom: 1em;
35 @ align-items: center;
36 @ }
37 @ #chat-input-line > input[type=submit] {
38 @ flex: 1 5 auto;
39 @ max-width: 6em;
40 @ }
41 @ #chat-input-line > input[type=text] {
42 @ 5 1 auto;
43 @ }
44 @ #K@1GC,1Q: {
45 @ display: flex;
46 @ flex-direction: row;
47 @ align-items: center;
48 @ }
49 @ #K@1GC,Ba: > .help-buttonlet,
50 @ #chat-input-file {
51 @ align-self: flex-startput-file { during drop-targeting*/
52 @ border-radius: 0.25em;
53 @ }
54 @ #chat-input-file > input {
55 @ flex: 1 0 auto;
56 @ }
57 @ .chat-timestamp {
58 @ font-family: monospace;
59 @ font-size: 0.8em;
60 @ white-space: pre;
61 @ text-align: left;
62 @ opacity: 00.25em50%%;
63 @ }
64 @ </style1: 1px dashed green;
65 @ }
66 @ #chat-drop-details {
67 @ flex: 0 1 auto;
68 @ padding: 0.5em 1em;
69 @ margin-left: 0.5em;
70 @ white-space: pre;
71 @ font-family: monospace;
72 @ max-width: 50%%;
73 @ }
74 @ </sty1@15Y,K@16k,5:area'S@1Fw,5:line'N@1Ax,L@17Vow;
75 @ align-items: center;
76 @ }
77 @ #K@1GC,Ba: > .help-buttonlet,
78 @>
79 @{ during drop-targetiarea' font-family: monospace;
80 @
+12
--- a/src/chat.js
+++ b/src/chat.js
@@ -0,0 +1,12 @@
1
+tes().toString()!="NaN" '#chat-form');nformative timestamps
2
+ // Dlet mxMsg = -50;
3
+ ate doesn't this._me = F.user.nameconst textNode = (T)=>
4
+
5
+
6
+ it with this text, but
7
+
8
+ const help = D.div();help);
9
+help,
10
+ "Select a file to upload, drag/drop a file into this spot, ",
11
+ "or paste an image from the clipboard if supported by ",
12
+ "your environment."
--- a/src/chat.js
+++ b/src/chat.js
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
--- a/src/chat.js
+++ b/src/chat.js
@@ -0,0 +1,12 @@
1 tes().toString()!="NaN" '#chat-form');nformative timestamps
2 // Dlet mxMsg = -50;
3 ate doesn't this._me = F.user.nameconst textNode = (T)=>
4
5
6 it with this text, but
7
8 const help = D.div();help);
9 help,
10 "Select a file to upload, drag/drop a file into this spot, ",
11 "or paste an image from the clipboard if supported by ",
12 "your environment."
--- src/default.css
+++ src/default.css
@@ -1461,5 +1461,43 @@
14611461
position: absolute !important;
14621462
opacity: 0 !important;
14631463
pointer-events: none !important;
14641464
display: none !important;
14651465
}
1466
+
1467
+/* Chat-related */
1468
+span.at-name { /* for @USERNAME references */
1469
+ text-decoration: underline;
1470
+ font-weight: bold;
1471
+}
1472
+/* A wrapper for a single single message (one row of the UI) */
1473
+.message-row {
1474
+ margin-bottom: 0.5em;
1475
+ border: none;
1476
+ display: flex;
1477
+ flex-direction: row;
1478
+ justify-content: flex-start;
1479
+ /*border: 1px solid rgba(0,0,0,0.2);
1480
+ border-radius: 0.25em;
1481
+ box-shadow: 0.2em 0.2em 0.2em rgba(0, 0, 0, 0.29);*/
1482
+ border: none;
1483
+}
1484
+/* The content area of a message (the body element of a FIELDSET) */
1485
+.message-content {
1486
+ display: inline-block;
1487
+ border-radius: 0.25em;
1488
+ border: 1px solid rgba(0,0,0,0.2);
1489
+ box-shadow: 0.2em 0.2em 0.2em rgba(0, 0, 0, 0.29);
1490
+ padding: 0.25em 1em;
1491
+ margin-top: -0.75em;
1492
+ min-width: 9em /*avoid unsightly "underlap" with the user name label*/;
1493
+}
1494
+/* User name for the post (a LEGEND element) */
1495
+.message-row .message-user {
1496
+ border-radius: 0.25em 0.25em 0 0;
1497
+ padding: 0 0.5em;
1498
+ /*text-align: left; Firefox requires the 'align' attribute */
1499
+ margin: 0 0.15em;
1500
+ padding: 0 0.5em 0em 0.5em;
1501
+ margin-bottom: 0.4em;
1502
+ cursor: pointer;
1503
+}
14661504
--- src/default.css
+++ src/default.css
@@ -1461,5 +1461,43 @@
1461 position: absolute !important;
1462 opacity: 0 !important;
1463 pointer-events: none !important;
1464 display: none !important;
1465 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1466
--- src/default.css
+++ src/default.css
@@ -1461,5 +1461,43 @@
1461 position: absolute !important;
1462 opacity: 0 !important;
1463 pointer-events: none !important;
1464 display: none !important;
1465 }
1466
1467 /* Chat-related */
1468 span.at-name { /* for @USERNAME references */
1469 text-decoration: underline;
1470 font-weight: bold;
1471 }
1472 /* A wrapper for a single single message (one row of the UI) */
1473 .message-row {
1474 margin-bottom: 0.5em;
1475 border: none;
1476 display: flex;
1477 flex-direction: row;
1478 justify-content: flex-start;
1479 /*border: 1px solid rgba(0,0,0,0.2);
1480 border-radius: 0.25em;
1481 box-shadow: 0.2em 0.2em 0.2em rgba(0, 0, 0, 0.29);*/
1482 border: none;
1483 }
1484 /* The content area of a message (the body element of a FIELDSET) */
1485 .message-content {
1486 display: inline-block;
1487 border-radius: 0.25em;
1488 border: 1px solid rgba(0,0,0,0.2);
1489 box-shadow: 0.2em 0.2em 0.2em rgba(0, 0, 0, 0.29);
1490 padding: 0.25em 1em;
1491 margin-top: -0.75em;
1492 min-width: 9em /*avoid unsightly "underlap" with the user name label*/;
1493 }
1494 /* User name for the post (a LEGEND element) */
1495 .message-row .message-user {
1496 border-radius: 0.25em 0.25em 0 0;
1497 padding: 0 0.5em;
1498 /*text-align: left; Firefox requires the 'align' attribute */
1499 margin: 0 0.15em;
1500 padding: 0 0.5em 0em 0.5em;
1501 margin-bottom: 0.4em;
1502 cursor: pointer;
1503 }
1504
+23 -4
--- src/dispatch.c
+++ src/dispatch.c
@@ -349,10 +349,12 @@
349349
** followed by two spaces and a non-space. <dd> elements can begin
350350
** on the same line as long as they are separated by at least
351351
** two spaces.
352352
**
353353
** * Indented text is show verbatim (<pre>...</pre>)
354
+**
355
+** * Lines that begin with "|" at the left margin are in <pre>...</pre>
354356
*/
355357
static void help_to_html(const char *zHelp, Blob *pHtml){
356358
int i;
357359
char c;
358360
int nIndent = 0;
@@ -361,10 +363,11 @@
361363
int aIndent[10];
362364
const char *azEnd[10];
363365
int iLevel = 0;
364366
int isLI = 0;
365367
int isDT = 0;
368
+ int inPRE = 0;
366369
static const char *zEndDL = "</dl></blockquote>";
367370
static const char *zEndPRE = "</pre></blockquote>";
368371
static const char *zEndUL = "</ul>";
369372
static const char *zEndDD = "</dd>";
370373
@@ -380,16 +383,32 @@
380383
wantBR = 1;
381384
continue;
382385
}
383386
i++;
384387
}
385
- if( i>2 && zHelp[0]=='>' && zHelp[1]==' ' ){
386
- isDT = 1;
387
- for(nIndent=1; nIndent<i && zHelp[nIndent]==' '; nIndent++){}
388
+ if( i>2 && (zHelp[0]=='>' || zHelp[0]=='|') && zHelp[1]==' ' ){
389
+ if( zHelp[0]=='>' ){
390
+ isDT = 1;
391
+ for(nIndent=1; nIndent<i && zHelp[nIndent]==' '; nIndent++){}
392
+ }else{
393
+ if( !inPRE ){
394
+ blob_append(pHtml, "<pre>\n", -1);
395
+ inPRE = 1;
396
+ }
397
+ }
388398
}else{
399
+ if( inPRE ){
400
+ blob_append(pHtml, "</pre>\n", -1);
401
+ inPRE = 0;
402
+ }
389403
isDT = 0;
390404
for(nIndent=0; nIndent<i && zHelp[nIndent]==' '; nIndent++){}
405
+ }
406
+ if( inPRE ){
407
+ blob_append(pHtml, zHelp+1, i);
408
+ zHelp += i + 1;
409
+ continue;
391410
}
392411
if( nIndent==i ){
393412
if( c==0 ) break;
394413
if( iLevel && azEnd[iLevel]==zEndPRE ){
395414
/* Skip the newline at the end of a <pre> */
@@ -491,11 +510,11 @@
491510
blob_append(pText, "fossil", 6);
492511
zHelp += i+7;
493512
i = -1;
494513
continue;
495514
}
496
- if( c=='\n' && strncmp(zHelp+i+1,"> ",2)==0 ){
515
+ if( c=='\n' && (zHelp[i+1]=='>' || zHelp[i+1]=='|') && zHelp[i+2]==' ' ){
497516
blob_append(pText, zHelp, i+1);
498517
blob_append(pText, " ", 1);
499518
zHelp += i+2;
500519
i = -1;
501520
continue;
502521
--- src/dispatch.c
+++ src/dispatch.c
@@ -349,10 +349,12 @@
349 ** followed by two spaces and a non-space. <dd> elements can begin
350 ** on the same line as long as they are separated by at least
351 ** two spaces.
352 **
353 ** * Indented text is show verbatim (<pre>...</pre>)
 
 
354 */
355 static void help_to_html(const char *zHelp, Blob *pHtml){
356 int i;
357 char c;
358 int nIndent = 0;
@@ -361,10 +363,11 @@
361 int aIndent[10];
362 const char *azEnd[10];
363 int iLevel = 0;
364 int isLI = 0;
365 int isDT = 0;
 
366 static const char *zEndDL = "</dl></blockquote>";
367 static const char *zEndPRE = "</pre></blockquote>";
368 static const char *zEndUL = "</ul>";
369 static const char *zEndDD = "</dd>";
370
@@ -380,16 +383,32 @@
380 wantBR = 1;
381 continue;
382 }
383 i++;
384 }
385 if( i>2 && zHelp[0]=='>' && zHelp[1]==' ' ){
386 isDT = 1;
387 for(nIndent=1; nIndent<i && zHelp[nIndent]==' '; nIndent++){}
 
 
 
 
 
 
 
388 }else{
 
 
 
 
389 isDT = 0;
390 for(nIndent=0; nIndent<i && zHelp[nIndent]==' '; nIndent++){}
 
 
 
 
 
391 }
392 if( nIndent==i ){
393 if( c==0 ) break;
394 if( iLevel && azEnd[iLevel]==zEndPRE ){
395 /* Skip the newline at the end of a <pre> */
@@ -491,11 +510,11 @@
491 blob_append(pText, "fossil", 6);
492 zHelp += i+7;
493 i = -1;
494 continue;
495 }
496 if( c=='\n' && strncmp(zHelp+i+1,"> ",2)==0 ){
497 blob_append(pText, zHelp, i+1);
498 blob_append(pText, " ", 1);
499 zHelp += i+2;
500 i = -1;
501 continue;
502
--- src/dispatch.c
+++ src/dispatch.c
@@ -349,10 +349,12 @@
349 ** followed by two spaces and a non-space. <dd> elements can begin
350 ** on the same line as long as they are separated by at least
351 ** two spaces.
352 **
353 ** * Indented text is show verbatim (<pre>...</pre>)
354 **
355 ** * Lines that begin with "|" at the left margin are in <pre>...</pre>
356 */
357 static void help_to_html(const char *zHelp, Blob *pHtml){
358 int i;
359 char c;
360 int nIndent = 0;
@@ -361,10 +363,11 @@
363 int aIndent[10];
364 const char *azEnd[10];
365 int iLevel = 0;
366 int isLI = 0;
367 int isDT = 0;
368 int inPRE = 0;
369 static const char *zEndDL = "</dl></blockquote>";
370 static const char *zEndPRE = "</pre></blockquote>";
371 static const char *zEndUL = "</ul>";
372 static const char *zEndDD = "</dd>";
373
@@ -380,16 +383,32 @@
383 wantBR = 1;
384 continue;
385 }
386 i++;
387 }
388 if( i>2 && (zHelp[0]=='>' || zHelp[0]=='|') && zHelp[1]==' ' ){
389 if( zHelp[0]=='>' ){
390 isDT = 1;
391 for(nIndent=1; nIndent<i && zHelp[nIndent]==' '; nIndent++){}
392 }else{
393 if( !inPRE ){
394 blob_append(pHtml, "<pre>\n", -1);
395 inPRE = 1;
396 }
397 }
398 }else{
399 if( inPRE ){
400 blob_append(pHtml, "</pre>\n", -1);
401 inPRE = 0;
402 }
403 isDT = 0;
404 for(nIndent=0; nIndent<i && zHelp[nIndent]==' '; nIndent++){}
405 }
406 if( inPRE ){
407 blob_append(pHtml, zHelp+1, i);
408 zHelp += i + 1;
409 continue;
410 }
411 if( nIndent==i ){
412 if( c==0 ) break;
413 if( iLevel && azEnd[iLevel]==zEndPRE ){
414 /* Skip the newline at the end of a <pre> */
@@ -491,11 +510,11 @@
510 blob_append(pText, "fossil", 6);
511 zHelp += i+7;
512 i = -1;
513 continue;
514 }
515 if( c=='\n' && (zHelp[i+1]=='>' || zHelp[i+1]=='|') && zHelp[i+2]==' ' ){
516 blob_append(pText, zHelp, i+1);
517 blob_append(pText, " ", 1);
518 zHelp += i+2;
519 i = -1;
520 continue;
521
--- src/fossil.popupwidget.js
+++ src/fossil.popupwidget.js
@@ -182,11 +182,27 @@
182182
this.e.style.removeProperty('top');
183183
}
184184
return this;
185185
},
186186
187
- hide: function(){return this.show(false)}
187
+ hide: function(){return this.show(false)},
188
+
189
+ /**
190
+ A convenience method which adds click handlers to this popup's
191
+ main element and document.body to hide the popup when either
192
+ element is clicked or the ESC key is pressed. Only call this
193
+ once per instance, if at all. Returns this;
194
+ */
195
+ installClickToHide: function f(){
196
+ this.e.addEventListener('click', ()=>this.show(false), false);
197
+ document.body.addEventListener('click', ()=>this.show(false), true);
198
+ const self = this;
199
+ document.body.addEventListener('keydown', function(ev){
200
+ if(self.isShown() && 27===ev.which) self.show(false);
201
+ }, true);
202
+ return this;
203
+ }
188204
}/*F.PopupWidget.prototype*/;
189205
190206
/**
191207
Internal impl for F.toast() and friends.
192208
@@ -297,18 +313,11 @@
297313
cssClass: ['fossil-tooltip', 'help-buttonlet-content'],
298314
refresh: function(){
299315
}
300316
});
301317
fch.popup.e.style.maxWidth = '80%'/*of body*/;
302
- const hide = ()=>fch.popup.hide();
303
- fch.popup.e.addEventListener('click', hide, false);
304
- document.body.addEventListener('click', hide, true);
305
- document.body.addEventListener('keydown', function(ev){
306
- if(fch.popup.isShown() && 27===ev.which){
307
- fch.popup.hide();
308
- }
309
- }, true);
318
+ fch.popup.installClickToHide();
310319
}
311320
D.append(D.clearElement(fch.popup.e), ev.target.$helpContent);
312321
var popupRect = ev.target.getClientRects()[0];
313322
var x = popupRect.left, y = popupRect.top;
314323
if(x<0) x = 0;
315324
--- src/fossil.popupwidget.js
+++ src/fossil.popupwidget.js
@@ -182,11 +182,27 @@
182 this.e.style.removeProperty('top');
183 }
184 return this;
185 },
186
187 hide: function(){return this.show(false)}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
188 }/*F.PopupWidget.prototype*/;
189
190 /**
191 Internal impl for F.toast() and friends.
192
@@ -297,18 +313,11 @@
297 cssClass: ['fossil-tooltip', 'help-buttonlet-content'],
298 refresh: function(){
299 }
300 });
301 fch.popup.e.style.maxWidth = '80%'/*of body*/;
302 const hide = ()=>fch.popup.hide();
303 fch.popup.e.addEventListener('click', hide, false);
304 document.body.addEventListener('click', hide, true);
305 document.body.addEventListener('keydown', function(ev){
306 if(fch.popup.isShown() && 27===ev.which){
307 fch.popup.hide();
308 }
309 }, true);
310 }
311 D.append(D.clearElement(fch.popup.e), ev.target.$helpContent);
312 var popupRect = ev.target.getClientRects()[0];
313 var x = popupRect.left, y = popupRect.top;
314 if(x<0) x = 0;
315
--- src/fossil.popupwidget.js
+++ src/fossil.popupwidget.js
@@ -182,11 +182,27 @@
182 this.e.style.removeProperty('top');
183 }
184 return this;
185 },
186
187 hide: function(){return this.show(false)},
188
189 /**
190 A convenience method which adds click handlers to this popup's
191 main element and document.body to hide the popup when either
192 element is clicked or the ESC key is pressed. Only call this
193 once per instance, if at all. Returns this;
194 */
195 installClickToHide: function f(){
196 this.e.addEventListener('click', ()=>this.show(false), false);
197 document.body.addEventListener('click', ()=>this.show(false), true);
198 const self = this;
199 document.body.addEventListener('keydown', function(ev){
200 if(self.isShown() && 27===ev.which) self.show(false);
201 }, true);
202 return this;
203 }
204 }/*F.PopupWidget.prototype*/;
205
206 /**
207 Internal impl for F.toast() and friends.
208
@@ -297,18 +313,11 @@
313 cssClass: ['fossil-tooltip', 'help-buttonlet-content'],
314 refresh: function(){
315 }
316 });
317 fch.popup.e.style.maxWidth = '80%'/*of body*/;
318 fch.popup.installClickToHide();
 
 
 
 
 
 
 
319 }
320 D.append(D.clearElement(fch.popup.e), ev.target.$helpContent);
321 var popupRect = ev.target.getClientRects()[0];
322 var x = popupRect.left, y = popupRect.top;
323 if(x<0) x = 0;
324
+3 -1
--- src/login.c
+++ src/login.c
@@ -1230,11 +1230,11 @@
12301230
p->ApndWiki = p->Hyperlink = p->Clone =
12311231
p->NewTkt = p->Password = p->RdAddr =
12321232
p->TktFmt = p->Attach = p->ApndTkt =
12331233
p->ModWiki = p->ModTkt =
12341234
p->RdForum = p->WrForum = p->ModForum =
1235
- p->WrTForum = p->AdminForum =
1235
+ p->WrTForum = p->AdminForum = p->Chat =
12361236
p->EmailAlert = p->Announce = p->Debug = 1;
12371237
/* Fall thru into Read/Write */
12381238
case 'i': p->Read = p->Write = 1; break;
12391239
case 'o': p->Read = 1; break;
12401240
case 'z': p->Zip = 1; break;
@@ -1267,10 +1267,11 @@
12671267
case '3': p->WrForum = 1;
12681268
case '2': p->RdForum = 1; break;
12691269
12701270
case '7': p->EmailAlert = 1; break;
12711271
case 'A': p->Announce = 1; break;
1272
+ case 'C': p->Chat = 1; break;
12721273
case 'D': p->Debug = 1; break;
12731274
12741275
/* The "u" privilege recursively
12751276
** inherits all privileges of the user named "reader" */
12761277
case 'u': {
@@ -1350,10 +1351,11 @@
13501351
case '4': rc = p->WrTForum; break;
13511352
case '5': rc = p->ModForum; break;
13521353
case '6': rc = p->AdminForum;break;
13531354
case '7': rc = p->EmailAlert;break;
13541355
case 'A': rc = p->Announce; break;
1356
+ case 'C': rc = p->Chat; break;
13551357
case 'D': rc = p->Debug; break;
13561358
default: rc = 0; break;
13571359
}
13581360
}
13591361
return rc;
13601362
--- src/login.c
+++ src/login.c
@@ -1230,11 +1230,11 @@
1230 p->ApndWiki = p->Hyperlink = p->Clone =
1231 p->NewTkt = p->Password = p->RdAddr =
1232 p->TktFmt = p->Attach = p->ApndTkt =
1233 p->ModWiki = p->ModTkt =
1234 p->RdForum = p->WrForum = p->ModForum =
1235 p->WrTForum = p->AdminForum =
1236 p->EmailAlert = p->Announce = p->Debug = 1;
1237 /* Fall thru into Read/Write */
1238 case 'i': p->Read = p->Write = 1; break;
1239 case 'o': p->Read = 1; break;
1240 case 'z': p->Zip = 1; break;
@@ -1267,10 +1267,11 @@
1267 case '3': p->WrForum = 1;
1268 case '2': p->RdForum = 1; break;
1269
1270 case '7': p->EmailAlert = 1; break;
1271 case 'A': p->Announce = 1; break;
 
1272 case 'D': p->Debug = 1; break;
1273
1274 /* The "u" privilege recursively
1275 ** inherits all privileges of the user named "reader" */
1276 case 'u': {
@@ -1350,10 +1351,11 @@
1350 case '4': rc = p->WrTForum; break;
1351 case '5': rc = p->ModForum; break;
1352 case '6': rc = p->AdminForum;break;
1353 case '7': rc = p->EmailAlert;break;
1354 case 'A': rc = p->Announce; break;
 
1355 case 'D': rc = p->Debug; break;
1356 default: rc = 0; break;
1357 }
1358 }
1359 return rc;
1360
--- src/login.c
+++ src/login.c
@@ -1230,11 +1230,11 @@
1230 p->ApndWiki = p->Hyperlink = p->Clone =
1231 p->NewTkt = p->Password = p->RdAddr =
1232 p->TktFmt = p->Attach = p->ApndTkt =
1233 p->ModWiki = p->ModTkt =
1234 p->RdForum = p->WrForum = p->ModForum =
1235 p->WrTForum = p->AdminForum = p->Chat =
1236 p->EmailAlert = p->Announce = p->Debug = 1;
1237 /* Fall thru into Read/Write */
1238 case 'i': p->Read = p->Write = 1; break;
1239 case 'o': p->Read = 1; break;
1240 case 'z': p->Zip = 1; break;
@@ -1267,10 +1267,11 @@
1267 case '3': p->WrForum = 1;
1268 case '2': p->RdForum = 1; break;
1269
1270 case '7': p->EmailAlert = 1; break;
1271 case 'A': p->Announce = 1; break;
1272 case 'C': p->Chat = 1; break;
1273 case 'D': p->Debug = 1; break;
1274
1275 /* The "u" privilege recursively
1276 ** inherits all privileges of the user named "reader" */
1277 case 'u': {
@@ -1350,10 +1351,11 @@
1351 case '4': rc = p->WrTForum; break;
1352 case '5': rc = p->ModForum; break;
1353 case '6': rc = p->AdminForum;break;
1354 case '7': rc = p->EmailAlert;break;
1355 case 'A': rc = p->Announce; break;
1356 case 'C': rc = p->Chat; break;
1357 case 'D': rc = p->Debug; break;
1358 default: rc = 0; break;
1359 }
1360 }
1361 return rc;
1362
+1
--- src/main.c
+++ src/main.c
@@ -107,10 +107,11 @@
107107
char WrTForum; /* 4: Post to forums not subject to moderation */
108108
char ModForum; /* 5: Moderate (approve or reject) forum posts */
109109
char AdminForum; /* 6: Grant capability 4 to other users */
110110
char EmailAlert; /* 7: Sign up for email notifications */
111111
char Announce; /* A: Send announcements */
112
+ char Chat; /* C: read or write the chatroom */
112113
char Debug; /* D: show extra Fossil debugging features */
113114
/* These last two are included to block infinite recursion */
114115
char XReader; /* u: Inherit all privileges of "reader" */
115116
char XDeveloper; /* v: Inherit all privileges of "developer" */
116117
};
117118
--- src/main.c
+++ src/main.c
@@ -107,10 +107,11 @@
107 char WrTForum; /* 4: Post to forums not subject to moderation */
108 char ModForum; /* 5: Moderate (approve or reject) forum posts */
109 char AdminForum; /* 6: Grant capability 4 to other users */
110 char EmailAlert; /* 7: Sign up for email notifications */
111 char Announce; /* A: Send announcements */
 
112 char Debug; /* D: show extra Fossil debugging features */
113 /* These last two are included to block infinite recursion */
114 char XReader; /* u: Inherit all privileges of "reader" */
115 char XDeveloper; /* v: Inherit all privileges of "developer" */
116 };
117
--- src/main.c
+++ src/main.c
@@ -107,10 +107,11 @@
107 char WrTForum; /* 4: Post to forums not subject to moderation */
108 char ModForum; /* 5: Moderate (approve or reject) forum posts */
109 char AdminForum; /* 6: Grant capability 4 to other users */
110 char EmailAlert; /* 7: Sign up for email notifications */
111 char Announce; /* A: Send announcements */
112 char Chat; /* C: read or write the chatroom */
113 char Debug; /* D: show extra Fossil debugging features */
114 /* These last two are included to block infinite recursion */
115 char XReader; /* u: Inherit all privileges of "reader" */
116 char XDeveloper; /* v: Inherit all privileges of "developer" */
117 };
118
+13
--- src/main.mk
+++ src/main.mk
@@ -32,10 +32,11 @@
3232
$(SRCDIR)/bundle.c \
3333
$(SRCDIR)/cache.c \
3434
$(SRCDIR)/capabilities.c \
3535
$(SRCDIR)/captcha.c \
3636
$(SRCDIR)/cgi.c \
37
+ $(SRCDIR)/chat.c \
3738
$(SRCDIR)/checkin.c \
3839
$(SRCDIR)/checkout.c \
3940
$(SRCDIR)/clearsign.c \
4041
$(SRCDIR)/clone.c \
4142
$(SRCDIR)/comformat.c \
@@ -219,10 +220,11 @@
219220
$(SRCDIR)/../skins/xekri/css.txt \
220221
$(SRCDIR)/../skins/xekri/details.txt \
221222
$(SRCDIR)/../skins/xekri/footer.txt \
222223
$(SRCDIR)/../skins/xekri/header.txt \
223224
$(SRCDIR)/accordion.js \
225
+ $(SRCDIR)/chat.js \
224226
$(SRCDIR)/ci_edit.js \
225227
$(SRCDIR)/copybtn.js \
226228
$(SRCDIR)/default.css \
227229
$(SRCDIR)/diff.tcl \
228230
$(SRCDIR)/forum.js \
@@ -290,10 +292,11 @@
290292
$(OBJDIR)/bundle_.c \
291293
$(OBJDIR)/cache_.c \
292294
$(OBJDIR)/capabilities_.c \
293295
$(OBJDIR)/captcha_.c \
294296
$(OBJDIR)/cgi_.c \
297
+ $(OBJDIR)/chat_.c \
295298
$(OBJDIR)/checkin_.c \
296299
$(OBJDIR)/checkout_.c \
297300
$(OBJDIR)/clearsign_.c \
298301
$(OBJDIR)/clone_.c \
299302
$(OBJDIR)/comformat_.c \
@@ -438,10 +441,11 @@
438441
$(OBJDIR)/bundle.o \
439442
$(OBJDIR)/cache.o \
440443
$(OBJDIR)/capabilities.o \
441444
$(OBJDIR)/captcha.o \
442445
$(OBJDIR)/cgi.o \
446
+ $(OBJDIR)/chat.o \
443447
$(OBJDIR)/checkin.o \
444448
$(OBJDIR)/checkout.o \
445449
$(OBJDIR)/clearsign.o \
446450
$(OBJDIR)/clone.o \
447451
$(OBJDIR)/comformat.o \
@@ -776,10 +780,11 @@
776780
$(OBJDIR)/bundle_.c:$(OBJDIR)/bundle.h \
777781
$(OBJDIR)/cache_.c:$(OBJDIR)/cache.h \
778782
$(OBJDIR)/capabilities_.c:$(OBJDIR)/capabilities.h \
779783
$(OBJDIR)/captcha_.c:$(OBJDIR)/captcha.h \
780784
$(OBJDIR)/cgi_.c:$(OBJDIR)/cgi.h \
785
+ $(OBJDIR)/chat_.c:$(OBJDIR)/chat.h \
781786
$(OBJDIR)/checkin_.c:$(OBJDIR)/checkin.h \
782787
$(OBJDIR)/checkout_.c:$(OBJDIR)/checkout.h \
783788
$(OBJDIR)/clearsign_.c:$(OBJDIR)/clearsign.h \
784789
$(OBJDIR)/clone_.c:$(OBJDIR)/clone.h \
785790
$(OBJDIR)/comformat_.c:$(OBJDIR)/comformat.h \
@@ -1054,10 +1059,18 @@
10541059
10551060
$(OBJDIR)/cgi.o: $(OBJDIR)/cgi_.c $(OBJDIR)/cgi.h $(SRCDIR)/config.h
10561061
$(XTCC) -o $(OBJDIR)/cgi.o -c $(OBJDIR)/cgi_.c
10571062
10581063
$(OBJDIR)/cgi.h: $(OBJDIR)/headers
1064
+
1065
+$(OBJDIR)/chat_.c: $(SRCDIR)/chat.c $(OBJDIR)/translate
1066
+ $(OBJDIR)/translate $(SRCDIR)/chat.c >$@
1067
+
1068
+$(OBJDIR)/chat.o: $(OBJDIR)/chat_.c $(OBJDIR)/chat.h $(SRCDIR)/config.h
1069
+ $(XTCC) -o $(OBJDIR)/chat.o -c $(OBJDIR)/chat_.c
1070
+
1071
+$(OBJDIR)/chat.h: $(OBJDIR)/headers
10591072
10601073
$(OBJDIR)/checkin_.c: $(SRCDIR)/checkin.c $(OBJDIR)/translate
10611074
$(OBJDIR)/translate $(SRCDIR)/checkin.c >$@
10621075
10631076
$(OBJDIR)/checkin.o: $(OBJDIR)/checkin_.c $(OBJDIR)/checkin.h $(SRCDIR)/config.h
10641077
--- src/main.mk
+++ src/main.mk
@@ -32,10 +32,11 @@
32 $(SRCDIR)/bundle.c \
33 $(SRCDIR)/cache.c \
34 $(SRCDIR)/capabilities.c \
35 $(SRCDIR)/captcha.c \
36 $(SRCDIR)/cgi.c \
 
37 $(SRCDIR)/checkin.c \
38 $(SRCDIR)/checkout.c \
39 $(SRCDIR)/clearsign.c \
40 $(SRCDIR)/clone.c \
41 $(SRCDIR)/comformat.c \
@@ -219,10 +220,11 @@
219 $(SRCDIR)/../skins/xekri/css.txt \
220 $(SRCDIR)/../skins/xekri/details.txt \
221 $(SRCDIR)/../skins/xekri/footer.txt \
222 $(SRCDIR)/../skins/xekri/header.txt \
223 $(SRCDIR)/accordion.js \
 
224 $(SRCDIR)/ci_edit.js \
225 $(SRCDIR)/copybtn.js \
226 $(SRCDIR)/default.css \
227 $(SRCDIR)/diff.tcl \
228 $(SRCDIR)/forum.js \
@@ -290,10 +292,11 @@
290 $(OBJDIR)/bundle_.c \
291 $(OBJDIR)/cache_.c \
292 $(OBJDIR)/capabilities_.c \
293 $(OBJDIR)/captcha_.c \
294 $(OBJDIR)/cgi_.c \
 
295 $(OBJDIR)/checkin_.c \
296 $(OBJDIR)/checkout_.c \
297 $(OBJDIR)/clearsign_.c \
298 $(OBJDIR)/clone_.c \
299 $(OBJDIR)/comformat_.c \
@@ -438,10 +441,11 @@
438 $(OBJDIR)/bundle.o \
439 $(OBJDIR)/cache.o \
440 $(OBJDIR)/capabilities.o \
441 $(OBJDIR)/captcha.o \
442 $(OBJDIR)/cgi.o \
 
443 $(OBJDIR)/checkin.o \
444 $(OBJDIR)/checkout.o \
445 $(OBJDIR)/clearsign.o \
446 $(OBJDIR)/clone.o \
447 $(OBJDIR)/comformat.o \
@@ -776,10 +780,11 @@
776 $(OBJDIR)/bundle_.c:$(OBJDIR)/bundle.h \
777 $(OBJDIR)/cache_.c:$(OBJDIR)/cache.h \
778 $(OBJDIR)/capabilities_.c:$(OBJDIR)/capabilities.h \
779 $(OBJDIR)/captcha_.c:$(OBJDIR)/captcha.h \
780 $(OBJDIR)/cgi_.c:$(OBJDIR)/cgi.h \
 
781 $(OBJDIR)/checkin_.c:$(OBJDIR)/checkin.h \
782 $(OBJDIR)/checkout_.c:$(OBJDIR)/checkout.h \
783 $(OBJDIR)/clearsign_.c:$(OBJDIR)/clearsign.h \
784 $(OBJDIR)/clone_.c:$(OBJDIR)/clone.h \
785 $(OBJDIR)/comformat_.c:$(OBJDIR)/comformat.h \
@@ -1054,10 +1059,18 @@
1054
1055 $(OBJDIR)/cgi.o: $(OBJDIR)/cgi_.c $(OBJDIR)/cgi.h $(SRCDIR)/config.h
1056 $(XTCC) -o $(OBJDIR)/cgi.o -c $(OBJDIR)/cgi_.c
1057
1058 $(OBJDIR)/cgi.h: $(OBJDIR)/headers
 
 
 
 
 
 
 
 
1059
1060 $(OBJDIR)/checkin_.c: $(SRCDIR)/checkin.c $(OBJDIR)/translate
1061 $(OBJDIR)/translate $(SRCDIR)/checkin.c >$@
1062
1063 $(OBJDIR)/checkin.o: $(OBJDIR)/checkin_.c $(OBJDIR)/checkin.h $(SRCDIR)/config.h
1064
--- src/main.mk
+++ src/main.mk
@@ -32,10 +32,11 @@
32 $(SRCDIR)/bundle.c \
33 $(SRCDIR)/cache.c \
34 $(SRCDIR)/capabilities.c \
35 $(SRCDIR)/captcha.c \
36 $(SRCDIR)/cgi.c \
37 $(SRCDIR)/chat.c \
38 $(SRCDIR)/checkin.c \
39 $(SRCDIR)/checkout.c \
40 $(SRCDIR)/clearsign.c \
41 $(SRCDIR)/clone.c \
42 $(SRCDIR)/comformat.c \
@@ -219,10 +220,11 @@
220 $(SRCDIR)/../skins/xekri/css.txt \
221 $(SRCDIR)/../skins/xekri/details.txt \
222 $(SRCDIR)/../skins/xekri/footer.txt \
223 $(SRCDIR)/../skins/xekri/header.txt \
224 $(SRCDIR)/accordion.js \
225 $(SRCDIR)/chat.js \
226 $(SRCDIR)/ci_edit.js \
227 $(SRCDIR)/copybtn.js \
228 $(SRCDIR)/default.css \
229 $(SRCDIR)/diff.tcl \
230 $(SRCDIR)/forum.js \
@@ -290,10 +292,11 @@
292 $(OBJDIR)/bundle_.c \
293 $(OBJDIR)/cache_.c \
294 $(OBJDIR)/capabilities_.c \
295 $(OBJDIR)/captcha_.c \
296 $(OBJDIR)/cgi_.c \
297 $(OBJDIR)/chat_.c \
298 $(OBJDIR)/checkin_.c \
299 $(OBJDIR)/checkout_.c \
300 $(OBJDIR)/clearsign_.c \
301 $(OBJDIR)/clone_.c \
302 $(OBJDIR)/comformat_.c \
@@ -438,10 +441,11 @@
441 $(OBJDIR)/bundle.o \
442 $(OBJDIR)/cache.o \
443 $(OBJDIR)/capabilities.o \
444 $(OBJDIR)/captcha.o \
445 $(OBJDIR)/cgi.o \
446 $(OBJDIR)/chat.o \
447 $(OBJDIR)/checkin.o \
448 $(OBJDIR)/checkout.o \
449 $(OBJDIR)/clearsign.o \
450 $(OBJDIR)/clone.o \
451 $(OBJDIR)/comformat.o \
@@ -776,10 +780,11 @@
780 $(OBJDIR)/bundle_.c:$(OBJDIR)/bundle.h \
781 $(OBJDIR)/cache_.c:$(OBJDIR)/cache.h \
782 $(OBJDIR)/capabilities_.c:$(OBJDIR)/capabilities.h \
783 $(OBJDIR)/captcha_.c:$(OBJDIR)/captcha.h \
784 $(OBJDIR)/cgi_.c:$(OBJDIR)/cgi.h \
785 $(OBJDIR)/chat_.c:$(OBJDIR)/chat.h \
786 $(OBJDIR)/checkin_.c:$(OBJDIR)/checkin.h \
787 $(OBJDIR)/checkout_.c:$(OBJDIR)/checkout.h \
788 $(OBJDIR)/clearsign_.c:$(OBJDIR)/clearsign.h \
789 $(OBJDIR)/clone_.c:$(OBJDIR)/clone.h \
790 $(OBJDIR)/comformat_.c:$(OBJDIR)/comformat.h \
@@ -1054,10 +1059,18 @@
1059
1060 $(OBJDIR)/cgi.o: $(OBJDIR)/cgi_.c $(OBJDIR)/cgi.h $(SRCDIR)/config.h
1061 $(XTCC) -o $(OBJDIR)/cgi.o -c $(OBJDIR)/cgi_.c
1062
1063 $(OBJDIR)/cgi.h: $(OBJDIR)/headers
1064
1065 $(OBJDIR)/chat_.c: $(SRCDIR)/chat.c $(OBJDIR)/translate
1066 $(OBJDIR)/translate $(SRCDIR)/chat.c >$@
1067
1068 $(OBJDIR)/chat.o: $(OBJDIR)/chat_.c $(OBJDIR)/chat.h $(SRCDIR)/config.h
1069 $(XTCC) -o $(OBJDIR)/chat.o -c $(OBJDIR)/chat_.c
1070
1071 $(OBJDIR)/chat.h: $(OBJDIR)/headers
1072
1073 $(OBJDIR)/checkin_.c: $(SRCDIR)/checkin.c $(OBJDIR)/translate
1074 $(OBJDIR)/translate $(SRCDIR)/checkin.c >$@
1075
1076 $(OBJDIR)/checkin.o: $(OBJDIR)/checkin_.c $(OBJDIR)/checkin.h $(SRCDIR)/config.h
1077
--- src/makemake.tcl
+++ src/makemake.tcl
@@ -43,10 +43,11 @@
4343
bundle
4444
cache
4545
capabilities
4646
captcha
4747
cgi
48
+ chat
4849
checkin
4950
checkout
5051
clearsign
5152
clone
5253
comformat
5354
--- src/makemake.tcl
+++ src/makemake.tcl
@@ -43,10 +43,11 @@
43 bundle
44 cache
45 capabilities
46 captcha
47 cgi
 
48 checkin
49 checkout
50 clearsign
51 clone
52 comformat
53
--- src/makemake.tcl
+++ src/makemake.tcl
@@ -43,10 +43,11 @@
43 bundle
44 cache
45 capabilities
46 captcha
47 cgi
48 chat
49 checkin
50 checkout
51 clearsign
52 clone
53 comformat
54
+2 -1
--- src/rebuild.c
+++ src/rebuild.c
@@ -394,11 +394,11 @@
394394
" WHERE type='table'"
395395
" AND name NOT IN ('admin_log', 'blob','delta','rcvfrom','user','alias',"
396396
"'config','shun','private','reportfmt',"
397397
"'concealed','accesslog','modreq',"
398398
"'purgeevent','purgeitem','unversioned',"
399
- "'subscriber','pending_alert','alert_bounce')"
399
+ "'subscriber','pending_alert','alert_bounce','chat')"
400400
" AND name NOT GLOB 'sqlite_*'"
401401
" AND name NOT GLOB 'fx_*'"
402402
);
403403
while( db_step(&q)==SQLITE_ROW ){
404404
blob_appendf(&sql, "DROP TABLE IF EXISTS \"%w\";\n", db_column_text(&q,0));
@@ -942,10 +942,11 @@
942942
"UPDATE user SET photo=NULL, info='';\n"
943943
"DROP TABLE IF EXISTS purgeevent;\n"
944944
"DROP TABLE IF EXISTS purgeitem;\n"
945945
"DROP TABLE IF EXISTS admin_log;\n"
946946
"DROP TABLE IF EXISTS vcache;\n"
947
+ "DROP TABLE IF EXISTS chat;\n"
947948
);
948949
}
949950
db_protect_pop();
950951
}
951952
if( !bNeedRebuild ){
952953
--- src/rebuild.c
+++ src/rebuild.c
@@ -394,11 +394,11 @@
394 " WHERE type='table'"
395 " AND name NOT IN ('admin_log', 'blob','delta','rcvfrom','user','alias',"
396 "'config','shun','private','reportfmt',"
397 "'concealed','accesslog','modreq',"
398 "'purgeevent','purgeitem','unversioned',"
399 "'subscriber','pending_alert','alert_bounce')"
400 " AND name NOT GLOB 'sqlite_*'"
401 " AND name NOT GLOB 'fx_*'"
402 );
403 while( db_step(&q)==SQLITE_ROW ){
404 blob_appendf(&sql, "DROP TABLE IF EXISTS \"%w\";\n", db_column_text(&q,0));
@@ -942,10 +942,11 @@
942 "UPDATE user SET photo=NULL, info='';\n"
943 "DROP TABLE IF EXISTS purgeevent;\n"
944 "DROP TABLE IF EXISTS purgeitem;\n"
945 "DROP TABLE IF EXISTS admin_log;\n"
946 "DROP TABLE IF EXISTS vcache;\n"
 
947 );
948 }
949 db_protect_pop();
950 }
951 if( !bNeedRebuild ){
952
--- src/rebuild.c
+++ src/rebuild.c
@@ -394,11 +394,11 @@
394 " WHERE type='table'"
395 " AND name NOT IN ('admin_log', 'blob','delta','rcvfrom','user','alias',"
396 "'config','shun','private','reportfmt',"
397 "'concealed','accesslog','modreq',"
398 "'purgeevent','purgeitem','unversioned',"
399 "'subscriber','pending_alert','alert_bounce','chat')"
400 " AND name NOT GLOB 'sqlite_*'"
401 " AND name NOT GLOB 'fx_*'"
402 );
403 while( db_step(&q)==SQLITE_ROW ){
404 blob_appendf(&sql, "DROP TABLE IF EXISTS \"%w\";\n", db_column_text(&q,0));
@@ -942,10 +942,11 @@
942 "UPDATE user SET photo=NULL, info='';\n"
943 "DROP TABLE IF EXISTS purgeevent;\n"
944 "DROP TABLE IF EXISTS purgeitem;\n"
945 "DROP TABLE IF EXISTS admin_log;\n"
946 "DROP TABLE IF EXISTS vcache;\n"
947 "DROP TABLE IF EXISTS chat;\n"
948 );
949 }
950 db_protect_pop();
951 }
952 if( !bNeedRebuild ){
953
--- src/setupuser.c
+++ src/setupuser.c
@@ -681,10 +681,12 @@
681681
@ Supervise Forum%s(B('6'))</label>
682682
@ <li><label><input type="checkbox" name="a7"%s(oa['7']) />
683683
@ Email Alerts%s(B('7'))</label>
684684
@ <li><label><input type="checkbox" name="aA"%s(oa['A']) />
685685
@ Send Announcements%s(B('A'))</label>
686
+ @ <li><label><input type="checkbox" name="aC"%s(oa['C']) />
687
+ @ Chatroom%s(B('C'))</label>
686688
@ <li><label><input type="checkbox" name="aD"%s(oa['D']) />
687689
@ Enable Debug%s(B('D'))</label>
688690
@ </ul></div>
689691
@ </td>
690692
@ </tr>
691693
--- src/setupuser.c
+++ src/setupuser.c
@@ -681,10 +681,12 @@
681 @ Supervise Forum%s(B('6'))</label>
682 @ <li><label><input type="checkbox" name="a7"%s(oa['7']) />
683 @ Email Alerts%s(B('7'))</label>
684 @ <li><label><input type="checkbox" name="aA"%s(oa['A']) />
685 @ Send Announcements%s(B('A'))</label>
 
 
686 @ <li><label><input type="checkbox" name="aD"%s(oa['D']) />
687 @ Enable Debug%s(B('D'))</label>
688 @ </ul></div>
689 @ </td>
690 @ </tr>
691
--- src/setupuser.c
+++ src/setupuser.c
@@ -681,10 +681,12 @@
681 @ Supervise Forum%s(B('6'))</label>
682 @ <li><label><input type="checkbox" name="a7"%s(oa['7']) />
683 @ Email Alerts%s(B('7'))</label>
684 @ <li><label><input type="checkbox" name="aA"%s(oa['A']) />
685 @ Send Announcements%s(B('A'))</label>
686 @ <li><label><input type="checkbox" name="aC"%s(oa['C']) />
687 @ Chatroom%s(B('C'))</label>
688 @ <li><label><input type="checkbox" name="aD"%s(oa['D']) />
689 @ Enable Debug%s(B('D'))</label>
690 @ </ul></div>
691 @ </td>
692 @ </tr>
693
--- src/sitemap.c
+++ src/sitemap.c
@@ -115,10 +115,13 @@
115115
@ </li>
116116
}
117117
if( srchFlags ){
118118
@ <li>%z(href("%R/search"))Search</a></li>
119119
}
120
+ if( g.perm.Chat ){
121
+ @ <li>%z(href("%R/chat"))Chat</a></li>
122
+ }
120123
if( g.perm.RdForum ){
121124
@ <li>%z(href("%R/forum"))Forum</a>
122125
@ <ul>
123126
@ <li>%z(href("%R/timeline?y=f"))Recent activity</a></li>
124127
@ </ul>
125128
--- src/sitemap.c
+++ src/sitemap.c
@@ -115,10 +115,13 @@
115 @ </li>
116 }
117 if( srchFlags ){
118 @ <li>%z(href("%R/search"))Search</a></li>
119 }
 
 
 
120 if( g.perm.RdForum ){
121 @ <li>%z(href("%R/forum"))Forum</a>
122 @ <ul>
123 @ <li>%z(href("%R/timeline?y=f"))Recent activity</a></li>
124 @ </ul>
125
--- src/sitemap.c
+++ src/sitemap.c
@@ -115,10 +115,13 @@
115 @ </li>
116 }
117 if( srchFlags ){
118 @ <li>%z(href("%R/search"))Search</a></li>
119 }
120 if( g.perm.Chat ){
121 @ <li>%z(href("%R/chat"))Chat</a></li>
122 }
123 if( g.perm.RdForum ){
124 @ <li>%z(href("%R/forum"))Forum</a>
125 @ <ul>
126 @ <li>%z(href("%R/timeline?y=f"))Recent activity</a></li>
127 @ </ul>
128
--- src/timeline.c
+++ src/timeline.c
@@ -122,10 +122,13 @@
122122
#define TIMELINE_DELTA 0x10000000 /* Background color shows delta manifests */
123123
#endif
124124
125125
/*
126126
** Hash a string and use the hash to determine a background color.
127
+**
128
+** This value returned is in static space and is overwritten with
129
+** each subsequent call.
127130
*/
128131
char *hash_color(const char *z){
129132
int i; /* Loop counter */
130133
unsigned int h = 0; /* Hash on the branch name */
131134
int r, g, b; /* Values for red, green, and blue */
132135
133136
ADDED tools/chat.tcl
--- src/timeline.c
+++ src/timeline.c
@@ -122,10 +122,13 @@
122 #define TIMELINE_DELTA 0x10000000 /* Background color shows delta manifests */
123 #endif
124
125 /*
126 ** Hash a string and use the hash to determine a background color.
 
 
 
127 */
128 char *hash_color(const char *z){
129 int i; /* Loop counter */
130 unsigned int h = 0; /* Hash on the branch name */
131 int r, g, b; /* Values for red, green, and blue */
132
133 DDED tools/chat.tcl
--- src/timeline.c
+++ src/timeline.c
@@ -122,10 +122,13 @@
122 #define TIMELINE_DELTA 0x10000000 /* Background color shows delta manifests */
123 #endif
124
125 /*
126 ** Hash a string and use the hash to determine a background color.
127 **
128 ** This value returned is in static space and is overwritten with
129 ** each subsequent call.
130 */
131 char *hash_color(const char *z){
132 int i; /* Loop counter */
133 unsigned int h = 0; /* Hash on the branch name */
134 int r, g, b; /* Values for red, green, and blue */
135
136 DDED tools/chat.tcl
--- a/tools/chat.tcl
+++ b/tools/chat.tcl
@@ -0,0 +1,509 @@
1
+#!/usr/bin/wapptclsh
2
+#
3
+# A chat program designed to run using the extcgi mechanism of Fossil.
4
+#
5
+encoding system utf-8
6
+
7
+# The name of the chat database file
8
+#
9
+proc chat-db-name {} {
10
+ set x [wapp-param SCRIPT_FILENAME]
11
+ set dir [file dir $x]
12
+ set fn [file tail $x]
13
+ return $dir/-$fn.db
14
+}
15
+
16
+# Verify permission to use chat. Return true if not authorized.
17
+# Return false if the Fossil user is allowed to access chat.
18
+#
19
+proc not-authorized {} {
20
+ set cap [wapp-param FOSSIL_CAPABILITIES]
21
+ return [expr {![string match *i* $cap]}]
22
+}
23
+
24
+# The default page.
25
+# Load the initial chat screen.
26
+#
27
+proc wapp-default {} {
28
+ wapp-content-security-policy off
29
+ wapp-trim {
30
+ <div class="fossil-doc" data-title="Chat">
31
+ }
32
+ if {[not-authorized]} {
33
+ wapp-trim {
34
+ <h1>Not authorized</h1>
35
+ <p>You must have privileges to use this chatroom</p>
36
+ </div>
37
+ }
38
+ return
39
+ }
40
+ set scriptFile [wapp-param SCRIPT_FILENAME]
41
+ set cgiFn [file tail $scriptFile]
42
+ wapp-trim {
43
+ <form accept-encoding="utf-8" id="chat-form">
44
+ <div id='chat-input-area'>
45
+ <div id='chat-input-line'>
46
+ <input type="text" name="msg" id="sbox" placeholder="Type message here.">
47
+ <input type="submit" value="Send">
48
+ </div>
49
+ <div id='chat-input-file'>
50
+ <span>File:</span>
51
+ <input type="file" name="file">
52
+ </div>
53
+ </div>
54
+ </form>
55
+ <hr>
56
+ <span id='message-inject-point'><!--
57
+ new chat messages get inserted immediately after this element
58
+ --></span>
59
+
60
+ </div><!-- .fossil-doc -->
61
+ <hr>
62
+ <p>
63
+ <a href="%string($cgiFn)/env">CGI environment</a> |
64
+ <a href="%string($cgiFn)/self">Wapp script</a>
65
+ <style>
66
+\#dialog {
67
+ width: 97%;
68
+}
69
+\#chat-input-area {
70
+ width: 100%;
71
+ display: flex;
72
+ flex-direction: column;
73
+}
74
+\#chat-input-line {
75
+ display: flex;
76
+ flex-direction: row;
77
+ margin-bottom: 1em;
78
+ align-items: center;
79
+}
80
+\#chat-input-line > input[type=submit] {
81
+ flex: 1 5 auto;
82
+ max-width: 6em;
83
+}
84
+\#chat-input-line > input[type=text] {
85
+ flex: 5 1 auto;
86
+}
87
+\#chat-input-file {
88
+ display: flex;
89
+ flex-direction: row;
90
+ align-items: center;
91
+}
92
+\#chat-input-file > input {
93
+ flex: 1 0 auto;
94
+}
95
+span.at-name { /* for @USERNAME references */
96
+ text-decoration: underline;
97
+ font-weight: bold;
98
+}
99
+/* A wrapper for a single single message (one row of the UI) */
100
+.message-row {
101
+ margin-bottom: 0.5em;
102
+ border: none;
103
+ display: flex;
104
+ flex-direction: row;
105
+ justify-content: flex-start;
106
+ /*border: 1px solid rgba(0,0,0,0.2);
107
+ border-radius: 0.25em;
108
+ box-shadow: 0.2em 0.2em 0.2em rgba(0, 0, 0, 0.29);*/
109
+ border: none;
110
+}
111
+/* Rows for the current user have the .user-is-me CSS class
112
+ and get right-aligned. */
113
+.message-row.user-is-me {
114
+ justify-content: flex-end;
115
+ /*background-color: #d2dde1;*/
116
+}
117
+/* The content area of a message (the body element of a FIELDSET) */
118
+.message-content {
119
+ display: inline-block;
120
+ border-radius: 0.25em;
121
+ border: 1px solid rgba(0,0,0,0.2);
122
+ box-shadow: 0.2em 0.2em 0.2em rgba(0, 0, 0, 0.29);
123
+ padding: 0.25em 1em;
124
+ margin-top: -0.75em;
125
+}
126
+.message-row.user-is-me .message-content {
127
+ background-color: #d2dde1;
128
+}
129
+/* User name for the post (a LEGEND element) */
130
+.message-row .message-user {
131
+ background: inherit;
132
+ border-radius: 0.25em 0.25em 0 0;
133
+ padding: 0 0.5em;
134
+ /*text-align: left; Firefox requires the 'align' attribute */
135
+ margin-left: 0.25em;
136
+ padding: 0 0.5em 0em 0.5em;
137
+ margin-bottom: 0.4em;
138
+ background-color: #d2dde1;
139
+}
140
+/* Reposition "my" posts to the right */
141
+.message-row.user-is-me .message-user {
142
+ /*text-align: right; Firefox requires the 'align' attribute */
143
+ margin-left: 0;
144
+ margin-right: 0.25em;
145
+}
146
+</style>
147
+ }
148
+ set nonce [wapp-param FOSSIL_NONCE]
149
+ set submiturl [wapp-param SCRIPT_NAME]/send
150
+ set pollurl [wapp-param SCRIPT_NAME]/poll
151
+ set downloadurl [wapp-param SCRIPT_NAME]/download
152
+ set me [wapp-param FOSSIL_USER]
153
+ wapp-trim {
154
+<script nonce="%string($nonce)">
155
+(function(){
156
+ const form = document.querySelector('#chat-form');
157
+ let mxMsg = 0;
158
+ let _me = "%string($me)";
159
+ form.addEventListener('submit',(e)=>{
160
+ e.preventDefault();
161
+ if( form.msg.value.length>0 || form.file.value.length>0 ){
162
+ fetch("%string($submiturl)",{
163
+ method: 'POST',
164
+ body: new FormData(form)
165
+ });
166
+ }
167
+ form.msg.value = "";
168
+ form.file.value = "";
169
+ form.msg.focus();
170
+ });
171
+ const rxUrl = /\\b(?:https?|ftp):\\/\\/\[a-z0-9-+&@\#\\/%?=~_|!:,.;]*\[a-z0-9-+&@\#\\/%=~_|]/gim;
172
+ const rxAtName = /@\\w+/gmi;
173
+ // ^^^ achtung, extra backslashes needed for the outer TCL.
174
+ const textNode = (T)=>document.createTextNode(T);
175
+
176
+ // Converts a message string to a message-containing DOM element
177
+ // and returns that element, which may contain child elements.
178
+ // If 2nd arg is passed, it must be a DOM element to which all
179
+ // child elements are appended.
180
+ const messageToDOM = function f(str, tgtElem){
181
+ "use strict";
182
+ if(!f.rxUrl){
183
+ f.rxUrl = rxUrl;
184
+ f.rxAt = rxAtName;
185
+ f.rxNS = /\\S/;
186
+ f.ce = (T)=>document.createElement(T);
187
+ f.ct = (T)=>document.createTextNode(T);
188
+ f.replaceUrls = function ff(sub, offset, whole){
189
+ if(offset > ff.prevStart){
190
+ f.accum.push((ff.prevStart?' ':'')+whole.substring(ff.prevStart, offset-1)+' ');
191
+ }
192
+ const a = f.ce('a');
193
+ a.setAttribute('href',sub);
194
+ a.setAttribute('target','_blank');
195
+ a.appendChild(f.ct(sub));
196
+ f.accum.push(a);
197
+ ff.prevStart = offset + sub.length + 1;
198
+ };
199
+ f.replaceAtName = function ff(sub, offset,whole){
200
+ if(offset > ff.prevStart){
201
+ ff.accum.push((ff.prevStart?' ':'')+whole.substring(ff.prevStart, offset-1)+' ');
202
+ }else if(offset && f.rxNS.test(whole[offset-1])){
203
+ // Sigh: https://stackoverflow.com/questions/52655367
204
+ ff.accum.push(sub);
205
+ return;
206
+ }
207
+ const e = f.ce('span');
208
+ e.classList.add('at-name');
209
+ e.appendChild(f.ct(sub));
210
+ ff.accum.push(e);
211
+ ff.prevStart = offset + sub.length + 1;
212
+ };
213
+ }
214
+ f.accum = []; // accumulate strings and DOM elements here.
215
+ f.rxUrl.lastIndex = f.replaceUrls.prevStart = 0; // reset regex cursor
216
+ str.replace(f.rxUrl, f.replaceUrls);
217
+ // Push remaining non-URL part of the string to the queue...
218
+ if(f.replaceUrls.prevStart < str.length){
219
+ f.accum.push((f.replaceUrls.prevStart?' ':'')+str.substring(f.replaceUrls.prevStart));
220
+ }
221
+ // Pass 2: process @NAME references...
222
+ // TODO: only match NAME if it's the name of a currently participating
223
+ // user. Add a second class if NAME == current user, and style that one
224
+ // differently so that people can more easily see when they're spoken to.
225
+ const accum2 = f.replaceAtName.accum = [];
226
+ //console.debug("f.accum =",f.accum);
227
+ f.accum.forEach(function(v){
228
+ //console.debug("v =",v);
229
+ if('string'===typeof v){
230
+ f.rxAt.lastIndex = f.replaceAtName.prevStart = 0;
231
+ v.replace(f.rxAt, f.replaceAtName);
232
+ if(f.replaceAtName.prevStart < v.length){
233
+ accum2.push((f.replaceAtName.prevStart?' ':'')+v.substring(f.replaceAtName.prevStart));
234
+ }
235
+ }else{
236
+ accum2.push(v);
237
+ }
238
+ //console.debug("accum2 =",accum2);
239
+ });
240
+ delete f.accum;
241
+ //console.debug("accum2 =",accum2);
242
+ const span = tgtElem || f.ce('span');
243
+ accum2.forEach(function(e){
244
+ if('string'===typeof e) e = f.ct(e);
245
+ span.appendChild(e);
246
+ });
247
+ //console.debug("span =",span.innerHTML);
248
+ return span;
249
+ }/*end messageToDOM()*/;
250
+ /* Injects element e as a new row in the chat, at the top of the list */
251
+ const injectMessage = function f(e){
252
+ if(!f.injectPoint){
253
+ f.injectPoint = document.querySelector('#message-inject-point');
254
+ }
255
+ if(f.injectPoint.nextSibling){
256
+ f.injectPoint.parentNode.insertBefore(e, f.injectPoint.nextSibling);
257
+ }else{
258
+ f.injectPoint.parentNode.appendChild(e);
259
+ }
260
+ };
261
+ /** Returns the local time string of Date object d, defaulting
262
+ to the current time. */
263
+ const localTimeString = function ff(d){
264
+ if(!ff.pad){
265
+ ff.pad = (x)=>(''+x).length>1 ? x : '0'+x;
266
+ }
267
+ d || (d = new Date());
268
+ return [
269
+ d.getFullYear(),'-',ff.pad(d.getMonth()+1/*sigh*/),
270
+ '-',ff.pad(d.getDate()),
271
+ ' ',ff.pad(d.getHours()),':',ff.pad(d.getMinutes()),
272
+ ':',ff.pad(d.getSeconds())
273
+ ].join('');
274
+ };
275
+ function newcontent(jx){
276
+ var i;
277
+ for(i=0; i<jx.msgs.length; ++i){
278
+ let m = jx.msgs[i];
279
+ let row = document.createElement("fieldset");
280
+ if( m.msgid>mxMsg ) mxMsg = m.msgid;
281
+ row.classList.add('message-row');
282
+ injectMessage(row);
283
+ const eWho = document.createElement('legend');
284
+ eWho.setAttribute('align', (m.xfrom===_me ? 'right' : 'left'));
285
+ row.appendChild(eWho);
286
+ eWho.classList.add('message-user');
287
+ let whoName;
288
+ if( m.xfrom===_me ){
289
+ whoName = 'me';
290
+ row.classList.add('user-is-me');
291
+ }else{
292
+ whoName = m.xfrom;
293
+ }
294
+ eWho.append(textNode(
295
+ whoName+' @ '+
296
+ localTimeString(new Date(Date.parse(m.mtime+".000Z"))))
297
+ );
298
+ let span = document.createElement("div");
299
+ span.classList.add('message-content');
300
+ row.appendChild(span);
301
+ if( m.fsize>0 ){
302
+ if( m.fmime && m.fmime.startsWith("image/") ){
303
+ let img = document.createElement("img");
304
+ img.src = "%string($downloadurl)/" + m.msgid;
305
+ span.appendChild(img);
306
+ }else{
307
+ let a = document.createElement("a");
308
+ let txt = "(" + m.fname + " " + m.fsize + " bytes)";
309
+ a.href = "%string($downloadurl)/" + m.msgid;
310
+ a.appendChild(document.createTextNode(txt));
311
+ span.appendChild(a);
312
+ }
313
+ let br = document.createElement("br");
314
+ br.style.clear = "both";
315
+ span.appendChild(br);
316
+ }
317
+ if(m.xmsg){
318
+ messageToDOM(m.xmsg, span);
319
+ }
320
+ span.classList.add('chat-message');
321
+ if( m.xfrom!=_me ){
322
+ span.classList.add('chat-mx');
323
+ }else{
324
+ span.classList.add('chat-ms');
325
+ }
326
+ }
327
+ }
328
+ async function poll(){
329
+ if(poll.running) return;
330
+ poll.running = true;
331
+ fetch("%string($pollurl)/" + mxMsg)
332
+ .then(x=>x.json())
333
+ .then(y=>newcontent(y))
334
+ .finally(()=>poll.running=false)
335
+ }
336
+ setInterval(poll, 1000);
337
+})();</script>
338
+ }
339
+
340
+ # Make sure the chat database exists
341
+ sqlite3 db [chat-db-name]
342
+ if {[db one {PRAGMA journal_mode}]!="wal"} {
343
+ db eval {PRAGMA journal_mode=WAL}
344
+ }
345
+ db eval {
346
+ CREATE TABLE IF NOT EXISTS chat(
347
+ msgid INTEGER PRIMARY KEY AUTOINCREMENT,
348
+ mtime JULIANDAY,
349
+ xfrom TEXT,
350
+ xto TEXT,
351
+ xmsg TEXT,
352
+ file BLOB,
353
+ fname TEXT,
354
+ fmime TEXT
355
+ );
356
+ CREATE TABLE IF NOT EXISTS ustat(
357
+ uname TEXT PRIMARY KEY,
358
+ mtime JULIANDAY, -- Last interaction
359
+ seen INT, -- Last message seen
360
+ logout JULIANDAY
361
+ ) WITHOUT ROWID;
362
+ }
363
+ db close
364
+}
365
+
366
+# Show the CGI environment. Used for testing only.
367
+#
368
+proc wapp-page-env {} {
369
+ wapp-trim {
370
+ <div class="fossil-doc" data-title="Chat CGI Environment">
371
+ <pre>%html([wapp-debug-env])</pre>
372
+ </div>
373
+ }
374
+}
375
+
376
+# Log the CGI environment into the "-logfile.txt" file in the same
377
+# directory as the script. Used for testing and development only.
378
+#
379
+proc logenv {} {
380
+ set fn [file dir [wapp-param SCRIPT_FILENAME]]/-logfile.txt
381
+ set out [open $fn a]
382
+ puts $out {************************************************************}
383
+ puts $out [wapp-debug-env]
384
+ close $out
385
+}
386
+
387
+# A no-op page. Used for testing and development only.
388
+#
389
+proc noop-page {} {
390
+ wapp-trim {
391
+ <div class="fossil-doc" data-title="No-op"><h1>No-Op</h1></div>
392
+ }
393
+}
394
+
395
+# Accept a new post via XHR.
396
+# No reply expected.
397
+#
398
+proc wapp-page-send {} {
399
+ if {[not-authorized]} return
400
+ set user [wapp-param FOSSIL_USER]
401
+ set fcontent [wapp-param file.content]
402
+ set fname [wapp-param file.filename]
403
+ set fmime [wapp-param file.mimetype]
404
+ set msg [wapp-param msg]
405
+ sqlite3 db [chat-db-name]
406
+ db eval BEGIN
407
+ if {$fcontent!=""} {
408
+ db eval {
409
+ INSERT INTO chat(mtime,xfrom,xmsg,file,fname,fmime)
410
+ VALUES(julianday('now'),$user,@msg,@fcontent,$fname,$fmime)
411
+ }
412
+ } else {
413
+ db eval {
414
+ INSERT INTO chat(mtime,xfrom,xmsg)
415
+ VALUES(julianday('now'),$user,@msg)
416
+ }
417
+ }
418
+ db eval {
419
+ INSERT INTO ustat(uname,mtime,seen) VALUES($user,julianday('now'),0)
420
+ ON CONFLICT(uname) DO UPDATE set mtime=julianday('now')
421
+ }
422
+ db eval COMMIT
423
+ db close
424
+}
425
+
426
+# Request updates.
427
+# Delay the response until something changes (as this system works
428
+# using the Hanging-GET or Long-Poll style of server-push).
429
+# The result is javascript describing the new content.
430
+#
431
+# Call is like this: /poll/N
432
+# Where N is the last message received so far. The reply stalls
433
+# until newer messages are available.
434
+#
435
+proc wapp-page-poll {} {
436
+ if {[not-authorized]} return
437
+ wapp-mimetype text/json
438
+ set msglist {}
439
+ sqlite3 db [chat-db-name]
440
+ set id 0
441
+ scan [wapp-param PATH_TAIL] %d id
442
+ while {1} {
443
+ set datavers [db one {PRAGMA data_version}]
444
+ db eval {SELECT msgid, datetime(mtime) AS dx, xfrom, CAST(xmsg AS text) mx,
445
+ length(file) AS lx, fname, fmime
446
+ FROM chat
447
+ WHERE msgid>$id
448
+ ORDER BY msgid} {
449
+ set quname [string map {\" \\\"} $xfrom]
450
+ set qmsg [string map {\" \\\"} $mx]
451
+ if {$lx==""} {set lx 0}
452
+ set qfname [string map {\" \\\"} $fname]
453
+ lappend msglist "\173\"msgid\":$msgid,\"mtime\":\"$dx\",\
454
+ \"xfrom\":\"$quname\",\
455
+ \"xmsg\":\"$qmsg\",\"fsize\":$lx,\
456
+ \"fname\":\"$qfname\",\"fmime\":\"$fmime\"\175"
457
+ }
458
+ if {[llength $msglist]>0} {
459
+ wapp-unsafe "\173\042msgs\042:\133[join $msglist ,]\135\175"
460
+ db close
461
+ return
462
+ }
463
+ after 2000
464
+ while {[db one {PRAGMA data_version}]==$datavers} {after 2000}
465
+ }
466
+}
467
+
468
+# Show the text of this script.
469
+#
470
+proc wapp-page-self {} {
471
+ wapp-trim {
472
+ <div class="fossil-doc" data-title="Wapp Script for Chat">
473
+ }
474
+ set fd [open [wapp-param SCRIPT_FILENAME] rb]
475
+ set script [read $fd]
476
+ wapp-trim {
477
+ <pre>%html($script)</pre>
478
+ }
479
+ wapp-trim {
480
+ </div>
481
+ }
482
+}
483
+
484
+# Download the file associated with a message.
485
+#
486
+# Call like this: /download/N
487
+# Where N is the message id.
488
+#
489
+proc wapp-page-download {} {
490
+ if {[not-authorized]} {
491
+ wapp-trim {
492
+ <h1>Not authorized</h1>
493
+ <p>You must have privileges to use this chatroom</p>
494
+ </div>
495
+ }
496
+ return
497
+ }
498
+ set id 0
499
+ scan [wapp-param PATH_TAIL] %d id
500
+ sqlite3 db [chat-db-name]
501
+ db eval {SELECT fname, fmime, file FROM chat WHERE msgid=$id} {
502
+ wapp-mimetype $fmime
503
+ wapp $file
504
+ }
505
+ db close
506
+}
507
+
508
+
509
+wapp-start $argv
--- a/tools/chat.tcl
+++ b/tools/chat.tcl
@@ -0,0 +1,509 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
--- a/tools/chat.tcl
+++ b/tools/chat.tcl
@@ -0,0 +1,509 @@
1 #!/usr/bin/wapptclsh
2 #
3 # A chat program designed to run using the extcgi mechanism of Fossil.
4 #
5 encoding system utf-8
6
7 # The name of the chat database file
8 #
9 proc chat-db-name {} {
10 set x [wapp-param SCRIPT_FILENAME]
11 set dir [file dir $x]
12 set fn [file tail $x]
13 return $dir/-$fn.db
14 }
15
16 # Verify permission to use chat. Return true if not authorized.
17 # Return false if the Fossil user is allowed to access chat.
18 #
19 proc not-authorized {} {
20 set cap [wapp-param FOSSIL_CAPABILITIES]
21 return [expr {![string match *i* $cap]}]
22 }
23
24 # The default page.
25 # Load the initial chat screen.
26 #
27 proc wapp-default {} {
28 wapp-content-security-policy off
29 wapp-trim {
30 <div class="fossil-doc" data-title="Chat">
31 }
32 if {[not-authorized]} {
33 wapp-trim {
34 <h1>Not authorized</h1>
35 <p>You must have privileges to use this chatroom</p>
36 </div>
37 }
38 return
39 }
40 set scriptFile [wapp-param SCRIPT_FILENAME]
41 set cgiFn [file tail $scriptFile]
42 wapp-trim {
43 <form accept-encoding="utf-8" id="chat-form">
44 <div id='chat-input-area'>
45 <div id='chat-input-line'>
46 <input type="text" name="msg" id="sbox" placeholder="Type message here.">
47 <input type="submit" value="Send">
48 </div>
49 <div id='chat-input-file'>
50 <span>File:</span>
51 <input type="file" name="file">
52 </div>
53 </div>
54 </form>
55 <hr>
56 <span id='message-inject-point'><!--
57 new chat messages get inserted immediately after this element
58 --></span>
59
60 </div><!-- .fossil-doc -->
61 <hr>
62 <p>
63 <a href="%string($cgiFn)/env">CGI environment</a> |
64 <a href="%string($cgiFn)/self">Wapp script</a>
65 <style>
66 \#dialog {
67 width: 97%;
68 }
69 \#chat-input-area {
70 width: 100%;
71 display: flex;
72 flex-direction: column;
73 }
74 \#chat-input-line {
75 display: flex;
76 flex-direction: row;
77 margin-bottom: 1em;
78 align-items: center;
79 }
80 \#chat-input-line > input[type=submit] {
81 flex: 1 5 auto;
82 max-width: 6em;
83 }
84 \#chat-input-line > input[type=text] {
85 flex: 5 1 auto;
86 }
87 \#chat-input-file {
88 display: flex;
89 flex-direction: row;
90 align-items: center;
91 }
92 \#chat-input-file > input {
93 flex: 1 0 auto;
94 }
95 span.at-name { /* for @USERNAME references */
96 text-decoration: underline;
97 font-weight: bold;
98 }
99 /* A wrapper for a single single message (one row of the UI) */
100 .message-row {
101 margin-bottom: 0.5em;
102 border: none;
103 display: flex;
104 flex-direction: row;
105 justify-content: flex-start;
106 /*border: 1px solid rgba(0,0,0,0.2);
107 border-radius: 0.25em;
108 box-shadow: 0.2em 0.2em 0.2em rgba(0, 0, 0, 0.29);*/
109 border: none;
110 }
111 /* Rows for the current user have the .user-is-me CSS class
112 and get right-aligned. */
113 .message-row.user-is-me {
114 justify-content: flex-end;
115 /*background-color: #d2dde1;*/
116 }
117 /* The content area of a message (the body element of a FIELDSET) */
118 .message-content {
119 display: inline-block;
120 border-radius: 0.25em;
121 border: 1px solid rgba(0,0,0,0.2);
122 box-shadow: 0.2em 0.2em 0.2em rgba(0, 0, 0, 0.29);
123 padding: 0.25em 1em;
124 margin-top: -0.75em;
125 }
126 .message-row.user-is-me .message-content {
127 background-color: #d2dde1;
128 }
129 /* User name for the post (a LEGEND element) */
130 .message-row .message-user {
131 background: inherit;
132 border-radius: 0.25em 0.25em 0 0;
133 padding: 0 0.5em;
134 /*text-align: left; Firefox requires the 'align' attribute */
135 margin-left: 0.25em;
136 padding: 0 0.5em 0em 0.5em;
137 margin-bottom: 0.4em;
138 background-color: #d2dde1;
139 }
140 /* Reposition "my" posts to the right */
141 .message-row.user-is-me .message-user {
142 /*text-align: right; Firefox requires the 'align' attribute */
143 margin-left: 0;
144 margin-right: 0.25em;
145 }
146 </style>
147 }
148 set nonce [wapp-param FOSSIL_NONCE]
149 set submiturl [wapp-param SCRIPT_NAME]/send
150 set pollurl [wapp-param SCRIPT_NAME]/poll
151 set downloadurl [wapp-param SCRIPT_NAME]/download
152 set me [wapp-param FOSSIL_USER]
153 wapp-trim {
154 <script nonce="%string($nonce)">
155 (function(){
156 const form = document.querySelector('#chat-form');
157 let mxMsg = 0;
158 let _me = "%string($me)";
159 form.addEventListener('submit',(e)=>{
160 e.preventDefault();
161 if( form.msg.value.length>0 || form.file.value.length>0 ){
162 fetch("%string($submiturl)",{
163 method: 'POST',
164 body: new FormData(form)
165 });
166 }
167 form.msg.value = "";
168 form.file.value = "";
169 form.msg.focus();
170 });
171 const rxUrl = /\\b(?:https?|ftp):\\/\\/\[a-z0-9-+&@\#\\/%?=~_|!:,.;]*\[a-z0-9-+&@\#\\/%=~_|]/gim;
172 const rxAtName = /@\\w+/gmi;
173 // ^^^ achtung, extra backslashes needed for the outer TCL.
174 const textNode = (T)=>document.createTextNode(T);
175
176 // Converts a message string to a message-containing DOM element
177 // and returns that element, which may contain child elements.
178 // If 2nd arg is passed, it must be a DOM element to which all
179 // child elements are appended.
180 const messageToDOM = function f(str, tgtElem){
181 "use strict";
182 if(!f.rxUrl){
183 f.rxUrl = rxUrl;
184 f.rxAt = rxAtName;
185 f.rxNS = /\\S/;
186 f.ce = (T)=>document.createElement(T);
187 f.ct = (T)=>document.createTextNode(T);
188 f.replaceUrls = function ff(sub, offset, whole){
189 if(offset > ff.prevStart){
190 f.accum.push((ff.prevStart?' ':'')+whole.substring(ff.prevStart, offset-1)+' ');
191 }
192 const a = f.ce('a');
193 a.setAttribute('href',sub);
194 a.setAttribute('target','_blank');
195 a.appendChild(f.ct(sub));
196 f.accum.push(a);
197 ff.prevStart = offset + sub.length + 1;
198 };
199 f.replaceAtName = function ff(sub, offset,whole){
200 if(offset > ff.prevStart){
201 ff.accum.push((ff.prevStart?' ':'')+whole.substring(ff.prevStart, offset-1)+' ');
202 }else if(offset && f.rxNS.test(whole[offset-1])){
203 // Sigh: https://stackoverflow.com/questions/52655367
204 ff.accum.push(sub);
205 return;
206 }
207 const e = f.ce('span');
208 e.classList.add('at-name');
209 e.appendChild(f.ct(sub));
210 ff.accum.push(e);
211 ff.prevStart = offset + sub.length + 1;
212 };
213 }
214 f.accum = []; // accumulate strings and DOM elements here.
215 f.rxUrl.lastIndex = f.replaceUrls.prevStart = 0; // reset regex cursor
216 str.replace(f.rxUrl, f.replaceUrls);
217 // Push remaining non-URL part of the string to the queue...
218 if(f.replaceUrls.prevStart < str.length){
219 f.accum.push((f.replaceUrls.prevStart?' ':'')+str.substring(f.replaceUrls.prevStart));
220 }
221 // Pass 2: process @NAME references...
222 // TODO: only match NAME if it's the name of a currently participating
223 // user. Add a second class if NAME == current user, and style that one
224 // differently so that people can more easily see when they're spoken to.
225 const accum2 = f.replaceAtName.accum = [];
226 //console.debug("f.accum =",f.accum);
227 f.accum.forEach(function(v){
228 //console.debug("v =",v);
229 if('string'===typeof v){
230 f.rxAt.lastIndex = f.replaceAtName.prevStart = 0;
231 v.replace(f.rxAt, f.replaceAtName);
232 if(f.replaceAtName.prevStart < v.length){
233 accum2.push((f.replaceAtName.prevStart?' ':'')+v.substring(f.replaceAtName.prevStart));
234 }
235 }else{
236 accum2.push(v);
237 }
238 //console.debug("accum2 =",accum2);
239 });
240 delete f.accum;
241 //console.debug("accum2 =",accum2);
242 const span = tgtElem || f.ce('span');
243 accum2.forEach(function(e){
244 if('string'===typeof e) e = f.ct(e);
245 span.appendChild(e);
246 });
247 //console.debug("span =",span.innerHTML);
248 return span;
249 }/*end messageToDOM()*/;
250 /* Injects element e as a new row in the chat, at the top of the list */
251 const injectMessage = function f(e){
252 if(!f.injectPoint){
253 f.injectPoint = document.querySelector('#message-inject-point');
254 }
255 if(f.injectPoint.nextSibling){
256 f.injectPoint.parentNode.insertBefore(e, f.injectPoint.nextSibling);
257 }else{
258 f.injectPoint.parentNode.appendChild(e);
259 }
260 };
261 /** Returns the local time string of Date object d, defaulting
262 to the current time. */
263 const localTimeString = function ff(d){
264 if(!ff.pad){
265 ff.pad = (x)=>(''+x).length>1 ? x : '0'+x;
266 }
267 d || (d = new Date());
268 return [
269 d.getFullYear(),'-',ff.pad(d.getMonth()+1/*sigh*/),
270 '-',ff.pad(d.getDate()),
271 ' ',ff.pad(d.getHours()),':',ff.pad(d.getMinutes()),
272 ':',ff.pad(d.getSeconds())
273 ].join('');
274 };
275 function newcontent(jx){
276 var i;
277 for(i=0; i<jx.msgs.length; ++i){
278 let m = jx.msgs[i];
279 let row = document.createElement("fieldset");
280 if( m.msgid>mxMsg ) mxMsg = m.msgid;
281 row.classList.add('message-row');
282 injectMessage(row);
283 const eWho = document.createElement('legend');
284 eWho.setAttribute('align', (m.xfrom===_me ? 'right' : 'left'));
285 row.appendChild(eWho);
286 eWho.classList.add('message-user');
287 let whoName;
288 if( m.xfrom===_me ){
289 whoName = 'me';
290 row.classList.add('user-is-me');
291 }else{
292 whoName = m.xfrom;
293 }
294 eWho.append(textNode(
295 whoName+' @ '+
296 localTimeString(new Date(Date.parse(m.mtime+".000Z"))))
297 );
298 let span = document.createElement("div");
299 span.classList.add('message-content');
300 row.appendChild(span);
301 if( m.fsize>0 ){
302 if( m.fmime && m.fmime.startsWith("image/") ){
303 let img = document.createElement("img");
304 img.src = "%string($downloadurl)/" + m.msgid;
305 span.appendChild(img);
306 }else{
307 let a = document.createElement("a");
308 let txt = "(" + m.fname + " " + m.fsize + " bytes)";
309 a.href = "%string($downloadurl)/" + m.msgid;
310 a.appendChild(document.createTextNode(txt));
311 span.appendChild(a);
312 }
313 let br = document.createElement("br");
314 br.style.clear = "both";
315 span.appendChild(br);
316 }
317 if(m.xmsg){
318 messageToDOM(m.xmsg, span);
319 }
320 span.classList.add('chat-message');
321 if( m.xfrom!=_me ){
322 span.classList.add('chat-mx');
323 }else{
324 span.classList.add('chat-ms');
325 }
326 }
327 }
328 async function poll(){
329 if(poll.running) return;
330 poll.running = true;
331 fetch("%string($pollurl)/" + mxMsg)
332 .then(x=>x.json())
333 .then(y=>newcontent(y))
334 .finally(()=>poll.running=false)
335 }
336 setInterval(poll, 1000);
337 })();</script>
338 }
339
340 # Make sure the chat database exists
341 sqlite3 db [chat-db-name]
342 if {[db one {PRAGMA journal_mode}]!="wal"} {
343 db eval {PRAGMA journal_mode=WAL}
344 }
345 db eval {
346 CREATE TABLE IF NOT EXISTS chat(
347 msgid INTEGER PRIMARY KEY AUTOINCREMENT,
348 mtime JULIANDAY,
349 xfrom TEXT,
350 xto TEXT,
351 xmsg TEXT,
352 file BLOB,
353 fname TEXT,
354 fmime TEXT
355 );
356 CREATE TABLE IF NOT EXISTS ustat(
357 uname TEXT PRIMARY KEY,
358 mtime JULIANDAY, -- Last interaction
359 seen INT, -- Last message seen
360 logout JULIANDAY
361 ) WITHOUT ROWID;
362 }
363 db close
364 }
365
366 # Show the CGI environment. Used for testing only.
367 #
368 proc wapp-page-env {} {
369 wapp-trim {
370 <div class="fossil-doc" data-title="Chat CGI Environment">
371 <pre>%html([wapp-debug-env])</pre>
372 </div>
373 }
374 }
375
376 # Log the CGI environment into the "-logfile.txt" file in the same
377 # directory as the script. Used for testing and development only.
378 #
379 proc logenv {} {
380 set fn [file dir [wapp-param SCRIPT_FILENAME]]/-logfile.txt
381 set out [open $fn a]
382 puts $out {************************************************************}
383 puts $out [wapp-debug-env]
384 close $out
385 }
386
387 # A no-op page. Used for testing and development only.
388 #
389 proc noop-page {} {
390 wapp-trim {
391 <div class="fossil-doc" data-title="No-op"><h1>No-Op</h1></div>
392 }
393 }
394
395 # Accept a new post via XHR.
396 # No reply expected.
397 #
398 proc wapp-page-send {} {
399 if {[not-authorized]} return
400 set user [wapp-param FOSSIL_USER]
401 set fcontent [wapp-param file.content]
402 set fname [wapp-param file.filename]
403 set fmime [wapp-param file.mimetype]
404 set msg [wapp-param msg]
405 sqlite3 db [chat-db-name]
406 db eval BEGIN
407 if {$fcontent!=""} {
408 db eval {
409 INSERT INTO chat(mtime,xfrom,xmsg,file,fname,fmime)
410 VALUES(julianday('now'),$user,@msg,@fcontent,$fname,$fmime)
411 }
412 } else {
413 db eval {
414 INSERT INTO chat(mtime,xfrom,xmsg)
415 VALUES(julianday('now'),$user,@msg)
416 }
417 }
418 db eval {
419 INSERT INTO ustat(uname,mtime,seen) VALUES($user,julianday('now'),0)
420 ON CONFLICT(uname) DO UPDATE set mtime=julianday('now')
421 }
422 db eval COMMIT
423 db close
424 }
425
426 # Request updates.
427 # Delay the response until something changes (as this system works
428 # using the Hanging-GET or Long-Poll style of server-push).
429 # The result is javascript describing the new content.
430 #
431 # Call is like this: /poll/N
432 # Where N is the last message received so far. The reply stalls
433 # until newer messages are available.
434 #
435 proc wapp-page-poll {} {
436 if {[not-authorized]} return
437 wapp-mimetype text/json
438 set msglist {}
439 sqlite3 db [chat-db-name]
440 set id 0
441 scan [wapp-param PATH_TAIL] %d id
442 while {1} {
443 set datavers [db one {PRAGMA data_version}]
444 db eval {SELECT msgid, datetime(mtime) AS dx, xfrom, CAST(xmsg AS text) mx,
445 length(file) AS lx, fname, fmime
446 FROM chat
447 WHERE msgid>$id
448 ORDER BY msgid} {
449 set quname [string map {\" \\\"} $xfrom]
450 set qmsg [string map {\" \\\"} $mx]
451 if {$lx==""} {set lx 0}
452 set qfname [string map {\" \\\"} $fname]
453 lappend msglist "\173\"msgid\":$msgid,\"mtime\":\"$dx\",\
454 \"xfrom\":\"$quname\",\
455 \"xmsg\":\"$qmsg\",\"fsize\":$lx,\
456 \"fname\":\"$qfname\",\"fmime\":\"$fmime\"\175"
457 }
458 if {[llength $msglist]>0} {
459 wapp-unsafe "\173\042msgs\042:\133[join $msglist ,]\135\175"
460 db close
461 return
462 }
463 after 2000
464 while {[db one {PRAGMA data_version}]==$datavers} {after 2000}
465 }
466 }
467
468 # Show the text of this script.
469 #
470 proc wapp-page-self {} {
471 wapp-trim {
472 <div class="fossil-doc" data-title="Wapp Script for Chat">
473 }
474 set fd [open [wapp-param SCRIPT_FILENAME] rb]
475 set script [read $fd]
476 wapp-trim {
477 <pre>%html($script)</pre>
478 }
479 wapp-trim {
480 </div>
481 }
482 }
483
484 # Download the file associated with a message.
485 #
486 # Call like this: /download/N
487 # Where N is the message id.
488 #
489 proc wapp-page-download {} {
490 if {[not-authorized]} {
491 wapp-trim {
492 <h1>Not authorized</h1>
493 <p>You must have privileges to use this chatroom</p>
494 </div>
495 }
496 return
497 }
498 set id 0
499 scan [wapp-param PATH_TAIL] %d id
500 sqlite3 db [chat-db-name]
501 db eval {SELECT fname, fmime, file FROM chat WHERE msgid=$id} {
502 wapp-mimetype $fmime
503 wapp $file
504 }
505 db close
506 }
507
508
509 wapp-start $argv
+10 -4
--- win/Makefile.dmc
+++ win/Makefile.dmc
@@ -28,13 +28,13 @@
2828
2929
SQLITE_OPTIONS = -DNDEBUG=1 -DSQLITE_DQS=0 -DSQLITE_THREADSAFE=0 -DSQLITE_DEFAULT_MEMSTATUS=0 -DSQLITE_DEFAULT_WAL_SYNCHRONOUS=1 -DSQLITE_LIKE_DOESNT_MATCH_BLOBS -DSQLITE_OMIT_DECLTYPE -DSQLITE_OMIT_DEPRECATED -DSQLITE_OMIT_PROGRESS_CALLBACK -DSQLITE_OMIT_SHARED_CACHE -DSQLITE_OMIT_LOAD_EXTENSION -DSQLITE_MAX_EXPR_DEPTH=0 -DSQLITE_USE_ALLOCA -DSQLITE_ENABLE_LOCKING_STYLE=0 -DSQLITE_DEFAULT_FILE_FORMAT=4 -DSQLITE_ENABLE_EXPLAIN_COMMENTS -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_DBSTAT_VTAB -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_FTS5 -DSQLITE_ENABLE_STMTVTAB -DSQLITE_HAVE_ZLIB -DSQLITE_INTROSPECTION_PRAGMAS -DSQLITE_ENABLE_DBPAGE_VTAB -DSQLITE_TRUSTED_SCHEMA=0
3030
3131
SHELL_OPTIONS = -DNDEBUG=1 -DSQLITE_DQS=0 -DSQLITE_THREADSAFE=0 -DSQLITE_DEFAULT_MEMSTATUS=0 -DSQLITE_DEFAULT_WAL_SYNCHRONOUS=1 -DSQLITE_LIKE_DOESNT_MATCH_BLOBS -DSQLITE_OMIT_DECLTYPE -DSQLITE_OMIT_DEPRECATED -DSQLITE_OMIT_PROGRESS_CALLBACK -DSQLITE_OMIT_SHARED_CACHE -DSQLITE_OMIT_LOAD_EXTENSION -DSQLITE_MAX_EXPR_DEPTH=0 -DSQLITE_USE_ALLOCA -DSQLITE_ENABLE_LOCKING_STYLE=0 -DSQLITE_DEFAULT_FILE_FORMAT=4 -DSQLITE_ENABLE_EXPLAIN_COMMENTS -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_DBSTAT_VTAB -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_FTS5 -DSQLITE_ENABLE_STMTVTAB -DSQLITE_HAVE_ZLIB -DSQLITE_INTROSPECTION_PRAGMAS -DSQLITE_ENABLE_DBPAGE_VTAB -DSQLITE_TRUSTED_SCHEMA=0 -Dmain=sqlite3_shell -DSQLITE_SHELL_IS_UTF8=1 -DSQLITE_OMIT_LOAD_EXTENSION=1 -DUSE_SYSTEM_SQLITE=$(USE_SYSTEM_SQLITE) -DSQLITE_SHELL_DBNAME_PROC=sqlcmd_get_dbname -DSQLITE_SHELL_INIT_PROC=sqlcmd_init_proc -Daccess=file_access -Dsystem=fossil_system -Dgetenv=fossil_getenv -Dfopen=fossil_fopen
3232
33
-SRC = add_.c ajax_.c alerts_.c allrepo_.c attach_.c backlink_.c backoffice_.c bag_.c bisect_.c blob_.c branch_.c browse_.c builtin_.c bundle_.c cache_.c capabilities_.c captcha_.c cgi_.c checkin_.c checkout_.c clearsign_.c clone_.c comformat_.c configure_.c content_.c cookies_.c db_.c delta_.c deltacmd_.c deltafunc_.c descendants_.c diff_.c diffcmd_.c dispatch_.c doc_.c encode_.c etag_.c event_.c export_.c extcgi_.c file_.c fileedit_.c finfo_.c foci_.c forum_.c fshell_.c fusefs_.c fuzz_.c glob_.c graph_.c gzip_.c hname_.c hook_.c http_.c http_socket_.c http_ssl_.c http_transport_.c import_.c info_.c interwiki_.c json_.c json_artifact_.c json_branch_.c json_config_.c json_diff_.c json_dir_.c json_finfo_.c json_login_.c json_query_.c json_report_.c json_status_.c json_tag_.c json_timeline_.c json_user_.c json_wiki_.c leaf_.c loadctrl_.c login_.c lookslike_.c main_.c manifest_.c markdown_.c markdown_html_.c md5_.c merge_.c merge3_.c moderate_.c name_.c path_.c piechart_.c pikchr_.c pikchrshow_.c pivot_.c popen_.c pqueue_.c printf_.c publish_.c purge_.c rebuild_.c regexp_.c repolist_.c report_.c rss_.c schema_.c search_.c security_audit_.c setup_.c setupuser_.c sha1_.c sha1hard_.c sha3_.c shun_.c sitemap_.c skins_.c smtp_.c sqlcmd_.c stash_.c stat_.c statrep_.c style_.c sync_.c tag_.c tar_.c terminal_.c th_main_.c timeline_.c tkt_.c tktsetup_.c undo_.c unicode_.c unversioned_.c update_.c url_.c user_.c utf8_.c util_.c verify_.c vfile_.c webmail_.c wiki_.c wikiformat_.c winfile_.c winhttp_.c xfer_.c xfersetup_.c zip_.c
33
+SRC = add_.c ajax_.c alerts_.c allrepo_.c attach_.c backlink_.c backoffice_.c bag_.c bisect_.c blob_.c branch_.c browse_.c builtin_.c bundle_.c cache_.c capabilities_.c captcha_.c cgi_.c chat_.c checkin_.c checkout_.c clearsign_.c clone_.c comformat_.c configure_.c content_.c cookies_.c db_.c delta_.c deltacmd_.c deltafunc_.c descendants_.c diff_.c diffcmd_.c dispatch_.c doc_.c encode_.c etag_.c event_.c export_.c extcgi_.c file_.c fileedit_.c finfo_.c foci_.c forum_.c fshell_.c fusefs_.c fuzz_.c glob_.c graph_.c gzip_.c hname_.c hook_.c http_.c http_socket_.c http_ssl_.c http_transport_.c import_.c info_.c interwiki_.c json_.c json_artifact_.c json_branch_.c json_config_.c json_diff_.c json_dir_.c json_finfo_.c json_login_.c json_query_.c json_report_.c json_status_.c json_tag_.c json_timeline_.c json_user_.c json_wiki_.c leaf_.c loadctrl_.c login_.c lookslike_.c main_.c manifest_.c markdown_.c markdown_html_.c md5_.c merge_.c merge3_.c moderate_.c name_.c path_.c piechart_.c pikchr_.c pikchrshow_.c pivot_.c popen_.c pqueue_.c printf_.c publish_.c purge_.c rebuild_.c regexp_.c repolist_.c report_.c rss_.c schema_.c search_.c security_audit_.c setup_.c setupuser_.c sha1_.c sha1hard_.c sha3_.c shun_.c sitemap_.c skins_.c smtp_.c sqlcmd_.c stash_.c stat_.c statrep_.c style_.c sync_.c tag_.c tar_.c terminal_.c th_main_.c timeline_.c tkt_.c tktsetup_.c undo_.c unicode_.c unversioned_.c update_.c url_.c user_.c utf8_.c util_.c verify_.c vfile_.c webmail_.c wiki_.c wikiformat_.c winfile_.c winhttp_.c xfer_.c xfersetup_.c zip_.c
3434
35
-OBJ = $(OBJDIR)\add$O $(OBJDIR)\ajax$O $(OBJDIR)\alerts$O $(OBJDIR)\allrepo$O $(OBJDIR)\attach$O $(OBJDIR)\backlink$O $(OBJDIR)\backoffice$O $(OBJDIR)\bag$O $(OBJDIR)\bisect$O $(OBJDIR)\blob$O $(OBJDIR)\branch$O $(OBJDIR)\browse$O $(OBJDIR)\builtin$O $(OBJDIR)\bundle$O $(OBJDIR)\cache$O $(OBJDIR)\capabilities$O $(OBJDIR)\captcha$O $(OBJDIR)\cgi$O $(OBJDIR)\checkin$O $(OBJDIR)\checkout$O $(OBJDIR)\clearsign$O $(OBJDIR)\clone$O $(OBJDIR)\comformat$O $(OBJDIR)\configure$O $(OBJDIR)\content$O $(OBJDIR)\cookies$O $(OBJDIR)\db$O $(OBJDIR)\delta$O $(OBJDIR)\deltacmd$O $(OBJDIR)\deltafunc$O $(OBJDIR)\descendants$O $(OBJDIR)\diff$O $(OBJDIR)\diffcmd$O $(OBJDIR)\dispatch$O $(OBJDIR)\doc$O $(OBJDIR)\encode$O $(OBJDIR)\etag$O $(OBJDIR)\event$O $(OBJDIR)\export$O $(OBJDIR)\extcgi$O $(OBJDIR)\file$O $(OBJDIR)\fileedit$O $(OBJDIR)\finfo$O $(OBJDIR)\foci$O $(OBJDIR)\forum$O $(OBJDIR)\fshell$O $(OBJDIR)\fusefs$O $(OBJDIR)\fuzz$O $(OBJDIR)\glob$O $(OBJDIR)\graph$O $(OBJDIR)\gzip$O $(OBJDIR)\hname$O $(OBJDIR)\hook$O $(OBJDIR)\http$O $(OBJDIR)\http_socket$O $(OBJDIR)\http_ssl$O $(OBJDIR)\http_transport$O $(OBJDIR)\import$O $(OBJDIR)\info$O $(OBJDIR)\interwiki$O $(OBJDIR)\json$O $(OBJDIR)\json_artifact$O $(OBJDIR)\json_branch$O $(OBJDIR)\json_config$O $(OBJDIR)\json_diff$O $(OBJDIR)\json_dir$O $(OBJDIR)\json_finfo$O $(OBJDIR)\json_login$O $(OBJDIR)\json_query$O $(OBJDIR)\json_report$O $(OBJDIR)\json_status$O $(OBJDIR)\json_tag$O $(OBJDIR)\json_timeline$O $(OBJDIR)\json_user$O $(OBJDIR)\json_wiki$O $(OBJDIR)\leaf$O $(OBJDIR)\loadctrl$O $(OBJDIR)\login$O $(OBJDIR)\lookslike$O $(OBJDIR)\main$O $(OBJDIR)\manifest$O $(OBJDIR)\markdown$O $(OBJDIR)\markdown_html$O $(OBJDIR)\md5$O $(OBJDIR)\merge$O $(OBJDIR)\merge3$O $(OBJDIR)\moderate$O $(OBJDIR)\name$O $(OBJDIR)\path$O $(OBJDIR)\piechart$O $(OBJDIR)\pikchr$O $(OBJDIR)\pikchrshow$O $(OBJDIR)\pivot$O $(OBJDIR)\popen$O $(OBJDIR)\pqueue$O $(OBJDIR)\printf$O $(OBJDIR)\publish$O $(OBJDIR)\purge$O $(OBJDIR)\rebuild$O $(OBJDIR)\regexp$O $(OBJDIR)\repolist$O $(OBJDIR)\report$O $(OBJDIR)\rss$O $(OBJDIR)\schema$O $(OBJDIR)\search$O $(OBJDIR)\security_audit$O $(OBJDIR)\setup$O $(OBJDIR)\setupuser$O $(OBJDIR)\sha1$O $(OBJDIR)\sha1hard$O $(OBJDIR)\sha3$O $(OBJDIR)\shun$O $(OBJDIR)\sitemap$O $(OBJDIR)\skins$O $(OBJDIR)\smtp$O $(OBJDIR)\sqlcmd$O $(OBJDIR)\stash$O $(OBJDIR)\stat$O $(OBJDIR)\statrep$O $(OBJDIR)\style$O $(OBJDIR)\sync$O $(OBJDIR)\tag$O $(OBJDIR)\tar$O $(OBJDIR)\terminal$O $(OBJDIR)\th_main$O $(OBJDIR)\timeline$O $(OBJDIR)\tkt$O $(OBJDIR)\tktsetup$O $(OBJDIR)\undo$O $(OBJDIR)\unicode$O $(OBJDIR)\unversioned$O $(OBJDIR)\update$O $(OBJDIR)\url$O $(OBJDIR)\user$O $(OBJDIR)\utf8$O $(OBJDIR)\util$O $(OBJDIR)\verify$O $(OBJDIR)\vfile$O $(OBJDIR)\webmail$O $(OBJDIR)\wiki$O $(OBJDIR)\wikiformat$O $(OBJDIR)\winfile$O $(OBJDIR)\winhttp$O $(OBJDIR)\xfer$O $(OBJDIR)\xfersetup$O $(OBJDIR)\zip$O $(OBJDIR)\shell$O $(OBJDIR)\sqlite3$O $(OBJDIR)\th$O $(OBJDIR)\th_lang$O
35
+OBJ = $(OBJDIR)\add$O $(OBJDIR)\ajax$O $(OBJDIR)\alerts$O $(OBJDIR)\allrepo$O $(OBJDIR)\attach$O $(OBJDIR)\backlink$O $(OBJDIR)\backoffice$O $(OBJDIR)\bag$O $(OBJDIR)\bisect$O $(OBJDIR)\blob$O $(OBJDIR)\branch$O $(OBJDIR)\browse$O $(OBJDIR)\builtin$O $(OBJDIR)\bundle$O $(OBJDIR)\cache$O $(OBJDIR)\capabilities$O $(OBJDIR)\captcha$O $(OBJDIR)\cgi$O $(OBJDIR)\chat$O $(OBJDIR)\checkin$O $(OBJDIR)\checkout$O $(OBJDIR)\clearsign$O $(OBJDIR)\clone$O $(OBJDIR)\comformat$O $(OBJDIR)\configure$O $(OBJDIR)\content$O $(OBJDIR)\cookies$O $(OBJDIR)\db$O $(OBJDIR)\delta$O $(OBJDIR)\deltacmd$O $(OBJDIR)\deltafunc$O $(OBJDIR)\descendants$O $(OBJDIR)\diff$O $(OBJDIR)\diffcmd$O $(OBJDIR)\dispatch$O $(OBJDIR)\doc$O $(OBJDIR)\encode$O $(OBJDIR)\etag$O $(OBJDIR)\event$O $(OBJDIR)\export$O $(OBJDIR)\extcgi$O $(OBJDIR)\file$O $(OBJDIR)\fileedit$O $(OBJDIR)\finfo$O $(OBJDIR)\foci$O $(OBJDIR)\forum$O $(OBJDIR)\fshell$O $(OBJDIR)\fusefs$O $(OBJDIR)\fuzz$O $(OBJDIR)\glob$O $(OBJDIR)\graph$O $(OBJDIR)\gzip$O $(OBJDIR)\hname$O $(OBJDIR)\hook$O $(OBJDIR)\http$O $(OBJDIR)\http_socket$O $(OBJDIR)\http_ssl$O $(OBJDIR)\http_transport$O $(OBJDIR)\import$O $(OBJDIR)\info$O $(OBJDIR)\interwiki$O $(OBJDIR)\json$O $(OBJDIR)\json_artifact$O $(OBJDIR)\json_branch$O $(OBJDIR)\json_config$O $(OBJDIR)\json_diff$O $(OBJDIR)\json_dir$O $(OBJDIR)\json_finfo$O $(OBJDIR)\json_login$O $(OBJDIR)\json_query$O $(OBJDIR)\json_report$O $(OBJDIR)\json_status$O $(OBJDIR)\json_tag$O $(OBJDIR)\json_timeline$O $(OBJDIR)\json_user$O $(OBJDIR)\json_wiki$O $(OBJDIR)\leaf$O $(OBJDIR)\loadctrl$O $(OBJDIR)\login$O $(OBJDIR)\lookslike$O $(OBJDIR)\main$O $(OBJDIR)\manifest$O $(OBJDIR)\markdown$O $(OBJDIR)\markdown_html$O $(OBJDIR)\md5$O $(OBJDIR)\merge$O $(OBJDIR)\merge3$O $(OBJDIR)\moderate$O $(OBJDIR)\name$O $(OBJDIR)\path$O $(OBJDIR)\piechart$O $(OBJDIR)\pikchr$O $(OBJDIR)\pikchrshow$O $(OBJDIR)\pivot$O $(OBJDIR)\popen$O $(OBJDIR)\pqueue$O $(OBJDIR)\printf$O $(OBJDIR)\publish$O $(OBJDIR)\purge$O $(OBJDIR)\rebuild$O $(OBJDIR)\regexp$O $(OBJDIR)\repolist$O $(OBJDIR)\report$O $(OBJDIR)\rss$O $(OBJDIR)\schema$O $(OBJDIR)\search$O $(OBJDIR)\security_audit$O $(OBJDIR)\setup$O $(OBJDIR)\setupuser$O $(OBJDIR)\sha1$O $(OBJDIR)\sha1hard$O $(OBJDIR)\sha3$O $(OBJDIR)\shun$O $(OBJDIR)\sitemap$O $(OBJDIR)\skins$O $(OBJDIR)\smtp$O $(OBJDIR)\sqlcmd$O $(OBJDIR)\stash$O $(OBJDIR)\stat$O $(OBJDIR)\statrep$O $(OBJDIR)\style$O $(OBJDIR)\sync$O $(OBJDIR)\tag$O $(OBJDIR)\tar$O $(OBJDIR)\terminal$O $(OBJDIR)\th_main$O $(OBJDIR)\timeline$O $(OBJDIR)\tkt$O $(OBJDIR)\tktsetup$O $(OBJDIR)\undo$O $(OBJDIR)\unicode$O $(OBJDIR)\unversioned$O $(OBJDIR)\update$O $(OBJDIR)\url$O $(OBJDIR)\user$O $(OBJDIR)\utf8$O $(OBJDIR)\util$O $(OBJDIR)\verify$O $(OBJDIR)\vfile$O $(OBJDIR)\webmail$O $(OBJDIR)\wiki$O $(OBJDIR)\wikiformat$O $(OBJDIR)\winfile$O $(OBJDIR)\winhttp$O $(OBJDIR)\xfer$O $(OBJDIR)\xfersetup$O $(OBJDIR)\zip$O $(OBJDIR)\shell$O $(OBJDIR)\sqlite3$O $(OBJDIR)\th$O $(OBJDIR)\th_lang$O
3636
3737
3838
RC=$(DMDIR)\bin\rcc
3939
RCFLAGS=-32 -w1 -I$(SRCDIR) /D__DMC__
4040
@@ -49,11 +49,11 @@
4949
5050
$(OBJDIR)\fossil.res: $B\win\fossil.rc
5151
$(RC) $(RCFLAGS) -o$@ $**
5252
5353
$(OBJDIR)\link: $B\win\Makefile.dmc $(OBJDIR)\fossil.res
54
- +echo add ajax alerts allrepo attach backlink backoffice bag bisect blob branch browse builtin bundle cache capabilities captcha cgi checkin checkout clearsign clone comformat configure content cookies db delta deltacmd deltafunc descendants diff diffcmd dispatch doc encode etag event export extcgi file fileedit finfo foci forum fshell fusefs fuzz glob graph gzip hname hook http http_socket http_ssl http_transport import info interwiki json json_artifact json_branch json_config json_diff json_dir json_finfo json_login json_query json_report json_status json_tag json_timeline json_user json_wiki leaf loadctrl login lookslike main manifest markdown markdown_html md5 merge merge3 moderate name path piechart pikchr pikchrshow pivot popen pqueue printf publish purge rebuild regexp repolist report rss schema search security_audit setup setupuser sha1 sha1hard sha3 shun sitemap skins smtp sqlcmd stash stat statrep style sync tag tar terminal th_main timeline tkt tktsetup undo unicode unversioned update url user utf8 util verify vfile webmail wiki wikiformat winfile winhttp xfer xfersetup zip shell sqlite3 th th_lang > $@
54
+ +echo add ajax alerts allrepo attach backlink backoffice bag bisect blob branch browse builtin bundle cache capabilities captcha cgi chat checkin checkout clearsign clone comformat configure content cookies db delta deltacmd deltafunc descendants diff diffcmd dispatch doc encode etag event export extcgi file fileedit finfo foci forum fshell fusefs fuzz glob graph gzip hname hook http http_socket http_ssl http_transport import info interwiki json json_artifact json_branch json_config json_diff json_dir json_finfo json_login json_query json_report json_status json_tag json_timeline json_user json_wiki leaf loadctrl login lookslike main manifest markdown markdown_html md5 merge merge3 moderate name path piechart pikchr pikchrshow pivot popen pqueue printf publish purge rebuild regexp repolist report rss schema search security_audit setup setupuser sha1 sha1hard sha3 shun sitemap skins smtp sqlcmd stash stat statrep style sync tag tar terminal th_main timeline tkt tktsetup undo unicode unversioned update url user utf8 util verify vfile webmail wiki wikiformat winfile winhttp xfer xfersetup zip shell sqlite3 th th_lang > $@
5555
+echo fossil >> $@
5656
+echo fossil >> $@
5757
+echo $(LIBS) >> $@
5858
+echo. >> $@
5959
+echo fossil >> $@
@@ -229,10 +229,16 @@
229229
$(OBJDIR)\cgi$O : cgi_.c cgi.h
230230
$(TCC) -o$@ -c cgi_.c
231231
232232
cgi_.c : $(SRCDIR)\cgi.c
233233
+translate$E $** > $@
234
+
235
+$(OBJDIR)\chat$O : chat_.c chat.h
236
+ $(TCC) -o$@ -c chat_.c
237
+
238
+chat_.c : $(SRCDIR)\chat.c
239
+ +translate$E $** > $@
234240
235241
$(OBJDIR)\checkin$O : checkin_.c checkin.h
236242
$(TCC) -o$@ -c checkin_.c
237243
238244
checkin_.c : $(SRCDIR)\checkin.c
@@ -999,7 +1005,7 @@
9991005
10001006
zip_.c : $(SRCDIR)\zip.c
10011007
+translate$E $** > $@
10021008
10031009
headers: makeheaders$E page_index.h builtin_data.h VERSION.h
1004
- +makeheaders$E add_.c:add.h ajax_.c:ajax.h alerts_.c:alerts.h allrepo_.c:allrepo.h attach_.c:attach.h backlink_.c:backlink.h backoffice_.c:backoffice.h bag_.c:bag.h bisect_.c:bisect.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h builtin_.c:builtin.h bundle_.c:bundle.h cache_.c:cache.h capabilities_.c:capabilities.h captcha_.c:captcha.h cgi_.c:cgi.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h comformat_.c:comformat.h configure_.c:configure.h content_.c:content.h cookies_.c:cookies.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h deltafunc_.c:deltafunc.h descendants_.c:descendants.h diff_.c:diff.h diffcmd_.c:diffcmd.h dispatch_.c:dispatch.h doc_.c:doc.h encode_.c:encode.h etag_.c:etag.h event_.c:event.h export_.c:export.h extcgi_.c:extcgi.h file_.c:file.h fileedit_.c:fileedit.h finfo_.c:finfo.h foci_.c:foci.h forum_.c:forum.h fshell_.c:fshell.h fusefs_.c:fusefs.h fuzz_.c:fuzz.h glob_.c:glob.h graph_.c:graph.h gzip_.c:gzip.h hname_.c:hname.h hook_.c:hook.h http_.c:http.h http_socket_.c:http_socket.h http_ssl_.c:http_ssl.h http_transport_.c:http_transport.h import_.c:import.h info_.c:info.h interwiki_.c:interwiki.h json_.c:json.h json_artifact_.c:json_artifact.h json_branch_.c:json_branch.h json_config_.c:json_config.h json_diff_.c:json_diff.h json_dir_.c:json_dir.h json_finfo_.c:json_finfo.h json_login_.c:json_login.h json_query_.c:json_query.h json_report_.c:json_report.h json_status_.c:json_status.h json_tag_.c:json_tag.h json_timeline_.c:json_timeline.h json_user_.c:json_user.h json_wiki_.c:json_wiki.h leaf_.c:leaf.h loadctrl_.c:loadctrl.h login_.c:login.h lookslike_.c:lookslike.h main_.c:main.h manifest_.c:manifest.h markdown_.c:markdown.h markdown_html_.c:markdown_html.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h moderate_.c:moderate.h name_.c:name.h path_.c:path.h piechart_.c:piechart.h pikchr_.c:pikchr.h pikchrshow_.c:pikchrshow.h pivot_.c:pivot.h popen_.c:popen.h pqueue_.c:pqueue.h printf_.c:printf.h publish_.c:publish.h purge_.c:purge.h rebuild_.c:rebuild.h regexp_.c:regexp.h repolist_.c:repolist.h report_.c:report.h rss_.c:rss.h schema_.c:schema.h search_.c:search.h security_audit_.c:security_audit.h setup_.c:setup.h setupuser_.c:setupuser.h sha1_.c:sha1.h sha1hard_.c:sha1hard.h sha3_.c:sha3.h shun_.c:shun.h sitemap_.c:sitemap.h skins_.c:skins.h smtp_.c:smtp.h sqlcmd_.c:sqlcmd.h stash_.c:stash.h stat_.c:stat.h statrep_.c:statrep.h style_.c:style.h sync_.c:sync.h tag_.c:tag.h tar_.c:tar.h terminal_.c:terminal.h th_main_.c:th_main.h timeline_.c:timeline.h tkt_.c:tkt.h tktsetup_.c:tktsetup.h undo_.c:undo.h unicode_.c:unicode.h unversioned_.c:unversioned.h update_.c:update.h url_.c:url.h user_.c:user.h utf8_.c:utf8.h util_.c:util.h verify_.c:verify.h vfile_.c:vfile.h webmail_.c:webmail.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h winfile_.c:winfile.h winhttp_.c:winhttp.h xfer_.c:xfer.h xfersetup_.c:xfersetup.h zip_.c:zip.h $(SRCDIR)\sqlite3.h $(SRCDIR)\th.h VERSION.h $(SRCDIR)\cson_amalgamation.h
1010
+ +makeheaders$E add_.c:add.h ajax_.c:ajax.h alerts_.c:alerts.h allrepo_.c:allrepo.h attach_.c:attach.h backlink_.c:backlink.h backoffice_.c:backoffice.h bag_.c:bag.h bisect_.c:bisect.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h builtin_.c:builtin.h bundle_.c:bundle.h cache_.c:cache.h capabilities_.c:capabilities.h captcha_.c:captcha.h cgi_.c:cgi.h chat_.c:chat.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h comformat_.c:comformat.h configure_.c:configure.h content_.c:content.h cookies_.c:cookies.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h deltafunc_.c:deltafunc.h descendants_.c:descendants.h diff_.c:diff.h diffcmd_.c:diffcmd.h dispatch_.c:dispatch.h doc_.c:doc.h encode_.c:encode.h etag_.c:etag.h event_.c:event.h export_.c:export.h extcgi_.c:extcgi.h file_.c:file.h fileedit_.c:fileedit.h finfo_.c:finfo.h foci_.c:foci.h forum_.c:forum.h fshell_.c:fshell.h fusefs_.c:fusefs.h fuzz_.c:fuzz.h glob_.c:glob.h graph_.c:graph.h gzip_.c:gzip.h hname_.c:hname.h hook_.c:hook.h http_.c:http.h http_socket_.c:http_socket.h http_ssl_.c:http_ssl.h http_transport_.c:http_transport.h import_.c:import.h info_.c:info.h interwiki_.c:interwiki.h json_.c:json.h json_artifact_.c:json_artifact.h json_branch_.c:json_branch.h json_config_.c:json_config.h json_diff_.c:json_diff.h json_dir_.c:json_dir.h json_finfo_.c:json_finfo.h json_login_.c:json_login.h json_query_.c:json_query.h json_report_.c:json_report.h json_status_.c:json_status.h json_tag_.c:json_tag.h json_timeline_.c:json_timeline.h json_user_.c:json_user.h json_wiki_.c:json_wiki.h leaf_.c:leaf.h loadctrl_.c:loadctrl.h login_.c:login.h lookslike_.c:lookslike.h main_.c:main.h manifest_.c:manifest.h markdown_.c:markdown.h markdown_html_.c:markdown_html.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h moderate_.c:moderate.h name_.c:name.h path_.c:path.h piechart_.c:piechart.h pikchr_.c:pikchr.h pikchrshow_.c:pikchrshow.h pivot_.c:pivot.h popen_.c:popen.h pqueue_.c:pqueue.h printf_.c:printf.h publish_.c:publish.h purge_.c:purge.h rebuild_.c:rebuild.h regexp_.c:regexp.h repolist_.c:repolist.h report_.c:report.h rss_.c:rss.h schema_.c:schema.h search_.c:search.h security_audit_.c:security_audit.h setup_.c:setup.h setupuser_.c:setupuser.h sha1_.c:sha1.h sha1hard_.c:sha1hard.h sha3_.c:sha3.h shun_.c:shun.h sitemap_.c:sitemap.h skins_.c:skins.h smtp_.c:smtp.h sqlcmd_.c:sqlcmd.h stash_.c:stash.h stat_.c:stat.h statrep_.c:statrep.h style_.c:style.h sync_.c:sync.h tag_.c:tag.h tar_.c:tar.h terminal_.c:terminal.h th_main_.c:th_main.h timeline_.c:timeline.h tkt_.c:tkt.h tktsetup_.c:tktsetup.h undo_.c:undo.h unicode_.c:unicode.h unversioned_.c:unversioned.h update_.c:update.h url_.c:url.h user_.c:user.h utf8_.c:utf8.h util_.c:util.h verify_.c:verify.h vfile_.c:vfile.h webmail_.c:webmail.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h winfile_.c:winfile.h winhttp_.c:winhttp.h xfer_.c:xfer.h xfersetup_.c:xfersetup.h zip_.c:zip.h $(SRCDIR)\sqlite3.h $(SRCDIR)\th.h VERSION.h $(SRCDIR)\cson_amalgamation.h
10051011
@copy /Y nul: headers
10061012
--- win/Makefile.dmc
+++ win/Makefile.dmc
@@ -28,13 +28,13 @@
28
29 SQLITE_OPTIONS = -DNDEBUG=1 -DSQLITE_DQS=0 -DSQLITE_THREADSAFE=0 -DSQLITE_DEFAULT_MEMSTATUS=0 -DSQLITE_DEFAULT_WAL_SYNCHRONOUS=1 -DSQLITE_LIKE_DOESNT_MATCH_BLOBS -DSQLITE_OMIT_DECLTYPE -DSQLITE_OMIT_DEPRECATED -DSQLITE_OMIT_PROGRESS_CALLBACK -DSQLITE_OMIT_SHARED_CACHE -DSQLITE_OMIT_LOAD_EXTENSION -DSQLITE_MAX_EXPR_DEPTH=0 -DSQLITE_USE_ALLOCA -DSQLITE_ENABLE_LOCKING_STYLE=0 -DSQLITE_DEFAULT_FILE_FORMAT=4 -DSQLITE_ENABLE_EXPLAIN_COMMENTS -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_DBSTAT_VTAB -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_FTS5 -DSQLITE_ENABLE_STMTVTAB -DSQLITE_HAVE_ZLIB -DSQLITE_INTROSPECTION_PRAGMAS -DSQLITE_ENABLE_DBPAGE_VTAB -DSQLITE_TRUSTED_SCHEMA=0
30
31 SHELL_OPTIONS = -DNDEBUG=1 -DSQLITE_DQS=0 -DSQLITE_THREADSAFE=0 -DSQLITE_DEFAULT_MEMSTATUS=0 -DSQLITE_DEFAULT_WAL_SYNCHRONOUS=1 -DSQLITE_LIKE_DOESNT_MATCH_BLOBS -DSQLITE_OMIT_DECLTYPE -DSQLITE_OMIT_DEPRECATED -DSQLITE_OMIT_PROGRESS_CALLBACK -DSQLITE_OMIT_SHARED_CACHE -DSQLITE_OMIT_LOAD_EXTENSION -DSQLITE_MAX_EXPR_DEPTH=0 -DSQLITE_USE_ALLOCA -DSQLITE_ENABLE_LOCKING_STYLE=0 -DSQLITE_DEFAULT_FILE_FORMAT=4 -DSQLITE_ENABLE_EXPLAIN_COMMENTS -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_DBSTAT_VTAB -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_FTS5 -DSQLITE_ENABLE_STMTVTAB -DSQLITE_HAVE_ZLIB -DSQLITE_INTROSPECTION_PRAGMAS -DSQLITE_ENABLE_DBPAGE_VTAB -DSQLITE_TRUSTED_SCHEMA=0 -Dmain=sqlite3_shell -DSQLITE_SHELL_IS_UTF8=1 -DSQLITE_OMIT_LOAD_EXTENSION=1 -DUSE_SYSTEM_SQLITE=$(USE_SYSTEM_SQLITE) -DSQLITE_SHELL_DBNAME_PROC=sqlcmd_get_dbname -DSQLITE_SHELL_INIT_PROC=sqlcmd_init_proc -Daccess=file_access -Dsystem=fossil_system -Dgetenv=fossil_getenv -Dfopen=fossil_fopen
32
33 SRC = add_.c ajax_.c alerts_.c allrepo_.c attach_.c backlink_.c backoffice_.c bag_.c bisect_.c blob_.c branch_.c browse_.c builtin_.c bundle_.c cache_.c capabilities_.c captcha_.c cgi_.c checkin_.c checkout_.c clearsign_.c clone_.c comformat_.c configure_.c content_.c cookies_.c db_.c delta_.c deltacmd_.c deltafunc_.c descendants_.c diff_.c diffcmd_.c dispatch_.c doc_.c encode_.c etag_.c event_.c export_.c extcgi_.c file_.c fileedit_.c finfo_.c foci_.c forum_.c fshell_.c fusefs_.c fuzz_.c glob_.c graph_.c gzip_.c hname_.c hook_.c http_.c http_socket_.c http_ssl_.c http_transport_.c import_.c info_.c interwiki_.c json_.c json_artifact_.c json_branch_.c json_config_.c json_diff_.c json_dir_.c json_finfo_.c json_login_.c json_query_.c json_report_.c json_status_.c json_tag_.c json_timeline_.c json_user_.c json_wiki_.c leaf_.c loadctrl_.c login_.c lookslike_.c main_.c manifest_.c markdown_.c markdown_html_.c md5_.c merge_.c merge3_.c moderate_.c name_.c path_.c piechart_.c pikchr_.c pikchrshow_.c pivot_.c popen_.c pqueue_.c printf_.c publish_.c purge_.c rebuild_.c regexp_.c repolist_.c report_.c rss_.c schema_.c search_.c security_audit_.c setup_.c setupuser_.c sha1_.c sha1hard_.c sha3_.c shun_.c sitemap_.c skins_.c smtp_.c sqlcmd_.c stash_.c stat_.c statrep_.c style_.c sync_.c tag_.c tar_.c terminal_.c th_main_.c timeline_.c tkt_.c tktsetup_.c undo_.c unicode_.c unversioned_.c update_.c url_.c user_.c utf8_.c util_.c verify_.c vfile_.c webmail_.c wiki_.c wikiformat_.c winfile_.c winhttp_.c xfer_.c xfersetup_.c zip_.c
34
35 OBJ = $(OBJDIR)\add$O $(OBJDIR)\ajax$O $(OBJDIR)\alerts$O $(OBJDIR)\allrepo$O $(OBJDIR)\attach$O $(OBJDIR)\backlink$O $(OBJDIR)\backoffice$O $(OBJDIR)\bag$O $(OBJDIR)\bisect$O $(OBJDIR)\blob$O $(OBJDIR)\branch$O $(OBJDIR)\browse$O $(OBJDIR)\builtin$O $(OBJDIR)\bundle$O $(OBJDIR)\cache$O $(OBJDIR)\capabilities$O $(OBJDIR)\captcha$O $(OBJDIR)\cgi$O $(OBJDIR)\checkin$O $(OBJDIR)\checkout$O $(OBJDIR)\clearsign$O $(OBJDIR)\clone$O $(OBJDIR)\comformat$O $(OBJDIR)\configure$O $(OBJDIR)\content$O $(OBJDIR)\cookies$O $(OBJDIR)\db$O $(OBJDIR)\delta$O $(OBJDIR)\deltacmd$O $(OBJDIR)\deltafunc$O $(OBJDIR)\descendants$O $(OBJDIR)\diff$O $(OBJDIR)\diffcmd$O $(OBJDIR)\dispatch$O $(OBJDIR)\doc$O $(OBJDIR)\encode$O $(OBJDIR)\etag$O $(OBJDIR)\event$O $(OBJDIR)\export$O $(OBJDIR)\extcgi$O $(OBJDIR)\file$O $(OBJDIR)\fileedit$O $(OBJDIR)\finfo$O $(OBJDIR)\foci$O $(OBJDIR)\forum$O $(OBJDIR)\fshell$O $(OBJDIR)\fusefs$O $(OBJDIR)\fuzz$O $(OBJDIR)\glob$O $(OBJDIR)\graph$O $(OBJDIR)\gzip$O $(OBJDIR)\hname$O $(OBJDIR)\hook$O $(OBJDIR)\http$O $(OBJDIR)\http_socket$O $(OBJDIR)\http_ssl$O $(OBJDIR)\http_transport$O $(OBJDIR)\import$O $(OBJDIR)\info$O $(OBJDIR)\interwiki$O $(OBJDIR)\json$O $(OBJDIR)\json_artifact$O $(OBJDIR)\json_branch$O $(OBJDIR)\json_config$O $(OBJDIR)\json_diff$O $(OBJDIR)\json_dir$O $(OBJDIR)\json_finfo$O $(OBJDIR)\json_login$O $(OBJDIR)\json_query$O $(OBJDIR)\json_report$O $(OBJDIR)\json_status$O $(OBJDIR)\json_tag$O $(OBJDIR)\json_timeline$O $(OBJDIR)\json_user$O $(OBJDIR)\json_wiki$O $(OBJDIR)\leaf$O $(OBJDIR)\loadctrl$O $(OBJDIR)\login$O $(OBJDIR)\lookslike$O $(OBJDIR)\main$O $(OBJDIR)\manifest$O $(OBJDIR)\markdown$O $(OBJDIR)\markdown_html$O $(OBJDIR)\md5$O $(OBJDIR)\merge$O $(OBJDIR)\merge3$O $(OBJDIR)\moderate$O $(OBJDIR)\name$O $(OBJDIR)\path$O $(OBJDIR)\piechart$O $(OBJDIR)\pikchr$O $(OBJDIR)\pikchrshow$O $(OBJDIR)\pivot$O $(OBJDIR)\popen$O $(OBJDIR)\pqueue$O $(OBJDIR)\printf$O $(OBJDIR)\publish$O $(OBJDIR)\purge$O $(OBJDIR)\rebuild$O $(OBJDIR)\regexp$O $(OBJDIR)\repolist$O $(OBJDIR)\report$O $(OBJDIR)\rss$O $(OBJDIR)\schema$O $(OBJDIR)\search$O $(OBJDIR)\security_audit$O $(OBJDIR)\setup$O $(OBJDIR)\setupuser$O $(OBJDIR)\sha1$O $(OBJDIR)\sha1hard$O $(OBJDIR)\sha3$O $(OBJDIR)\shun$O $(OBJDIR)\sitemap$O $(OBJDIR)\skins$O $(OBJDIR)\smtp$O $(OBJDIR)\sqlcmd$O $(OBJDIR)\stash$O $(OBJDIR)\stat$O $(OBJDIR)\statrep$O $(OBJDIR)\style$O $(OBJDIR)\sync$O $(OBJDIR)\tag$O $(OBJDIR)\tar$O $(OBJDIR)\terminal$O $(OBJDIR)\th_main$O $(OBJDIR)\timeline$O $(OBJDIR)\tkt$O $(OBJDIR)\tktsetup$O $(OBJDIR)\undo$O $(OBJDIR)\unicode$O $(OBJDIR)\unversioned$O $(OBJDIR)\update$O $(OBJDIR)\url$O $(OBJDIR)\user$O $(OBJDIR)\utf8$O $(OBJDIR)\util$O $(OBJDIR)\verify$O $(OBJDIR)\vfile$O $(OBJDIR)\webmail$O $(OBJDIR)\wiki$O $(OBJDIR)\wikiformat$O $(OBJDIR)\winfile$O $(OBJDIR)\winhttp$O $(OBJDIR)\xfer$O $(OBJDIR)\xfersetup$O $(OBJDIR)\zip$O $(OBJDIR)\shell$O $(OBJDIR)\sqlite3$O $(OBJDIR)\th$O $(OBJDIR)\th_lang$O
36
37
38 RC=$(DMDIR)\bin\rcc
39 RCFLAGS=-32 -w1 -I$(SRCDIR) /D__DMC__
40
@@ -49,11 +49,11 @@
49
50 $(OBJDIR)\fossil.res: $B\win\fossil.rc
51 $(RC) $(RCFLAGS) -o$@ $**
52
53 $(OBJDIR)\link: $B\win\Makefile.dmc $(OBJDIR)\fossil.res
54 +echo add ajax alerts allrepo attach backlink backoffice bag bisect blob branch browse builtin bundle cache capabilities captcha cgi checkin checkout clearsign clone comformat configure content cookies db delta deltacmd deltafunc descendants diff diffcmd dispatch doc encode etag event export extcgi file fileedit finfo foci forum fshell fusefs fuzz glob graph gzip hname hook http http_socket http_ssl http_transport import info interwiki json json_artifact json_branch json_config json_diff json_dir json_finfo json_login json_query json_report json_status json_tag json_timeline json_user json_wiki leaf loadctrl login lookslike main manifest markdown markdown_html md5 merge merge3 moderate name path piechart pikchr pikchrshow pivot popen pqueue printf publish purge rebuild regexp repolist report rss schema search security_audit setup setupuser sha1 sha1hard sha3 shun sitemap skins smtp sqlcmd stash stat statrep style sync tag tar terminal th_main timeline tkt tktsetup undo unicode unversioned update url user utf8 util verify vfile webmail wiki wikiformat winfile winhttp xfer xfersetup zip shell sqlite3 th th_lang > $@
55 +echo fossil >> $@
56 +echo fossil >> $@
57 +echo $(LIBS) >> $@
58 +echo. >> $@
59 +echo fossil >> $@
@@ -229,10 +229,16 @@
229 $(OBJDIR)\cgi$O : cgi_.c cgi.h
230 $(TCC) -o$@ -c cgi_.c
231
232 cgi_.c : $(SRCDIR)\cgi.c
233 +translate$E $** > $@
 
 
 
 
 
 
234
235 $(OBJDIR)\checkin$O : checkin_.c checkin.h
236 $(TCC) -o$@ -c checkin_.c
237
238 checkin_.c : $(SRCDIR)\checkin.c
@@ -999,7 +1005,7 @@
999
1000 zip_.c : $(SRCDIR)\zip.c
1001 +translate$E $** > $@
1002
1003 headers: makeheaders$E page_index.h builtin_data.h VERSION.h
1004 +makeheaders$E add_.c:add.h ajax_.c:ajax.h alerts_.c:alerts.h allrepo_.c:allrepo.h attach_.c:attach.h backlink_.c:backlink.h backoffice_.c:backoffice.h bag_.c:bag.h bisect_.c:bisect.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h builtin_.c:builtin.h bundle_.c:bundle.h cache_.c:cache.h capabilities_.c:capabilities.h captcha_.c:captcha.h cgi_.c:cgi.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h comformat_.c:comformat.h configure_.c:configure.h content_.c:content.h cookies_.c:cookies.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h deltafunc_.c:deltafunc.h descendants_.c:descendants.h diff_.c:diff.h diffcmd_.c:diffcmd.h dispatch_.c:dispatch.h doc_.c:doc.h encode_.c:encode.h etag_.c:etag.h event_.c:event.h export_.c:export.h extcgi_.c:extcgi.h file_.c:file.h fileedit_.c:fileedit.h finfo_.c:finfo.h foci_.c:foci.h forum_.c:forum.h fshell_.c:fshell.h fusefs_.c:fusefs.h fuzz_.c:fuzz.h glob_.c:glob.h graph_.c:graph.h gzip_.c:gzip.h hname_.c:hname.h hook_.c:hook.h http_.c:http.h http_socket_.c:http_socket.h http_ssl_.c:http_ssl.h http_transport_.c:http_transport.h import_.c:import.h info_.c:info.h interwiki_.c:interwiki.h json_.c:json.h json_artifact_.c:json_artifact.h json_branch_.c:json_branch.h json_config_.c:json_config.h json_diff_.c:json_diff.h json_dir_.c:json_dir.h json_finfo_.c:json_finfo.h json_login_.c:json_login.h json_query_.c:json_query.h json_report_.c:json_report.h json_status_.c:json_status.h json_tag_.c:json_tag.h json_timeline_.c:json_timeline.h json_user_.c:json_user.h json_wiki_.c:json_wiki.h leaf_.c:leaf.h loadctrl_.c:loadctrl.h login_.c:login.h lookslike_.c:lookslike.h main_.c:main.h manifest_.c:manifest.h markdown_.c:markdown.h markdown_html_.c:markdown_html.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h moderate_.c:moderate.h name_.c:name.h path_.c:path.h piechart_.c:piechart.h pikchr_.c:pikchr.h pikchrshow_.c:pikchrshow.h pivot_.c:pivot.h popen_.c:popen.h pqueue_.c:pqueue.h printf_.c:printf.h publish_.c:publish.h purge_.c:purge.h rebuild_.c:rebuild.h regexp_.c:regexp.h repolist_.c:repolist.h report_.c:report.h rss_.c:rss.h schema_.c:schema.h search_.c:search.h security_audit_.c:security_audit.h setup_.c:setup.h setupuser_.c:setupuser.h sha1_.c:sha1.h sha1hard_.c:sha1hard.h sha3_.c:sha3.h shun_.c:shun.h sitemap_.c:sitemap.h skins_.c:skins.h smtp_.c:smtp.h sqlcmd_.c:sqlcmd.h stash_.c:stash.h stat_.c:stat.h statrep_.c:statrep.h style_.c:style.h sync_.c:sync.h tag_.c:tag.h tar_.c:tar.h terminal_.c:terminal.h th_main_.c:th_main.h timeline_.c:timeline.h tkt_.c:tkt.h tktsetup_.c:tktsetup.h undo_.c:undo.h unicode_.c:unicode.h unversioned_.c:unversioned.h update_.c:update.h url_.c:url.h user_.c:user.h utf8_.c:utf8.h util_.c:util.h verify_.c:verify.h vfile_.c:vfile.h webmail_.c:webmail.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h winfile_.c:winfile.h winhttp_.c:winhttp.h xfer_.c:xfer.h xfersetup_.c:xfersetup.h zip_.c:zip.h $(SRCDIR)\sqlite3.h $(SRCDIR)\th.h VERSION.h $(SRCDIR)\cson_amalgamation.h
1005 @copy /Y nul: headers
1006
--- win/Makefile.dmc
+++ win/Makefile.dmc
@@ -28,13 +28,13 @@
28
29 SQLITE_OPTIONS = -DNDEBUG=1 -DSQLITE_DQS=0 -DSQLITE_THREADSAFE=0 -DSQLITE_DEFAULT_MEMSTATUS=0 -DSQLITE_DEFAULT_WAL_SYNCHRONOUS=1 -DSQLITE_LIKE_DOESNT_MATCH_BLOBS -DSQLITE_OMIT_DECLTYPE -DSQLITE_OMIT_DEPRECATED -DSQLITE_OMIT_PROGRESS_CALLBACK -DSQLITE_OMIT_SHARED_CACHE -DSQLITE_OMIT_LOAD_EXTENSION -DSQLITE_MAX_EXPR_DEPTH=0 -DSQLITE_USE_ALLOCA -DSQLITE_ENABLE_LOCKING_STYLE=0 -DSQLITE_DEFAULT_FILE_FORMAT=4 -DSQLITE_ENABLE_EXPLAIN_COMMENTS -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_DBSTAT_VTAB -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_FTS5 -DSQLITE_ENABLE_STMTVTAB -DSQLITE_HAVE_ZLIB -DSQLITE_INTROSPECTION_PRAGMAS -DSQLITE_ENABLE_DBPAGE_VTAB -DSQLITE_TRUSTED_SCHEMA=0
30
31 SHELL_OPTIONS = -DNDEBUG=1 -DSQLITE_DQS=0 -DSQLITE_THREADSAFE=0 -DSQLITE_DEFAULT_MEMSTATUS=0 -DSQLITE_DEFAULT_WAL_SYNCHRONOUS=1 -DSQLITE_LIKE_DOESNT_MATCH_BLOBS -DSQLITE_OMIT_DECLTYPE -DSQLITE_OMIT_DEPRECATED -DSQLITE_OMIT_PROGRESS_CALLBACK -DSQLITE_OMIT_SHARED_CACHE -DSQLITE_OMIT_LOAD_EXTENSION -DSQLITE_MAX_EXPR_DEPTH=0 -DSQLITE_USE_ALLOCA -DSQLITE_ENABLE_LOCKING_STYLE=0 -DSQLITE_DEFAULT_FILE_FORMAT=4 -DSQLITE_ENABLE_EXPLAIN_COMMENTS -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_DBSTAT_VTAB -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_FTS5 -DSQLITE_ENABLE_STMTVTAB -DSQLITE_HAVE_ZLIB -DSQLITE_INTROSPECTION_PRAGMAS -DSQLITE_ENABLE_DBPAGE_VTAB -DSQLITE_TRUSTED_SCHEMA=0 -Dmain=sqlite3_shell -DSQLITE_SHELL_IS_UTF8=1 -DSQLITE_OMIT_LOAD_EXTENSION=1 -DUSE_SYSTEM_SQLITE=$(USE_SYSTEM_SQLITE) -DSQLITE_SHELL_DBNAME_PROC=sqlcmd_get_dbname -DSQLITE_SHELL_INIT_PROC=sqlcmd_init_proc -Daccess=file_access -Dsystem=fossil_system -Dgetenv=fossil_getenv -Dfopen=fossil_fopen
32
33 SRC = add_.c ajax_.c alerts_.c allrepo_.c attach_.c backlink_.c backoffice_.c bag_.c bisect_.c blob_.c branch_.c browse_.c builtin_.c bundle_.c cache_.c capabilities_.c captcha_.c cgi_.c chat_.c checkin_.c checkout_.c clearsign_.c clone_.c comformat_.c configure_.c content_.c cookies_.c db_.c delta_.c deltacmd_.c deltafunc_.c descendants_.c diff_.c diffcmd_.c dispatch_.c doc_.c encode_.c etag_.c event_.c export_.c extcgi_.c file_.c fileedit_.c finfo_.c foci_.c forum_.c fshell_.c fusefs_.c fuzz_.c glob_.c graph_.c gzip_.c hname_.c hook_.c http_.c http_socket_.c http_ssl_.c http_transport_.c import_.c info_.c interwiki_.c json_.c json_artifact_.c json_branch_.c json_config_.c json_diff_.c json_dir_.c json_finfo_.c json_login_.c json_query_.c json_report_.c json_status_.c json_tag_.c json_timeline_.c json_user_.c json_wiki_.c leaf_.c loadctrl_.c login_.c lookslike_.c main_.c manifest_.c markdown_.c markdown_html_.c md5_.c merge_.c merge3_.c moderate_.c name_.c path_.c piechart_.c pikchr_.c pikchrshow_.c pivot_.c popen_.c pqueue_.c printf_.c publish_.c purge_.c rebuild_.c regexp_.c repolist_.c report_.c rss_.c schema_.c search_.c security_audit_.c setup_.c setupuser_.c sha1_.c sha1hard_.c sha3_.c shun_.c sitemap_.c skins_.c smtp_.c sqlcmd_.c stash_.c stat_.c statrep_.c style_.c sync_.c tag_.c tar_.c terminal_.c th_main_.c timeline_.c tkt_.c tktsetup_.c undo_.c unicode_.c unversioned_.c update_.c url_.c user_.c utf8_.c util_.c verify_.c vfile_.c webmail_.c wiki_.c wikiformat_.c winfile_.c winhttp_.c xfer_.c xfersetup_.c zip_.c
34
35 OBJ = $(OBJDIR)\add$O $(OBJDIR)\ajax$O $(OBJDIR)\alerts$O $(OBJDIR)\allrepo$O $(OBJDIR)\attach$O $(OBJDIR)\backlink$O $(OBJDIR)\backoffice$O $(OBJDIR)\bag$O $(OBJDIR)\bisect$O $(OBJDIR)\blob$O $(OBJDIR)\branch$O $(OBJDIR)\browse$O $(OBJDIR)\builtin$O $(OBJDIR)\bundle$O $(OBJDIR)\cache$O $(OBJDIR)\capabilities$O $(OBJDIR)\captcha$O $(OBJDIR)\cgi$O $(OBJDIR)\chat$O $(OBJDIR)\checkin$O $(OBJDIR)\checkout$O $(OBJDIR)\clearsign$O $(OBJDIR)\clone$O $(OBJDIR)\comformat$O $(OBJDIR)\configure$O $(OBJDIR)\content$O $(OBJDIR)\cookies$O $(OBJDIR)\db$O $(OBJDIR)\delta$O $(OBJDIR)\deltacmd$O $(OBJDIR)\deltafunc$O $(OBJDIR)\descendants$O $(OBJDIR)\diff$O $(OBJDIR)\diffcmd$O $(OBJDIR)\dispatch$O $(OBJDIR)\doc$O $(OBJDIR)\encode$O $(OBJDIR)\etag$O $(OBJDIR)\event$O $(OBJDIR)\export$O $(OBJDIR)\extcgi$O $(OBJDIR)\file$O $(OBJDIR)\fileedit$O $(OBJDIR)\finfo$O $(OBJDIR)\foci$O $(OBJDIR)\forum$O $(OBJDIR)\fshell$O $(OBJDIR)\fusefs$O $(OBJDIR)\fuzz$O $(OBJDIR)\glob$O $(OBJDIR)\graph$O $(OBJDIR)\gzip$O $(OBJDIR)\hname$O $(OBJDIR)\hook$O $(OBJDIR)\http$O $(OBJDIR)\http_socket$O $(OBJDIR)\http_ssl$O $(OBJDIR)\http_transport$O $(OBJDIR)\import$O $(OBJDIR)\info$O $(OBJDIR)\interwiki$O $(OBJDIR)\json$O $(OBJDIR)\json_artifact$O $(OBJDIR)\json_branch$O $(OBJDIR)\json_config$O $(OBJDIR)\json_diff$O $(OBJDIR)\json_dir$O $(OBJDIR)\json_finfo$O $(OBJDIR)\json_login$O $(OBJDIR)\json_query$O $(OBJDIR)\json_report$O $(OBJDIR)\json_status$O $(OBJDIR)\json_tag$O $(OBJDIR)\json_timeline$O $(OBJDIR)\json_user$O $(OBJDIR)\json_wiki$O $(OBJDIR)\leaf$O $(OBJDIR)\loadctrl$O $(OBJDIR)\login$O $(OBJDIR)\lookslike$O $(OBJDIR)\main$O $(OBJDIR)\manifest$O $(OBJDIR)\markdown$O $(OBJDIR)\markdown_html$O $(OBJDIR)\md5$O $(OBJDIR)\merge$O $(OBJDIR)\merge3$O $(OBJDIR)\moderate$O $(OBJDIR)\name$O $(OBJDIR)\path$O $(OBJDIR)\piechart$O $(OBJDIR)\pikchr$O $(OBJDIR)\pikchrshow$O $(OBJDIR)\pivot$O $(OBJDIR)\popen$O $(OBJDIR)\pqueue$O $(OBJDIR)\printf$O $(OBJDIR)\publish$O $(OBJDIR)\purge$O $(OBJDIR)\rebuild$O $(OBJDIR)\regexp$O $(OBJDIR)\repolist$O $(OBJDIR)\report$O $(OBJDIR)\rss$O $(OBJDIR)\schema$O $(OBJDIR)\search$O $(OBJDIR)\security_audit$O $(OBJDIR)\setup$O $(OBJDIR)\setupuser$O $(OBJDIR)\sha1$O $(OBJDIR)\sha1hard$O $(OBJDIR)\sha3$O $(OBJDIR)\shun$O $(OBJDIR)\sitemap$O $(OBJDIR)\skins$O $(OBJDIR)\smtp$O $(OBJDIR)\sqlcmd$O $(OBJDIR)\stash$O $(OBJDIR)\stat$O $(OBJDIR)\statrep$O $(OBJDIR)\style$O $(OBJDIR)\sync$O $(OBJDIR)\tag$O $(OBJDIR)\tar$O $(OBJDIR)\terminal$O $(OBJDIR)\th_main$O $(OBJDIR)\timeline$O $(OBJDIR)\tkt$O $(OBJDIR)\tktsetup$O $(OBJDIR)\undo$O $(OBJDIR)\unicode$O $(OBJDIR)\unversioned$O $(OBJDIR)\update$O $(OBJDIR)\url$O $(OBJDIR)\user$O $(OBJDIR)\utf8$O $(OBJDIR)\util$O $(OBJDIR)\verify$O $(OBJDIR)\vfile$O $(OBJDIR)\webmail$O $(OBJDIR)\wiki$O $(OBJDIR)\wikiformat$O $(OBJDIR)\winfile$O $(OBJDIR)\winhttp$O $(OBJDIR)\xfer$O $(OBJDIR)\xfersetup$O $(OBJDIR)\zip$O $(OBJDIR)\shell$O $(OBJDIR)\sqlite3$O $(OBJDIR)\th$O $(OBJDIR)\th_lang$O
36
37
38 RC=$(DMDIR)\bin\rcc
39 RCFLAGS=-32 -w1 -I$(SRCDIR) /D__DMC__
40
@@ -49,11 +49,11 @@
49
50 $(OBJDIR)\fossil.res: $B\win\fossil.rc
51 $(RC) $(RCFLAGS) -o$@ $**
52
53 $(OBJDIR)\link: $B\win\Makefile.dmc $(OBJDIR)\fossil.res
54 +echo add ajax alerts allrepo attach backlink backoffice bag bisect blob branch browse builtin bundle cache capabilities captcha cgi chat checkin checkout clearsign clone comformat configure content cookies db delta deltacmd deltafunc descendants diff diffcmd dispatch doc encode etag event export extcgi file fileedit finfo foci forum fshell fusefs fuzz glob graph gzip hname hook http http_socket http_ssl http_transport import info interwiki json json_artifact json_branch json_config json_diff json_dir json_finfo json_login json_query json_report json_status json_tag json_timeline json_user json_wiki leaf loadctrl login lookslike main manifest markdown markdown_html md5 merge merge3 moderate name path piechart pikchr pikchrshow pivot popen pqueue printf publish purge rebuild regexp repolist report rss schema search security_audit setup setupuser sha1 sha1hard sha3 shun sitemap skins smtp sqlcmd stash stat statrep style sync tag tar terminal th_main timeline tkt tktsetup undo unicode unversioned update url user utf8 util verify vfile webmail wiki wikiformat winfile winhttp xfer xfersetup zip shell sqlite3 th th_lang > $@
55 +echo fossil >> $@
56 +echo fossil >> $@
57 +echo $(LIBS) >> $@
58 +echo. >> $@
59 +echo fossil >> $@
@@ -229,10 +229,16 @@
229 $(OBJDIR)\cgi$O : cgi_.c cgi.h
230 $(TCC) -o$@ -c cgi_.c
231
232 cgi_.c : $(SRCDIR)\cgi.c
233 +translate$E $** > $@
234
235 $(OBJDIR)\chat$O : chat_.c chat.h
236 $(TCC) -o$@ -c chat_.c
237
238 chat_.c : $(SRCDIR)\chat.c
239 +translate$E $** > $@
240
241 $(OBJDIR)\checkin$O : checkin_.c checkin.h
242 $(TCC) -o$@ -c checkin_.c
243
244 checkin_.c : $(SRCDIR)\checkin.c
@@ -999,7 +1005,7 @@
1005
1006 zip_.c : $(SRCDIR)\zip.c
1007 +translate$E $** > $@
1008
1009 headers: makeheaders$E page_index.h builtin_data.h VERSION.h
1010 +makeheaders$E add_.c:add.h ajax_.c:ajax.h alerts_.c:alerts.h allrepo_.c:allrepo.h attach_.c:attach.h backlink_.c:backlink.h backoffice_.c:backoffice.h bag_.c:bag.h bisect_.c:bisect.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h builtin_.c:builtin.h bundle_.c:bundle.h cache_.c:cache.h capabilities_.c:capabilities.h captcha_.c:captcha.h cgi_.c:cgi.h chat_.c:chat.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h comformat_.c:comformat.h configure_.c:configure.h content_.c:content.h cookies_.c:cookies.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h deltafunc_.c:deltafunc.h descendants_.c:descendants.h diff_.c:diff.h diffcmd_.c:diffcmd.h dispatch_.c:dispatch.h doc_.c:doc.h encode_.c:encode.h etag_.c:etag.h event_.c:event.h export_.c:export.h extcgi_.c:extcgi.h file_.c:file.h fileedit_.c:fileedit.h finfo_.c:finfo.h foci_.c:foci.h forum_.c:forum.h fshell_.c:fshell.h fusefs_.c:fusefs.h fuzz_.c:fuzz.h glob_.c:glob.h graph_.c:graph.h gzip_.c:gzip.h hname_.c:hname.h hook_.c:hook.h http_.c:http.h http_socket_.c:http_socket.h http_ssl_.c:http_ssl.h http_transport_.c:http_transport.h import_.c:import.h info_.c:info.h interwiki_.c:interwiki.h json_.c:json.h json_artifact_.c:json_artifact.h json_branch_.c:json_branch.h json_config_.c:json_config.h json_diff_.c:json_diff.h json_dir_.c:json_dir.h json_finfo_.c:json_finfo.h json_login_.c:json_login.h json_query_.c:json_query.h json_report_.c:json_report.h json_status_.c:json_status.h json_tag_.c:json_tag.h json_timeline_.c:json_timeline.h json_user_.c:json_user.h json_wiki_.c:json_wiki.h leaf_.c:leaf.h loadctrl_.c:loadctrl.h login_.c:login.h lookslike_.c:lookslike.h main_.c:main.h manifest_.c:manifest.h markdown_.c:markdown.h markdown_html_.c:markdown_html.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h moderate_.c:moderate.h name_.c:name.h path_.c:path.h piechart_.c:piechart.h pikchr_.c:pikchr.h pikchrshow_.c:pikchrshow.h pivot_.c:pivot.h popen_.c:popen.h pqueue_.c:pqueue.h printf_.c:printf.h publish_.c:publish.h purge_.c:purge.h rebuild_.c:rebuild.h regexp_.c:regexp.h repolist_.c:repolist.h report_.c:report.h rss_.c:rss.h schema_.c:schema.h search_.c:search.h security_audit_.c:security_audit.h setup_.c:setup.h setupuser_.c:setupuser.h sha1_.c:sha1.h sha1hard_.c:sha1hard.h sha3_.c:sha3.h shun_.c:shun.h sitemap_.c:sitemap.h skins_.c:skins.h smtp_.c:smtp.h sqlcmd_.c:sqlcmd.h stash_.c:stash.h stat_.c:stat.h statrep_.c:statrep.h style_.c:style.h sync_.c:sync.h tag_.c:tag.h tar_.c:tar.h terminal_.c:terminal.h th_main_.c:th_main.h timeline_.c:timeline.h tkt_.c:tkt.h tktsetup_.c:tktsetup.h undo_.c:undo.h unicode_.c:unicode.h unversioned_.c:unversioned.h update_.c:update.h url_.c:url.h user_.c:user.h utf8_.c:utf8.h util_.c:util.h verify_.c:verify.h vfile_.c:vfile.h webmail_.c:webmail.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h winfile_.c:winfile.h winhttp_.c:winhttp.h xfer_.c:xfer.h xfersetup_.c:xfersetup.h zip_.c:zip.h $(SRCDIR)\sqlite3.h $(SRCDIR)\th.h VERSION.h $(SRCDIR)\cson_amalgamation.h
1011 @copy /Y nul: headers
1012
--- win/Makefile.mingw
+++ win/Makefile.mingw
@@ -444,10 +444,11 @@
444444
$(SRCDIR)/bundle.c \
445445
$(SRCDIR)/cache.c \
446446
$(SRCDIR)/capabilities.c \
447447
$(SRCDIR)/captcha.c \
448448
$(SRCDIR)/cgi.c \
449
+ $(SRCDIR)/chat.c \
449450
$(SRCDIR)/checkin.c \
450451
$(SRCDIR)/checkout.c \
451452
$(SRCDIR)/clearsign.c \
452453
$(SRCDIR)/clone.c \
453454
$(SRCDIR)/comformat.c \
@@ -631,10 +632,11 @@
631632
$(SRCDIR)/../skins/xekri/css.txt \
632633
$(SRCDIR)/../skins/xekri/details.txt \
633634
$(SRCDIR)/../skins/xekri/footer.txt \
634635
$(SRCDIR)/../skins/xekri/header.txt \
635636
$(SRCDIR)/accordion.js \
637
+ $(SRCDIR)/chat.js \
636638
$(SRCDIR)/ci_edit.js \
637639
$(SRCDIR)/copybtn.js \
638640
$(SRCDIR)/default.css \
639641
$(SRCDIR)/diff.tcl \
640642
$(SRCDIR)/forum.js \
@@ -702,10 +704,11 @@
702704
$(OBJDIR)/bundle_.c \
703705
$(OBJDIR)/cache_.c \
704706
$(OBJDIR)/capabilities_.c \
705707
$(OBJDIR)/captcha_.c \
706708
$(OBJDIR)/cgi_.c \
709
+ $(OBJDIR)/chat_.c \
707710
$(OBJDIR)/checkin_.c \
708711
$(OBJDIR)/checkout_.c \
709712
$(OBJDIR)/clearsign_.c \
710713
$(OBJDIR)/clone_.c \
711714
$(OBJDIR)/comformat_.c \
@@ -850,10 +853,11 @@
850853
$(OBJDIR)/bundle.o \
851854
$(OBJDIR)/cache.o \
852855
$(OBJDIR)/capabilities.o \
853856
$(OBJDIR)/captcha.o \
854857
$(OBJDIR)/cgi.o \
858
+ $(OBJDIR)/chat.o \
855859
$(OBJDIR)/checkin.o \
856860
$(OBJDIR)/checkout.o \
857861
$(OBJDIR)/clearsign.o \
858862
$(OBJDIR)/clone.o \
859863
$(OBJDIR)/comformat.o \
@@ -1213,10 +1217,11 @@
12131217
$(OBJDIR)/bundle_.c:$(OBJDIR)/bundle.h \
12141218
$(OBJDIR)/cache_.c:$(OBJDIR)/cache.h \
12151219
$(OBJDIR)/capabilities_.c:$(OBJDIR)/capabilities.h \
12161220
$(OBJDIR)/captcha_.c:$(OBJDIR)/captcha.h \
12171221
$(OBJDIR)/cgi_.c:$(OBJDIR)/cgi.h \
1222
+ $(OBJDIR)/chat_.c:$(OBJDIR)/chat.h \
12181223
$(OBJDIR)/checkin_.c:$(OBJDIR)/checkin.h \
12191224
$(OBJDIR)/checkout_.c:$(OBJDIR)/checkout.h \
12201225
$(OBJDIR)/clearsign_.c:$(OBJDIR)/clearsign.h \
12211226
$(OBJDIR)/clone_.c:$(OBJDIR)/clone.h \
12221227
$(OBJDIR)/comformat_.c:$(OBJDIR)/comformat.h \
@@ -1493,10 +1498,18 @@
14931498
14941499
$(OBJDIR)/cgi.o: $(OBJDIR)/cgi_.c $(OBJDIR)/cgi.h $(SRCDIR)/config.h
14951500
$(XTCC) -o $(OBJDIR)/cgi.o -c $(OBJDIR)/cgi_.c
14961501
14971502
$(OBJDIR)/cgi.h: $(OBJDIR)/headers
1503
+
1504
+$(OBJDIR)/chat_.c: $(SRCDIR)/chat.c $(TRANSLATE)
1505
+ $(TRANSLATE) $(SRCDIR)/chat.c >$@
1506
+
1507
+$(OBJDIR)/chat.o: $(OBJDIR)/chat_.c $(OBJDIR)/chat.h $(SRCDIR)/config.h
1508
+ $(XTCC) -o $(OBJDIR)/chat.o -c $(OBJDIR)/chat_.c
1509
+
1510
+$(OBJDIR)/chat.h: $(OBJDIR)/headers
14981511
14991512
$(OBJDIR)/checkin_.c: $(SRCDIR)/checkin.c $(TRANSLATE)
15001513
$(TRANSLATE) $(SRCDIR)/checkin.c >$@
15011514
15021515
$(OBJDIR)/checkin.o: $(OBJDIR)/checkin_.c $(OBJDIR)/checkin.h $(SRCDIR)/config.h
15031516
--- win/Makefile.mingw
+++ win/Makefile.mingw
@@ -444,10 +444,11 @@
444 $(SRCDIR)/bundle.c \
445 $(SRCDIR)/cache.c \
446 $(SRCDIR)/capabilities.c \
447 $(SRCDIR)/captcha.c \
448 $(SRCDIR)/cgi.c \
 
449 $(SRCDIR)/checkin.c \
450 $(SRCDIR)/checkout.c \
451 $(SRCDIR)/clearsign.c \
452 $(SRCDIR)/clone.c \
453 $(SRCDIR)/comformat.c \
@@ -631,10 +632,11 @@
631 $(SRCDIR)/../skins/xekri/css.txt \
632 $(SRCDIR)/../skins/xekri/details.txt \
633 $(SRCDIR)/../skins/xekri/footer.txt \
634 $(SRCDIR)/../skins/xekri/header.txt \
635 $(SRCDIR)/accordion.js \
 
636 $(SRCDIR)/ci_edit.js \
637 $(SRCDIR)/copybtn.js \
638 $(SRCDIR)/default.css \
639 $(SRCDIR)/diff.tcl \
640 $(SRCDIR)/forum.js \
@@ -702,10 +704,11 @@
702 $(OBJDIR)/bundle_.c \
703 $(OBJDIR)/cache_.c \
704 $(OBJDIR)/capabilities_.c \
705 $(OBJDIR)/captcha_.c \
706 $(OBJDIR)/cgi_.c \
 
707 $(OBJDIR)/checkin_.c \
708 $(OBJDIR)/checkout_.c \
709 $(OBJDIR)/clearsign_.c \
710 $(OBJDIR)/clone_.c \
711 $(OBJDIR)/comformat_.c \
@@ -850,10 +853,11 @@
850 $(OBJDIR)/bundle.o \
851 $(OBJDIR)/cache.o \
852 $(OBJDIR)/capabilities.o \
853 $(OBJDIR)/captcha.o \
854 $(OBJDIR)/cgi.o \
 
855 $(OBJDIR)/checkin.o \
856 $(OBJDIR)/checkout.o \
857 $(OBJDIR)/clearsign.o \
858 $(OBJDIR)/clone.o \
859 $(OBJDIR)/comformat.o \
@@ -1213,10 +1217,11 @@
1213 $(OBJDIR)/bundle_.c:$(OBJDIR)/bundle.h \
1214 $(OBJDIR)/cache_.c:$(OBJDIR)/cache.h \
1215 $(OBJDIR)/capabilities_.c:$(OBJDIR)/capabilities.h \
1216 $(OBJDIR)/captcha_.c:$(OBJDIR)/captcha.h \
1217 $(OBJDIR)/cgi_.c:$(OBJDIR)/cgi.h \
 
1218 $(OBJDIR)/checkin_.c:$(OBJDIR)/checkin.h \
1219 $(OBJDIR)/checkout_.c:$(OBJDIR)/checkout.h \
1220 $(OBJDIR)/clearsign_.c:$(OBJDIR)/clearsign.h \
1221 $(OBJDIR)/clone_.c:$(OBJDIR)/clone.h \
1222 $(OBJDIR)/comformat_.c:$(OBJDIR)/comformat.h \
@@ -1493,10 +1498,18 @@
1493
1494 $(OBJDIR)/cgi.o: $(OBJDIR)/cgi_.c $(OBJDIR)/cgi.h $(SRCDIR)/config.h
1495 $(XTCC) -o $(OBJDIR)/cgi.o -c $(OBJDIR)/cgi_.c
1496
1497 $(OBJDIR)/cgi.h: $(OBJDIR)/headers
 
 
 
 
 
 
 
 
1498
1499 $(OBJDIR)/checkin_.c: $(SRCDIR)/checkin.c $(TRANSLATE)
1500 $(TRANSLATE) $(SRCDIR)/checkin.c >$@
1501
1502 $(OBJDIR)/checkin.o: $(OBJDIR)/checkin_.c $(OBJDIR)/checkin.h $(SRCDIR)/config.h
1503
--- win/Makefile.mingw
+++ win/Makefile.mingw
@@ -444,10 +444,11 @@
444 $(SRCDIR)/bundle.c \
445 $(SRCDIR)/cache.c \
446 $(SRCDIR)/capabilities.c \
447 $(SRCDIR)/captcha.c \
448 $(SRCDIR)/cgi.c \
449 $(SRCDIR)/chat.c \
450 $(SRCDIR)/checkin.c \
451 $(SRCDIR)/checkout.c \
452 $(SRCDIR)/clearsign.c \
453 $(SRCDIR)/clone.c \
454 $(SRCDIR)/comformat.c \
@@ -631,10 +632,11 @@
632 $(SRCDIR)/../skins/xekri/css.txt \
633 $(SRCDIR)/../skins/xekri/details.txt \
634 $(SRCDIR)/../skins/xekri/footer.txt \
635 $(SRCDIR)/../skins/xekri/header.txt \
636 $(SRCDIR)/accordion.js \
637 $(SRCDIR)/chat.js \
638 $(SRCDIR)/ci_edit.js \
639 $(SRCDIR)/copybtn.js \
640 $(SRCDIR)/default.css \
641 $(SRCDIR)/diff.tcl \
642 $(SRCDIR)/forum.js \
@@ -702,10 +704,11 @@
704 $(OBJDIR)/bundle_.c \
705 $(OBJDIR)/cache_.c \
706 $(OBJDIR)/capabilities_.c \
707 $(OBJDIR)/captcha_.c \
708 $(OBJDIR)/cgi_.c \
709 $(OBJDIR)/chat_.c \
710 $(OBJDIR)/checkin_.c \
711 $(OBJDIR)/checkout_.c \
712 $(OBJDIR)/clearsign_.c \
713 $(OBJDIR)/clone_.c \
714 $(OBJDIR)/comformat_.c \
@@ -850,10 +853,11 @@
853 $(OBJDIR)/bundle.o \
854 $(OBJDIR)/cache.o \
855 $(OBJDIR)/capabilities.o \
856 $(OBJDIR)/captcha.o \
857 $(OBJDIR)/cgi.o \
858 $(OBJDIR)/chat.o \
859 $(OBJDIR)/checkin.o \
860 $(OBJDIR)/checkout.o \
861 $(OBJDIR)/clearsign.o \
862 $(OBJDIR)/clone.o \
863 $(OBJDIR)/comformat.o \
@@ -1213,10 +1217,11 @@
1217 $(OBJDIR)/bundle_.c:$(OBJDIR)/bundle.h \
1218 $(OBJDIR)/cache_.c:$(OBJDIR)/cache.h \
1219 $(OBJDIR)/capabilities_.c:$(OBJDIR)/capabilities.h \
1220 $(OBJDIR)/captcha_.c:$(OBJDIR)/captcha.h \
1221 $(OBJDIR)/cgi_.c:$(OBJDIR)/cgi.h \
1222 $(OBJDIR)/chat_.c:$(OBJDIR)/chat.h \
1223 $(OBJDIR)/checkin_.c:$(OBJDIR)/checkin.h \
1224 $(OBJDIR)/checkout_.c:$(OBJDIR)/checkout.h \
1225 $(OBJDIR)/clearsign_.c:$(OBJDIR)/clearsign.h \
1226 $(OBJDIR)/clone_.c:$(OBJDIR)/clone.h \
1227 $(OBJDIR)/comformat_.c:$(OBJDIR)/comformat.h \
@@ -1493,10 +1498,18 @@
1498
1499 $(OBJDIR)/cgi.o: $(OBJDIR)/cgi_.c $(OBJDIR)/cgi.h $(SRCDIR)/config.h
1500 $(XTCC) -o $(OBJDIR)/cgi.o -c $(OBJDIR)/cgi_.c
1501
1502 $(OBJDIR)/cgi.h: $(OBJDIR)/headers
1503
1504 $(OBJDIR)/chat_.c: $(SRCDIR)/chat.c $(TRANSLATE)
1505 $(TRANSLATE) $(SRCDIR)/chat.c >$@
1506
1507 $(OBJDIR)/chat.o: $(OBJDIR)/chat_.c $(OBJDIR)/chat.h $(SRCDIR)/config.h
1508 $(XTCC) -o $(OBJDIR)/chat.o -c $(OBJDIR)/chat_.c
1509
1510 $(OBJDIR)/chat.h: $(OBJDIR)/headers
1511
1512 $(OBJDIR)/checkin_.c: $(SRCDIR)/checkin.c $(TRANSLATE)
1513 $(TRANSLATE) $(SRCDIR)/checkin.c >$@
1514
1515 $(OBJDIR)/checkin.o: $(OBJDIR)/checkin_.c $(OBJDIR)/checkin.h $(SRCDIR)/config.h
1516
--- win/Makefile.msc
+++ win/Makefile.msc
@@ -366,10 +366,11 @@
366366
"$(OX)\bundle_.c" \
367367
"$(OX)\cache_.c" \
368368
"$(OX)\capabilities_.c" \
369369
"$(OX)\captcha_.c" \
370370
"$(OX)\cgi_.c" \
371
+ "$(OX)\chat_.c" \
371372
"$(OX)\checkin_.c" \
372373
"$(OX)\checkout_.c" \
373374
"$(OX)\clearsign_.c" \
374375
"$(OX)\clone_.c" \
375376
"$(OX)\comformat_.c" \
@@ -552,10 +553,11 @@
552553
"$(SRCDIR)\..\skins\xekri\css.txt" \
553554
"$(SRCDIR)\..\skins\xekri\details.txt" \
554555
"$(SRCDIR)\..\skins\xekri\footer.txt" \
555556
"$(SRCDIR)\..\skins\xekri\header.txt" \
556557
"$(SRCDIR)\accordion.js" \
558
+ "$(SRCDIR)\chat.js" \
557559
"$(SRCDIR)\ci_edit.js" \
558560
"$(SRCDIR)\copybtn.js" \
559561
"$(SRCDIR)\default.css" \
560562
"$(SRCDIR)\diff.tcl" \
561563
"$(SRCDIR)\forum.js" \
@@ -622,10 +624,11 @@
622624
"$(OX)\bundle$O" \
623625
"$(OX)\cache$O" \
624626
"$(OX)\capabilities$O" \
625627
"$(OX)\captcha$O" \
626628
"$(OX)\cgi$O" \
629
+ "$(OX)\chat$O" \
627630
"$(OX)\checkin$O" \
628631
"$(OX)\checkout$O" \
629632
"$(OX)\clearsign$O" \
630633
"$(OX)\clone$O" \
631634
"$(OX)\comformat$O" \
@@ -851,10 +854,11 @@
851854
echo "$(OX)\bundle.obj" >> $@
852855
echo "$(OX)\cache.obj" >> $@
853856
echo "$(OX)\capabilities.obj" >> $@
854857
echo "$(OX)\captcha.obj" >> $@
855858
echo "$(OX)\cgi.obj" >> $@
859
+ echo "$(OX)\chat.obj" >> $@
856860
echo "$(OX)\checkin.obj" >> $@
857861
echo "$(OX)\checkout.obj" >> $@
858862
echo "$(OX)\clearsign.obj" >> $@
859863
echo "$(OX)\clone.obj" >> $@
860864
echo "$(OX)\comformat.obj" >> $@
@@ -1158,10 +1162,11 @@
11581162
echo "$(SRCDIR)\../skins/xekri/css.txt" >> $@
11591163
echo "$(SRCDIR)\../skins/xekri/details.txt" >> $@
11601164
echo "$(SRCDIR)\../skins/xekri/footer.txt" >> $@
11611165
echo "$(SRCDIR)\../skins/xekri/header.txt" >> $@
11621166
echo "$(SRCDIR)\accordion.js" >> $@
1167
+ echo "$(SRCDIR)\chat.js" >> $@
11631168
echo "$(SRCDIR)\ci_edit.js" >> $@
11641169
echo "$(SRCDIR)\copybtn.js" >> $@
11651170
echo "$(SRCDIR)\default.css" >> $@
11661171
echo "$(SRCDIR)\diff.tcl" >> $@
11671172
echo "$(SRCDIR)\forum.js" >> $@
@@ -1317,10 +1322,16 @@
13171322
"$(OX)\cgi$O" : "$(OX)\cgi_.c" "$(OX)\cgi.h"
13181323
$(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\cgi_.c"
13191324
13201325
"$(OX)\cgi_.c" : "$(SRCDIR)\cgi.c"
13211326
"$(OBJDIR)\translate$E" $** > $@
1327
+
1328
+"$(OX)\chat$O" : "$(OX)\chat_.c" "$(OX)\chat.h"
1329
+ $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\chat_.c"
1330
+
1331
+"$(OX)\chat_.c" : "$(SRCDIR)\chat.c"
1332
+ "$(OBJDIR)\translate$E" $** > $@
13221333
13231334
"$(OX)\checkin$O" : "$(OX)\checkin_.c" "$(OX)\checkin.h"
13241335
$(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\checkin_.c"
13251336
13261337
"$(OX)\checkin_.c" : "$(SRCDIR)\checkin.c"
@@ -2108,10 +2119,11 @@
21082119
"$(OX)\bundle_.c":"$(OX)\bundle.h" \
21092120
"$(OX)\cache_.c":"$(OX)\cache.h" \
21102121
"$(OX)\capabilities_.c":"$(OX)\capabilities.h" \
21112122
"$(OX)\captcha_.c":"$(OX)\captcha.h" \
21122123
"$(OX)\cgi_.c":"$(OX)\cgi.h" \
2124
+ "$(OX)\chat_.c":"$(OX)\chat.h" \
21132125
"$(OX)\checkin_.c":"$(OX)\checkin.h" \
21142126
"$(OX)\checkout_.c":"$(OX)\checkout.h" \
21152127
"$(OX)\clearsign_.c":"$(OX)\clearsign.h" \
21162128
"$(OX)\clone_.c":"$(OX)\clone.h" \
21172129
"$(OX)\comformat_.c":"$(OX)\comformat.h" \
21182130
--- win/Makefile.msc
+++ win/Makefile.msc
@@ -366,10 +366,11 @@
366 "$(OX)\bundle_.c" \
367 "$(OX)\cache_.c" \
368 "$(OX)\capabilities_.c" \
369 "$(OX)\captcha_.c" \
370 "$(OX)\cgi_.c" \
 
371 "$(OX)\checkin_.c" \
372 "$(OX)\checkout_.c" \
373 "$(OX)\clearsign_.c" \
374 "$(OX)\clone_.c" \
375 "$(OX)\comformat_.c" \
@@ -552,10 +553,11 @@
552 "$(SRCDIR)\..\skins\xekri\css.txt" \
553 "$(SRCDIR)\..\skins\xekri\details.txt" \
554 "$(SRCDIR)\..\skins\xekri\footer.txt" \
555 "$(SRCDIR)\..\skins\xekri\header.txt" \
556 "$(SRCDIR)\accordion.js" \
 
557 "$(SRCDIR)\ci_edit.js" \
558 "$(SRCDIR)\copybtn.js" \
559 "$(SRCDIR)\default.css" \
560 "$(SRCDIR)\diff.tcl" \
561 "$(SRCDIR)\forum.js" \
@@ -622,10 +624,11 @@
622 "$(OX)\bundle$O" \
623 "$(OX)\cache$O" \
624 "$(OX)\capabilities$O" \
625 "$(OX)\captcha$O" \
626 "$(OX)\cgi$O" \
 
627 "$(OX)\checkin$O" \
628 "$(OX)\checkout$O" \
629 "$(OX)\clearsign$O" \
630 "$(OX)\clone$O" \
631 "$(OX)\comformat$O" \
@@ -851,10 +854,11 @@
851 echo "$(OX)\bundle.obj" >> $@
852 echo "$(OX)\cache.obj" >> $@
853 echo "$(OX)\capabilities.obj" >> $@
854 echo "$(OX)\captcha.obj" >> $@
855 echo "$(OX)\cgi.obj" >> $@
 
856 echo "$(OX)\checkin.obj" >> $@
857 echo "$(OX)\checkout.obj" >> $@
858 echo "$(OX)\clearsign.obj" >> $@
859 echo "$(OX)\clone.obj" >> $@
860 echo "$(OX)\comformat.obj" >> $@
@@ -1158,10 +1162,11 @@
1158 echo "$(SRCDIR)\../skins/xekri/css.txt" >> $@
1159 echo "$(SRCDIR)\../skins/xekri/details.txt" >> $@
1160 echo "$(SRCDIR)\../skins/xekri/footer.txt" >> $@
1161 echo "$(SRCDIR)\../skins/xekri/header.txt" >> $@
1162 echo "$(SRCDIR)\accordion.js" >> $@
 
1163 echo "$(SRCDIR)\ci_edit.js" >> $@
1164 echo "$(SRCDIR)\copybtn.js" >> $@
1165 echo "$(SRCDIR)\default.css" >> $@
1166 echo "$(SRCDIR)\diff.tcl" >> $@
1167 echo "$(SRCDIR)\forum.js" >> $@
@@ -1317,10 +1322,16 @@
1317 "$(OX)\cgi$O" : "$(OX)\cgi_.c" "$(OX)\cgi.h"
1318 $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\cgi_.c"
1319
1320 "$(OX)\cgi_.c" : "$(SRCDIR)\cgi.c"
1321 "$(OBJDIR)\translate$E" $** > $@
 
 
 
 
 
 
1322
1323 "$(OX)\checkin$O" : "$(OX)\checkin_.c" "$(OX)\checkin.h"
1324 $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\checkin_.c"
1325
1326 "$(OX)\checkin_.c" : "$(SRCDIR)\checkin.c"
@@ -2108,10 +2119,11 @@
2108 "$(OX)\bundle_.c":"$(OX)\bundle.h" \
2109 "$(OX)\cache_.c":"$(OX)\cache.h" \
2110 "$(OX)\capabilities_.c":"$(OX)\capabilities.h" \
2111 "$(OX)\captcha_.c":"$(OX)\captcha.h" \
2112 "$(OX)\cgi_.c":"$(OX)\cgi.h" \
 
2113 "$(OX)\checkin_.c":"$(OX)\checkin.h" \
2114 "$(OX)\checkout_.c":"$(OX)\checkout.h" \
2115 "$(OX)\clearsign_.c":"$(OX)\clearsign.h" \
2116 "$(OX)\clone_.c":"$(OX)\clone.h" \
2117 "$(OX)\comformat_.c":"$(OX)\comformat.h" \
2118
--- win/Makefile.msc
+++ win/Makefile.msc
@@ -366,10 +366,11 @@
366 "$(OX)\bundle_.c" \
367 "$(OX)\cache_.c" \
368 "$(OX)\capabilities_.c" \
369 "$(OX)\captcha_.c" \
370 "$(OX)\cgi_.c" \
371 "$(OX)\chat_.c" \
372 "$(OX)\checkin_.c" \
373 "$(OX)\checkout_.c" \
374 "$(OX)\clearsign_.c" \
375 "$(OX)\clone_.c" \
376 "$(OX)\comformat_.c" \
@@ -552,10 +553,11 @@
553 "$(SRCDIR)\..\skins\xekri\css.txt" \
554 "$(SRCDIR)\..\skins\xekri\details.txt" \
555 "$(SRCDIR)\..\skins\xekri\footer.txt" \
556 "$(SRCDIR)\..\skins\xekri\header.txt" \
557 "$(SRCDIR)\accordion.js" \
558 "$(SRCDIR)\chat.js" \
559 "$(SRCDIR)\ci_edit.js" \
560 "$(SRCDIR)\copybtn.js" \
561 "$(SRCDIR)\default.css" \
562 "$(SRCDIR)\diff.tcl" \
563 "$(SRCDIR)\forum.js" \
@@ -622,10 +624,11 @@
624 "$(OX)\bundle$O" \
625 "$(OX)\cache$O" \
626 "$(OX)\capabilities$O" \
627 "$(OX)\captcha$O" \
628 "$(OX)\cgi$O" \
629 "$(OX)\chat$O" \
630 "$(OX)\checkin$O" \
631 "$(OX)\checkout$O" \
632 "$(OX)\clearsign$O" \
633 "$(OX)\clone$O" \
634 "$(OX)\comformat$O" \
@@ -851,10 +854,11 @@
854 echo "$(OX)\bundle.obj" >> $@
855 echo "$(OX)\cache.obj" >> $@
856 echo "$(OX)\capabilities.obj" >> $@
857 echo "$(OX)\captcha.obj" >> $@
858 echo "$(OX)\cgi.obj" >> $@
859 echo "$(OX)\chat.obj" >> $@
860 echo "$(OX)\checkin.obj" >> $@
861 echo "$(OX)\checkout.obj" >> $@
862 echo "$(OX)\clearsign.obj" >> $@
863 echo "$(OX)\clone.obj" >> $@
864 echo "$(OX)\comformat.obj" >> $@
@@ -1158,10 +1162,11 @@
1162 echo "$(SRCDIR)\../skins/xekri/css.txt" >> $@
1163 echo "$(SRCDIR)\../skins/xekri/details.txt" >> $@
1164 echo "$(SRCDIR)\../skins/xekri/footer.txt" >> $@
1165 echo "$(SRCDIR)\../skins/xekri/header.txt" >> $@
1166 echo "$(SRCDIR)\accordion.js" >> $@
1167 echo "$(SRCDIR)\chat.js" >> $@
1168 echo "$(SRCDIR)\ci_edit.js" >> $@
1169 echo "$(SRCDIR)\copybtn.js" >> $@
1170 echo "$(SRCDIR)\default.css" >> $@
1171 echo "$(SRCDIR)\diff.tcl" >> $@
1172 echo "$(SRCDIR)\forum.js" >> $@
@@ -1317,10 +1322,16 @@
1322 "$(OX)\cgi$O" : "$(OX)\cgi_.c" "$(OX)\cgi.h"
1323 $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\cgi_.c"
1324
1325 "$(OX)\cgi_.c" : "$(SRCDIR)\cgi.c"
1326 "$(OBJDIR)\translate$E" $** > $@
1327
1328 "$(OX)\chat$O" : "$(OX)\chat_.c" "$(OX)\chat.h"
1329 $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\chat_.c"
1330
1331 "$(OX)\chat_.c" : "$(SRCDIR)\chat.c"
1332 "$(OBJDIR)\translate$E" $** > $@
1333
1334 "$(OX)\checkin$O" : "$(OX)\checkin_.c" "$(OX)\checkin.h"
1335 $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\checkin_.c"
1336
1337 "$(OX)\checkin_.c" : "$(SRCDIR)\checkin.c"
@@ -2108,10 +2119,11 @@
2119 "$(OX)\bundle_.c":"$(OX)\bundle.h" \
2120 "$(OX)\cache_.c":"$(OX)\cache.h" \
2121 "$(OX)\capabilities_.c":"$(OX)\capabilities.h" \
2122 "$(OX)\captcha_.c":"$(OX)\captcha.h" \
2123 "$(OX)\cgi_.c":"$(OX)\cgi.h" \
2124 "$(OX)\chat_.c":"$(OX)\chat.h" \
2125 "$(OX)\checkin_.c":"$(OX)\checkin.h" \
2126 "$(OX)\checkout_.c":"$(OX)\checkout.h" \
2127 "$(OX)\clearsign_.c":"$(OX)\clearsign.h" \
2128 "$(OX)\clone_.c":"$(OX)\clone.h" \
2129 "$(OX)\comformat_.c":"$(OX)\comformat.h" \
2130

Keyboard Shortcuts

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