Fossil SCM

The ssh:// method on windows is now working well with plink. It will even prompt for passwords if the URL contains a "*" password.

drh 2010-08-27 20:40 trunk
Commit 0cdb6403cb1dd73dee52dfc2c6c556be657acf5a
+21
--- src/blob.c
+++ src/blob.c
@@ -896,5 +896,26 @@
896896
if( z[i]!='\r' ) z[j++] = z[i];
897897
}
898898
z[j] = 0;
899899
p->nUsed = j;
900900
}
901
+
902
+/*
903
+** Shell-escape the given string. Append the result to a blob.
904
+*/
905
+void shell_escape(Blob *pBlob, const char *zIn){
906
+ int n = blob_size(pBlob);
907
+ int k = strlen(zIn);
908
+ int i, c;
909
+ char *z;
910
+ for(i=0; (c = zIn[i])!=0; i++){
911
+ if( isspace(c) || c=='"' || (c=='\\' && zIn[i+1]!=0) ){
912
+ blob_appendf(pBlob, "\"%s\"", zIn);
913
+ z = blob_buffer(pBlob);
914
+ for(i=n+1; i<=n+k; i++){
915
+ if( z[i]=='"' ) z[i] = '_';
916
+ }
917
+ return;
918
+ }
919
+ }
920
+ blob_append(pBlob, zIn, -1);
921
+}
901922
--- src/blob.c
+++ src/blob.c
@@ -896,5 +896,26 @@
896 if( z[i]!='\r' ) z[j++] = z[i];
897 }
898 z[j] = 0;
899 p->nUsed = j;
900 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
901
--- src/blob.c
+++ src/blob.c
@@ -896,5 +896,26 @@
896 if( z[i]!='\r' ) z[j++] = z[i];
897 }
898 z[j] = 0;
899 p->nUsed = j;
900 }
901
902 /*
903 ** Shell-escape the given string. Append the result to a blob.
904 */
905 void shell_escape(Blob *pBlob, const char *zIn){
906 int n = blob_size(pBlob);
907 int k = strlen(zIn);
908 int i, c;
909 char *z;
910 for(i=0; (c = zIn[i])!=0; i++){
911 if( isspace(c) || c=='"' || (c=='\\' && zIn[i+1]!=0) ){
912 blob_appendf(pBlob, "\"%s\"", zIn);
913 z = blob_buffer(pBlob);
914 for(i=n+1; i<=n+k; i++){
915 if( z[i]=='"' ) z[i] = '_';
916 }
917 return;
918 }
919 }
920 blob_append(pBlob, zIn, -1);
921 }
922
+4
--- src/db.c
+++ src/db.c
@@ -1554,10 +1554,13 @@
15541554
**
15551555
** proxy URL of the HTTP proxy. If undefined or "off" then
15561556
** the "http_proxy" environment variable is consulted.
15571557
** If the http_proxy environment variable is undefined
15581558
** then a direct HTTP connection is used.
1559
+**
1560
+** ssh-command Command used to talk to a remote machine with
1561
+** the "ssh://" protocol.
15591562
**
15601563
** web-browser A shell command used to launch your preferred
15611564
** web browser when given a URL as an argument.
15621565
** Defaults to "start" on windows, "open" on Mac,
15631566
** and "firefox" on Unix.
@@ -1577,10 +1580,11 @@
15771580
"http-port",
15781581
"localauth",
15791582
"mtime-changes",
15801583
"pgp-command",
15811584
"proxy",
1585
+ "ssh-command",
15821586
"web-browser",
15831587
};
15841588
int i;
15851589
int globalFlag = find_option("global","g",0)!=0;
15861590
int unsetFlag = g.argv[1][0]=='u';
15871591
--- src/db.c
+++ src/db.c
@@ -1554,10 +1554,13 @@
1554 **
1555 ** proxy URL of the HTTP proxy. If undefined or "off" then
1556 ** the "http_proxy" environment variable is consulted.
1557 ** If the http_proxy environment variable is undefined
1558 ** then a direct HTTP connection is used.
 
 
 
1559 **
1560 ** web-browser A shell command used to launch your preferred
1561 ** web browser when given a URL as an argument.
1562 ** Defaults to "start" on windows, "open" on Mac,
1563 ** and "firefox" on Unix.
@@ -1577,10 +1580,11 @@
1577 "http-port",
1578 "localauth",
1579 "mtime-changes",
1580 "pgp-command",
1581 "proxy",
 
1582 "web-browser",
1583 };
1584 int i;
1585 int globalFlag = find_option("global","g",0)!=0;
1586 int unsetFlag = g.argv[1][0]=='u';
1587
--- src/db.c
+++ src/db.c
@@ -1554,10 +1554,13 @@
1554 **
1555 ** proxy URL of the HTTP proxy. If undefined or "off" then
1556 ** the "http_proxy" environment variable is consulted.
1557 ** If the http_proxy environment variable is undefined
1558 ** then a direct HTTP connection is used.
1559 **
1560 ** ssh-command Command used to talk to a remote machine with
1561 ** the "ssh://" protocol.
1562 **
1563 ** web-browser A shell command used to launch your preferred
1564 ** web browser when given a URL as an argument.
1565 ** Defaults to "start" on windows, "open" on Mac,
1566 ** and "firefox" on Unix.
@@ -1577,10 +1580,11 @@
1580 "http-port",
1581 "localauth",
1582 "mtime-changes",
1583 "pgp-command",
1584 "proxy",
1585 "ssh-command",
1586 "web-browser",
1587 };
1588 int i;
1589 int globalFlag = find_option("global","g",0)!=0;
1590 int unsetFlag = g.argv[1][0]=='u';
1591
--- src/diffcmd.c
+++ src/diffcmd.c
@@ -19,31 +19,10 @@
1919
*/
2020
#include "config.h"
2121
#include "diffcmd.h"
2222
#include <assert.h>
2323
24
-/*
25
-** Shell-escape the given string. Append the result to a blob.
26
-*/
27
-void shell_escape(Blob *pBlob, const char *zIn){
28
- int n = blob_size(pBlob);
29
- int k = strlen(zIn);
30
- int i, c;
31
- char *z;
32
- for(i=0; (c = zIn[i])!=0; i++){
33
- if( isspace(c) || c=='"' || (c=='\\' && zIn[i+1]!=0) ){
34
- blob_appendf(pBlob, "\"%s\"", zIn);
35
- z = blob_buffer(pBlob);
36
- for(i=n+1; i<=n+k; i++){
37
- if( z[i]=='"' ) z[i] = '_';
38
- }
39
- return;
40
- }
41
- }
42
- blob_append(pBlob, zIn, -1);
43
-}
44
-
4524
/*
4625
** This function implements a cross-platform "system()" interface.
4726
*/
4827
int portable_system(const char *zOrigCmd){
4928
int rc;
5029
--- src/diffcmd.c
+++ src/diffcmd.c
@@ -19,31 +19,10 @@
19 */
20 #include "config.h"
21 #include "diffcmd.h"
22 #include <assert.h>
23
24 /*
25 ** Shell-escape the given string. Append the result to a blob.
26 */
27 void shell_escape(Blob *pBlob, const char *zIn){
28 int n = blob_size(pBlob);
29 int k = strlen(zIn);
30 int i, c;
31 char *z;
32 for(i=0; (c = zIn[i])!=0; i++){
33 if( isspace(c) || c=='"' || (c=='\\' && zIn[i+1]!=0) ){
34 blob_appendf(pBlob, "\"%s\"", zIn);
35 z = blob_buffer(pBlob);
36 for(i=n+1; i<=n+k; i++){
37 if( z[i]=='"' ) z[i] = '_';
38 }
39 return;
40 }
41 }
42 blob_append(pBlob, zIn, -1);
43 }
44
45 /*
46 ** This function implements a cross-platform "system()" interface.
47 */
48 int portable_system(const char *zOrigCmd){
49 int rc;
50
--- src/diffcmd.c
+++ src/diffcmd.c
@@ -19,31 +19,10 @@
19 */
20 #include "config.h"
21 #include "diffcmd.h"
22 #include <assert.h>
23
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
24 /*
25 ** This function implements a cross-platform "system()" interface.
26 */
27 int portable_system(const char *zOrigCmd){
28 int rc;
29
--- src/http_transport.c
+++ src/http_transport.c
@@ -88,38 +88,79 @@
8888
if( got==0 || !isspace(zBuf[got-1]) ) break;
8989
got--;
9090
}
9191
}
9292
93
+/*
94
+** Default SSH command
95
+*/
96
+#ifdef __MINGW32__
97
+static char zDefaultSshCmd[] = "ssh -T";
98
+#else
99
+static char zDefaultSshCmd[] = "ssh -e none -T";
100
+#endif
101
+
93102
/*
94103
** Global initialization of the transport layer
95104
*/
96105
void transport_global_startup(void){
97106
if( g.urlIsSsh ){
98
-#ifdef __MINGW32__
99
- static const char *zSshCmd = "ssh";
100
-#else
101
- static const char *zSshCmd = "ssh -e none";
102
-#endif
103
- char *zCmd;
104
- char zIn[20];
107
+ /* Only SSH requires a global initialization. For SSH we need to create
108
+ ** and run an SSH command to talk to the remote machine.
109
+ */
110
+ const char *zSsh; /* The base SSH command */
111
+ Blob zCmd; /* The SSH command */
112
+ char *zHost; /* The host name to contact */
113
+ char zIn[200]; /* An input line received back from remote */
114
+
115
+ zSsh = db_get("ssh-command", zDefaultSshCmd);
116
+ blob_init(&zCmd, zSsh, -1);
117
+ if( g.urlPort!=g.urlDfltPort ){
118
+ blob_appendf(&zCmd, " -P %d", g.urlPort);
119
+ }
105120
if( g.urlUser && g.urlUser[0] ){
106
- zCmd = mprintf("%s %s@%s", zSshCmd, g.urlUser, g.urlName);
121
+ zHost = mprintf("%s@%s", g.urlUser, g.urlName);
122
+#ifdef __MINGW32__
123
+ /* Only win32 (and specifically PLINK.EXE support the -pw option */
124
+ if( g.urlPasswd && g.urlPasswd[0] ){
125
+ Blob pw;
126
+ blob_zero(&pw);
127
+ if( g.urlPasswd[0]=='*' ){
128
+ char *zPrompt;
129
+ zPrompt = mprintf("Password for [%s]: ", zHost);
130
+ prompt_for_password(zPrompt, &pw, 0);
131
+ free(zPrompt);
132
+ }else{
133
+ blob_init(&pw, g.urlPasswd, -1);
134
+ }
135
+ blob_append(&zCmd, " -pw ", -1);
136
+ shell_escape(&zCmd, blob_str(&pw));
137
+ blob_reset(&pw);
138
+ }
139
+#endif
107140
}else{
108
- zCmd = mprintf("%s %s", zSshCmd, g.urlName);
141
+ zHost = mprintf("%s", g.urlName);
109142
}
110
- /* printf("%s\n", zCmd); */
111
- popen2(zCmd, &sshIn, &sshOut, &sshPid);
143
+ blob_append(&zCmd, " ", 1);
144
+ shell_escape(&zCmd, zHost);
145
+ free(zHost);
146
+ /* printf("%s\n", blob_str(&zCmd)); */
147
+ popen2(blob_str(&zCmd), &sshIn, &sshOut, &sshPid);
112148
if( sshPid==0 ){
113
- fossil_fatal("cannot start ssh tunnel using [%s]", zCmd);
149
+ fossil_fatal("cannot start ssh tunnel using [%b]", &zCmd);
114150
}
115
- free(zCmd);
151
+ blob_reset(&zCmd);
152
+
153
+ /* Send an "echo" command to the other side to make sure that the
154
+ ** connection is up and working.
155
+ */
116156
fprintf(sshOut, "echo test\n");
117157
fflush(sshOut);
118158
sshin_read(zIn, sizeof(zIn));
119159
if( memcmp(zIn, "test", 4)!=0 ){
120
- fossil_fatal("ssh connection failed");
160
+ pclose2(sshIn, sshOut, sshPid);
161
+ fossil_fatal("ssh connection failed: [%s]", zIn);
121162
}
122163
}
123164
}
124165
125166
/*
126167
--- src/http_transport.c
+++ src/http_transport.c
@@ -88,38 +88,79 @@
88 if( got==0 || !isspace(zBuf[got-1]) ) break;
89 got--;
90 }
91 }
92
 
 
 
 
 
 
 
 
 
93 /*
94 ** Global initialization of the transport layer
95 */
96 void transport_global_startup(void){
97 if( g.urlIsSsh ){
98 #ifdef __MINGW32__
99 static const char *zSshCmd = "ssh";
100 #else
101 static const char *zSshCmd = "ssh -e none";
102 #endif
103 char *zCmd;
104 char zIn[20];
 
 
 
 
 
 
105 if( g.urlUser && g.urlUser[0] ){
106 zCmd = mprintf("%s %s@%s", zSshCmd, g.urlUser, g.urlName);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
107 }else{
108 zCmd = mprintf("%s %s", zSshCmd, g.urlName);
109 }
110 /* printf("%s\n", zCmd); */
111 popen2(zCmd, &sshIn, &sshOut, &sshPid);
 
 
 
112 if( sshPid==0 ){
113 fossil_fatal("cannot start ssh tunnel using [%s]", zCmd);
114 }
115 free(zCmd);
 
 
 
 
116 fprintf(sshOut, "echo test\n");
117 fflush(sshOut);
118 sshin_read(zIn, sizeof(zIn));
119 if( memcmp(zIn, "test", 4)!=0 ){
120 fossil_fatal("ssh connection failed");
 
121 }
122 }
123 }
124
125 /*
126
--- src/http_transport.c
+++ src/http_transport.c
@@ -88,38 +88,79 @@
88 if( got==0 || !isspace(zBuf[got-1]) ) break;
89 got--;
90 }
91 }
92
93 /*
94 ** Default SSH command
95 */
96 #ifdef __MINGW32__
97 static char zDefaultSshCmd[] = "ssh -T";
98 #else
99 static char zDefaultSshCmd[] = "ssh -e none -T";
100 #endif
101
102 /*
103 ** Global initialization of the transport layer
104 */
105 void transport_global_startup(void){
106 if( g.urlIsSsh ){
107 /* Only SSH requires a global initialization. For SSH we need to create
108 ** and run an SSH command to talk to the remote machine.
109 */
110 const char *zSsh; /* The base SSH command */
111 Blob zCmd; /* The SSH command */
112 char *zHost; /* The host name to contact */
113 char zIn[200]; /* An input line received back from remote */
114
115 zSsh = db_get("ssh-command", zDefaultSshCmd);
116 blob_init(&zCmd, zSsh, -1);
117 if( g.urlPort!=g.urlDfltPort ){
118 blob_appendf(&zCmd, " -P %d", g.urlPort);
119 }
120 if( g.urlUser && g.urlUser[0] ){
121 zHost = mprintf("%s@%s", g.urlUser, g.urlName);
122 #ifdef __MINGW32__
123 /* Only win32 (and specifically PLINK.EXE support the -pw option */
124 if( g.urlPasswd && g.urlPasswd[0] ){
125 Blob pw;
126 blob_zero(&pw);
127 if( g.urlPasswd[0]=='*' ){
128 char *zPrompt;
129 zPrompt = mprintf("Password for [%s]: ", zHost);
130 prompt_for_password(zPrompt, &pw, 0);
131 free(zPrompt);
132 }else{
133 blob_init(&pw, g.urlPasswd, -1);
134 }
135 blob_append(&zCmd, " -pw ", -1);
136 shell_escape(&zCmd, blob_str(&pw));
137 blob_reset(&pw);
138 }
139 #endif
140 }else{
141 zHost = mprintf("%s", g.urlName);
142 }
143 blob_append(&zCmd, " ", 1);
144 shell_escape(&zCmd, zHost);
145 free(zHost);
146 /* printf("%s\n", blob_str(&zCmd)); */
147 popen2(blob_str(&zCmd), &sshIn, &sshOut, &sshPid);
148 if( sshPid==0 ){
149 fossil_fatal("cannot start ssh tunnel using [%b]", &zCmd);
150 }
151 blob_reset(&zCmd);
152
153 /* Send an "echo" command to the other side to make sure that the
154 ** connection is up and working.
155 */
156 fprintf(sshOut, "echo test\n");
157 fflush(sshOut);
158 sshin_read(zIn, sizeof(zIn));
159 if( memcmp(zIn, "test", 4)!=0 ){
160 pclose2(sshIn, sshOut, sshPid);
161 fossil_fatal("ssh connection failed: [%s]", zIn);
162 }
163 }
164 }
165
166 /*
167
--- src/popen.c
+++ src/popen.c
@@ -173,10 +173,12 @@
173173
** popen2(). Kill off the child process, then close the pipes.
174174
*/
175175
void pclose2(int fdIn, FILE *pOut, int childPid){
176176
#ifdef __MINGW32__
177177
/* Not implemented, yet */
178
+ close(fdIn);
179
+ fclose(pOut);
178180
#else
179181
close(fdIn);
180182
fclose(pOut);
181183
kill(childPid, SIGINT);
182184
#endif
183185
--- src/popen.c
+++ src/popen.c
@@ -173,10 +173,12 @@
173 ** popen2(). Kill off the child process, then close the pipes.
174 */
175 void pclose2(int fdIn, FILE *pOut, int childPid){
176 #ifdef __MINGW32__
177 /* Not implemented, yet */
 
 
178 #else
179 close(fdIn);
180 fclose(pOut);
181 kill(childPid, SIGINT);
182 #endif
183
--- src/popen.c
+++ src/popen.c
@@ -173,10 +173,12 @@
173 ** popen2(). Kill off the child process, then close the pipes.
174 */
175 void pclose2(int fdIn, FILE *pOut, int childPid){
176 #ifdef __MINGW32__
177 /* Not implemented, yet */
178 close(fdIn);
179 fclose(pOut);
180 #else
181 close(fdIn);
182 fclose(pOut);
183 kill(childPid, SIGINT);
184 #endif
185
+33 -54
--- src/url.c
+++ src/url.c
@@ -46,29 +46,40 @@
4646
** g.urlHostname HOST:PORT or just HOST if port is the default.
4747
** g.urlCanonical The URL in canonical form, omitting the password
4848
**
4949
** HTTP url format is:
5050
**
51
-** http://userid:password@host:port/path?query#fragment
51
+** http://userid:password@host:port/path
5252
**
5353
** SSH url format is:
5454
**
55
-** ssh://userid@host:port/path?fossil=path/to/fossil.exe
55
+** ssh://userid:password@host:port/path?fossil=path/to/fossil.exe
5656
**
5757
*/
5858
void url_parse(const char *zUrl){
5959
int i, j, c;
6060
char *zFile = 0;
61
- if( strncmp(zUrl, "http://", 7)==0 || strncmp(zUrl, "https://", 8)==0 ){
61
+ if( strncmp(zUrl, "http://", 7)==0
62
+ || strncmp(zUrl, "https://", 8)==0
63
+ || strncmp(zUrl, "ssh://", 6)==0
64
+ ){
6265
int iStart;
6366
char *zLogin;
67
+ char *zExe;
68
+
6469
g.urlIsFile = 0;
6570
if( zUrl[4]=='s' ){
6671
g.urlIsHttps = 1;
6772
g.urlProtocol = "https";
6873
g.urlDfltPort = 443;
6974
iStart = 8;
75
+ }else if( zUrl[0]=='s' ){
76
+ g.urlIsSsh = 1;
77
+ g.urlProtocol = "ssh";
78
+ g.urlDfltPort = 22;
79
+ g.urlFossil = "fossil";
80
+ iStart = 6;
7081
}else{
7182
g.urlIsHttps = 0;
7283
g.urlProtocol = "http";
7384
g.urlDfltPort = 80;
7485
iStart = 7;
@@ -83,11 +94,15 @@
8394
dehttpize(g.urlPasswd);
8495
}
8596
for(j=i+1; (c=zUrl[j])!=0 && c!='/' && c!=':'; j++){}
8697
g.urlName = mprintf("%.*s", j-i-1, &zUrl[i+1]);
8798
i = j;
88
- zLogin = mprintf("%t@", g.urlUser);
99
+ if( g.urlIsSsh && g.urlPasswd ){
100
+ zLogin = mprintf("%t:*@", g.urlUser);
101
+ }else{
102
+ zLogin = mprintf("%t@", g.urlUser);
103
+ }
89104
}else{
90105
g.urlName = mprintf("%.*s", i-iStart, &zUrl[iStart]);
91106
zLogin = mprintf("");
92107
}
93108
url_tolower(g.urlName);
@@ -101,56 +116,13 @@
101116
g.urlHostname = mprintf("%s:%d", g.urlName, g.urlPort);
102117
}else{
103118
g.urlPort = g.urlDfltPort;
104119
g.urlHostname = g.urlName;
105120
}
106
- g.urlPath = mprintf(&zUrl[i]);
107121
dehttpize(g.urlName);
108
- dehttpize(g.urlPath);
109
- if( g.urlDfltPort==g.urlPort ){
110
- g.urlCanonical = mprintf(
111
- "%s://%s%T%T",
112
- g.urlProtocol, zLogin, g.urlName, g.urlPath
113
- );
114
- }else{
115
- g.urlCanonical = mprintf(
116
- "%s://%s%T:%d%T",
117
- g.urlProtocol, zLogin, g.urlName, g.urlPort, g.urlPath
118
- );
119
- }
120
- free(zLogin);
121
- }else if( strncmp(zUrl, "ssh://", 6)==0 ){
122
- char *zLogin;
123
- char *zExe;
124
- int i, j;
125
- g.urlIsFile = 0;
126
- g.urlIsSsh = 1;
127
- g.urlProtocol = "ssh";
128
- g.urlPort = 22;
129
- g.urlDfltPort = 22;
130
- g.urlPasswd = "(not-used)";
131
- g.urlFossil = "fossil";
132
- for(i=6; (c=zUrl[i])!=0 && c!='/' && c!='@'; i++){}
133
- if( c=='@' ){
134
- for(j=6; j<i && zUrl[j]!=':'; j++){}
135
- g.urlUser = mprintf("%.*s", j-6, &zUrl[6]);
136
- dehttpize(g.urlUser);
137
- if( j<i ){
138
- g.urlPasswd = mprintf("%.*s", i-j-1, &zUrl[j+1]);
139
- dehttpize(g.urlPasswd);
140
- }
141
- for(j=i+1; (c=zUrl[j])!=0 && c!='/'; j++){}
142
- g.urlName = mprintf("%.*s", j-i-1, &zUrl[i+1]);
143
- i = j;
144
- zLogin = mprintf("%t@", g.urlUser);
145
- }else{
146
- g.urlName = mprintf("%.*s", i-6, &zUrl[6]);
147
- zLogin = mprintf("");
148
- }
149
- url_tolower(g.urlName);
150
- g.urlHostname = g.urlName;
151
- g.urlPath = mprintf(&zUrl[i+1]);
122
+ g.urlPath = mprintf(&zUrl[i]);
123
+ if( g.urlIsSsh && g.urlPath[1] ) g.urlPath++;
152124
for(i=0; g.urlPath[i] && g.urlPath[i]!='?'; i++){}
153125
if( g.urlPath[i] ){
154126
g.urlPath[i] = 0;
155127
i++;
156128
}
@@ -174,17 +146,24 @@
174146
g.urlFossil = zValue;
175147
dehttpize(g.urlFossil);
176148
zExe = mprintf("?fossil=%T", g.urlFossil);
177149
}
178150
}
151
+
179152
dehttpize(g.urlPath);
180
- g.urlCanonical = mprintf(
181
- "ssh://%s%T/%T%s",
182
- zLogin, g.urlName, g.urlPath, zExe
183
- );
153
+ if( g.urlDfltPort==g.urlPort ){
154
+ g.urlCanonical = mprintf(
155
+ "%s://%s%T%T%s",
156
+ g.urlProtocol, zLogin, g.urlName, g.urlPath, zExe
157
+ );
158
+ }else{
159
+ g.urlCanonical = mprintf(
160
+ "%s://%s%T:%d%T%s",
161
+ g.urlProtocol, zLogin, g.urlName, g.urlPort, g.urlPath, zExe
162
+ );
163
+ }
184164
free(zLogin);
185
- free(zExe);
186165
}else if( strncmp(zUrl, "file:", 5)==0 ){
187166
g.urlIsFile = 1;
188167
if( zUrl[5]=='/' && zUrl[6]=='/' ){
189168
i = 7;
190169
}else{
191170
--- src/url.c
+++ src/url.c
@@ -46,29 +46,40 @@
46 ** g.urlHostname HOST:PORT or just HOST if port is the default.
47 ** g.urlCanonical The URL in canonical form, omitting the password
48 **
49 ** HTTP url format is:
50 **
51 ** http://userid:password@host:port/path?query#fragment
52 **
53 ** SSH url format is:
54 **
55 ** ssh://userid@host:port/path?fossil=path/to/fossil.exe
56 **
57 */
58 void url_parse(const char *zUrl){
59 int i, j, c;
60 char *zFile = 0;
61 if( strncmp(zUrl, "http://", 7)==0 || strncmp(zUrl, "https://", 8)==0 ){
 
 
 
62 int iStart;
63 char *zLogin;
 
 
64 g.urlIsFile = 0;
65 if( zUrl[4]=='s' ){
66 g.urlIsHttps = 1;
67 g.urlProtocol = "https";
68 g.urlDfltPort = 443;
69 iStart = 8;
 
 
 
 
 
 
70 }else{
71 g.urlIsHttps = 0;
72 g.urlProtocol = "http";
73 g.urlDfltPort = 80;
74 iStart = 7;
@@ -83,11 +94,15 @@
83 dehttpize(g.urlPasswd);
84 }
85 for(j=i+1; (c=zUrl[j])!=0 && c!='/' && c!=':'; j++){}
86 g.urlName = mprintf("%.*s", j-i-1, &zUrl[i+1]);
87 i = j;
88 zLogin = mprintf("%t@", g.urlUser);
 
 
 
 
89 }else{
90 g.urlName = mprintf("%.*s", i-iStart, &zUrl[iStart]);
91 zLogin = mprintf("");
92 }
93 url_tolower(g.urlName);
@@ -101,56 +116,13 @@
101 g.urlHostname = mprintf("%s:%d", g.urlName, g.urlPort);
102 }else{
103 g.urlPort = g.urlDfltPort;
104 g.urlHostname = g.urlName;
105 }
106 g.urlPath = mprintf(&zUrl[i]);
107 dehttpize(g.urlName);
108 dehttpize(g.urlPath);
109 if( g.urlDfltPort==g.urlPort ){
110 g.urlCanonical = mprintf(
111 "%s://%s%T%T",
112 g.urlProtocol, zLogin, g.urlName, g.urlPath
113 );
114 }else{
115 g.urlCanonical = mprintf(
116 "%s://%s%T:%d%T",
117 g.urlProtocol, zLogin, g.urlName, g.urlPort, g.urlPath
118 );
119 }
120 free(zLogin);
121 }else if( strncmp(zUrl, "ssh://", 6)==0 ){
122 char *zLogin;
123 char *zExe;
124 int i, j;
125 g.urlIsFile = 0;
126 g.urlIsSsh = 1;
127 g.urlProtocol = "ssh";
128 g.urlPort = 22;
129 g.urlDfltPort = 22;
130 g.urlPasswd = "(not-used)";
131 g.urlFossil = "fossil";
132 for(i=6; (c=zUrl[i])!=0 && c!='/' && c!='@'; i++){}
133 if( c=='@' ){
134 for(j=6; j<i && zUrl[j]!=':'; j++){}
135 g.urlUser = mprintf("%.*s", j-6, &zUrl[6]);
136 dehttpize(g.urlUser);
137 if( j<i ){
138 g.urlPasswd = mprintf("%.*s", i-j-1, &zUrl[j+1]);
139 dehttpize(g.urlPasswd);
140 }
141 for(j=i+1; (c=zUrl[j])!=0 && c!='/'; j++){}
142 g.urlName = mprintf("%.*s", j-i-1, &zUrl[i+1]);
143 i = j;
144 zLogin = mprintf("%t@", g.urlUser);
145 }else{
146 g.urlName = mprintf("%.*s", i-6, &zUrl[6]);
147 zLogin = mprintf("");
148 }
149 url_tolower(g.urlName);
150 g.urlHostname = g.urlName;
151 g.urlPath = mprintf(&zUrl[i+1]);
152 for(i=0; g.urlPath[i] && g.urlPath[i]!='?'; i++){}
153 if( g.urlPath[i] ){
154 g.urlPath[i] = 0;
155 i++;
156 }
@@ -174,17 +146,24 @@
174 g.urlFossil = zValue;
175 dehttpize(g.urlFossil);
176 zExe = mprintf("?fossil=%T", g.urlFossil);
177 }
178 }
 
179 dehttpize(g.urlPath);
180 g.urlCanonical = mprintf(
181 "ssh://%s%T/%T%s",
182 zLogin, g.urlName, g.urlPath, zExe
183 );
 
 
 
 
 
 
 
184 free(zLogin);
185 free(zExe);
186 }else if( strncmp(zUrl, "file:", 5)==0 ){
187 g.urlIsFile = 1;
188 if( zUrl[5]=='/' && zUrl[6]=='/' ){
189 i = 7;
190 }else{
191
--- src/url.c
+++ src/url.c
@@ -46,29 +46,40 @@
46 ** g.urlHostname HOST:PORT or just HOST if port is the default.
47 ** g.urlCanonical The URL in canonical form, omitting the password
48 **
49 ** HTTP url format is:
50 **
51 ** http://userid:password@host:port/path
52 **
53 ** SSH url format is:
54 **
55 ** ssh://userid:password@host:port/path?fossil=path/to/fossil.exe
56 **
57 */
58 void url_parse(const char *zUrl){
59 int i, j, c;
60 char *zFile = 0;
61 if( strncmp(zUrl, "http://", 7)==0
62 || strncmp(zUrl, "https://", 8)==0
63 || strncmp(zUrl, "ssh://", 6)==0
64 ){
65 int iStart;
66 char *zLogin;
67 char *zExe;
68
69 g.urlIsFile = 0;
70 if( zUrl[4]=='s' ){
71 g.urlIsHttps = 1;
72 g.urlProtocol = "https";
73 g.urlDfltPort = 443;
74 iStart = 8;
75 }else if( zUrl[0]=='s' ){
76 g.urlIsSsh = 1;
77 g.urlProtocol = "ssh";
78 g.urlDfltPort = 22;
79 g.urlFossil = "fossil";
80 iStart = 6;
81 }else{
82 g.urlIsHttps = 0;
83 g.urlProtocol = "http";
84 g.urlDfltPort = 80;
85 iStart = 7;
@@ -83,11 +94,15 @@
94 dehttpize(g.urlPasswd);
95 }
96 for(j=i+1; (c=zUrl[j])!=0 && c!='/' && c!=':'; j++){}
97 g.urlName = mprintf("%.*s", j-i-1, &zUrl[i+1]);
98 i = j;
99 if( g.urlIsSsh && g.urlPasswd ){
100 zLogin = mprintf("%t:*@", g.urlUser);
101 }else{
102 zLogin = mprintf("%t@", g.urlUser);
103 }
104 }else{
105 g.urlName = mprintf("%.*s", i-iStart, &zUrl[iStart]);
106 zLogin = mprintf("");
107 }
108 url_tolower(g.urlName);
@@ -101,56 +116,13 @@
116 g.urlHostname = mprintf("%s:%d", g.urlName, g.urlPort);
117 }else{
118 g.urlPort = g.urlDfltPort;
119 g.urlHostname = g.urlName;
120 }
 
121 dehttpize(g.urlName);
122 g.urlPath = mprintf(&zUrl[i]);
123 if( g.urlIsSsh && g.urlPath[1] ) g.urlPath++;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
124 for(i=0; g.urlPath[i] && g.urlPath[i]!='?'; i++){}
125 if( g.urlPath[i] ){
126 g.urlPath[i] = 0;
127 i++;
128 }
@@ -174,17 +146,24 @@
146 g.urlFossil = zValue;
147 dehttpize(g.urlFossil);
148 zExe = mprintf("?fossil=%T", g.urlFossil);
149 }
150 }
151
152 dehttpize(g.urlPath);
153 if( g.urlDfltPort==g.urlPort ){
154 g.urlCanonical = mprintf(
155 "%s://%s%T%T%s",
156 g.urlProtocol, zLogin, g.urlName, g.urlPath, zExe
157 );
158 }else{
159 g.urlCanonical = mprintf(
160 "%s://%s%T:%d%T%s",
161 g.urlProtocol, zLogin, g.urlName, g.urlPort, g.urlPath, zExe
162 );
163 }
164 free(zLogin);
 
165 }else if( strncmp(zUrl, "file:", 5)==0 ){
166 g.urlIsFile = 1;
167 if( zUrl[5]=='/' && zUrl[6]=='/' ){
168 i = 7;
169 }else{
170

Keyboard Shortcuts

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