292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
|
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
|
-
+
|
}else{
CX("}");
}
fossil_free(zTime);
}
/*
** WEBPAGE: chat-send
** WEBPAGE: chat-send hidden
**
** This page receives (via XHR) a new chat-message and/or a new file
** to be entered into the chat history.
**
** On success it responds with an empty response: the new message
** should be fetched via /chat-poll. On error, e.g. login expiry,
** it emits a JSON response in the same form as described for
|
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
|
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
|
-
-
+
+
-
-
+
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
+
-
-
-
-
+
-
-
-
-
-
-
-
+
-
-
-
-
-
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
|
blob_reset(&b);
}
db_commit_transaction();
}
/*
** This routine receives raw (user-entered) message text and transforms
** it into HTML that is safe to insert using innerHTML.
**
** it into HTML that is safe to insert using innerHTML. As of 2021-09-19,
** it does so by using markdown_to_html() to convert markdown-formatted
** * HTML in the original text is escaped.
**
** zMsg to HTML.
** * Hyperlinks are identified and tagged. Hyperlinks are:
**
** - Undelimited text of the form https:... or http:...
** - Any text enclosed within [...]
**
** Space to hold the returned string is obtained from fossil_malloc()
** and must be freed by the caller.
*/
static char *chat_format_to_html(const char *zMsg){
char *zSafe = mprintf("%h", zMsg);
int i, j, k;
Blob out;
char zClose[20];
blob_init(&out, 0, 0);
blob_init(&out, "", 0);
for(i=j=0; zSafe[i]; i++){
if( zSafe[i]=='[' ){
for(k=i+1; zSafe[k] && zSafe[k]!=']'; k++){}
if( zSafe[k]==']' ){
zSafe[k] = 0;
if( j<i ){
if(*zMsg){
blob_append(&out, zSafe + j, i-j);
j = i;
}
blob_append_char(&out, '[');
Blob bIn;
wiki_resolve_hyperlink(&out,
WIKI_NOBADLINKS|WIKI_TARGET_BLANK|WIKI_NOBRACKET,
zSafe+i+1, zClose, sizeof(zClose), zSafe, 0);
zSafe[k] = ']';
j++;
blob_append(&out, zSafe + j, k - j);
blob_append(&out, zClose, -1);
blob_init(&bIn, zMsg, (int)strlen(zMsg));
blob_append_char(&out, ']');
i = k;
j = k+1;
continue;
}
markdown_to_html(&bIn, NULL, &out);
}
}else if( zSafe[i]=='h'
&& (strncmp(zSafe+i,"http:",5)==0
|| strncmp(zSafe+i,"https:",6)==0) ){
for(k=i+1; zSafe[k] && !fossil_isspace(zSafe[k]); k++){}
if( k>i+7 ){
char c = zSafe[k];
if( !fossil_isalnum(zSafe[k-1]) && zSafe[k-1]!='/' ){
k--;
c = zSafe[k];
}
if( j<i ){
blob_append(&out, zSafe + j, i-j);
j = i;
}
zSafe[k] = 0;
wiki_resolve_hyperlink(&out, WIKI_NOBADLINKS|WIKI_TARGET_BLANK,
zSafe+i, zClose, sizeof(zClose), zSafe, 0);
zSafe[k] = c;
blob_append(&out, zSafe + j, k - j);
blob_append(&out, zClose, -1);
i = j = k;
continue;
}
}
}
if( j<i ){
blob_append(&out, zSafe+j, j-i);
}
fossil_free(zSafe);
return blob_str(&out);
}
/*
** COMMAND: test-chat-formatter
**
** Usage: %fossil test-chat-formatter STRING ...
|
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
|
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
|
-
+
|
zOut = chat_format_to_html(g.argv[i]);
fossil_print("[%d]: %s\n", i, zOut);
fossil_free(zOut);
}
}
/*
** WEBPAGE: chat-poll
** WEBPAGE: chat-poll hidden
**
** The chat page generated by /chat using an XHR to this page to
** request new chat content. A typical invocation is:
**
** /chat-poll/N
** /chat-poll?name=N
**
|
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
|
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
|
-
+
|
db_finalize(&q1);
blob_append(&json, "\n]}", 3);
cgi_set_content(&json);
return;
}
/*
** WEBPAGE: chat-download
** WEBPAGE: chat-download hidden
**
** 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. The integer may be followed
** by a / and a filename, which will indicate to the browser to use
** the indicated name when saving the file.
*/
|
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
|
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
|
-
+
|
db_blob(&r, "SELECT file FROM chat WHERE msgid=%d", msgid);
cgi_set_content_type(zMime);
cgi_set_content(&r);
}
/*
** WEBPAGE: chat-delete
** WEBPAGE: chat-delete hidden
**
** 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:
|