Fossil SCM

Merge src & doc leaves back.

kejoki 2008-11-19 16:55 trunk merge
Commit d14adf1032924428f6eda72570fa81b68fe69621
+16
--- src/cgi.c
+++ src/cgi.c
@@ -336,11 +336,27 @@
336336
blob_compress(&cgiContent[0], &cgiContent[0]);
337337
}
338338
339339
if( iReplyStatus != 304 ) {
340340
total_size = blob_size(&cgiContent[0]) + blob_size(&cgiContent[1]);
341
+#ifdef __MINGW32__
342
+ /* In windows versions of Apache, extra \r characters get added to the
343
+ ** response, which mess up the Content-Length. So let apache figure
344
+ ** out the content length for itself if we are using CGI. If this
345
+ ** is a complete stand-alone webserver, on the other hand, we still
346
+ ** need the Content-Length.
347
+ */
348
+ if( g.fullHttpReply ){
349
+ fprintf(g.httpOut, "Content-Length: %d\r\n", total_size);
350
+ }
351
+#else
352
+ /* On unix, \n to \r\n translation is never a problem. We know the
353
+ ** content length, so we might as well go ahead and tell the webserver
354
+ ** what it is in all cases.
355
+ */
341356
fprintf(g.httpOut, "Content-Length: %d\r\n", total_size);
357
+#endif
342358
}
343359
fprintf(g.httpOut, "\r\n");
344360
if( total_size>0 && iReplyStatus != 304 ){
345361
int i, size;
346362
for(i=0; i<2; i++){
347363
--- src/cgi.c
+++ src/cgi.c
@@ -336,11 +336,27 @@
336 blob_compress(&cgiContent[0], &cgiContent[0]);
337 }
338
339 if( iReplyStatus != 304 ) {
340 total_size = blob_size(&cgiContent[0]) + blob_size(&cgiContent[1]);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
341 fprintf(g.httpOut, "Content-Length: %d\r\n", total_size);
 
342 }
343 fprintf(g.httpOut, "\r\n");
344 if( total_size>0 && iReplyStatus != 304 ){
345 int i, size;
346 for(i=0; i<2; i++){
347
--- src/cgi.c
+++ src/cgi.c
@@ -336,11 +336,27 @@
336 blob_compress(&cgiContent[0], &cgiContent[0]);
337 }
338
339 if( iReplyStatus != 304 ) {
340 total_size = blob_size(&cgiContent[0]) + blob_size(&cgiContent[1]);
341 #ifdef __MINGW32__
342 /* In windows versions of Apache, extra \r characters get added to the
343 ** response, which mess up the Content-Length. So let apache figure
344 ** out the content length for itself if we are using CGI. If this
345 ** is a complete stand-alone webserver, on the other hand, we still
346 ** need the Content-Length.
347 */
348 if( g.fullHttpReply ){
349 fprintf(g.httpOut, "Content-Length: %d\r\n", total_size);
350 }
351 #else
352 /* On unix, \n to \r\n translation is never a problem. We know the
353 ** content length, so we might as well go ahead and tell the webserver
354 ** what it is in all cases.
355 */
356 fprintf(g.httpOut, "Content-Length: %d\r\n", total_size);
357 #endif
358 }
359 fprintf(g.httpOut, "\r\n");
360 if( total_size>0 && iReplyStatus != 304 ){
361 int i, size;
362 for(i=0; i<2; i++){
363
--- src/clearsign.c
+++ src/clearsign.c
@@ -37,10 +37,13 @@
3737
char *zIn;
3838
char *zOut;
3939
char *zBase = db_get("pgp-command", "gpg --clearsign -o ");
4040
char *zCmd;
4141
int rc;
42
+ if( is_false(zBase) ){
43
+ return 0;
44
+ }
4245
zRand = db_text(0, "SELECT hex(randomblob(10))");
4346
zOut = mprintf("out-%s", zRand);
4447
zIn = mprintf("in-%z", zRand);
4548
blob_write_to_file(pIn, zOut);
4649
zCmd = mprintf("%s %s %s", zBase, zIn, zOut);
4750
--- src/clearsign.c
+++ src/clearsign.c
@@ -37,10 +37,13 @@
37 char *zIn;
38 char *zOut;
39 char *zBase = db_get("pgp-command", "gpg --clearsign -o ");
40 char *zCmd;
41 int rc;
 
 
 
42 zRand = db_text(0, "SELECT hex(randomblob(10))");
43 zOut = mprintf("out-%s", zRand);
44 zIn = mprintf("in-%z", zRand);
45 blob_write_to_file(pIn, zOut);
46 zCmd = mprintf("%s %s %s", zBase, zIn, zOut);
47
--- src/clearsign.c
+++ src/clearsign.c
@@ -37,10 +37,13 @@
37 char *zIn;
38 char *zOut;
39 char *zBase = db_get("pgp-command", "gpg --clearsign -o ");
40 char *zCmd;
41 int rc;
42 if( is_false(zBase) ){
43 return 0;
44 }
45 zRand = db_text(0, "SELECT hex(randomblob(10))");
46 zOut = mprintf("out-%s", zRand);
47 zIn = mprintf("in-%z", zRand);
48 blob_write_to_file(pIn, zOut);
49 zCmd = mprintf("%s %s %s", zBase, zIn, zOut);
50
+52
--- src/doc.c
+++ src/doc.c
@@ -25,10 +25,62 @@
2525
** pages.
2626
*/
2727
#include "config.h"
2828
#include "doc.h"
2929
#include <assert.h>
30
+
31
+/*
32
+** Try to guess the mimetype from content.
33
+**
34
+** If the content is pure text, return NULL.
35
+**
36
+** For image types, attempt to return an appropriate mimetype
37
+** name like "image/gif" or "image/jpeg".
38
+**
39
+** For any other binary type, return "unknown/unknown".
40
+*/
41
+const char *mimetype_from_content(Blob *pBlob){
42
+ int i;
43
+ int n;
44
+ const unsigned char *x;
45
+
46
+ static const char isBinary[] = {
47
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1,
48
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1,
49
+ };
50
+
51
+ /* A table of mimetypes based on file content prefixes
52
+ */
53
+ static const struct {
54
+ const char *zPrefix; /* The file prefix */
55
+ int size; /* Length of the prefix */
56
+ const char *zMimetype; /* The corresponding mimetype */
57
+ } aMime[] = {
58
+ { "GIF87a", 6, "image/gif" },
59
+ { "GIF89a", 6, "image/gif" },
60
+ { "\211PNG\r\n\032\r", 8, "image/png" },
61
+ { "\377\332\377", 3, "image/jpeg" },
62
+ };
63
+
64
+ x = (const unsigned char*)blob_buffer(pBlob);
65
+ n = blob_size(pBlob);
66
+ for(i=0; i<n; i++){
67
+ unsigned char c = x[i];
68
+ if( c<=0x1f && isBinary[c] ){
69
+ break;
70
+ }
71
+ }
72
+ if( i>=n ){
73
+ return 0; /* Plain text */
74
+ }
75
+ for(i=0; i<sizeof(aMime)/sizeof(aMime[0]); i++){
76
+ if( n>=aMime[i].size && memcmp(x, aMime[i].zPrefix, aMime[i].size)==0 ){
77
+ return aMime[i].zMimetype;
78
+ }
79
+ }
80
+ return "unknown/unknown";
81
+}
3082
3183
/*
3284
** Guess the mime-type of a document based on its name.
3385
*/
3486
const char *mimetype_from_name(const char *zName){
3587
--- src/doc.c
+++ src/doc.c
@@ -25,10 +25,62 @@
25 ** pages.
26 */
27 #include "config.h"
28 #include "doc.h"
29 #include <assert.h>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
30
31 /*
32 ** Guess the mime-type of a document based on its name.
33 */
34 const char *mimetype_from_name(const char *zName){
35
--- src/doc.c
+++ src/doc.c
@@ -25,10 +25,62 @@
25 ** pages.
26 */
27 #include "config.h"
28 #include "doc.h"
29 #include <assert.h>
30
31 /*
32 ** Try to guess the mimetype from content.
33 **
34 ** If the content is pure text, return NULL.
35 **
36 ** For image types, attempt to return an appropriate mimetype
37 ** name like "image/gif" or "image/jpeg".
38 **
39 ** For any other binary type, return "unknown/unknown".
40 */
41 const char *mimetype_from_content(Blob *pBlob){
42 int i;
43 int n;
44 const unsigned char *x;
45
46 static const char isBinary[] = {
47 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1,
48 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1,
49 };
50
51 /* A table of mimetypes based on file content prefixes
52 */
53 static const struct {
54 const char *zPrefix; /* The file prefix */
55 int size; /* Length of the prefix */
56 const char *zMimetype; /* The corresponding mimetype */
57 } aMime[] = {
58 { "GIF87a", 6, "image/gif" },
59 { "GIF89a", 6, "image/gif" },
60 { "\211PNG\r\n\032\r", 8, "image/png" },
61 { "\377\332\377", 3, "image/jpeg" },
62 };
63
64 x = (const unsigned char*)blob_buffer(pBlob);
65 n = blob_size(pBlob);
66 for(i=0; i<n; i++){
67 unsigned char c = x[i];
68 if( c<=0x1f && isBinary[c] ){
69 break;
70 }
71 }
72 if( i>=n ){
73 return 0; /* Plain text */
74 }
75 for(i=0; i<sizeof(aMime)/sizeof(aMime[0]); i++){
76 if( n>=aMime[i].size && memcmp(x, aMime[i].zPrefix, aMime[i].size)==0 ){
77 return aMime[i].zMimetype;
78 }
79 }
80 return "unknown/unknown";
81 }
82
83 /*
84 ** Guess the mime-type of a document based on its name.
85 */
86 const char *mimetype_from_name(const char *zName){
87
+149 -10
--- src/info.c
+++ src/info.c
@@ -686,11 +686,14 @@
686686
**
687687
** * It's uuid
688688
** * date of check-in
689689
** * Comment & user
690690
*/
691
-static void object_description(int rid, int linkToView){
691
+static void object_description(
692
+ int rid, /* The artifact ID */
693
+ int linkToView /* Add viewer link if true */
694
+){
692695
Stmt q;
693696
int cnt = 0;
694697
int nWiki = 0;
695698
db_prepare(&q,
696699
"SELECT filename.name, datetime(event.mtime), substr(a.uuid,1,10),"
@@ -710,14 +713,19 @@
710713
const char *zDate = db_column_text(&q, 1);
711714
const char *zFuuid = db_column_text(&q, 2);
712715
const char *zCom = db_column_text(&q, 3);
713716
const char *zUser = db_column_text(&q, 4);
714717
const char *zVers = db_column_text(&q, 5);
715
- @ File <a href="%s(g.zBaseURL)/finfo?name=%T(zName)">%h(zName)</a>
718
+ if( cnt>0 ){
719
+ @ Also file
720
+ }else{
721
+ @ File
722
+ }
723
+ @ <a href="%s(g.zBaseURL)/finfo?name=%T(zName)">%h(zName)</a>
716724
@ uuid %s(zFuuid) part of check-in
717725
hyperlink_to_uuid(zVers);
718
- @ %w(zCom) by %h(zUser) on %s(zDate)
726
+ @ %w(zCom) by %h(zUser) on %s(zDate).
719727
cnt++;
720728
}
721729
db_finalize(&q);
722730
db_prepare(&q,
723731
"SELECT substr(tagname, 6, 10000), datetime(event.mtime),"
@@ -733,13 +741,17 @@
733741
while( db_step(&q)==SQLITE_ROW ){
734742
const char *zPagename = db_column_text(&q, 0);
735743
const char *zDate = db_column_text(&q, 1);
736744
const char *zUser = db_column_text(&q, 2);
737745
const char *zUuid = db_column_text(&q, 3);
738
- @ Wiki page
746
+ if( cnt>0 ){
747
+ @ Also wiki page
748
+ }else{
749
+ @ Wiki page
750
+ }
739751
@ [<a href="%s(g.zBaseURL)/wiki?name=%t(zPagename)">%h(zPagename)</a>]
740
- @ uuid %s(zUuid) by %h(zUser) on %s(zDate)
752
+ @ uuid %s(zUuid) by %h(zUser) on %s(zDate).
741753
nWiki++;
742754
cnt++;
743755
}
744756
db_finalize(&q);
745757
if( nWiki==0 ){
@@ -754,10 +766,13 @@
754766
const char *zDate = db_column_text(&q, 0);
755767
const char *zUuid = db_column_text(&q, 3);
756768
const char *zUser = db_column_text(&q, 1);
757769
const char *zCom = db_column_text(&q, 2);
758770
const char *zType = db_column_text(&q, 4);
771
+ if( cnt>0 ){
772
+ @ Also
773
+ }
759774
if( zType[0]=='w' ){
760775
@ Wiki edit
761776
}else if( zType[0]=='t' ){
762777
@ Ticket change
763778
}else if( zType[0]=='c' ){
@@ -764,11 +779,11 @@
764779
@ Manifest of baseline
765780
}else{
766781
@ Control file referencing
767782
}
768783
hyperlink_to_uuid(zUuid);
769
- @ %w(zCom) by %h(zUser) on %s(zDate)
784
+ @ %w(zCom) by %h(zUser) on %s(zDate).
770785
cnt++;
771786
}
772787
db_finalize(&q);
773788
}
774789
if( cnt==0 ){
@@ -812,10 +827,121 @@
812827
@ %h(blob_str(&diff))
813828
@ </pre></blockquote>
814829
blob_reset(&diff);
815830
style_footer();
816831
}
832
+
833
+/*
834
+** WEBPAGE: raw
835
+** URL: /raw?name=ARTIFACTID&m=TYPE
836
+**
837
+** Return the uninterpreted content of an artifact. Used primarily
838
+** to view artifacts that are images.
839
+*/
840
+void rawartifact_page(void){
841
+ int rid;
842
+ const char *zMime;
843
+ Blob content;
844
+
845
+ rid = name_to_rid(PD("name","0"));
846
+ zMime = PD("m","application/x-fossil-artifact");
847
+ login_check_credentials();
848
+ if( !g.okRead ){ login_needed(); return; }
849
+ if( rid==0 ){ cgi_redirect("/home"); }
850
+ content_get(rid, &content);
851
+ cgi_set_content_type(zMime);
852
+ cgi_set_content(&content);
853
+}
854
+
855
+/*
856
+** Render a hex dump of a file.
857
+*/
858
+static void hexdump(Blob *pBlob){
859
+ const unsigned char *x;
860
+ int n, i, j, k;
861
+ char zLine[100];
862
+ static const char zHex[] = "0123456789abcdef";
863
+
864
+ x = (const unsigned char*)blob_buffer(pBlob);
865
+ n = blob_size(pBlob);
866
+ for(i=0; i<n; i+=16){
867
+ j = 0;
868
+ zLine[0] = zHex[(i>>24)&0xf];
869
+ zLine[1] = zHex[(i>>16)&0xf];
870
+ zLine[2] = zHex[(i>>8)&0xf];
871
+ zLine[3] = zHex[i&0xf];
872
+ zLine[4] = ':';
873
+ sprintf(zLine, "%04x: ", i);
874
+ for(j=0; j<16; j++){
875
+ k = 5+j*3;
876
+ zLine[k] = ' ';
877
+ if( i+j<n ){
878
+ unsigned char c = x[i+j];
879
+ zLine[k+1] = zHex[c>>4];
880
+ zLine[k+2] = zHex[c&0xf];
881
+ }else{
882
+ zLine[k+1] = ' ';
883
+ zLine[k+2] = ' ';
884
+ }
885
+ }
886
+ zLine[53] = ' ';
887
+ zLine[54] = ' ';
888
+ for(j=0; j<16; j++){
889
+ k = j+55;
890
+ if( i+j<n ){
891
+ unsigned char c = x[i+j];
892
+ if( c>=0x20 && c<=0x7e ){
893
+ zLine[k] = c;
894
+ }else{
895
+ zLine[k] = '.';
896
+ }
897
+ }else{
898
+ zLine[k] = 0;
899
+ }
900
+ }
901
+ zLine[71] = 0;
902
+ @ %h(zLine)
903
+ }
904
+}
905
+
906
+/*
907
+** WEBPAGE: hexdump
908
+** URL: /hexdump?name=ARTIFACTID
909
+**
910
+** Show the complete content of a file identified by ARTIFACTID
911
+** as preformatted text.
912
+*/
913
+void hexdump_page(void){
914
+ int rid;
915
+ Blob content;
916
+
917
+ rid = name_to_rid(PD("name","0"));
918
+ login_check_credentials();
919
+ if( !g.okRead ){ login_needed(); return; }
920
+ if( rid==0 ){ cgi_redirect("/home"); }
921
+ if( g.okAdmin ){
922
+ const char *zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d", rid);
923
+ if( db_exists("SELECT 1 FROM shun WHERE uuid='%s'", zUuid) ){
924
+ style_submenu_element("Unshun","Unshun", "%s/shun?uuid=%s&sub=1",
925
+ g.zTop, zUuid);
926
+ }else{
927
+ style_submenu_element("Shun","Shun", "%s/shun?shun=%s#addshun",
928
+ g.zTop, zUuid);
929
+ }
930
+ }
931
+ style_header("Hex Artifact Content");
932
+ @ <h2>Hexadecimal Content Of:</h2>
933
+ @ <blockquote>
934
+ object_description(rid, 0);
935
+ @ </blockquote>
936
+ @ <hr>
937
+ content_get(rid, &content);
938
+ @ <blockquote><pre>
939
+ hexdump(&content);
940
+ @ </pre></blockquote>
941
+ style_footer();
942
+}
817943
818944
/*
819945
** WEBPAGE: artifact
820946
** URL: /artifact?name=ARTIFACTID
821947
**
@@ -823,10 +949,11 @@
823949
** as preformatted text.
824950
*/
825951
void artifact_page(void){
826952
int rid;
827953
Blob content;
954
+ const char *zMime;
828955
829956
rid = name_to_rid(PD("name","0"));
830957
login_check_credentials();
831958
if( !g.okRead ){ login_needed(); return; }
832959
if( rid==0 ){ cgi_redirect("/home"); }
@@ -844,15 +971,27 @@
844971
@ <h2>Content Of:</h2>
845972
@ <blockquote>
846973
object_description(rid, 0);
847974
@ </blockquote>
848975
@ <hr>
849
- @ <blockquote><pre>
976
+ @ <blockquote>
850977
content_get(rid, &content);
851
- @ %h(blob_str(&content))
852
- @ </pre></blockquote>
853
- blob_reset(&content);
978
+ zMime = mimetype_from_content(&content);
979
+ if( zMime==0 ){
980
+ @ <pre>
981
+ @ %h(blob_str(&content))
982
+ @ </pre>
983
+ style_submenu_element("Hex","Hex", "%s/hexdump?name=%d", g.zTop, rid);
984
+ }else if( strncmp(zMime, "image/", 6)==0 ){
985
+ @ <img src="%s(g.zBaseURL)/raw?name=%d(rid)&m=%s(zMime)"></img>
986
+ style_submenu_element("Hex","Hex", "%s/hexdump?name=%d", g.zTop, rid);
987
+ }else{
988
+ @ <pre>
989
+ hexdump(&content);
990
+ @ </pre>
991
+ }
992
+ @ </blockquote>
854993
style_footer();
855994
}
856995
857996
/*
858997
** WEBPAGE: tinfo
859998
--- src/info.c
+++ src/info.c
@@ -686,11 +686,14 @@
686 **
687 ** * It's uuid
688 ** * date of check-in
689 ** * Comment & user
690 */
691 static void object_description(int rid, int linkToView){
 
 
 
692 Stmt q;
693 int cnt = 0;
694 int nWiki = 0;
695 db_prepare(&q,
696 "SELECT filename.name, datetime(event.mtime), substr(a.uuid,1,10),"
@@ -710,14 +713,19 @@
710 const char *zDate = db_column_text(&q, 1);
711 const char *zFuuid = db_column_text(&q, 2);
712 const char *zCom = db_column_text(&q, 3);
713 const char *zUser = db_column_text(&q, 4);
714 const char *zVers = db_column_text(&q, 5);
715 @ File <a href="%s(g.zBaseURL)/finfo?name=%T(zName)">%h(zName)</a>
 
 
 
 
 
716 @ uuid %s(zFuuid) part of check-in
717 hyperlink_to_uuid(zVers);
718 @ %w(zCom) by %h(zUser) on %s(zDate)
719 cnt++;
720 }
721 db_finalize(&q);
722 db_prepare(&q,
723 "SELECT substr(tagname, 6, 10000), datetime(event.mtime),"
@@ -733,13 +741,17 @@
733 while( db_step(&q)==SQLITE_ROW ){
734 const char *zPagename = db_column_text(&q, 0);
735 const char *zDate = db_column_text(&q, 1);
736 const char *zUser = db_column_text(&q, 2);
737 const char *zUuid = db_column_text(&q, 3);
738 @ Wiki page
 
 
 
 
739 @ [<a href="%s(g.zBaseURL)/wiki?name=%t(zPagename)">%h(zPagename)</a>]
740 @ uuid %s(zUuid) by %h(zUser) on %s(zDate)
741 nWiki++;
742 cnt++;
743 }
744 db_finalize(&q);
745 if( nWiki==0 ){
@@ -754,10 +766,13 @@
754 const char *zDate = db_column_text(&q, 0);
755 const char *zUuid = db_column_text(&q, 3);
756 const char *zUser = db_column_text(&q, 1);
757 const char *zCom = db_column_text(&q, 2);
758 const char *zType = db_column_text(&q, 4);
 
 
 
759 if( zType[0]=='w' ){
760 @ Wiki edit
761 }else if( zType[0]=='t' ){
762 @ Ticket change
763 }else if( zType[0]=='c' ){
@@ -764,11 +779,11 @@
764 @ Manifest of baseline
765 }else{
766 @ Control file referencing
767 }
768 hyperlink_to_uuid(zUuid);
769 @ %w(zCom) by %h(zUser) on %s(zDate)
770 cnt++;
771 }
772 db_finalize(&q);
773 }
774 if( cnt==0 ){
@@ -812,10 +827,121 @@
812 @ %h(blob_str(&diff))
813 @ </pre></blockquote>
814 blob_reset(&diff);
815 style_footer();
816 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
817
818 /*
819 ** WEBPAGE: artifact
820 ** URL: /artifact?name=ARTIFACTID
821 **
@@ -823,10 +949,11 @@
823 ** as preformatted text.
824 */
825 void artifact_page(void){
826 int rid;
827 Blob content;
 
828
829 rid = name_to_rid(PD("name","0"));
830 login_check_credentials();
831 if( !g.okRead ){ login_needed(); return; }
832 if( rid==0 ){ cgi_redirect("/home"); }
@@ -844,15 +971,27 @@
844 @ <h2>Content Of:</h2>
845 @ <blockquote>
846 object_description(rid, 0);
847 @ </blockquote>
848 @ <hr>
849 @ <blockquote><pre>
850 content_get(rid, &content);
851 @ %h(blob_str(&content))
852 @ </pre></blockquote>
853 blob_reset(&content);
 
 
 
 
 
 
 
 
 
 
 
 
854 style_footer();
855 }
856
857 /*
858 ** WEBPAGE: tinfo
859
--- src/info.c
+++ src/info.c
@@ -686,11 +686,14 @@
686 **
687 ** * It's uuid
688 ** * date of check-in
689 ** * Comment & user
690 */
691 static void object_description(
692 int rid, /* The artifact ID */
693 int linkToView /* Add viewer link if true */
694 ){
695 Stmt q;
696 int cnt = 0;
697 int nWiki = 0;
698 db_prepare(&q,
699 "SELECT filename.name, datetime(event.mtime), substr(a.uuid,1,10),"
@@ -710,14 +713,19 @@
713 const char *zDate = db_column_text(&q, 1);
714 const char *zFuuid = db_column_text(&q, 2);
715 const char *zCom = db_column_text(&q, 3);
716 const char *zUser = db_column_text(&q, 4);
717 const char *zVers = db_column_text(&q, 5);
718 if( cnt>0 ){
719 @ Also file
720 }else{
721 @ File
722 }
723 @ <a href="%s(g.zBaseURL)/finfo?name=%T(zName)">%h(zName)</a>
724 @ uuid %s(zFuuid) part of check-in
725 hyperlink_to_uuid(zVers);
726 @ %w(zCom) by %h(zUser) on %s(zDate).
727 cnt++;
728 }
729 db_finalize(&q);
730 db_prepare(&q,
731 "SELECT substr(tagname, 6, 10000), datetime(event.mtime),"
@@ -733,13 +741,17 @@
741 while( db_step(&q)==SQLITE_ROW ){
742 const char *zPagename = db_column_text(&q, 0);
743 const char *zDate = db_column_text(&q, 1);
744 const char *zUser = db_column_text(&q, 2);
745 const char *zUuid = db_column_text(&q, 3);
746 if( cnt>0 ){
747 @ Also wiki page
748 }else{
749 @ Wiki page
750 }
751 @ [<a href="%s(g.zBaseURL)/wiki?name=%t(zPagename)">%h(zPagename)</a>]
752 @ uuid %s(zUuid) by %h(zUser) on %s(zDate).
753 nWiki++;
754 cnt++;
755 }
756 db_finalize(&q);
757 if( nWiki==0 ){
@@ -754,10 +766,13 @@
766 const char *zDate = db_column_text(&q, 0);
767 const char *zUuid = db_column_text(&q, 3);
768 const char *zUser = db_column_text(&q, 1);
769 const char *zCom = db_column_text(&q, 2);
770 const char *zType = db_column_text(&q, 4);
771 if( cnt>0 ){
772 @ Also
773 }
774 if( zType[0]=='w' ){
775 @ Wiki edit
776 }else if( zType[0]=='t' ){
777 @ Ticket change
778 }else if( zType[0]=='c' ){
@@ -764,11 +779,11 @@
779 @ Manifest of baseline
780 }else{
781 @ Control file referencing
782 }
783 hyperlink_to_uuid(zUuid);
784 @ %w(zCom) by %h(zUser) on %s(zDate).
785 cnt++;
786 }
787 db_finalize(&q);
788 }
789 if( cnt==0 ){
@@ -812,10 +827,121 @@
827 @ %h(blob_str(&diff))
828 @ </pre></blockquote>
829 blob_reset(&diff);
830 style_footer();
831 }
832
833 /*
834 ** WEBPAGE: raw
835 ** URL: /raw?name=ARTIFACTID&m=TYPE
836 **
837 ** Return the uninterpreted content of an artifact. Used primarily
838 ** to view artifacts that are images.
839 */
840 void rawartifact_page(void){
841 int rid;
842 const char *zMime;
843 Blob content;
844
845 rid = name_to_rid(PD("name","0"));
846 zMime = PD("m","application/x-fossil-artifact");
847 login_check_credentials();
848 if( !g.okRead ){ login_needed(); return; }
849 if( rid==0 ){ cgi_redirect("/home"); }
850 content_get(rid, &content);
851 cgi_set_content_type(zMime);
852 cgi_set_content(&content);
853 }
854
855 /*
856 ** Render a hex dump of a file.
857 */
858 static void hexdump(Blob *pBlob){
859 const unsigned char *x;
860 int n, i, j, k;
861 char zLine[100];
862 static const char zHex[] = "0123456789abcdef";
863
864 x = (const unsigned char*)blob_buffer(pBlob);
865 n = blob_size(pBlob);
866 for(i=0; i<n; i+=16){
867 j = 0;
868 zLine[0] = zHex[(i>>24)&0xf];
869 zLine[1] = zHex[(i>>16)&0xf];
870 zLine[2] = zHex[(i>>8)&0xf];
871 zLine[3] = zHex[i&0xf];
872 zLine[4] = ':';
873 sprintf(zLine, "%04x: ", i);
874 for(j=0; j<16; j++){
875 k = 5+j*3;
876 zLine[k] = ' ';
877 if( i+j<n ){
878 unsigned char c = x[i+j];
879 zLine[k+1] = zHex[c>>4];
880 zLine[k+2] = zHex[c&0xf];
881 }else{
882 zLine[k+1] = ' ';
883 zLine[k+2] = ' ';
884 }
885 }
886 zLine[53] = ' ';
887 zLine[54] = ' ';
888 for(j=0; j<16; j++){
889 k = j+55;
890 if( i+j<n ){
891 unsigned char c = x[i+j];
892 if( c>=0x20 && c<=0x7e ){
893 zLine[k] = c;
894 }else{
895 zLine[k] = '.';
896 }
897 }else{
898 zLine[k] = 0;
899 }
900 }
901 zLine[71] = 0;
902 @ %h(zLine)
903 }
904 }
905
906 /*
907 ** WEBPAGE: hexdump
908 ** URL: /hexdump?name=ARTIFACTID
909 **
910 ** Show the complete content of a file identified by ARTIFACTID
911 ** as preformatted text.
912 */
913 void hexdump_page(void){
914 int rid;
915 Blob content;
916
917 rid = name_to_rid(PD("name","0"));
918 login_check_credentials();
919 if( !g.okRead ){ login_needed(); return; }
920 if( rid==0 ){ cgi_redirect("/home"); }
921 if( g.okAdmin ){
922 const char *zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d", rid);
923 if( db_exists("SELECT 1 FROM shun WHERE uuid='%s'", zUuid) ){
924 style_submenu_element("Unshun","Unshun", "%s/shun?uuid=%s&sub=1",
925 g.zTop, zUuid);
926 }else{
927 style_submenu_element("Shun","Shun", "%s/shun?shun=%s#addshun",
928 g.zTop, zUuid);
929 }
930 }
931 style_header("Hex Artifact Content");
932 @ <h2>Hexadecimal Content Of:</h2>
933 @ <blockquote>
934 object_description(rid, 0);
935 @ </blockquote>
936 @ <hr>
937 content_get(rid, &content);
938 @ <blockquote><pre>
939 hexdump(&content);
940 @ </pre></blockquote>
941 style_footer();
942 }
943
944 /*
945 ** WEBPAGE: artifact
946 ** URL: /artifact?name=ARTIFACTID
947 **
@@ -823,10 +949,11 @@
949 ** as preformatted text.
950 */
951 void artifact_page(void){
952 int rid;
953 Blob content;
954 const char *zMime;
955
956 rid = name_to_rid(PD("name","0"));
957 login_check_credentials();
958 if( !g.okRead ){ login_needed(); return; }
959 if( rid==0 ){ cgi_redirect("/home"); }
@@ -844,15 +971,27 @@
971 @ <h2>Content Of:</h2>
972 @ <blockquote>
973 object_description(rid, 0);
974 @ </blockquote>
975 @ <hr>
976 @ <blockquote>
977 content_get(rid, &content);
978 zMime = mimetype_from_content(&content);
979 if( zMime==0 ){
980 @ <pre>
981 @ %h(blob_str(&content))
982 @ </pre>
983 style_submenu_element("Hex","Hex", "%s/hexdump?name=%d", g.zTop, rid);
984 }else if( strncmp(zMime, "image/", 6)==0 ){
985 @ <img src="%s(g.zBaseURL)/raw?name=%d(rid)&m=%s(zMime)"></img>
986 style_submenu_element("Hex","Hex", "%s/hexdump?name=%d", g.zTop, rid);
987 }else{
988 @ <pre>
989 hexdump(&content);
990 @ </pre>
991 }
992 @ </blockquote>
993 style_footer();
994 }
995
996 /*
997 ** WEBPAGE: tinfo
998
+15 -14
--- src/wiki.c
+++ src/wiki.c
@@ -83,13 +83,11 @@
8383
if( zPageName ){
8484
login_check_credentials();
8585
g.zExtra = zPageName;
8686
cgi_set_parameter_nocopy("name", g.zExtra);
8787
g.okRdWiki = 1;
88
- g.okApndWiki = 0;
89
- g.okWrWiki = 0;
90
- g.okHistory = 0;
88
+ g.argv[1] = "home";
9189
wiki_page();
9290
return;
9391
}
9492
login_check_credentials();
9593
style_header("Home");
@@ -121,10 +119,11 @@
121119
Blob wiki;
122120
Manifest m;
123121
const char *zPageName;
124122
char *zHtmlPageName;
125123
char *zBody = mprintf("%s","<i>Empty Page</i>");
124
+ int isHome = g.argv[1][0]=='h';
126125
127126
login_check_credentials();
128127
if( !g.okRdWiki ){ login_needed(); return; }
129128
zPageName = P("name");
130129
if( zPageName==0 ){
@@ -169,21 +168,23 @@
169168
if( m.type==CFTYPE_WIKI ){
170169
zBody = m.zWiki;
171170
}
172171
}
173172
}
174
- if( isSandbox || (rid && g.okWrWiki) || (!rid && g.okNewWiki) ){
175
- style_submenu_element("Edit", "Edit Wiki Page", "%s/wikiedit?name=%T",
176
- g.zTop, zPageName);
177
- }
178
- if( isSandbox || (rid && g.okApndWiki) ){
179
- style_submenu_element("Append", "Add A Comment", "%s/wikiappend?name=%T",
180
- g.zTop, zPageName);
181
- }
182
- if( !isSandbox && g.okHistory ){
183
- style_submenu_element("History", "History", "%s/whistory?name=%T",
184
- g.zTop, zPageName);
173
+ if( !isHome ){
174
+ if( isSandbox || (rid && g.okWrWiki) || (!rid && g.okNewWiki) ){
175
+ style_submenu_element("Edit", "Edit Wiki Page", "%s/wikiedit?name=%T",
176
+ g.zTop, zPageName);
177
+ }
178
+ if( isSandbox || (rid && g.okApndWiki) ){
179
+ style_submenu_element("Append", "Add A Comment", "%s/wikiappend?name=%T",
180
+ g.zTop, zPageName);
181
+ }
182
+ if( !isSandbox && g.okHistory ){
183
+ style_submenu_element("History", "History", "%s/whistory?name=%T",
184
+ g.zTop, zPageName);
185
+ }
185186
}
186187
zHtmlPageName = mprintf("%h", zPageName);
187188
style_header(zHtmlPageName);
188189
blob_init(&wiki, zBody, -1);
189190
wiki_convert(&wiki, 0, 0);
190191
--- src/wiki.c
+++ src/wiki.c
@@ -83,13 +83,11 @@
83 if( zPageName ){
84 login_check_credentials();
85 g.zExtra = zPageName;
86 cgi_set_parameter_nocopy("name", g.zExtra);
87 g.okRdWiki = 1;
88 g.okApndWiki = 0;
89 g.okWrWiki = 0;
90 g.okHistory = 0;
91 wiki_page();
92 return;
93 }
94 login_check_credentials();
95 style_header("Home");
@@ -121,10 +119,11 @@
121 Blob wiki;
122 Manifest m;
123 const char *zPageName;
124 char *zHtmlPageName;
125 char *zBody = mprintf("%s","<i>Empty Page</i>");
 
126
127 login_check_credentials();
128 if( !g.okRdWiki ){ login_needed(); return; }
129 zPageName = P("name");
130 if( zPageName==0 ){
@@ -169,21 +168,23 @@
169 if( m.type==CFTYPE_WIKI ){
170 zBody = m.zWiki;
171 }
172 }
173 }
174 if( isSandbox || (rid && g.okWrWiki) || (!rid && g.okNewWiki) ){
175 style_submenu_element("Edit", "Edit Wiki Page", "%s/wikiedit?name=%T",
176 g.zTop, zPageName);
177 }
178 if( isSandbox || (rid && g.okApndWiki) ){
179 style_submenu_element("Append", "Add A Comment", "%s/wikiappend?name=%T",
180 g.zTop, zPageName);
181 }
182 if( !isSandbox && g.okHistory ){
183 style_submenu_element("History", "History", "%s/whistory?name=%T",
184 g.zTop, zPageName);
 
 
185 }
186 zHtmlPageName = mprintf("%h", zPageName);
187 style_header(zHtmlPageName);
188 blob_init(&wiki, zBody, -1);
189 wiki_convert(&wiki, 0, 0);
190
--- src/wiki.c
+++ src/wiki.c
@@ -83,13 +83,11 @@
83 if( zPageName ){
84 login_check_credentials();
85 g.zExtra = zPageName;
86 cgi_set_parameter_nocopy("name", g.zExtra);
87 g.okRdWiki = 1;
88 g.argv[1] = "home";
 
 
89 wiki_page();
90 return;
91 }
92 login_check_credentials();
93 style_header("Home");
@@ -121,10 +119,11 @@
119 Blob wiki;
120 Manifest m;
121 const char *zPageName;
122 char *zHtmlPageName;
123 char *zBody = mprintf("%s","<i>Empty Page</i>");
124 int isHome = g.argv[1][0]=='h';
125
126 login_check_credentials();
127 if( !g.okRdWiki ){ login_needed(); return; }
128 zPageName = P("name");
129 if( zPageName==0 ){
@@ -169,21 +168,23 @@
168 if( m.type==CFTYPE_WIKI ){
169 zBody = m.zWiki;
170 }
171 }
172 }
173 if( !isHome ){
174 if( isSandbox || (rid && g.okWrWiki) || (!rid && g.okNewWiki) ){
175 style_submenu_element("Edit", "Edit Wiki Page", "%s/wikiedit?name=%T",
176 g.zTop, zPageName);
177 }
178 if( isSandbox || (rid && g.okApndWiki) ){
179 style_submenu_element("Append", "Add A Comment", "%s/wikiappend?name=%T",
180 g.zTop, zPageName);
181 }
182 if( !isSandbox && g.okHistory ){
183 style_submenu_element("History", "History", "%s/whistory?name=%T",
184 g.zTop, zPageName);
185 }
186 }
187 zHtmlPageName = mprintf("%h", zPageName);
188 style_header(zHtmlPageName);
189 blob_init(&wiki, zBody, -1);
190 wiki_convert(&wiki, 0, 0);
191
--- src/wikiformat.c
+++ src/wikiformat.c
@@ -938,10 +938,16 @@
938938
}else if( zTarget[0]=='/' ){
939939
if( g.okHistory ){
940940
blob_appendf(p->pOut, "<a href=\"%s%h\">", g.zBaseURL, zTarget);
941941
}else{
942942
zTerm = "";
943
+ }
944
+ }else if( zTarget[0]=='.' ){
945
+ if( g.okHistory ){
946
+ blob_appendf(p->pOut, "<a href=\"%h\">", zTarget);
947
+ }else{
948
+ zTerm = "";
943949
}
944950
}else if( is_valid_uuid(zTarget) ){
945951
int isClosed;
946952
if( is_ticket(zTarget, &isClosed) ){
947953
/* Special display processing for tickets. Display the hyperlink
948954
--- src/wikiformat.c
+++ src/wikiformat.c
@@ -938,10 +938,16 @@
938 }else if( zTarget[0]=='/' ){
939 if( g.okHistory ){
940 blob_appendf(p->pOut, "<a href=\"%s%h\">", g.zBaseURL, zTarget);
941 }else{
942 zTerm = "";
 
 
 
 
 
 
943 }
944 }else if( is_valid_uuid(zTarget) ){
945 int isClosed;
946 if( is_ticket(zTarget, &isClosed) ){
947 /* Special display processing for tickets. Display the hyperlink
948
--- src/wikiformat.c
+++ src/wikiformat.c
@@ -938,10 +938,16 @@
938 }else if( zTarget[0]=='/' ){
939 if( g.okHistory ){
940 blob_appendf(p->pOut, "<a href=\"%s%h\">", g.zBaseURL, zTarget);
941 }else{
942 zTerm = "";
943 }
944 }else if( zTarget[0]=='.' ){
945 if( g.okHistory ){
946 blob_appendf(p->pOut, "<a href=\"%h\">", zTarget);
947 }else{
948 zTerm = "";
949 }
950 }else if( is_valid_uuid(zTarget) ){
951 int isClosed;
952 if( is_ticket(zTarget, &isClosed) ){
953 /* Special display processing for tickets. Display the hyperlink
954

Keyboard Shortcuts

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