Fossil SCM

Add the "fossil chat backup" command and the "/chat-backup" webpage to support it.

drh 2022-02-18 20:25 trunk
Commit 1827a314878fecb2d105e5fe3c67839bbd9e7c3969039e0b1bc6d1ff0ad3234c
1 file changed +107
+107
--- src/chat.c
+++ src/chat.c
@@ -815,10 +815,40 @@
815815
" VALUES(julianday('now'), %Q, %d);\n"
816816
"COMMIT;",
817817
mdel, g.zLogin, mdel
818818
);
819819
}
820
+
821
+/*
822
+** WEBPAGE: chat-backup hidden
823
+**
824
+** Download an SQLite database containing all chat content with a
825
+** message-id larger than the "msgid" query parameter. Setup
826
+** privilege is required to use this URL.
827
+*/
828
+void chat_backup_webpage(void){
829
+ int msgid;
830
+ unsigned char *pDb = 0;
831
+ sqlite3_int64 szDb = 0;
832
+ Blob chatDb;
833
+ login_check_credentials();
834
+ if( !g.perm.Setup ) return;
835
+ msgid = atoi(PD("msgid","0"));
836
+ db_multi_exec(
837
+ "ATTACH ':memory:' AS mem1;\n"
838
+ "PRAGMA mem1.page_size=512;\n"
839
+ "CREATE TABLE mem1.chat AS SELECT * FROM repository.chat WHERE msgid>%d;\n",
840
+ msgid
841
+ );
842
+ pDb = sqlite3_serialize(g.db, "mem1", &szDb, 0);
843
+ if( pDb==0 ){
844
+ fossil_fatal("Out of memory");
845
+ }
846
+ blob_init(&chatDb, (const char*)pDb, (int)szDb);
847
+ cgi_set_content_type("application/x-sqlite3");
848
+ cgi_set_content(&chatDb);
849
+}
820850
821851
/*
822852
** COMMAND: chat
823853
**
824854
** Usage: %fossil chat [SUBCOMMAND] [--remote URL] [ARGS...]
@@ -838,10 +868,22 @@
838868
** the response is to bring up a web-browser window to the chatroom
839869
** on the default system web-browser. You can accomplish the same by
840870
** typing the appropriate URL into the web-browser yourself. This
841871
** command is merely a convenience for command-line oriented people.
842872
**
873
+** > fossil chat backup
874
+**
875
+** Copy chat content from the server down into the local clone,
876
+** as a backup. Setup privilege is required on the server.
877
+**
878
+** --all Download all chat content. Normally only
879
+** previously undownloaded content is retrieved.
880
+** --debug Additional debugging output.
881
+** --out DATABASE Store CHAT table in separate database file
882
+** DATABASE rather that adding to local clone
883
+** --unsafe Allow the use of unencrypted http://
884
+**
843885
** > fossil chat send [ARGUMENTS]
844886
**
845887
** This command sends a new message to the chatroom. The message
846888
** to be sent is determined by arguments as follows:
847889
**
@@ -981,12 +1023,77 @@
9811023
fossil_print("ERROR: %s\n", blob_str(&down));
9821024
}
9831025
fossil_fatal("unable to send the chat message");
9841026
}
9851027
blob_reset(&down);
1028
+ }else if( strcmp(g.argv[2],"backup")==0 ){
1029
+ /* Pull the CHAT table from the default server down into the repository
1030
+ ** here on the local side */
1031
+ int allowUnsafe = find_option("unsafe",0,0)!=0;
1032
+ int bDebug = find_option("debug",0,0)!=0;
1033
+ const char *zOut = find_option("out",0,1);
1034
+ int bAll = find_option("all",0,0)!=0;
1035
+ int mFlags = HTTP_GENERIC | HTTP_QUIET | HTTP_NOCOMPRESS;
1036
+ int msgid;
1037
+ Blob reqUri; /* The REQUEST_URI: .../chat-backup?msgid=... */
1038
+ char *zObs;
1039
+ const char *zPw;
1040
+ Blob up, down;
1041
+ int nChat;
1042
+ int rc;
1043
+ verify_all_options();
1044
+ chat_create_tables();
1045
+ msgid = bAll ? 0 : db_int(0,"SELECT max(msgid) FROM chat");
1046
+ if( !g.url.isHttps && !allowUnsafe ){
1047
+ fossil_fatal("URL \"%s\" is unencrypted. Use https:// instead", zUrl);
1048
+ }
1049
+ blob_init(&reqUri, g.url.path, -1);
1050
+ blob_appendf(&reqUri, "/chat-backup?msgid=%d", msgid);
1051
+ if( g.url.user && g.url.user[0] ){
1052
+ zObs = obscure(g.url.user);
1053
+ blob_appendf(&reqUri, "&resid=%t", zObs);
1054
+ fossil_free(zObs);
1055
+ }
1056
+ zPw = g.url.passwd;
1057
+ if( zPw==0 && isDefaultUrl ) zPw = unobscure(db_get("last-sync-pw", 0));
1058
+ if( zPw && zPw[0] ){
1059
+ zObs = obscure(zPw);
1060
+ blob_appendf(&reqUri, "&token=%t", zObs);
1061
+ fossil_free(zObs);
1062
+ }
1063
+ g.url.path = blob_str(&reqUri);
1064
+ if( bDebug ){
1065
+ fossil_print("REQUEST_URI: %s\n", g.url.path);
1066
+ mFlags &= ~HTTP_QUIET;
1067
+ mFlags |= HTTP_VERBOSE;
1068
+ }
1069
+ blob_init(&up, 0, 0);
1070
+ blob_init(&down, 0, 0);
1071
+ http_exchange(&up, &down, mFlags, 4, 0);
1072
+ if( zOut ){
1073
+ blob_write_to_file(&down, zOut);
1074
+ fossil_print("Chat database at %s is %d bytes\n", zOut, blob_size(&down));
1075
+ }else{
1076
+ db_multi_exec("ATTACH ':memory:' AS chatbu;");
1077
+ if( g.fSqlTrace ){
1078
+ fossil_trace("-- deserialize(\"chatbu\", pData, %d);\n",
1079
+ blob_size(&down));
1080
+ }
1081
+ rc = sqlite3_deserialize(g.db, "chatbu",
1082
+ (unsigned char*)blob_buffer(&down),
1083
+ blob_size(&down), blob_size(&down), 0);
1084
+ if( rc ){
1085
+ fossil_fatal("cannot open patch database: %s", sqlite3_errmsg(g.db));
1086
+ }
1087
+ nChat = db_int(0, "SELECT count(*) FROM chatbu.chat");
1088
+ fossil_print("Got %d new records, %d bytes\n", nChat, blob_size(&down));
1089
+ db_multi_exec(
1090
+ "REPLACE INTO repository.chat SELECT * FROM chatbu.chat;"
1091
+ );
1092
+ }
9861093
}else if( strcmp(g.argv[2],"url")==0 ){
9871094
/* Show the URL to access chat. */
9881095
fossil_print("%s/chat\n", zUrl);
9891096
}else{
9901097
fossil_fatal("no such subcommand \"%s\". Use --help for help", g.argv[2]);
9911098
}
9921099
}
9931100
--- src/chat.c
+++ src/chat.c
@@ -815,10 +815,40 @@
815 " VALUES(julianday('now'), %Q, %d);\n"
816 "COMMIT;",
817 mdel, g.zLogin, mdel
818 );
819 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
820
821 /*
822 ** COMMAND: chat
823 **
824 ** Usage: %fossil chat [SUBCOMMAND] [--remote URL] [ARGS...]
@@ -838,10 +868,22 @@
838 ** the response is to bring up a web-browser window to the chatroom
839 ** on the default system web-browser. You can accomplish the same by
840 ** typing the appropriate URL into the web-browser yourself. This
841 ** command is merely a convenience for command-line oriented people.
842 **
 
 
 
 
 
 
 
 
 
 
 
 
843 ** > fossil chat send [ARGUMENTS]
844 **
845 ** This command sends a new message to the chatroom. The message
846 ** to be sent is determined by arguments as follows:
847 **
@@ -981,12 +1023,77 @@
981 fossil_print("ERROR: %s\n", blob_str(&down));
982 }
983 fossil_fatal("unable to send the chat message");
984 }
985 blob_reset(&down);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
986 }else if( strcmp(g.argv[2],"url")==0 ){
987 /* Show the URL to access chat. */
988 fossil_print("%s/chat\n", zUrl);
989 }else{
990 fossil_fatal("no such subcommand \"%s\". Use --help for help", g.argv[2]);
991 }
992 }
993
--- src/chat.c
+++ src/chat.c
@@ -815,10 +815,40 @@
815 " VALUES(julianday('now'), %Q, %d);\n"
816 "COMMIT;",
817 mdel, g.zLogin, mdel
818 );
819 }
820
821 /*
822 ** WEBPAGE: chat-backup hidden
823 **
824 ** Download an SQLite database containing all chat content with a
825 ** message-id larger than the "msgid" query parameter. Setup
826 ** privilege is required to use this URL.
827 */
828 void chat_backup_webpage(void){
829 int msgid;
830 unsigned char *pDb = 0;
831 sqlite3_int64 szDb = 0;
832 Blob chatDb;
833 login_check_credentials();
834 if( !g.perm.Setup ) return;
835 msgid = atoi(PD("msgid","0"));
836 db_multi_exec(
837 "ATTACH ':memory:' AS mem1;\n"
838 "PRAGMA mem1.page_size=512;\n"
839 "CREATE TABLE mem1.chat AS SELECT * FROM repository.chat WHERE msgid>%d;\n",
840 msgid
841 );
842 pDb = sqlite3_serialize(g.db, "mem1", &szDb, 0);
843 if( pDb==0 ){
844 fossil_fatal("Out of memory");
845 }
846 blob_init(&chatDb, (const char*)pDb, (int)szDb);
847 cgi_set_content_type("application/x-sqlite3");
848 cgi_set_content(&chatDb);
849 }
850
851 /*
852 ** COMMAND: chat
853 **
854 ** Usage: %fossil chat [SUBCOMMAND] [--remote URL] [ARGS...]
@@ -838,10 +868,22 @@
868 ** the response is to bring up a web-browser window to the chatroom
869 ** on the default system web-browser. You can accomplish the same by
870 ** typing the appropriate URL into the web-browser yourself. This
871 ** command is merely a convenience for command-line oriented people.
872 **
873 ** > fossil chat backup
874 **
875 ** Copy chat content from the server down into the local clone,
876 ** as a backup. Setup privilege is required on the server.
877 **
878 ** --all Download all chat content. Normally only
879 ** previously undownloaded content is retrieved.
880 ** --debug Additional debugging output.
881 ** --out DATABASE Store CHAT table in separate database file
882 ** DATABASE rather that adding to local clone
883 ** --unsafe Allow the use of unencrypted http://
884 **
885 ** > fossil chat send [ARGUMENTS]
886 **
887 ** This command sends a new message to the chatroom. The message
888 ** to be sent is determined by arguments as follows:
889 **
@@ -981,12 +1023,77 @@
1023 fossil_print("ERROR: %s\n", blob_str(&down));
1024 }
1025 fossil_fatal("unable to send the chat message");
1026 }
1027 blob_reset(&down);
1028 }else if( strcmp(g.argv[2],"backup")==0 ){
1029 /* Pull the CHAT table from the default server down into the repository
1030 ** here on the local side */
1031 int allowUnsafe = find_option("unsafe",0,0)!=0;
1032 int bDebug = find_option("debug",0,0)!=0;
1033 const char *zOut = find_option("out",0,1);
1034 int bAll = find_option("all",0,0)!=0;
1035 int mFlags = HTTP_GENERIC | HTTP_QUIET | HTTP_NOCOMPRESS;
1036 int msgid;
1037 Blob reqUri; /* The REQUEST_URI: .../chat-backup?msgid=... */
1038 char *zObs;
1039 const char *zPw;
1040 Blob up, down;
1041 int nChat;
1042 int rc;
1043 verify_all_options();
1044 chat_create_tables();
1045 msgid = bAll ? 0 : db_int(0,"SELECT max(msgid) FROM chat");
1046 if( !g.url.isHttps && !allowUnsafe ){
1047 fossil_fatal("URL \"%s\" is unencrypted. Use https:// instead", zUrl);
1048 }
1049 blob_init(&reqUri, g.url.path, -1);
1050 blob_appendf(&reqUri, "/chat-backup?msgid=%d", msgid);
1051 if( g.url.user && g.url.user[0] ){
1052 zObs = obscure(g.url.user);
1053 blob_appendf(&reqUri, "&resid=%t", zObs);
1054 fossil_free(zObs);
1055 }
1056 zPw = g.url.passwd;
1057 if( zPw==0 && isDefaultUrl ) zPw = unobscure(db_get("last-sync-pw", 0));
1058 if( zPw && zPw[0] ){
1059 zObs = obscure(zPw);
1060 blob_appendf(&reqUri, "&token=%t", zObs);
1061 fossil_free(zObs);
1062 }
1063 g.url.path = blob_str(&reqUri);
1064 if( bDebug ){
1065 fossil_print("REQUEST_URI: %s\n", g.url.path);
1066 mFlags &= ~HTTP_QUIET;
1067 mFlags |= HTTP_VERBOSE;
1068 }
1069 blob_init(&up, 0, 0);
1070 blob_init(&down, 0, 0);
1071 http_exchange(&up, &down, mFlags, 4, 0);
1072 if( zOut ){
1073 blob_write_to_file(&down, zOut);
1074 fossil_print("Chat database at %s is %d bytes\n", zOut, blob_size(&down));
1075 }else{
1076 db_multi_exec("ATTACH ':memory:' AS chatbu;");
1077 if( g.fSqlTrace ){
1078 fossil_trace("-- deserialize(\"chatbu\", pData, %d);\n",
1079 blob_size(&down));
1080 }
1081 rc = sqlite3_deserialize(g.db, "chatbu",
1082 (unsigned char*)blob_buffer(&down),
1083 blob_size(&down), blob_size(&down), 0);
1084 if( rc ){
1085 fossil_fatal("cannot open patch database: %s", sqlite3_errmsg(g.db));
1086 }
1087 nChat = db_int(0, "SELECT count(*) FROM chatbu.chat");
1088 fossil_print("Got %d new records, %d bytes\n", nChat, blob_size(&down));
1089 db_multi_exec(
1090 "REPLACE INTO repository.chat SELECT * FROM chatbu.chat;"
1091 );
1092 }
1093 }else if( strcmp(g.argv[2],"url")==0 ){
1094 /* Show the URL to access chat. */
1095 fossil_print("%s/chat\n", zUrl);
1096 }else{
1097 fossil_fatal("no such subcommand \"%s\". Use --help for help", g.argv[2]);
1098 }
1099 }
1100

Keyboard Shortcuts

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