Wez Furlong's patch to add xterm mouse reporting and proper mouse
[sgt/putty] / psftp.c
diff --git a/psftp.c b/psftp.c
index 08c89e7..1e89575 100644 (file)
--- a/psftp.c
+++ b/psftp.c
@@ -94,8 +94,75 @@ char *canonify(char *name) {
     if (canonname) {
        sfree(fullname);
        return canonname;
-    } else
-       return fullname;
+    } else {
+        /*
+         * Attempt number 2. Some FXP_REALPATH implementations
+         * (glibc-based ones, in particular) require the _whole_
+         * path to point to something that exists, whereas others
+         * (BSD-based) only require all but the last component to
+         * exist. So if the first call failed, we should strip off
+         * everything from the last slash onwards and try again,
+         * then put the final component back on.
+         * 
+         * Special cases:
+         * 
+         *  - if the last component is "/." or "/..", then we don't
+         *    bother trying this because there's no way it can work.
+         * 
+         *  - if the thing actually ends with a "/", we remove it
+         *    before we start. Except if the string is "/" itself
+         *    (although I can't see why we'd have got here if so,
+         *    because surely "/" would have worked the first
+         *    time?), in which case we don't bother.
+         * 
+         *  - if there's no slash in the string at all, give up in
+         *    confusion (we expect at least one because of the way
+         *    we constructed the string).
+         */
+        
+        int i;
+        char *returnname;
+
+        i = strlen(fullname);
+        if (i > 2 && fullname[i-1] == '/')
+            fullname[--i] = '\0';      /* strip trailing / unless at pos 0 */
+        while (i > 0 && fullname[--i] != '/');
+
+        /*
+         * Give up on special cases.
+         */
+        if (fullname[i] != '/' ||      /* no slash at all */
+            !strcmp(fullname+i, "/.") ||   /* ends in /. */
+            !strcmp(fullname+i, "/..") ||   /* ends in /.. */
+            !strcmp(fullname, "/")) {
+            return fullname;
+        }
+
+        /*
+         * Now i points at the slash. Deal with the final special
+         * case i==0 (ie the whole path was "/nonexistentfile").
+         */
+        fullname[i] = '\0';            /* separate the string */
+        if (i == 0) {
+            canonname = fxp_realpath("/");
+        } else {
+            canonname = fxp_realpath(fullname);
+        }
+
+        if (!canonname)
+            return fullname;           /* even that failed; give up */
+
+        /*
+         * We have a canonical name for all but the last path
+         * component. Concatenate the last component and return.
+         */
+        returnname = dupcat(canonname,
+                            canonname[strlen(canonname)-1] == '/' ? "" : "/",
+                            fullname+i+1, NULL);
+        sfree(fullname);
+        sfree(canonname);
+        return returnname;
+    }
 }
 
 /* ----------------------------------------------------------------------
@@ -339,7 +406,6 @@ int sftp_cmd_put(struct sftp_command *cmd) {
     fp = fopen(fname, "rb");
     if (!fp) {
        printf("local: unable to open %s\n", fname);
-        fxp_close(fh);
        sfree(outfname);
        return 0;
     }
@@ -523,6 +589,7 @@ void do_sftp(void) {
        fprintf(stderr,
                "Fatal: unable to initialise SFTP: %s\n",
                fxp_error());
+       return;
     }
 
     /*
@@ -793,10 +860,10 @@ static void ssh_sftp_init(void) {
 }
 
 static char *password = NULL;
-static int get_password(const char *prompt, char *str, int maxlen)
+static int get_line(const char *prompt, char *str, int maxlen, int is_pw)
 {
     HANDLE hin, hout;
-    DWORD savemode, i;
+    DWORD savemode, newmode, i;
 
     if (password) {
         static int tried_once = 0;
@@ -819,8 +886,12 @@ static int get_password(const char *prompt, char *str, int maxlen)
     }
 
     GetConsoleMode(hin, &savemode);
-    SetConsoleMode(hin, (savemode & (~ENABLE_ECHO_INPUT)) |
-                  ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT);
+    newmode = savemode | ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT;
+    if (is_pw)
+        newmode &= ~ENABLE_ECHO_INPUT;
+    else
+        newmode |= ENABLE_ECHO_INPUT;
+    SetConsoleMode(hin, newmode);
 
     WriteFile(hout, prompt, strlen(prompt), &i, NULL);
     ReadFile(hin, str, maxlen-1, &i, NULL);
@@ -830,7 +901,8 @@ static int get_password(const char *prompt, char *str, int maxlen)
     if ((int)i > maxlen) i = maxlen-1; else i = i - 2;
     str[i] = '\0';
 
-    WriteFile(hout, "\r\n", 2, &i, NULL);
+    if (is_pw)
+        WriteFile(hout, "\r\n", 2, &i, NULL);
 
     return 1;
 }
@@ -881,7 +953,7 @@ int main(int argc, char *argv[])
     char *err;
 
     flags = FLAG_STDERR;
-    ssh_get_password = &get_password;
+    ssh_get_line = &get_line;
     init_winsock();
     sk_init();