Index: pageant.c
===================================================================
RCS file: /home/cvs/putty/pageant.c,v
retrieving revision 1.70
diff -u -r1.70 pageant.c
--- pageant.c	1 Aug 2004 12:07:11 -0000	1.70
+++ pageant.c	2 Aug 2004 10:33:26 -0000
@@ -19,6 +19,8 @@
 #include <aclapi.h>
 #endif
 
+#include <shlobj.h>
+
 #define IDI_MAINICON 200
 #define IDI_TRAYICON 201
 
@@ -54,6 +56,8 @@
 char *help_path;
 static char *putty_path;
 
+static FILE* xfer_fp;
+
 #define IDM_PUTTY         0x0060
 #define IDM_SESSIONS_BASE 0x1000
 #define IDM_SESSIONS_MAX  0x2000
@@ -1262,6 +1266,82 @@
 	    ret[4] = SSH_AGENT_SUCCESS;
 	}
 	break;
+	  case SSH_AGENTC_XFER_REQUEST:
+	{
+	    int fnamelen;
+	    int pathlen;
+	    char path[MAX_PATH];
+	    LPMALLOC lpmalloc;
+	    LPITEMIDLIST lpiil;
+	    
+	    if(xfer_fp || msgend < p+4) /* can't have an already open connection */
+	        goto failure;
+	
+	    fnamelen = GET_32BIT(p);
+	    if(msgend < p+12+fnamelen) /* expect 3 int32's plus the filename */
+	        goto failure;
+
+	    /* Get the location of the user's desktop, in ASCII. We should probably
+	     * use UNICODE here and convert the ssh-xfer supplied name, instead.
+	     */
+	    if(SHGetSpecialFolderLocation(0, CSIDL_DESKTOPDIRECTORY, &lpiil) != S_OK)
+	        goto failure;
+	    if(SHGetPathFromIDList(lpiil, path) != TRUE)
+	        goto failure;
+	    if(SHGetMalloc(&lpmalloc)) { /* free space using the shell COM object's allocator */
+	        lpmalloc->lpVtbl->Free(lpmalloc, lpiil);
+	        lpmalloc->lpVtbl->Release(lpmalloc);
+	    }
+
+	    /* Tack the given filename onto the end of the provided path */
+	    pathlen = strlen(path);
+	    if(MAX_PATH < pathlen + fnamelen + 2)
+	        goto failure;
+	    path[pathlen] = '\\';
+	    memcpy(path + pathlen + 1, p+4, fnamelen);
+	    path[pathlen + fnamelen + 1] = '\0';
+	    
+	    xfer_fp = fopen(path, "wb");
+	    if(!xfer_fp)
+	        goto failure;
+	    PUT_32BIT(ret, 1);
+	    ret[4] = SSH_AGENT_SUCCESS;
+
+	}
+	break;
+	  case SSH_AGENTC_XFER_DONE:
+	{
+	    PUT_32BIT(ret, 1);
+
+	    if(xfer_fp) {
+	        fclose(xfer_fp);
+	        xfer_fp = NULL;
+	        ret[4] = SSH_AGENT_SUCCESS;
+	    } else {
+	        ret[4] = SSH_AGENT_FAILURE;
+	    }
+	    
+	}
+	break;
+	  case SSH_AGENTC_XFER_DATA:
+	{
+	    int len;
+
+	    if(!xfer_fp || msgend < p+4)
+	        goto failure;
+
+	    len = GET_32BIT(p);
+	    
+	    /* 
+	    * Make sure we're not going to overrun our buffer,
+	     * and then make sure the write succeeds.
+	     */
+	    if((msgend < p+len+4) || len != fwrite(p+4, 1, len, xfer_fp)) {
+	        fclose(xfer_fp);
+	        xfer_fp = NULL;
+	    }
+	}
+	break;
       default:
       failure:
 	/*
@@ -2179,6 +2259,11 @@
 	    FreeLibrary(advapi);
 	return 0;
     }
+
+	/*
+	 * Initialise ssh-xfer
+	 */
+	xfer_fp = NULL;
 
     /*
      * Main message loop.
Index: pageantc.c
===================================================================
RCS file: /home/cvs/putty/pageantc.c,v
retrieving revision 1.10
diff -u -r1.10 pageantc.c
--- pageantc.c	21 Jan 2004 21:11:03 -0000	1.10
+++ pageantc.c	2 Aug 2004 10:33:26 -0000
@@ -81,16 +81,30 @@
     unsigned char *p, *ret;
     int id, retlen;
     COPYDATASTRUCT cds;
+    int maplen;
 
     *out = NULL;
     *outlen = 0;
 
+    /* Establish the length of the mapping. As we're allocating the memory,
+     * we are not constrained by AGENT_MAX_MSGLEN - this is just the minimum
+     * amount of memory the agent expects to have for data that comes back
+     * to us.
+     *
+     * Round up to the nearest multiple of AGENT_MAX_MSGLEN. That way it's
+     * the minimum size, and if AGENT_MAX_MSGLEN is a multiple of the
+     * page size, we will be too.
+     */
+    maplen = inlen + (AGENT_MAX_MSGLEN-1);
+    if(maplen < 1) maplen = 1;
+    maplen -= (maplen % AGENT_MAX_MSGLEN);
+
     hwnd = FindWindow("Pageant", "Pageant");
     if (!hwnd)
 	return 1;		       /* *out == NULL, so failure */
     mapname = dupprintf("PageantRequest%08x", (unsigned)GetCurrentThreadId());
     filemap = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE,
-				0, AGENT_MAX_MSGLEN, mapname);
+				0, maplen, mapname);
     if (!filemap)
 	return 1;		       /* *out == NULL, so failure */
     p = MapViewOfFile(filemap, FILE_MAP_WRITE, 0, 0, 0);
Index: ssh.h
===================================================================
RCS file: /home/cvs/putty/ssh.h,v
retrieving revision 1.76
diff -u -r1.76 ssh.h
--- ssh.h	1 Aug 2004 12:07:11 -0000	1.76
+++ ssh.h	2 Aug 2004 10:33:29 -0000
@@ -452,6 +452,11 @@
 #define SSH2_AGENTC_REMOVE_IDENTITY             18
 #define SSH2_AGENTC_REMOVE_ALL_IDENTITIES       19
 
+/* matt's filexfer-over-agent */
+#define SSH_AGENTC_XFER_REQUEST 90
+#define SSH_AGENTC_XFER_DONE 91
+#define SSH_AGENTC_XFER_DATA 92
+
 /*
  * Need this to warn about support for the original SSH2 keyfile
  * format.
