Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Changes In Branch chatroom-dev Excluding Merge-Ins
This is equivalent to a diff from 112c713be1 to 6f424a32b5
2020-12-23
| ||
18:27 | 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. ... (check-in: e8ba89b168 user: drh tags: trunk) | |
18:21 | Fix the /chat-poll page so that it works even when called from "fossil ui". ... (Closed-Leaf check-in: 6f424a32b5 user: drh tags: chatroom-dev) | |
17:27 | The /test_env page is not an error page. ... (check-in: f2a26bca3a user: drh tags: trunk) | |
16:19 | Additional documentation on the /chat-poll page. ... (check-in: 2261b29415 user: drh tags: chatroom-dev) | |
2020-12-22
| ||
20:06 | Merge the styling changes from trunk into the chatroom-dev branch. ... (check-in: b8d6319b5a user: drh tags: chatroom-dev) | |
18:31 | Add support for the "$current_feature" TH1 variable as a possibly better way to do page-specific of feature-specific styling. ... (check-in: 112c713be1 user: drh tags: trunk) | |
12:30 | Whitespace style fix ... (Closed-Leaf check-in: 358f7d80c2 user: wyoung tags: body-feature-class) | |
10:31 | Comment fix to track a code change made in commit [3d6444fc]. ... (check-in: e6e8ea8ffb user: wyoung tags: trunk) | |
Changes to src/builtin.c.
︙ | ︙ | |||
634 635 636 637 638 639 640 641 642 643 644 645 646 647 | /* can leak a local filesystem path: CX("name: %!j,", skin_in_use());*/ CX("isDark: %s" "/*true if the current skin has the 'white-foreground' detail*/", skin_detail_boolean("white-foreground") ? "true" : "false"); CX("}\n"/*fossil.config.skin*/); CX("};\n"/* fossil.config */); CX("if(fossil.config.skin.isDark) " "document.body.classList.add('fossil-dark-style');\n"); #if 0 /* Is it safe to emit the CSRF token here? Some pages add it ** as a hidden form field. */ if(g.zCsrfToken[0]!=0){ CX("window.fossil.csrfToken = %!j;\n", | > > > | 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 | /* can leak a local filesystem path: CX("name: %!j,", skin_in_use());*/ CX("isDark: %s" "/*true if the current skin has the 'white-foreground' detail*/", skin_detail_boolean("white-foreground") ? "true" : "false"); CX("}\n"/*fossil.config.skin*/); CX("};\n"/* fossil.config */); CX("window.fossil.user = {"); CX("name: %!j", (g.zLogin&&*g.zLogin) ? g.zLogin : "guest"); CX("};\n"/*fossil.user*/); CX("if(fossil.config.skin.isDark) " "document.body.classList.add('fossil-dark-style');\n"); #if 0 /* Is it safe to emit the CSRF token here? Some pages add it ** as a hidden form field. */ if(g.zCsrfToken[0]!=0){ CX("window.fossil.csrfToken = %!j;\n", |
︙ | ︙ |
Changes to src/capabilities.c.
︙ | ︙ | |||
302 303 304 305 306 307 308 309 310 311 312 313 314 315 | "Forum-Mod", "Moderator for forum messages" }, { '6', CAPCLASS_FORUM|CAPCLASS_SUPER, 0, "Forum-Admin", "Grant capability '4' to other users" }, { '7', CAPCLASS_ALERT, 0, "Alerts", "Sign up for email alerts" }, { 'A', CAPCLASS_ALERT|CAPCLASS_SUPER, 0, "Announce", "Send announcements to all subscribers" }, { 'D', CAPCLASS_OTHER, 0, "Debug", "Enable debugging features" }, }; /* ** Populate the aCap[].nUser values based on the current content ** of the USER table. | > > | 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 | "Forum-Mod", "Moderator for forum messages" }, { '6', CAPCLASS_FORUM|CAPCLASS_SUPER, 0, "Forum-Admin", "Grant capability '4' to other users" }, { '7', CAPCLASS_ALERT, 0, "Alerts", "Sign up for email alerts" }, { 'A', CAPCLASS_ALERT|CAPCLASS_SUPER, 0, "Announce", "Send announcements to all subscribers" }, { 'C', CAPCLASS_FORUM, 0, "Chat", "Read and/or writes messages in the chatroom" }, { 'D', CAPCLASS_OTHER, 0, "Debug", "Enable debugging features" }, }; /* ** Populate the aCap[].nUser values based on the current content ** of the USER table. |
︙ | ︙ | |||
389 390 391 392 393 394 395 | " UNION ALL" " SELECT 'Adminstrator', fullcap(capunion(cap)), 300, count(*) FROM user" " WHERE cap GLOB '*[as]*'" " ORDER BY 3 ASC", zSelfCap, hasPubPages, zSelfCap ); @ <table id='capabilitySummary' cellpadding="0" cellspacing="0" border="1"> | | | 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 | " UNION ALL" " SELECT 'Adminstrator', fullcap(capunion(cap)), 300, count(*) FROM user" " WHERE cap GLOB '*[as]*'" " ORDER BY 3 ASC", zSelfCap, hasPubPages, zSelfCap ); @ <table id='capabilitySummary' cellpadding="0" cellspacing="0" border="1"> @ <tr><th> <th>Code<th>Forum<th>Tickets<th>Wiki<th>Chat\ @ <th>Unversioned Content</th></tr> while( db_step(&q)==SQLITE_ROW ){ const char *zId = db_column_text(&q, 0); const char *zCap = db_column_text(&q, 1); int n = db_column_int(&q, 3); int eType; static const char *const azType[] = { "off", "read", "write" }; |
︙ | ︙ | |||
444 445 446 447 448 449 450 451 452 453 454 455 456 457 | @ <td class="%s(azClass[eType])">%s(azType[eType])</td> /* Wiki */ if( sqlite3_strglob("*[asdfklm]*",zCap)==0 ){ eType = 2; }else if( sqlite3_strglob("*j*",zCap)==0 ){ eType = 1; }else{ eType = 0; } @ <td class="%s(azClass[eType])">%s(azType[eType])</td> /* Unversioned */ if( sqlite3_strglob("*y*",zCap)==0 ){ | > > > > > > > > | 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 | @ <td class="%s(azClass[eType])">%s(azType[eType])</td> /* Wiki */ if( sqlite3_strglob("*[asdfklm]*",zCap)==0 ){ eType = 2; }else if( sqlite3_strglob("*j*",zCap)==0 ){ eType = 1; }else{ eType = 0; } @ <td class="%s(azClass[eType])">%s(azType[eType])</td> /* Chat */ if( sqlite3_strglob("*C*",zCap)==0 ){ eType = 2; }else{ eType = 0; } @ <td class="%s(azClass[eType])">%s(azType[eType])</td> /* Unversioned */ if( sqlite3_strglob("*y*",zCap)==0 ){ |
︙ | ︙ |
Added src/chat.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 | /* ** Copyright (c) 2020 D. Richard Hipp ** ** This program is free software; you can redistribute it and/or ** modify it under the terms of the Simplified BSD License (also ** known as the "2-Clause License" or "FreeBSD License".) ** ** This program is distributed in the hope that it will be useful, ** but without any warranty; without even the implied warranty of ** merchantability or fitness for a particular purpose. ** ** Author contact information: ** drh@hwaci.com ** http://www.hwaci.com/drh/ ** ******************************************************************************* ** ** This file contains code used to implement the Fossil chatroom. ** ** Initial design goals: ** ** * Keep it simple. This chatroom is not intended as a competitor ** or replacement for IRC, Discord, Telegram, Slack, etc. The goal ** is zero- or near-zero-configuration, not an abundance of features. ** ** * Intended as a place for insiders to have ephemeral conversations ** about a project. This is not a public gather place. Think ** "boardroom", not "corner pub". ** ** * One chatroom per repository. ** ** * Chat content lives in a single repository. It is never synced. ** Content expires and is deleted after a set interval (a week or so). ** ** Notification is accomplished using the "hanging GET" or "long poll" design ** in which a GET request is issued but the server does not send a reply until ** new content arrives. Newer Web Sockets and Server Sent Event protocols are ** more elegant, but are not compatible with CGI, and would thus complicate ** configuration. */ #include "config.h" #include <assert.h> #include "chat.h" /* ** WEBPAGE: chat ** ** Start up a browser-based chat session. */ void chat_webpage(void){ login_check_credentials(); style_set_current_feature("chat"); if( !g.perm.Chat ){ style_header("Chat Not Authorized"); @ <h1>Not Authorized</h1> @ <p>You do not have permission to use the chatroom on this @ repository.</p> style_finish_page(); return; } style_header("Chat"); @ <style> @ #dialog { @ width: 97%%; @ } @ #chat-input-area { @ width: 100%%; @ display: flex; @ flex-direction: column; @ } @ #chat-input-line { @ display: flex; @ flex-direction: row; @ margin-bottom: 1em; @ align-items: center; @ } @ #chat-input-line > input[type=submit] { @ flex: 1 5 auto; @ max-width: 6em; @ } @ #chat-input-line > input[type=text] { @ flex: 5 1 auto; @ } @ #chat-input-file-area { @ display: flex; @ flex-direction: row; @ align-items: center; @ } @ #chat-input-file-area > .help-buttonlet, @ #chat-input-file { @ align-self: flex-start; @ margin-right: 0.5em; @ flex: 0 1 auto; @ } @ #chat-input-file { @ border: 1px solid rgba(0,0,0,0);/*to avoid UI shift during drop-targeting*/ @ border-radius: 0.25em; @ } @ #chat-input-file > input { @ flex: 1 0 auto; @ } @ .chat-timestamp { @ font-family: monospace; @ font-size: 0.8em; @ white-space: pre; @ text-align: left; @ opacity: 0.8; @ } @ #chat-input-file.dragover { @ border: 1px dashed green; @ } @ #chat-drop-details { @ flex: 0 1 auto; @ padding: 0.5em 1em; @ margin-left: 0.5em; @ white-space: pre; @ font-family: monospace; @ max-width: 50%%; @ } @ </style> @ <form accept-encoding="utf-8" id="chat-form"> @ <div id='chat-input-area'> @ <div id='chat-input-line'> @ <input type="text" name="msg" id="sbox" \ @ placeholder="Type message here."> @ <input type="submit" value="Send"> @ </div> @ <div id='chat-input-file-area'> @ <input type="file" name="file" id="chat-input-file"> @ <div id="chat-drop-details"></div> @ </div> @ </div> @ </form> @ <hr> /* New chat messages get inserted immediately after this element */ @ <span id='message-inject-point'></span> builtin_fossil_js_bundle_or("popupwidget", NULL); /* Always in-line the javascript for the chat page */ @ <script nonce="%h(style_nonce())">/* chat.c:%d(__LINE__) */ @ window.addEventListener('load', function(){ /* We need an onload handler to ensure that window.fossil is loaded first. */ cgi_append_content(builtin_text("chat.js"),-1); @ }, false); @ </script> style_finish_page(); } /* Definition of repository tables used by chat */ static const char zChatSchema1[] = @ CREATE TABLE repository.chat( @ msgid INTEGER PRIMARY KEY AUTOINCREMENT, @ mtime JULIANDAY, -- Time for this entry - Julianday Zulu @ xfrom TEXT, -- Login of the sender @ xmsg TEXT, -- Raw, unformatted text of the message @ file BLOB, -- Text of the uploaded file, or NULL @ fname TEXT, -- Filename of the uploaded file, or NULL @ fmime TEXT, -- MIMEType of the upload file, or NULL @ mdel INT -- msgid of another message to delete @ ); ; /* ** Make sure the repository data tables used by chat exist. Create them ** if they do not. */ static void chat_create_tables(void){ if( !db_table_exists("repository","chat") ){ db_multi_exec(zChatSchema1/*works-like:""*/); }else if( !db_table_has_column("repository","chat","mdel") ){ db_multi_exec("ALTER TABLE chat ADD COLUMN mdel INT"); } } /* ** WEBPAGE: chat-send ** ** This page receives (via XHR) a new chat-message and/or a new file ** to be entered into the chat history. */ void chat_send_webpage(void){ int nByte; const char *zMsg; login_check_credentials(); if( !g.perm.Chat ) return; chat_create_tables(); nByte = atoi(PD("file:bytes",0)); zMsg = PD("msg",""); if( nByte==0 ){ if( zMsg[0] ){ db_multi_exec( "INSERT INTO chat(mtime,xfrom,xmsg)" "VALUES(julianday('now'),%Q,%Q)", g.zLogin, zMsg ); } }else{ Stmt q; Blob b; db_prepare(&q, "INSERT INTO chat(mtime, xfrom,xmsg,file,fname,fmime)" "VALUES(julianday('now'),%Q,%Q,:file,%Q,%Q)", g.zLogin, zMsg, PD("file:filename",""), PD("file:mimetype","application/octet-stream")); blob_init(&b, P("file"), nByte); db_bind_blob(&q, ":file", &b); db_step(&q); db_finalize(&q); blob_reset(&b); } } /* ** WEBPAGE: chat-poll ** ** The chat page generated by /chat using a XHR to this page in order ** to ask for new chat content. The "name" argument should begin with ** an integer which is the largest "msgid" that the chat page currently ** holds. If newer content is available, this routine returns that ** content straight away. If no new content is available, this webpage ** blocks until the new content becomes available. In this way, the ** system implements "hanging-GET" or "long-poll" style event notification. ** ** /chat-poll/N ** ** If N is negative, then the return value is the N most recent messages. ** Hence a request like /chat-poll/-100 can be used to initialize a new ** chat session to just the most recent messages. ** ** Some webservers (althttpd) do not allow a term of the URL path to ** begin with "-". Then /chat-poll/-100 cannot be used. Instead you ** have to say "/chat-poll?name=-100". ** ** The reply from this webpage is JSON that describes the new content. ** Format of the json: ** ** | { ** | "msg":[ ** | { ** | "msgid": integer // message id ** | "mtime": text // When sent: YYYY-MM-DD HH:MM:SS UTC ** | "xfrom": text // Login name of sender ** | "uclr": text // Color string associated with the user ** | "xmsg": text // HTML text of the message ** | "fsize": integer // file attachment size in bytes ** | "fname": text // Name of file attachment ** | "fmime": text // MIME-type of file attachment ** | "mdel": integer // message id of prior message to delete ** | } ** | ] ** | } ** ** The "fname" and "fmime" fields are only present if "fsize" is greater ** than zero. The "xmsg" field may be an empty string if "fsize" is zero. ** ** The "msgid" values will be in increasing order. ** ** The "mdel" will only exist if "xmsg" is an empty string and "fsize" is zero. */ void chat_poll_webpage(void){ Blob json; /* The json to be constructed and returned */ sqlite3_int64 dataVersion; /* Data version. Used for polling. */ int iDelay = 1000; /* Delay until next poll (milliseconds) */ const char *zSep = "{\"msgs\":[\n"; /* List separator */ int msgid = atoi(PD("name","0")); Stmt q1; login_check_credentials(); if( !g.perm.Chat ) return; chat_create_tables(); cgi_set_content_type("text/json"); dataVersion = db_int64(0, "PRAGMA data_version"); if( msgid<0 ){ msgid = db_int(0, "SELECT msgid FROM chat WHERE mdel IS NOT true" " ORDER BY msgid DESC LIMIT 1 OFFSET %d", -msgid); } db_prepare(&q1, "SELECT msgid, datetime(mtime), xfrom, xmsg, length(file)," " fname, fmime, mdel" " FROM chat" " WHERE msgid>%d" " ORDER BY msgid", msgid ); blob_init(&json, 0, 0); while(1){ int cnt = 0; while( db_step(&q1)==SQLITE_ROW ){ int id = db_column_int(&q1, 0); const char *zDate = db_column_text(&q1, 1); const char *zFrom = db_column_text(&q1, 2); const char *zRawMsg = db_column_text(&q1, 3); int nByte = db_column_int(&q1, 4); const char *zFName = db_column_text(&q1, 5); const char *zFMime = db_column_text(&q1, 6); int iToDel = db_column_int(&q1, 7); char *zMsg; cnt++; blob_append(&json, zSep, -1); zSep = ",\n"; blob_appendf(&json, "{\"msgid\":%d,\"mtime\":%!j,", id, zDate); blob_appendf(&json, "\"xfrom\":%!j,", zFrom); blob_appendf(&json, "\"uclr\":%!j,", hash_color(zFrom)); /* TBD: Convert the raw message into HTML, perhaps by running it ** through a text formatter, or putting markup on @name phrases, ** etc. */ zMsg = mprintf("%h", zRawMsg ? zRawMsg : ""); blob_appendf(&json, "\"xmsg\":%!j,", zMsg); fossil_free(zMsg); if( nByte==0 ){ blob_appendf(&json, "\"fsize\":0"); }else{ blob_appendf(&json, "\"fsize\":%d,\"fname\":%!j,\"fmime\":%!j", nByte, zFName, zFMime); } if( iToDel ){ blob_appendf(&json, ",\"mdel\":%d}", iToDel); }else{ blob_append(&json, "}", 1); } } db_reset(&q1); if( cnt ){ blob_append(&json, "\n]}", 3); cgi_set_content(&json); break; } sqlite3_sleep(iDelay); while( 1 ){ sqlite3_int64 newDataVers = db_int64(0,"PRAGMA repository.data_version"); if( newDataVers!=dataVersion ){ dataVersion = newDataVers; break; } sqlite3_sleep(iDelay); } } /* Exit by "break" */ db_finalize(&q1); return; } /* ** WEBPAGE: chat-download ** ** Download the CHAT.FILE attachment associated with a single chat ** entry. The "name" query parameter begins with an integer that ** identifies the particular chat message. */ void chat_download_webpage(void){ int msgid; Blob r; const char *zMime; login_check_credentials(); if( !g.perm.Chat ){ style_header("Chat Not Authorized"); @ <h1>Not Authorized</h1> @ <p>You do not have permission to use the chatroom on this @ repository.</p> style_finish_page(); return; } chat_create_tables(); msgid = atoi(PD("name","0")); blob_zero(&r); zMime = db_text(0, "SELECT fmime FROM chat wHERE msgid=%d", msgid); if( zMime==0 ) return; db_blob(&r, "SELECT file FROM chat WHERE msgid=%d", msgid); cgi_set_content_type(zMime); cgi_set_content(&r); } /* ** WEBPAGE: chat-delete ** ** Delete the chat entry identified by the name query parameter. ** Invoking fetch("chat-delete/"+msgid) from javascript in the client ** will delete a chat entry from the CHAT table. ** ** This routine both deletes the identified chat entry and also inserts ** a new entry with the current timestamp and with: ** ** * xmsg = NULL ** * file = NULL ** * mdel = The msgid of the row that was deleted ** ** This new entry will then be propagated to all listeners so that they ** will know to delete their copies of the message too. */ void chat_delete_webpage(void){ int mdel; char *zOwner; login_check_credentials(); if( !g.perm.Chat ) return; chat_create_tables(); mdel = atoi(PD("name","0")); zOwner = db_text(0, "SELECT xfrom FROM chat WHERE msgid=%d", mdel); if( zOwner==0 ) return; if( fossil_strcmp(zOwner, g.zLogin)!=0 && !g.perm.Admin ) return; db_multi_exec( "BEGIN;\n" "DELETE FROM chat WHERE msgid=%d;\n" "INSERT INTO chat(mtime, xfrom, mdel)" " VALUES(julianday('now'), %Q, %d);\n" "COMMIT;", mdel, g.zLogin, mdel ); } |
Added src/chat.js.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 | (function(){ const form = document.querySelector('#chat-form'); let mxMsg = -50; const F = window.fossil, D = F.dom; const _me = F.user.name; /* State for paste and drag/drop */ const BlobXferState = { dropDetails: document.querySelector('#chat-drop-details'), blob: undefined }; /** Updates the paste/drop zone with details of the pasted/dropped data. */ const updateDropZoneContent = function(blob){ const bx = BlobXferState, dd = bx.dropDetails; bx.blob = blob; D.clearElement(dd); if(!blob){ form.file.value = ''; return; } D.append(dd, "Name: ", blob.name, D.br(), "Size: ",blob.size); if(blob.type && blob.type.startsWith("image/")){ const img = D.img(); D.append(dd, D.br(), img); const reader = new FileReader(); reader.onload = (e)=>img.setAttribute('src', e.target.result); reader.readAsDataURL(blob); } const btn = D.button("Cancel"); D.append(dd, D.br(), btn); btn.addEventListener('click', ()=>updateDropZoneContent(), false); }; form.file.addEventListener('change', function(ev){ //console.debug("this =",this); updateDropZoneContent(this.files && this.files[0] ? this.files[0] : undefined) }); form.addEventListener('submit',(e)=>{ e.preventDefault(); const fd = new FormData(form); if(BlobXferState.blob/*replace file content with this*/){ fd.set("file", BlobXferState.blob); } if( form.msg.value.length>0 || form.file.value.length>0 || BlobXferState.blob ){ fetch("chat-send",{ method: 'POST', body: fd }); } BlobXferState.blob = undefined; D.clearElement(BlobXferState.dropDetails); form.msg.value = ""; form.file.value = ""; form.msg.focus(); }); /* Handle image paste from clipboard. TODO: figure out how we can paste non-image binary data as if it had been selected via the file selection element. */ document.onpaste = function(event){ const items = event.clipboardData.items, item = items[0]; if(!item || !item.type) return; //console.debug("pasted item =",item); if('file'===item.kind){ updateDropZoneContent(false/*clear prev state*/); updateDropZoneContent(items[0].getAsFile()); }else if('string'===item.kind){ item.getAsString((v)=>form.msg.value = v); } }; if(true){/* Add help button for drag/drop/paste zone */ const help = D.div(); form.file.parentNode.insertBefore(help, form.file); F.helpButtonlets.create( help, "Select a file to upload, drag/drop a file into this spot, ", "or paste an image from the clipboard if supported by ", "your environment." ); } //////////////////////////////////////////////////////////// // File drag/drop visual notification. const dropHighlight = form.file /* target zone */; const dropEvents = { drop: function(ev){ D.removeClass(dropHighlight, 'dragover'); }, dragenter: function(ev){ ev.preventDefault(); ev.dataTransfer.dropEffect = "copy"; D.addClass(dropHighlight, 'dragover'); }, dragleave: function(ev){ D.removeClass(dropHighlight, 'dragover'); }, dragend: function(ev){ D.removeClass(dropHighlight, 'dragover'); } }; Object.keys(dropEvents).forEach( (k)=>form.file.addEventListener(k, dropEvents[k], true) ); /* Injects element e as a new row in the chat, at the top of the list */ const injectMessage = function f(e){ if(!f.injectPoint){ f.injectPoint = document.querySelector('#message-inject-point'); } if(f.injectPoint.nextSibling){ f.injectPoint.parentNode.insertBefore(e, f.injectPoint.nextSibling); }else{ f.injectPoint.parentNode.appendChild(e); } }; /* Returns a new TEXT node with the given text content. */ const textNode = (T)=>document.createTextNode(T); /** Returns the local time string of Date object d, defaulting to the current time. */ const localTimeString = function ff(d){ if(!ff.pad){ ff.pad = (x)=>(''+x).length>1 ? x : '0'+x; } d || (d = new Date()); return [ d.getFullYear(),'-',ff.pad(d.getMonth()+1/*sigh*/), '-',ff.pad(d.getDate()), ' ',ff.pad(d.getHours()),':',ff.pad(d.getMinutes()), ':',ff.pad(d.getSeconds()) ].join(''); }; /* Returns an almost-ISO8601 form of Date object d. */ const iso8601ish = function(d){ return d.toISOString() .replace('T',' ').replace(/\.\d+/,'').replace('Z', ' GMT'); }; /* Event handler for clicking .message-user elements to show their timestamps. */ const handleLegendClicked = function f(ev){ if(!f.popup){ /* Timestamp popup widget */ f.popup = new F.PopupWidget({ cssClass: ['fossil-tooltip', 'chat-timestamp'], refresh:function(){ const D = F.dom; D.clearElement(this.e); const d = new Date(this._timestamp+"Z"); if(d.getMinutes().toString()!=="NaN"){ // Date works, render informative timestamps D.append(this.e, localTimeString(d)," client-local", D.br(), iso8601ish(d)); }else{ // Date doesn't work, so dumb it down... D.append(this.e, this._timestamp," GMT"); } } }); f.popup.installClickToHide(); } const rect = ev.target.getBoundingClientRect(); f.popup._timestamp = ev.target.dataset.timestamp; let x = rect.left, y = rect.top - 10; f.popup.show(ev.target)/*so we can get its computed size*/; if('right'===ev.target.getAttribute('align')){ // Shift popup to the left for right-aligned messages to avoid // truncation off the right edge of the page. const pRect = f.popup.e.getBoundingClientRect(); x -= pRect.width/3*2; } f.popup.show(x, y); }; /** Callback for poll() to inject new content into the page. */ function newcontent(jx){ var i; for(i=0; i<jx.msgs.length; ++i){ let m = jx.msgs[i]; let row = document.createElement("fieldset"); if( m.msgid>mxMsg ) mxMsg = m.msgid; row.classList.add('message-row'); injectMessage(row); const eWho = document.createElement('legend'); eWho.dataset.timestamp = m.mtime; eWho.addEventListener('click', handleLegendClicked, false); if( m.xfrom==_me && window.outerWidth<1000 ){ eWho.setAttribute('align', 'right'); row.style.justifyContent = "flex-end"; }else{ eWho.setAttribute('align', 'left'); } eWho.style.backgroundColor = m.uclr; row.appendChild(eWho); eWho.classList.add('message-user'); let whoName = m.xfrom; var d = new Date(m.mtime + "Z"); if( d.getMinutes().toString()!="NaN" ){ /* Show local time when we can compute it */ eWho.append(textNode(whoName+' @ '+ d.getHours()+":"+(d.getMinutes()+100).toString().slice(1,3) )) }else{ /* Show UTC on systems where Date() does not work */ eWho.append(textNode(whoName+' @ '+m.mtime.slice(11,16))) } let span = document.createElement("div"); span.classList.add('message-content'); span.style.backgroundColor = m.uclr; row.appendChild(span); if( m.fsize>0 ){ if( m.fmime && m.fmime.startsWith("image/") ){ let img = document.createElement("img"); img.src = "chat-download/" + m.msgid; span.appendChild(img); }else{ let a = document.createElement("a"); let txt = "(" + m.fname + " " + m.fsize + " bytes)"; a.href = window.fossil.rootPath+ 'chat-download/' + m.msgid+'/'+encodeURIComponent(m.fname); // ^^^ add m.fname to URL to cause downloaded file to have that name. a.appendChild(textNode(txt)); span.appendChild(a); } let br = document.createElement("br"); br.style.clear = "both"; span.appendChild(br); } if(m.xmsg){ span.innerHTML += m.xmsg; } span.classList.add('chat-message'); } } async function poll(){ if(poll.running) return; poll.running = true; fetch("chat-poll?name=" + mxMsg) .then(x=>x.json()) .then(y=>newcontent(y)) .catch(e=>console.error(e)) .finally(()=>poll.running=false) } poll(); setInterval(poll, 1000); })(); |
Changes to src/default.css.
︙ | ︙ | |||
1459 1460 1461 1462 1463 1464 1465 | div.pikchr-wrapper.source > div.pikchr-svg { /* Hide image when sources are being shown. */ position: absolute !important; opacity: 0 !important; pointer-events: none !important; display: none !important; } | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 | div.pikchr-wrapper.source > div.pikchr-svg { /* Hide image when sources are being shown. */ position: absolute !important; opacity: 0 !important; pointer-events: none !important; display: none !important; } /* Chat-related */ span.at-name { /* for @USERNAME references */ text-decoration: underline; font-weight: bold; } /* A wrapper for a single single message (one row of the UI) */ .message-row { margin-bottom: 0.5em; border: none; display: flex; flex-direction: row; justify-content: flex-start; /*border: 1px solid rgba(0,0,0,0.2); border-radius: 0.25em; box-shadow: 0.2em 0.2em 0.2em rgba(0, 0, 0, 0.29);*/ border: none; } /* The content area of a message (the body element of a FIELDSET) */ .message-content { display: inline-block; border-radius: 0.25em; border: 1px solid rgba(0,0,0,0.2); box-shadow: 0.2em 0.2em 0.2em rgba(0, 0, 0, 0.29); padding: 0.25em 1em; margin-top: -0.75em; min-width: 9em /*avoid unsightly "underlap" with the user name label*/; } /* User name for the post (a LEGEND element) */ .message-row .message-user { border-radius: 0.25em 0.25em 0 0; padding: 0 0.5em; /*text-align: left; Firefox requires the 'align' attribute */ margin: 0 0.15em; padding: 0 0.5em 0em 0.5em; margin-bottom: 0.4em; cursor: pointer; } |
Changes to src/dispatch.c.
︙ | ︙ | |||
347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 | ** * Display lists are indented from the surrounding text. ** Each tag begins with "-" or occur on a line that is ** followed by two spaces and a non-space. <dd> elements can begin ** on the same line as long as they are separated by at least ** two spaces. ** ** * Indented text is show verbatim (<pre>...</pre>) */ static void help_to_html(const char *zHelp, Blob *pHtml){ int i; char c; int nIndent = 0; int wantP = 0; int wantBR = 0; int aIndent[10]; const char *azEnd[10]; int iLevel = 0; int isLI = 0; int isDT = 0; static const char *zEndDL = "</dl></blockquote>"; static const char *zEndPRE = "</pre></blockquote>"; static const char *zEndUL = "</ul>"; static const char *zEndDD = "</dd>"; aIndent[0] = 0; azEnd[0] = ""; while( zHelp[0] ){ i = 0; while( (c = zHelp[i])!=0 && c!='\n' ){ if( c=='%' && i>2 && zHelp[i-2]==':' && strncmp(zHelp+i,"%fossil",7)==0 ){ appendLinked(pHtml, zHelp, i); zHelp += i+1; i = 0; wantBR = 1; continue; } i++; } | > > > > | | | | > > > > > > > > > > > > > > > | 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 | ** * Display lists are indented from the surrounding text. ** Each tag begins with "-" or occur on a line that is ** followed by two spaces and a non-space. <dd> elements can begin ** on the same line as long as they are separated by at least ** two spaces. ** ** * Indented text is show verbatim (<pre>...</pre>) ** ** * Lines that begin with "|" at the left margin are in <pre>...</pre> */ static void help_to_html(const char *zHelp, Blob *pHtml){ int i; char c; int nIndent = 0; int wantP = 0; int wantBR = 0; int aIndent[10]; const char *azEnd[10]; int iLevel = 0; int isLI = 0; int isDT = 0; int inPRE = 0; static const char *zEndDL = "</dl></blockquote>"; static const char *zEndPRE = "</pre></blockquote>"; static const char *zEndUL = "</ul>"; static const char *zEndDD = "</dd>"; aIndent[0] = 0; azEnd[0] = ""; while( zHelp[0] ){ i = 0; while( (c = zHelp[i])!=0 && c!='\n' ){ if( c=='%' && i>2 && zHelp[i-2]==':' && strncmp(zHelp+i,"%fossil",7)==0 ){ appendLinked(pHtml, zHelp, i); zHelp += i+1; i = 0; wantBR = 1; continue; } i++; } if( i>2 && (zHelp[0]=='>' || zHelp[0]=='|') && zHelp[1]==' ' ){ if( zHelp[0]=='>' ){ isDT = 1; for(nIndent=1; nIndent<i && zHelp[nIndent]==' '; nIndent++){} }else{ if( !inPRE ){ blob_append(pHtml, "<pre>\n", -1); inPRE = 1; } } }else{ if( inPRE ){ blob_append(pHtml, "</pre>\n", -1); inPRE = 0; } isDT = 0; for(nIndent=0; nIndent<i && zHelp[nIndent]==' '; nIndent++){} } if( inPRE ){ blob_append(pHtml, zHelp+1, i); zHelp += i + 1; continue; } if( nIndent==i ){ if( c==0 ) break; if( iLevel && azEnd[iLevel]==zEndPRE ){ /* Skip the newline at the end of a <pre> */ }else{ blob_append_char(pHtml, '\n'); |
︙ | ︙ | |||
489 490 491 492 493 494 495 | if( c=='%' && strncmp(zHelp+i,"%fossil",7)==0 ){ if( i>0 ) blob_append(pText, zHelp, i); blob_append(pText, "fossil", 6); zHelp += i+7; i = -1; continue; } | | | 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 | if( c=='%' && strncmp(zHelp+i,"%fossil",7)==0 ){ if( i>0 ) blob_append(pText, zHelp, i); blob_append(pText, "fossil", 6); zHelp += i+7; i = -1; continue; } if( c=='\n' && (zHelp[i+1]=='>' || zHelp[i+1]=='|') && zHelp[i+2]==' ' ){ blob_append(pText, zHelp, i+1); blob_append(pText, " ", 1); zHelp += i+2; i = -1; continue; } if( c=='[' && (x = help_is_link(zHelp+i, 100000))!=0 ){ |
︙ | ︙ |
Changes to src/fossil.popupwidget.js.
︙ | ︙ | |||
180 181 182 183 184 185 186 | D.addClass(this.e, 'hidden'); this.e.style.removeProperty('left'); this.e.style.removeProperty('top'); } return this; }, | | > > > > > > > > > > > > > > > > | 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 | D.addClass(this.e, 'hidden'); this.e.style.removeProperty('left'); this.e.style.removeProperty('top'); } return this; }, hide: function(){return this.show(false)}, /** A convenience method which adds click handlers to this popup's main element and document.body to hide the popup when either element is clicked or the ESC key is pressed. Only call this once per instance, if at all. Returns this; */ installClickToHide: function f(){ this.e.addEventListener('click', ()=>this.show(false), false); document.body.addEventListener('click', ()=>this.show(false), true); const self = this; document.body.addEventListener('keydown', function(ev){ if(self.isShown() && 27===ev.which) self.show(false); }, true); return this; } }/*F.PopupWidget.prototype*/; /** Internal impl for F.toast() and friends. args: |
︙ | ︙ | |||
295 296 297 298 299 300 301 | if(!fch.popup){ fch.popup = new F.PopupWidget({ cssClass: ['fossil-tooltip', 'help-buttonlet-content'], refresh: function(){ } }); fch.popup.e.style.maxWidth = '80%'/*of body*/; | < < < < < | < < | 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 | if(!fch.popup){ fch.popup = new F.PopupWidget({ cssClass: ['fossil-tooltip', 'help-buttonlet-content'], refresh: function(){ } }); fch.popup.e.style.maxWidth = '80%'/*of body*/; fch.popup.installClickToHide(); } D.append(D.clearElement(fch.popup.e), ev.target.$helpContent); var popupRect = ev.target.getClientRects()[0]; var x = popupRect.left, y = popupRect.top; if(x<0) x = 0; if(y<0) y = 0; /* Shift the help around a bit to "better" fit the |
︙ | ︙ |
Changes to src/login.c.
︙ | ︙ | |||
1228 1229 1230 1231 1232 1233 1234 | case 'a': p->Admin = p->RdTkt = p->WrTkt = p->Zip = p->RdWiki = p->WrWiki = p->NewWiki = p->ApndWiki = p->Hyperlink = p->Clone = p->NewTkt = p->Password = p->RdAddr = p->TktFmt = p->Attach = p->ApndTkt = p->ModWiki = p->ModTkt = p->RdForum = p->WrForum = p->ModForum = | | | 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 | case 'a': p->Admin = p->RdTkt = p->WrTkt = p->Zip = p->RdWiki = p->WrWiki = p->NewWiki = p->ApndWiki = p->Hyperlink = p->Clone = p->NewTkt = p->Password = p->RdAddr = p->TktFmt = p->Attach = p->ApndTkt = p->ModWiki = p->ModTkt = p->RdForum = p->WrForum = p->ModForum = p->WrTForum = p->AdminForum = p->Chat = p->EmailAlert = p->Announce = p->Debug = 1; /* Fall thru into Read/Write */ case 'i': p->Read = p->Write = 1; break; case 'o': p->Read = 1; break; case 'z': p->Zip = 1; break; case 'h': p->Hyperlink = 1; break; |
︙ | ︙ | |||
1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 | case '5': p->ModForum = 1; case '4': p->WrTForum = 1; case '3': p->WrForum = 1; case '2': p->RdForum = 1; break; case '7': p->EmailAlert = 1; break; case 'A': p->Announce = 1; break; case 'D': p->Debug = 1; break; /* The "u" privilege recursively ** inherits all privileges of the user named "reader" */ case 'u': { if( p->XReader==0 ){ const char *zUser; | > | 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 | case '5': p->ModForum = 1; case '4': p->WrTForum = 1; case '3': p->WrForum = 1; case '2': p->RdForum = 1; break; case '7': p->EmailAlert = 1; break; case 'A': p->Announce = 1; break; case 'C': p->Chat = 1; break; case 'D': p->Debug = 1; break; /* The "u" privilege recursively ** inherits all privileges of the user named "reader" */ case 'u': { if( p->XReader==0 ){ const char *zUser; |
︙ | ︙ | |||
1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 | case '2': rc = p->RdForum; break; case '3': rc = p->WrForum; break; case '4': rc = p->WrTForum; break; case '5': rc = p->ModForum; break; case '6': rc = p->AdminForum;break; case '7': rc = p->EmailAlert;break; case 'A': rc = p->Announce; break; case 'D': rc = p->Debug; break; default: rc = 0; break; } } return rc; } | > | 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 | case '2': rc = p->RdForum; break; case '3': rc = p->WrForum; break; case '4': rc = p->WrTForum; break; case '5': rc = p->ModForum; break; case '6': rc = p->AdminForum;break; case '7': rc = p->EmailAlert;break; case 'A': rc = p->Announce; break; case 'C': rc = p->Chat; break; case 'D': rc = p->Debug; break; default: rc = 0; break; } } return rc; } |
︙ | ︙ |
Changes to src/main.c.
︙ | ︙ | |||
105 106 107 108 109 110 111 112 113 114 115 116 117 118 | char RdForum; /* 2: Read forum posts */ char WrForum; /* 3: Create new forum posts */ char WrTForum; /* 4: Post to forums not subject to moderation */ char ModForum; /* 5: Moderate (approve or reject) forum posts */ char AdminForum; /* 6: Grant capability 4 to other users */ char EmailAlert; /* 7: Sign up for email notifications */ char Announce; /* A: Send announcements */ char Debug; /* D: show extra Fossil debugging features */ /* These last two are included to block infinite recursion */ char XReader; /* u: Inherit all privileges of "reader" */ char XDeveloper; /* v: Inherit all privileges of "developer" */ }; #ifdef FOSSIL_ENABLE_TCL | > | 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 | char RdForum; /* 2: Read forum posts */ char WrForum; /* 3: Create new forum posts */ char WrTForum; /* 4: Post to forums not subject to moderation */ char ModForum; /* 5: Moderate (approve or reject) forum posts */ char AdminForum; /* 6: Grant capability 4 to other users */ char EmailAlert; /* 7: Sign up for email notifications */ char Announce; /* A: Send announcements */ char Chat; /* C: read or write the chatroom */ char Debug; /* D: show extra Fossil debugging features */ /* These last two are included to block infinite recursion */ char XReader; /* u: Inherit all privileges of "reader" */ char XDeveloper; /* v: Inherit all privileges of "developer" */ }; #ifdef FOSSIL_ENABLE_TCL |
︙ | ︙ |
Changes to src/main.mk.
︙ | ︙ | |||
30 31 32 33 34 35 36 37 38 39 40 41 42 43 | $(SRCDIR)/browse.c \ $(SRCDIR)/builtin.c \ $(SRCDIR)/bundle.c \ $(SRCDIR)/cache.c \ $(SRCDIR)/capabilities.c \ $(SRCDIR)/captcha.c \ $(SRCDIR)/cgi.c \ $(SRCDIR)/checkin.c \ $(SRCDIR)/checkout.c \ $(SRCDIR)/clearsign.c \ $(SRCDIR)/clone.c \ $(SRCDIR)/comformat.c \ $(SRCDIR)/configure.c \ $(SRCDIR)/content.c \ | > | 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | $(SRCDIR)/browse.c \ $(SRCDIR)/builtin.c \ $(SRCDIR)/bundle.c \ $(SRCDIR)/cache.c \ $(SRCDIR)/capabilities.c \ $(SRCDIR)/captcha.c \ $(SRCDIR)/cgi.c \ $(SRCDIR)/chat.c \ $(SRCDIR)/checkin.c \ $(SRCDIR)/checkout.c \ $(SRCDIR)/clearsign.c \ $(SRCDIR)/clone.c \ $(SRCDIR)/comformat.c \ $(SRCDIR)/configure.c \ $(SRCDIR)/content.c \ |
︙ | ︙ | |||
217 218 219 220 221 222 223 224 225 226 227 228 229 230 | $(SRCDIR)/../skins/rounded1/footer.txt \ $(SRCDIR)/../skins/rounded1/header.txt \ $(SRCDIR)/../skins/xekri/css.txt \ $(SRCDIR)/../skins/xekri/details.txt \ $(SRCDIR)/../skins/xekri/footer.txt \ $(SRCDIR)/../skins/xekri/header.txt \ $(SRCDIR)/accordion.js \ $(SRCDIR)/ci_edit.js \ $(SRCDIR)/copybtn.js \ $(SRCDIR)/default.css \ $(SRCDIR)/diff.tcl \ $(SRCDIR)/forum.js \ $(SRCDIR)/fossil.bootstrap.js \ $(SRCDIR)/fossil.confirmer.js \ | > | 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 | $(SRCDIR)/../skins/rounded1/footer.txt \ $(SRCDIR)/../skins/rounded1/header.txt \ $(SRCDIR)/../skins/xekri/css.txt \ $(SRCDIR)/../skins/xekri/details.txt \ $(SRCDIR)/../skins/xekri/footer.txt \ $(SRCDIR)/../skins/xekri/header.txt \ $(SRCDIR)/accordion.js \ $(SRCDIR)/chat.js \ $(SRCDIR)/ci_edit.js \ $(SRCDIR)/copybtn.js \ $(SRCDIR)/default.css \ $(SRCDIR)/diff.tcl \ $(SRCDIR)/forum.js \ $(SRCDIR)/fossil.bootstrap.js \ $(SRCDIR)/fossil.confirmer.js \ |
︙ | ︙ | |||
288 289 290 291 292 293 294 295 296 297 298 299 300 301 | $(OBJDIR)/browse_.c \ $(OBJDIR)/builtin_.c \ $(OBJDIR)/bundle_.c \ $(OBJDIR)/cache_.c \ $(OBJDIR)/capabilities_.c \ $(OBJDIR)/captcha_.c \ $(OBJDIR)/cgi_.c \ $(OBJDIR)/checkin_.c \ $(OBJDIR)/checkout_.c \ $(OBJDIR)/clearsign_.c \ $(OBJDIR)/clone_.c \ $(OBJDIR)/comformat_.c \ $(OBJDIR)/configure_.c \ $(OBJDIR)/content_.c \ | > | 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 | $(OBJDIR)/browse_.c \ $(OBJDIR)/builtin_.c \ $(OBJDIR)/bundle_.c \ $(OBJDIR)/cache_.c \ $(OBJDIR)/capabilities_.c \ $(OBJDIR)/captcha_.c \ $(OBJDIR)/cgi_.c \ $(OBJDIR)/chat_.c \ $(OBJDIR)/checkin_.c \ $(OBJDIR)/checkout_.c \ $(OBJDIR)/clearsign_.c \ $(OBJDIR)/clone_.c \ $(OBJDIR)/comformat_.c \ $(OBJDIR)/configure_.c \ $(OBJDIR)/content_.c \ |
︙ | ︙ | |||
436 437 438 439 440 441 442 443 444 445 446 447 448 449 | $(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 \ | > | 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 | $(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 \ |
︙ | ︙ | |||
774 775 776 777 778 779 780 781 782 783 784 785 786 787 | $(OBJDIR)/browse_.c:$(OBJDIR)/browse.h \ $(OBJDIR)/builtin_.c:$(OBJDIR)/builtin.h \ $(OBJDIR)/bundle_.c:$(OBJDIR)/bundle.h \ $(OBJDIR)/cache_.c:$(OBJDIR)/cache.h \ $(OBJDIR)/capabilities_.c:$(OBJDIR)/capabilities.h \ $(OBJDIR)/captcha_.c:$(OBJDIR)/captcha.h \ $(OBJDIR)/cgi_.c:$(OBJDIR)/cgi.h \ $(OBJDIR)/checkin_.c:$(OBJDIR)/checkin.h \ $(OBJDIR)/checkout_.c:$(OBJDIR)/checkout.h \ $(OBJDIR)/clearsign_.c:$(OBJDIR)/clearsign.h \ $(OBJDIR)/clone_.c:$(OBJDIR)/clone.h \ $(OBJDIR)/comformat_.c:$(OBJDIR)/comformat.h \ $(OBJDIR)/configure_.c:$(OBJDIR)/configure.h \ $(OBJDIR)/content_.c:$(OBJDIR)/content.h \ | > | 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 | $(OBJDIR)/browse_.c:$(OBJDIR)/browse.h \ $(OBJDIR)/builtin_.c:$(OBJDIR)/builtin.h \ $(OBJDIR)/bundle_.c:$(OBJDIR)/bundle.h \ $(OBJDIR)/cache_.c:$(OBJDIR)/cache.h \ $(OBJDIR)/capabilities_.c:$(OBJDIR)/capabilities.h \ $(OBJDIR)/captcha_.c:$(OBJDIR)/captcha.h \ $(OBJDIR)/cgi_.c:$(OBJDIR)/cgi.h \ $(OBJDIR)/chat_.c:$(OBJDIR)/chat.h \ $(OBJDIR)/checkin_.c:$(OBJDIR)/checkin.h \ $(OBJDIR)/checkout_.c:$(OBJDIR)/checkout.h \ $(OBJDIR)/clearsign_.c:$(OBJDIR)/clearsign.h \ $(OBJDIR)/clone_.c:$(OBJDIR)/clone.h \ $(OBJDIR)/comformat_.c:$(OBJDIR)/comformat.h \ $(OBJDIR)/configure_.c:$(OBJDIR)/configure.h \ $(OBJDIR)/content_.c:$(OBJDIR)/content.h \ |
︙ | ︙ | |||
1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 | $(OBJDIR)/cgi_.c: $(SRCDIR)/cgi.c $(OBJDIR)/translate $(OBJDIR)/translate $(SRCDIR)/cgi.c >$@ $(OBJDIR)/cgi.o: $(OBJDIR)/cgi_.c $(OBJDIR)/cgi.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/cgi.o -c $(OBJDIR)/cgi_.c $(OBJDIR)/cgi.h: $(OBJDIR)/headers $(OBJDIR)/checkin_.c: $(SRCDIR)/checkin.c $(OBJDIR)/translate $(OBJDIR)/translate $(SRCDIR)/checkin.c >$@ $(OBJDIR)/checkin.o: $(OBJDIR)/checkin_.c $(OBJDIR)/checkin.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/checkin.o -c $(OBJDIR)/checkin_.c | > > > > > > > > | 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 | $(OBJDIR)/cgi_.c: $(SRCDIR)/cgi.c $(OBJDIR)/translate $(OBJDIR)/translate $(SRCDIR)/cgi.c >$@ $(OBJDIR)/cgi.o: $(OBJDIR)/cgi_.c $(OBJDIR)/cgi.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/cgi.o -c $(OBJDIR)/cgi_.c $(OBJDIR)/cgi.h: $(OBJDIR)/headers $(OBJDIR)/chat_.c: $(SRCDIR)/chat.c $(OBJDIR)/translate $(OBJDIR)/translate $(SRCDIR)/chat.c >$@ $(OBJDIR)/chat.o: $(OBJDIR)/chat_.c $(OBJDIR)/chat.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/chat.o -c $(OBJDIR)/chat_.c $(OBJDIR)/chat.h: $(OBJDIR)/headers $(OBJDIR)/checkin_.c: $(SRCDIR)/checkin.c $(OBJDIR)/translate $(OBJDIR)/translate $(SRCDIR)/checkin.c >$@ $(OBJDIR)/checkin.o: $(OBJDIR)/checkin_.c $(OBJDIR)/checkin.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/checkin.o -c $(OBJDIR)/checkin_.c |
︙ | ︙ |
Changes to src/makemake.tcl.
︙ | ︙ | |||
41 42 43 44 45 46 47 48 49 50 51 52 53 54 | browse builtin bundle cache capabilities captcha cgi checkin checkout clearsign clone comformat configure content | > | 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 | browse builtin bundle cache capabilities captcha cgi chat checkin checkout clearsign clone comformat configure content |
︙ | ︙ |
Changes to src/rebuild.c.
︙ | ︙ | |||
392 393 394 395 396 397 398 | db_prepare(&q, "SELECT name FROM sqlite_schema /*scan*/" " WHERE type='table'" " AND name NOT IN ('admin_log', 'blob','delta','rcvfrom','user','alias'," "'config','shun','private','reportfmt'," "'concealed','accesslog','modreq'," "'purgeevent','purgeitem','unversioned'," | | | 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 | db_prepare(&q, "SELECT name FROM sqlite_schema /*scan*/" " WHERE type='table'" " AND name NOT IN ('admin_log', 'blob','delta','rcvfrom','user','alias'," "'config','shun','private','reportfmt'," "'concealed','accesslog','modreq'," "'purgeevent','purgeitem','unversioned'," "'subscriber','pending_alert','alert_bounce','chat')" " AND name NOT GLOB 'sqlite_*'" " AND name NOT GLOB 'fx_*'" ); while( db_step(&q)==SQLITE_ROW ){ blob_appendf(&sql, "DROP TABLE IF EXISTS \"%w\";\n", db_column_text(&q,0)); } db_finalize(&q); |
︙ | ︙ | |||
940 941 942 943 944 945 946 947 948 949 950 951 952 953 | "UPDATE rcvfrom SET ipaddr='unknown';\n" "DROP TABLE IF EXISTS accesslog;\n" "UPDATE user SET photo=NULL, info='';\n" "DROP TABLE IF EXISTS purgeevent;\n" "DROP TABLE IF EXISTS purgeitem;\n" "DROP TABLE IF EXISTS admin_log;\n" "DROP TABLE IF EXISTS vcache;\n" ); } db_protect_pop(); } if( !bNeedRebuild ){ db_end_transaction(0); db_unprotect(PROTECT_ALL); | > | 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 | "UPDATE rcvfrom SET ipaddr='unknown';\n" "DROP TABLE IF EXISTS accesslog;\n" "UPDATE user SET photo=NULL, info='';\n" "DROP TABLE IF EXISTS purgeevent;\n" "DROP TABLE IF EXISTS purgeitem;\n" "DROP TABLE IF EXISTS admin_log;\n" "DROP TABLE IF EXISTS vcache;\n" "DROP TABLE IF EXISTS chat;\n" ); } db_protect_pop(); } if( !bNeedRebuild ){ db_end_transaction(0); db_unprotect(PROTECT_ALL); |
︙ | ︙ |
Changes to src/setupuser.c.
︙ | ︙ | |||
679 680 681 682 683 684 685 686 687 688 689 690 691 692 | @ Moderate Forum%s(B('5'))</label> @ <li><label><input type="checkbox" name="a6"%s(oa['6']) /> @ Supervise Forum%s(B('6'))</label> @ <li><label><input type="checkbox" name="a7"%s(oa['7']) /> @ Email Alerts%s(B('7'))</label> @ <li><label><input type="checkbox" name="aA"%s(oa['A']) /> @ Send Announcements%s(B('A'))</label> @ <li><label><input type="checkbox" name="aD"%s(oa['D']) /> @ Enable Debug%s(B('D'))</label> @ </ul></div> @ </td> @ </tr> @ <tr> @ <td class="usetupEditLabel">Selected Cap:</td> | > > | 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 | @ Moderate Forum%s(B('5'))</label> @ <li><label><input type="checkbox" name="a6"%s(oa['6']) /> @ Supervise Forum%s(B('6'))</label> @ <li><label><input type="checkbox" name="a7"%s(oa['7']) /> @ Email Alerts%s(B('7'))</label> @ <li><label><input type="checkbox" name="aA"%s(oa['A']) /> @ Send Announcements%s(B('A'))</label> @ <li><label><input type="checkbox" name="aC"%s(oa['C']) /> @ Chatroom%s(B('C'))</label> @ <li><label><input type="checkbox" name="aD"%s(oa['D']) /> @ Enable Debug%s(B('D'))</label> @ </ul></div> @ </td> @ </tr> @ <tr> @ <td class="usetupEditLabel">Selected Cap:</td> |
︙ | ︙ |
Changes to src/sitemap.c.
︙ | ︙ | |||
113 114 115 116 117 118 119 120 121 122 123 124 125 126 | @ <li>%z(href("%R/leaves"))Leaf Check-ins</a></li> @ </ul> @ </li> } if( srchFlags ){ @ <li>%z(href("%R/search"))Search</a></li> } if( g.perm.RdForum ){ @ <li>%z(href("%R/forum"))Forum</a> @ <ul> @ <li>%z(href("%R/timeline?y=f"))Recent activity</a></li> @ </ul> @ </li> } | > > > | 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 | @ <li>%z(href("%R/leaves"))Leaf Check-ins</a></li> @ </ul> @ </li> } if( srchFlags ){ @ <li>%z(href("%R/search"))Search</a></li> } if( g.perm.Chat ){ @ <li>%z(href("%R/chat"))Chat</a></li> } if( g.perm.RdForum ){ @ <li>%z(href("%R/forum"))Forum</a> @ <ul> @ <li>%z(href("%R/timeline?y=f"))Recent activity</a></li> @ </ul> @ </li> } |
︙ | ︙ |
Changes to src/timeline.c.
︙ | ︙ | |||
120 121 122 123 124 125 126 127 128 129 130 131 132 133 | #define TIMELINE_FORUMTXT 0x4000000 /* Render all forum messages */ #define TIMELINE_REFS 0x8000000 /* Output intended for References tab */ #define TIMELINE_DELTA 0x10000000 /* Background color shows delta manifests */ #endif /* ** Hash a string and use the hash to determine a background color. */ char *hash_color(const char *z){ int i; /* Loop counter */ unsigned int h = 0; /* Hash on the branch name */ int r, g, b; /* Values for red, green, and blue */ int h1, h2, h3, h4; /* Elements of the hash value */ int mx, mn; /* Components of HSV */ | > > > | 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 | #define TIMELINE_FORUMTXT 0x4000000 /* Render all forum messages */ #define TIMELINE_REFS 0x8000000 /* Output intended for References tab */ #define TIMELINE_DELTA 0x10000000 /* Background color shows delta manifests */ #endif /* ** Hash a string and use the hash to determine a background color. ** ** This value returned is in static space and is overwritten with ** each subsequent call. */ char *hash_color(const char *z){ int i; /* Loop counter */ unsigned int h = 0; /* Hash on the branch name */ int r, g, b; /* Values for red, green, and blue */ int h1, h2, h3, h4; /* Elements of the hash value */ int mx, mn; /* Components of HSV */ |
︙ | ︙ |
Added tools/chat.tcl.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 | #!/usr/bin/wapptclsh # # A chat program designed to run using the extcgi mechanism of Fossil. # encoding system utf-8 # The name of the chat database file # proc chat-db-name {} { set x [wapp-param SCRIPT_FILENAME] set dir [file dir $x] set fn [file tail $x] return $dir/-$fn.db } # Verify permission to use chat. Return true if not authorized. # Return false if the Fossil user is allowed to access chat. # proc not-authorized {} { set cap [wapp-param FOSSIL_CAPABILITIES] return [expr {![string match *i* $cap]}] } # The default page. # Load the initial chat screen. # proc wapp-default {} { wapp-content-security-policy off wapp-trim { <div class="fossil-doc" data-title="Chat"> } if {[not-authorized]} { wapp-trim { <h1>Not authorized</h1> <p>You must have privileges to use this chatroom</p> </div> } return } set scriptFile [wapp-param SCRIPT_FILENAME] set cgiFn [file tail $scriptFile] wapp-trim { <form accept-encoding="utf-8" id="chat-form"> <div id='chat-input-area'> <div id='chat-input-line'> <input type="text" name="msg" id="sbox" placeholder="Type message here."> <input type="submit" value="Send"> </div> <div id='chat-input-file'> <span>File:</span> <input type="file" name="file"> </div> </div> </form> <hr> <span id='message-inject-point'><!-- new chat messages get inserted immediately after this element --></span> </div><!-- .fossil-doc --> <hr> <p> <a href="%string($cgiFn)/env">CGI environment</a> | <a href="%string($cgiFn)/self">Wapp script</a> <style> \#dialog { width: 97%; } \#chat-input-area { width: 100%; display: flex; flex-direction: column; } \#chat-input-line { display: flex; flex-direction: row; margin-bottom: 1em; align-items: center; } \#chat-input-line > input[type=submit] { flex: 1 5 auto; max-width: 6em; } \#chat-input-line > input[type=text] { flex: 5 1 auto; } \#chat-input-file { display: flex; flex-direction: row; align-items: center; } \#chat-input-file > input { flex: 1 0 auto; } span.at-name { /* for @USERNAME references */ text-decoration: underline; font-weight: bold; } /* A wrapper for a single single message (one row of the UI) */ .message-row { margin-bottom: 0.5em; border: none; display: flex; flex-direction: row; justify-content: flex-start; /*border: 1px solid rgba(0,0,0,0.2); border-radius: 0.25em; box-shadow: 0.2em 0.2em 0.2em rgba(0, 0, 0, 0.29);*/ border: none; } /* Rows for the current user have the .user-is-me CSS class and get right-aligned. */ .message-row.user-is-me { justify-content: flex-end; /*background-color: #d2dde1;*/ } /* The content area of a message (the body element of a FIELDSET) */ .message-content { display: inline-block; border-radius: 0.25em; border: 1px solid rgba(0,0,0,0.2); box-shadow: 0.2em 0.2em 0.2em rgba(0, 0, 0, 0.29); padding: 0.25em 1em; margin-top: -0.75em; } .message-row.user-is-me .message-content { background-color: #d2dde1; } /* User name for the post (a LEGEND element) */ .message-row .message-user { background: inherit; border-radius: 0.25em 0.25em 0 0; padding: 0 0.5em; /*text-align: left; Firefox requires the 'align' attribute */ margin-left: 0.25em; padding: 0 0.5em 0em 0.5em; margin-bottom: 0.4em; background-color: #d2dde1; } /* Reposition "my" posts to the right */ .message-row.user-is-me .message-user { /*text-align: right; Firefox requires the 'align' attribute */ margin-left: 0; margin-right: 0.25em; } </style> } set nonce [wapp-param FOSSIL_NONCE] set submiturl [wapp-param SCRIPT_NAME]/send set pollurl [wapp-param SCRIPT_NAME]/poll set downloadurl [wapp-param SCRIPT_NAME]/download set me [wapp-param FOSSIL_USER] wapp-trim { <script nonce="%string($nonce)"> (function(){ const form = document.querySelector('#chat-form'); let mxMsg = 0; let _me = "%string($me)"; form.addEventListener('submit',(e)=>{ e.preventDefault(); if( form.msg.value.length>0 || form.file.value.length>0 ){ fetch("%string($submiturl)",{ method: 'POST', body: new FormData(form) }); } form.msg.value = ""; form.file.value = ""; form.msg.focus(); }); const rxUrl = /\\b(?:https?|ftp):\\/\\/\[a-z0-9-+&@\#\\/%?=~_|!:,.;]*\[a-z0-9-+&@\#\\/%=~_|]/gim; const rxAtName = /@\\w+/gmi; // ^^^ achtung, extra backslashes needed for the outer TCL. const textNode = (T)=>document.createTextNode(T); // Converts a message string to a message-containing DOM element // and returns that element, which may contain child elements. // If 2nd arg is passed, it must be a DOM element to which all // child elements are appended. const messageToDOM = function f(str, tgtElem){ "use strict"; if(!f.rxUrl){ f.rxUrl = rxUrl; f.rxAt = rxAtName; f.rxNS = /\\S/; f.ce = (T)=>document.createElement(T); f.ct = (T)=>document.createTextNode(T); f.replaceUrls = function ff(sub, offset, whole){ if(offset > ff.prevStart){ f.accum.push((ff.prevStart?' ':'')+whole.substring(ff.prevStart, offset-1)+' '); } const a = f.ce('a'); a.setAttribute('href',sub); a.setAttribute('target','_blank'); a.appendChild(f.ct(sub)); f.accum.push(a); ff.prevStart = offset + sub.length + 1; }; f.replaceAtName = function ff(sub, offset,whole){ if(offset > ff.prevStart){ ff.accum.push((ff.prevStart?' ':'')+whole.substring(ff.prevStart, offset-1)+' '); }else if(offset && f.rxNS.test(whole[offset-1])){ // Sigh: https://stackoverflow.com/questions/52655367 ff.accum.push(sub); return; } const e = f.ce('span'); e.classList.add('at-name'); e.appendChild(f.ct(sub)); ff.accum.push(e); ff.prevStart = offset + sub.length + 1; }; } f.accum = []; // accumulate strings and DOM elements here. f.rxUrl.lastIndex = f.replaceUrls.prevStart = 0; // reset regex cursor str.replace(f.rxUrl, f.replaceUrls); // Push remaining non-URL part of the string to the queue... if(f.replaceUrls.prevStart < str.length){ f.accum.push((f.replaceUrls.prevStart?' ':'')+str.substring(f.replaceUrls.prevStart)); } // Pass 2: process @NAME references... // TODO: only match NAME if it's the name of a currently participating // user. Add a second class if NAME == current user, and style that one // differently so that people can more easily see when they're spoken to. const accum2 = f.replaceAtName.accum = []; //console.debug("f.accum =",f.accum); f.accum.forEach(function(v){ //console.debug("v =",v); if('string'===typeof v){ f.rxAt.lastIndex = f.replaceAtName.prevStart = 0; v.replace(f.rxAt, f.replaceAtName); if(f.replaceAtName.prevStart < v.length){ accum2.push((f.replaceAtName.prevStart?' ':'')+v.substring(f.replaceAtName.prevStart)); } }else{ accum2.push(v); } //console.debug("accum2 =",accum2); }); delete f.accum; //console.debug("accum2 =",accum2); const span = tgtElem || f.ce('span'); accum2.forEach(function(e){ if('string'===typeof e) e = f.ct(e); span.appendChild(e); }); //console.debug("span =",span.innerHTML); return span; }/*end messageToDOM()*/; /* Injects element e as a new row in the chat, at the top of the list */ const injectMessage = function f(e){ if(!f.injectPoint){ f.injectPoint = document.querySelector('#message-inject-point'); } if(f.injectPoint.nextSibling){ f.injectPoint.parentNode.insertBefore(e, f.injectPoint.nextSibling); }else{ f.injectPoint.parentNode.appendChild(e); } }; /** Returns the local time string of Date object d, defaulting to the current time. */ const localTimeString = function ff(d){ if(!ff.pad){ ff.pad = (x)=>(''+x).length>1 ? x : '0'+x; } d || (d = new Date()); return [ d.getFullYear(),'-',ff.pad(d.getMonth()+1/*sigh*/), '-',ff.pad(d.getDate()), ' ',ff.pad(d.getHours()),':',ff.pad(d.getMinutes()), ':',ff.pad(d.getSeconds()) ].join(''); }; function newcontent(jx){ var i; for(i=0; i<jx.msgs.length; ++i){ let m = jx.msgs[i]; let row = document.createElement("fieldset"); if( m.msgid>mxMsg ) mxMsg = m.msgid; row.classList.add('message-row'); injectMessage(row); const eWho = document.createElement('legend'); eWho.setAttribute('align', (m.xfrom===_me ? 'right' : 'left')); row.appendChild(eWho); eWho.classList.add('message-user'); let whoName; if( m.xfrom===_me ){ whoName = 'me'; row.classList.add('user-is-me'); }else{ whoName = m.xfrom; } eWho.append(textNode( whoName+' @ '+ localTimeString(new Date(Date.parse(m.mtime+".000Z")))) ); let span = document.createElement("div"); span.classList.add('message-content'); row.appendChild(span); if( m.fsize>0 ){ if( m.fmime && m.fmime.startsWith("image/") ){ let img = document.createElement("img"); img.src = "%string($downloadurl)/" + m.msgid; span.appendChild(img); }else{ let a = document.createElement("a"); let txt = "(" + m.fname + " " + m.fsize + " bytes)"; a.href = "%string($downloadurl)/" + m.msgid; a.appendChild(document.createTextNode(txt)); span.appendChild(a); } let br = document.createElement("br"); br.style.clear = "both"; span.appendChild(br); } if(m.xmsg){ messageToDOM(m.xmsg, span); } span.classList.add('chat-message'); if( m.xfrom!=_me ){ span.classList.add('chat-mx'); }else{ span.classList.add('chat-ms'); } } } async function poll(){ if(poll.running) return; poll.running = true; fetch("%string($pollurl)/" + mxMsg) .then(x=>x.json()) .then(y=>newcontent(y)) .finally(()=>poll.running=false) } setInterval(poll, 1000); })();</script> } # Make sure the chat database exists sqlite3 db [chat-db-name] if {[db one {PRAGMA journal_mode}]!="wal"} { db eval {PRAGMA journal_mode=WAL} } db eval { CREATE TABLE IF NOT EXISTS chat( msgid INTEGER PRIMARY KEY AUTOINCREMENT, mtime JULIANDAY, xfrom TEXT, xto TEXT, xmsg TEXT, file BLOB, fname TEXT, fmime TEXT ); CREATE TABLE IF NOT EXISTS ustat( uname TEXT PRIMARY KEY, mtime JULIANDAY, -- Last interaction seen INT, -- Last message seen logout JULIANDAY ) WITHOUT ROWID; } db close } # Show the CGI environment. Used for testing only. # proc wapp-page-env {} { wapp-trim { <div class="fossil-doc" data-title="Chat CGI Environment"> <pre>%html([wapp-debug-env])</pre> </div> } } # Log the CGI environment into the "-logfile.txt" file in the same # directory as the script. Used for testing and development only. # proc logenv {} { set fn [file dir [wapp-param SCRIPT_FILENAME]]/-logfile.txt set out [open $fn a] puts $out {************************************************************} puts $out [wapp-debug-env] close $out } # A no-op page. Used for testing and development only. # proc noop-page {} { wapp-trim { <div class="fossil-doc" data-title="No-op"><h1>No-Op</h1></div> } } # Accept a new post via XHR. # No reply expected. # proc wapp-page-send {} { if {[not-authorized]} return set user [wapp-param FOSSIL_USER] set fcontent [wapp-param file.content] set fname [wapp-param file.filename] set fmime [wapp-param file.mimetype] set msg [wapp-param msg] sqlite3 db [chat-db-name] db eval BEGIN if {$fcontent!=""} { db eval { INSERT INTO chat(mtime,xfrom,xmsg,file,fname,fmime) VALUES(julianday('now'),$user,@msg,@fcontent,$fname,$fmime) } } else { db eval { INSERT INTO chat(mtime,xfrom,xmsg) VALUES(julianday('now'),$user,@msg) } } db eval { INSERT INTO ustat(uname,mtime,seen) VALUES($user,julianday('now'),0) ON CONFLICT(uname) DO UPDATE set mtime=julianday('now') } db eval COMMIT db close } # Request updates. # Delay the response until something changes (as this system works # using the Hanging-GET or Long-Poll style of server-push). # The result is javascript describing the new content. # # Call is like this: /poll/N # Where N is the last message received so far. The reply stalls # until newer messages are available. # proc wapp-page-poll {} { if {[not-authorized]} return wapp-mimetype text/json set msglist {} sqlite3 db [chat-db-name] set id 0 scan [wapp-param PATH_TAIL] %d id while {1} { set datavers [db one {PRAGMA data_version}] db eval {SELECT msgid, datetime(mtime) AS dx, xfrom, CAST(xmsg AS text) mx, length(file) AS lx, fname, fmime FROM chat WHERE msgid>$id ORDER BY msgid} { set quname [string map {\" \\\"} $xfrom] set qmsg [string map {\" \\\"} $mx] if {$lx==""} {set lx 0} set qfname [string map {\" \\\"} $fname] lappend msglist "\173\"msgid\":$msgid,\"mtime\":\"$dx\",\ \"xfrom\":\"$quname\",\ \"xmsg\":\"$qmsg\",\"fsize\":$lx,\ \"fname\":\"$qfname\",\"fmime\":\"$fmime\"\175" } if {[llength $msglist]>0} { wapp-unsafe "\173\042msgs\042:\133[join $msglist ,]\135\175" db close return } after 2000 while {[db one {PRAGMA data_version}]==$datavers} {after 2000} } } # Show the text of this script. # proc wapp-page-self {} { wapp-trim { <div class="fossil-doc" data-title="Wapp Script for Chat"> } set fd [open [wapp-param SCRIPT_FILENAME] rb] set script [read $fd] wapp-trim { <pre>%html($script)</pre> } wapp-trim { </div> } } # Download the file associated with a message. # # Call like this: /download/N # Where N is the message id. # proc wapp-page-download {} { if {[not-authorized]} { wapp-trim { <h1>Not authorized</h1> <p>You must have privileges to use this chatroom</p> </div> } return } set id 0 scan [wapp-param PATH_TAIL] %d id sqlite3 db [chat-db-name] db eval {SELECT fname, fmime, file FROM chat WHERE msgid=$id} { wapp-mimetype $fmime wapp $file } db close } wapp-start $argv |
Changes to win/Makefile.dmc.
︙ | ︙ | |||
26 27 28 29 30 31 32 | TCC = $(DMDIR)\bin\dmc $(CFLAGS) $(DMCDEF) $(SSL) $(INCL) LIBS = $(DMDIR)\extra\lib\ zlib wsock32 advapi32 dnsapi 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 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 | | | | | 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 | TCC = $(DMDIR)\bin\dmc $(CFLAGS) $(DMCDEF) $(SSL) $(INCL) LIBS = $(DMDIR)\extra\lib\ zlib wsock32 advapi32 dnsapi 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 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 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 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 RC=$(DMDIR)\bin\rcc RCFLAGS=-32 -w1 -I$(SRCDIR) /D__DMC__ APPNAME = $(OBJDIR)\fossil$(E) all: $(APPNAME) $(APPNAME) : translate$E mkindex$E codecheck1$E headers $(OBJ) $(OBJDIR)\link cd $(OBJDIR) codecheck1$E $(SRC) $(DMDIR)\bin\link @link $(OBJDIR)\fossil.res: $B\win\fossil.rc $(RC) $(RCFLAGS) -o$@ $** $(OBJDIR)\link: $B\win\Makefile.dmc $(OBJDIR)\fossil.res +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 > $@ +echo fossil >> $@ +echo fossil >> $@ +echo $(LIBS) >> $@ +echo. >> $@ +echo fossil >> $@ translate$E: $(SRCDIR)\translate.c |
︙ | ︙ | |||
227 228 229 230 231 232 233 234 235 236 237 238 239 240 | +translate$E $** > $@ $(OBJDIR)\cgi$O : cgi_.c cgi.h $(TCC) -o$@ -c cgi_.c cgi_.c : $(SRCDIR)\cgi.c +translate$E $** > $@ $(OBJDIR)\checkin$O : checkin_.c checkin.h $(TCC) -o$@ -c checkin_.c checkin_.c : $(SRCDIR)\checkin.c +translate$E $** > $@ | > > > > > > | 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 | +translate$E $** > $@ $(OBJDIR)\cgi$O : cgi_.c cgi.h $(TCC) -o$@ -c cgi_.c cgi_.c : $(SRCDIR)\cgi.c +translate$E $** > $@ $(OBJDIR)\chat$O : chat_.c chat.h $(TCC) -o$@ -c chat_.c chat_.c : $(SRCDIR)\chat.c +translate$E $** > $@ $(OBJDIR)\checkin$O : checkin_.c checkin.h $(TCC) -o$@ -c checkin_.c checkin_.c : $(SRCDIR)\checkin.c +translate$E $** > $@ |
︙ | ︙ | |||
997 998 999 1000 1001 1002 1003 | $(OBJDIR)\zip$O : zip_.c zip.h $(TCC) -o$@ -c zip_.c zip_.c : $(SRCDIR)\zip.c +translate$E $** > $@ headers: makeheaders$E page_index.h builtin_data.h VERSION.h | | | 1003 1004 1005 1006 1007 1008 1009 1010 1011 | $(OBJDIR)\zip$O : zip_.c zip.h $(TCC) -o$@ -c zip_.c zip_.c : $(SRCDIR)\zip.c +translate$E $** > $@ headers: makeheaders$E page_index.h builtin_data.h VERSION.h +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 @copy /Y nul: headers |
Changes to win/Makefile.mingw.
︙ | ︙ | |||
442 443 444 445 446 447 448 449 450 451 452 453 454 455 | $(SRCDIR)/browse.c \ $(SRCDIR)/builtin.c \ $(SRCDIR)/bundle.c \ $(SRCDIR)/cache.c \ $(SRCDIR)/capabilities.c \ $(SRCDIR)/captcha.c \ $(SRCDIR)/cgi.c \ $(SRCDIR)/checkin.c \ $(SRCDIR)/checkout.c \ $(SRCDIR)/clearsign.c \ $(SRCDIR)/clone.c \ $(SRCDIR)/comformat.c \ $(SRCDIR)/configure.c \ $(SRCDIR)/content.c \ | > | 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 | $(SRCDIR)/browse.c \ $(SRCDIR)/builtin.c \ $(SRCDIR)/bundle.c \ $(SRCDIR)/cache.c \ $(SRCDIR)/capabilities.c \ $(SRCDIR)/captcha.c \ $(SRCDIR)/cgi.c \ $(SRCDIR)/chat.c \ $(SRCDIR)/checkin.c \ $(SRCDIR)/checkout.c \ $(SRCDIR)/clearsign.c \ $(SRCDIR)/clone.c \ $(SRCDIR)/comformat.c \ $(SRCDIR)/configure.c \ $(SRCDIR)/content.c \ |
︙ | ︙ | |||
629 630 631 632 633 634 635 636 637 638 639 640 641 642 | $(SRCDIR)/../skins/rounded1/footer.txt \ $(SRCDIR)/../skins/rounded1/header.txt \ $(SRCDIR)/../skins/xekri/css.txt \ $(SRCDIR)/../skins/xekri/details.txt \ $(SRCDIR)/../skins/xekri/footer.txt \ $(SRCDIR)/../skins/xekri/header.txt \ $(SRCDIR)/accordion.js \ $(SRCDIR)/ci_edit.js \ $(SRCDIR)/copybtn.js \ $(SRCDIR)/default.css \ $(SRCDIR)/diff.tcl \ $(SRCDIR)/forum.js \ $(SRCDIR)/fossil.bootstrap.js \ $(SRCDIR)/fossil.confirmer.js \ | > | 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 | $(SRCDIR)/../skins/rounded1/footer.txt \ $(SRCDIR)/../skins/rounded1/header.txt \ $(SRCDIR)/../skins/xekri/css.txt \ $(SRCDIR)/../skins/xekri/details.txt \ $(SRCDIR)/../skins/xekri/footer.txt \ $(SRCDIR)/../skins/xekri/header.txt \ $(SRCDIR)/accordion.js \ $(SRCDIR)/chat.js \ $(SRCDIR)/ci_edit.js \ $(SRCDIR)/copybtn.js \ $(SRCDIR)/default.css \ $(SRCDIR)/diff.tcl \ $(SRCDIR)/forum.js \ $(SRCDIR)/fossil.bootstrap.js \ $(SRCDIR)/fossil.confirmer.js \ |
︙ | ︙ | |||
700 701 702 703 704 705 706 707 708 709 710 711 712 713 | $(OBJDIR)/browse_.c \ $(OBJDIR)/builtin_.c \ $(OBJDIR)/bundle_.c \ $(OBJDIR)/cache_.c \ $(OBJDIR)/capabilities_.c \ $(OBJDIR)/captcha_.c \ $(OBJDIR)/cgi_.c \ $(OBJDIR)/checkin_.c \ $(OBJDIR)/checkout_.c \ $(OBJDIR)/clearsign_.c \ $(OBJDIR)/clone_.c \ $(OBJDIR)/comformat_.c \ $(OBJDIR)/configure_.c \ $(OBJDIR)/content_.c \ | > | 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 | $(OBJDIR)/browse_.c \ $(OBJDIR)/builtin_.c \ $(OBJDIR)/bundle_.c \ $(OBJDIR)/cache_.c \ $(OBJDIR)/capabilities_.c \ $(OBJDIR)/captcha_.c \ $(OBJDIR)/cgi_.c \ $(OBJDIR)/chat_.c \ $(OBJDIR)/checkin_.c \ $(OBJDIR)/checkout_.c \ $(OBJDIR)/clearsign_.c \ $(OBJDIR)/clone_.c \ $(OBJDIR)/comformat_.c \ $(OBJDIR)/configure_.c \ $(OBJDIR)/content_.c \ |
︙ | ︙ | |||
848 849 850 851 852 853 854 855 856 857 858 859 860 861 | $(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 \ | > | 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 | $(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 \ |
︙ | ︙ | |||
1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 | $(OBJDIR)/browse_.c:$(OBJDIR)/browse.h \ $(OBJDIR)/builtin_.c:$(OBJDIR)/builtin.h \ $(OBJDIR)/bundle_.c:$(OBJDIR)/bundle.h \ $(OBJDIR)/cache_.c:$(OBJDIR)/cache.h \ $(OBJDIR)/capabilities_.c:$(OBJDIR)/capabilities.h \ $(OBJDIR)/captcha_.c:$(OBJDIR)/captcha.h \ $(OBJDIR)/cgi_.c:$(OBJDIR)/cgi.h \ $(OBJDIR)/checkin_.c:$(OBJDIR)/checkin.h \ $(OBJDIR)/checkout_.c:$(OBJDIR)/checkout.h \ $(OBJDIR)/clearsign_.c:$(OBJDIR)/clearsign.h \ $(OBJDIR)/clone_.c:$(OBJDIR)/clone.h \ $(OBJDIR)/comformat_.c:$(OBJDIR)/comformat.h \ $(OBJDIR)/configure_.c:$(OBJDIR)/configure.h \ $(OBJDIR)/content_.c:$(OBJDIR)/content.h \ | > | 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 | $(OBJDIR)/browse_.c:$(OBJDIR)/browse.h \ $(OBJDIR)/builtin_.c:$(OBJDIR)/builtin.h \ $(OBJDIR)/bundle_.c:$(OBJDIR)/bundle.h \ $(OBJDIR)/cache_.c:$(OBJDIR)/cache.h \ $(OBJDIR)/capabilities_.c:$(OBJDIR)/capabilities.h \ $(OBJDIR)/captcha_.c:$(OBJDIR)/captcha.h \ $(OBJDIR)/cgi_.c:$(OBJDIR)/cgi.h \ $(OBJDIR)/chat_.c:$(OBJDIR)/chat.h \ $(OBJDIR)/checkin_.c:$(OBJDIR)/checkin.h \ $(OBJDIR)/checkout_.c:$(OBJDIR)/checkout.h \ $(OBJDIR)/clearsign_.c:$(OBJDIR)/clearsign.h \ $(OBJDIR)/clone_.c:$(OBJDIR)/clone.h \ $(OBJDIR)/comformat_.c:$(OBJDIR)/comformat.h \ $(OBJDIR)/configure_.c:$(OBJDIR)/configure.h \ $(OBJDIR)/content_.c:$(OBJDIR)/content.h \ |
︙ | ︙ | |||
1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 | $(OBJDIR)/cgi_.c: $(SRCDIR)/cgi.c $(TRANSLATE) $(TRANSLATE) $(SRCDIR)/cgi.c >$@ $(OBJDIR)/cgi.o: $(OBJDIR)/cgi_.c $(OBJDIR)/cgi.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/cgi.o -c $(OBJDIR)/cgi_.c $(OBJDIR)/cgi.h: $(OBJDIR)/headers $(OBJDIR)/checkin_.c: $(SRCDIR)/checkin.c $(TRANSLATE) $(TRANSLATE) $(SRCDIR)/checkin.c >$@ $(OBJDIR)/checkin.o: $(OBJDIR)/checkin_.c $(OBJDIR)/checkin.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/checkin.o -c $(OBJDIR)/checkin_.c | > > > > > > > > | 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 | $(OBJDIR)/cgi_.c: $(SRCDIR)/cgi.c $(TRANSLATE) $(TRANSLATE) $(SRCDIR)/cgi.c >$@ $(OBJDIR)/cgi.o: $(OBJDIR)/cgi_.c $(OBJDIR)/cgi.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/cgi.o -c $(OBJDIR)/cgi_.c $(OBJDIR)/cgi.h: $(OBJDIR)/headers $(OBJDIR)/chat_.c: $(SRCDIR)/chat.c $(TRANSLATE) $(TRANSLATE) $(SRCDIR)/chat.c >$@ $(OBJDIR)/chat.o: $(OBJDIR)/chat_.c $(OBJDIR)/chat.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/chat.o -c $(OBJDIR)/chat_.c $(OBJDIR)/chat.h: $(OBJDIR)/headers $(OBJDIR)/checkin_.c: $(SRCDIR)/checkin.c $(TRANSLATE) $(TRANSLATE) $(SRCDIR)/checkin.c >$@ $(OBJDIR)/checkin.o: $(OBJDIR)/checkin_.c $(OBJDIR)/checkin.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/checkin.o -c $(OBJDIR)/checkin_.c |
︙ | ︙ |
Changes to win/Makefile.msc.
︙ | ︙ | |||
364 365 366 367 368 369 370 371 372 373 374 375 376 377 | "$(OX)\browse_.c" \ "$(OX)\builtin_.c" \ "$(OX)\bundle_.c" \ "$(OX)\cache_.c" \ "$(OX)\capabilities_.c" \ "$(OX)\captcha_.c" \ "$(OX)\cgi_.c" \ "$(OX)\checkin_.c" \ "$(OX)\checkout_.c" \ "$(OX)\clearsign_.c" \ "$(OX)\clone_.c" \ "$(OX)\comformat_.c" \ "$(OX)\configure_.c" \ "$(OX)\content_.c" \ | > | 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 | "$(OX)\browse_.c" \ "$(OX)\builtin_.c" \ "$(OX)\bundle_.c" \ "$(OX)\cache_.c" \ "$(OX)\capabilities_.c" \ "$(OX)\captcha_.c" \ "$(OX)\cgi_.c" \ "$(OX)\chat_.c" \ "$(OX)\checkin_.c" \ "$(OX)\checkout_.c" \ "$(OX)\clearsign_.c" \ "$(OX)\clone_.c" \ "$(OX)\comformat_.c" \ "$(OX)\configure_.c" \ "$(OX)\content_.c" \ |
︙ | ︙ | |||
550 551 552 553 554 555 556 557 558 559 560 561 562 563 | "$(SRCDIR)\..\skins\rounded1\footer.txt" \ "$(SRCDIR)\..\skins\rounded1\header.txt" \ "$(SRCDIR)\..\skins\xekri\css.txt" \ "$(SRCDIR)\..\skins\xekri\details.txt" \ "$(SRCDIR)\..\skins\xekri\footer.txt" \ "$(SRCDIR)\..\skins\xekri\header.txt" \ "$(SRCDIR)\accordion.js" \ "$(SRCDIR)\ci_edit.js" \ "$(SRCDIR)\copybtn.js" \ "$(SRCDIR)\default.css" \ "$(SRCDIR)\diff.tcl" \ "$(SRCDIR)\forum.js" \ "$(SRCDIR)\fossil.bootstrap.js" \ "$(SRCDIR)\fossil.confirmer.js" \ | > | 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 | "$(SRCDIR)\..\skins\rounded1\footer.txt" \ "$(SRCDIR)\..\skins\rounded1\header.txt" \ "$(SRCDIR)\..\skins\xekri\css.txt" \ "$(SRCDIR)\..\skins\xekri\details.txt" \ "$(SRCDIR)\..\skins\xekri\footer.txt" \ "$(SRCDIR)\..\skins\xekri\header.txt" \ "$(SRCDIR)\accordion.js" \ "$(SRCDIR)\chat.js" \ "$(SRCDIR)\ci_edit.js" \ "$(SRCDIR)\copybtn.js" \ "$(SRCDIR)\default.css" \ "$(SRCDIR)\diff.tcl" \ "$(SRCDIR)\forum.js" \ "$(SRCDIR)\fossil.bootstrap.js" \ "$(SRCDIR)\fossil.confirmer.js" \ |
︙ | ︙ | |||
620 621 622 623 624 625 626 627 628 629 630 631 632 633 | "$(OX)\browse$O" \ "$(OX)\builtin$O" \ "$(OX)\bundle$O" \ "$(OX)\cache$O" \ "$(OX)\capabilities$O" \ "$(OX)\captcha$O" \ "$(OX)\cgi$O" \ "$(OX)\checkin$O" \ "$(OX)\checkout$O" \ "$(OX)\clearsign$O" \ "$(OX)\clone$O" \ "$(OX)\comformat$O" \ "$(OX)\configure$O" \ "$(OX)\content$O" \ | > | 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 | "$(OX)\browse$O" \ "$(OX)\builtin$O" \ "$(OX)\bundle$O" \ "$(OX)\cache$O" \ "$(OX)\capabilities$O" \ "$(OX)\captcha$O" \ "$(OX)\cgi$O" \ "$(OX)\chat$O" \ "$(OX)\checkin$O" \ "$(OX)\checkout$O" \ "$(OX)\clearsign$O" \ "$(OX)\clone$O" \ "$(OX)\comformat$O" \ "$(OX)\configure$O" \ "$(OX)\content$O" \ |
︙ | ︙ | |||
849 850 851 852 853 854 855 856 857 858 859 860 861 862 | echo "$(OX)\browse.obj" >> $@ echo "$(OX)\builtin.obj" >> $@ echo "$(OX)\bundle.obj" >> $@ echo "$(OX)\cache.obj" >> $@ echo "$(OX)\capabilities.obj" >> $@ echo "$(OX)\captcha.obj" >> $@ echo "$(OX)\cgi.obj" >> $@ echo "$(OX)\checkin.obj" >> $@ echo "$(OX)\checkout.obj" >> $@ echo "$(OX)\clearsign.obj" >> $@ echo "$(OX)\clone.obj" >> $@ echo "$(OX)\comformat.obj" >> $@ echo "$(OX)\configure.obj" >> $@ echo "$(OX)\content.obj" >> $@ | > | 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 | echo "$(OX)\browse.obj" >> $@ echo "$(OX)\builtin.obj" >> $@ echo "$(OX)\bundle.obj" >> $@ echo "$(OX)\cache.obj" >> $@ echo "$(OX)\capabilities.obj" >> $@ echo "$(OX)\captcha.obj" >> $@ echo "$(OX)\cgi.obj" >> $@ echo "$(OX)\chat.obj" >> $@ echo "$(OX)\checkin.obj" >> $@ echo "$(OX)\checkout.obj" >> $@ echo "$(OX)\clearsign.obj" >> $@ echo "$(OX)\clone.obj" >> $@ echo "$(OX)\comformat.obj" >> $@ echo "$(OX)\configure.obj" >> $@ echo "$(OX)\content.obj" >> $@ |
︙ | ︙ | |||
1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 | echo "$(SRCDIR)\../skins/rounded1/footer.txt" >> $@ echo "$(SRCDIR)\../skins/rounded1/header.txt" >> $@ echo "$(SRCDIR)\../skins/xekri/css.txt" >> $@ echo "$(SRCDIR)\../skins/xekri/details.txt" >> $@ echo "$(SRCDIR)\../skins/xekri/footer.txt" >> $@ echo "$(SRCDIR)\../skins/xekri/header.txt" >> $@ echo "$(SRCDIR)\accordion.js" >> $@ echo "$(SRCDIR)\ci_edit.js" >> $@ echo "$(SRCDIR)\copybtn.js" >> $@ echo "$(SRCDIR)\default.css" >> $@ echo "$(SRCDIR)\diff.tcl" >> $@ echo "$(SRCDIR)\forum.js" >> $@ echo "$(SRCDIR)\fossil.bootstrap.js" >> $@ echo "$(SRCDIR)\fossil.confirmer.js" >> $@ | > | 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 | echo "$(SRCDIR)\../skins/rounded1/footer.txt" >> $@ echo "$(SRCDIR)\../skins/rounded1/header.txt" >> $@ echo "$(SRCDIR)\../skins/xekri/css.txt" >> $@ echo "$(SRCDIR)\../skins/xekri/details.txt" >> $@ echo "$(SRCDIR)\../skins/xekri/footer.txt" >> $@ echo "$(SRCDIR)\../skins/xekri/header.txt" >> $@ echo "$(SRCDIR)\accordion.js" >> $@ echo "$(SRCDIR)\chat.js" >> $@ echo "$(SRCDIR)\ci_edit.js" >> $@ echo "$(SRCDIR)\copybtn.js" >> $@ echo "$(SRCDIR)\default.css" >> $@ echo "$(SRCDIR)\diff.tcl" >> $@ echo "$(SRCDIR)\forum.js" >> $@ echo "$(SRCDIR)\fossil.bootstrap.js" >> $@ echo "$(SRCDIR)\fossil.confirmer.js" >> $@ |
︙ | ︙ | |||
1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 | "$(OBJDIR)\translate$E" $** > $@ "$(OX)\cgi$O" : "$(OX)\cgi_.c" "$(OX)\cgi.h" $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\cgi_.c" "$(OX)\cgi_.c" : "$(SRCDIR)\cgi.c" "$(OBJDIR)\translate$E" $** > $@ "$(OX)\checkin$O" : "$(OX)\checkin_.c" "$(OX)\checkin.h" $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\checkin_.c" "$(OX)\checkin_.c" : "$(SRCDIR)\checkin.c" "$(OBJDIR)\translate$E" $** > $@ | > > > > > > | 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 | "$(OBJDIR)\translate$E" $** > $@ "$(OX)\cgi$O" : "$(OX)\cgi_.c" "$(OX)\cgi.h" $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\cgi_.c" "$(OX)\cgi_.c" : "$(SRCDIR)\cgi.c" "$(OBJDIR)\translate$E" $** > $@ "$(OX)\chat$O" : "$(OX)\chat_.c" "$(OX)\chat.h" $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\chat_.c" "$(OX)\chat_.c" : "$(SRCDIR)\chat.c" "$(OBJDIR)\translate$E" $** > $@ "$(OX)\checkin$O" : "$(OX)\checkin_.c" "$(OX)\checkin.h" $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\checkin_.c" "$(OX)\checkin_.c" : "$(SRCDIR)\checkin.c" "$(OBJDIR)\translate$E" $** > $@ |
︙ | ︙ | |||
2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 | "$(OX)\browse_.c":"$(OX)\browse.h" \ "$(OX)\builtin_.c":"$(OX)\builtin.h" \ "$(OX)\bundle_.c":"$(OX)\bundle.h" \ "$(OX)\cache_.c":"$(OX)\cache.h" \ "$(OX)\capabilities_.c":"$(OX)\capabilities.h" \ "$(OX)\captcha_.c":"$(OX)\captcha.h" \ "$(OX)\cgi_.c":"$(OX)\cgi.h" \ "$(OX)\checkin_.c":"$(OX)\checkin.h" \ "$(OX)\checkout_.c":"$(OX)\checkout.h" \ "$(OX)\clearsign_.c":"$(OX)\clearsign.h" \ "$(OX)\clone_.c":"$(OX)\clone.h" \ "$(OX)\comformat_.c":"$(OX)\comformat.h" \ "$(OX)\configure_.c":"$(OX)\configure.h" \ "$(OX)\content_.c":"$(OX)\content.h" \ | > | 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 | "$(OX)\browse_.c":"$(OX)\browse.h" \ "$(OX)\builtin_.c":"$(OX)\builtin.h" \ "$(OX)\bundle_.c":"$(OX)\bundle.h" \ "$(OX)\cache_.c":"$(OX)\cache.h" \ "$(OX)\capabilities_.c":"$(OX)\capabilities.h" \ "$(OX)\captcha_.c":"$(OX)\captcha.h" \ "$(OX)\cgi_.c":"$(OX)\cgi.h" \ "$(OX)\chat_.c":"$(OX)\chat.h" \ "$(OX)\checkin_.c":"$(OX)\checkin.h" \ "$(OX)\checkout_.c":"$(OX)\checkout.h" \ "$(OX)\clearsign_.c":"$(OX)\clearsign.h" \ "$(OX)\clone_.c":"$(OX)\clone.h" \ "$(OX)\comformat_.c":"$(OX)\comformat.h" \ "$(OX)\configure_.c":"$(OX)\configure.h" \ "$(OX)\content_.c":"$(OX)\content.h" \ |
︙ | ︙ |