Martin Prikryl 14 years ago
parent
commit
ad531c27a2

+ 1 - 1
Console.rc

@@ -16,7 +16,7 @@ FILETYPE 0x1
             VALUE "LegalTrademarks", "\0"
             VALUE "OriginalFilename", "winscp.com\0"
             VALUE "ProductName", "WinSCP\0"
-            VALUE "ProductVersion", "4.3.3.0\0"
+            VALUE "ProductVersion", "4.3.4.0\0"
             VALUE "ReleaseType", "stable\0"
             VALUE "WWW", "http://winscp.net/\0"
         }

+ 1 - 1
DragExt.rc

@@ -16,7 +16,7 @@ FILETYPE 0x2
             VALUE "LegalTrademarks", "\0"
             VALUE "OriginalFilename", "dragext.dll\0"
             VALUE "ProductName", "WinSCP\0"
-            VALUE "ProductVersion", "4.3.3.0\0"
+            VALUE "ProductVersion", "4.3.4.0\0"
             VALUE "ReleaseType", "stable\0"
             VALUE "WWW", "http://winscp.net/\0"
         }

+ 1 - 1
DragExt64.rc

@@ -16,7 +16,7 @@ FILETYPE 0x2
             VALUE "LegalTrademarks", "\0"
             VALUE "OriginalFilename", "dragext64.dll\0"
             VALUE "ProductName", "WinSCP\0"
-            VALUE "ProductVersion", "4.3.3.0\0"
+            VALUE "ProductVersion", "4.3.4.0\0"
             VALUE "ReleaseType", "stable\0"
             VALUE "WWW", "http://winscp.net/\0"
         }

+ 1 - 1
Putty.bpr

@@ -28,7 +28,7 @@
     <PATHRC value=".;"/>
     <PATHASM value=".;"/>
     <LINKER value="TLib"/>
-    <USERDEFINES value="SECURITY_WIN32;NO_SECURITY;NET_SETUP_DIAGNOSTICS;MPEXT;_WINDOWS"/>
+    <USERDEFINES value="SECURITY_WIN32;NET_SETUP_DIAGNOSTICS;MPEXT;_WINDOWS"/>
     <SYSDEFINES value="_RTLDLL;NO_STRICT"/>
     <MAINSOURCE value="Putty.bpf"/>
     <INCLUDEPATH value="putty;putty\CHARSET;putty\WINDOWS;$(BCB)\include;$(BCB)\include\vcl"/>

+ 4 - 4
WinSCP.rc

@@ -1,6 +1,6 @@
 1 VERSIONINFO
-FILEVERSION 4,3,3,1340
-PRODUCTVERSION 4,3,3,1340
+FILEVERSION 4,3,4,1428
+PRODUCTVERSION 4,3,4,1428
 FILEOS 0x4
 FILETYPE 0x1
 {
@@ -10,13 +10,13 @@ FILETYPE 0x1
         {
             VALUE "CompanyName", "Martin Prikryl\0"
             VALUE "FileDescription", "WinSCP: SFTP, FTP and SCP client\0"
-            VALUE "FileVersion", "4.3.3.1340\0"
+            VALUE "FileVersion", "4.3.4.1428\0"
             VALUE "InternalName", "winscp\0"
             VALUE "LegalCopyright", "(c) 2000-2011 Martin Prikryl\0"
             VALUE "LegalTrademarks", "\0"
             VALUE "OriginalFilename", "winscp.exe\0"
             VALUE "ProductName", "WinSCP\0"
-            VALUE "ProductVersion", "4.3.3.0\0"
+            VALUE "ProductVersion", "4.3.4.0\0"
             VALUE "ReleaseType", "stable\0"
             VALUE "WWW", "http://winscp.net/\0"
         }

+ 44 - 0
core/Common.cpp

@@ -412,6 +412,50 @@ AnsiString __fastcall ExpandFileNameCommand(const AnsiString Command,
     AddPathQuotes(FileName));
 }
 //---------------------------------------------------------------------------
+AnsiString __fastcall EscapePuttyCommandParam(AnsiString Param)
+{
+  bool Space = false;
+
+  for (int i = 1; i <= Param.Length(); i++)
+  {
+    switch (Param[i])
+    {
+      case '"':
+        Param.Insert("\\", i);
+        i++;
+        break;
+
+      case ' ':
+        Space = true;
+        break;
+
+      case '\\':
+        int i2 = i;
+        while ((i2 <= Param.Length()) && (Param[i2] == '\\'))
+        {
+          i2++;
+        }
+        if ((i2 <= Param.Length()) && (Param[i2] == '"'))
+        {
+          while (Param[i] == '\\')
+          {
+            Param.Insert("\\", i);
+            i += 2;
+          }
+          i--;
+        }
+        break;
+    }
+  }
+
+  if (Space)
+  {
+    Param = "\"" + Param + '"';
+  }
+
+  return Param;
+}
+//---------------------------------------------------------------------------
 AnsiString __fastcall ExpandEnvironmentVariables(const AnsiString & Str)
 {
   AnsiString Buf;

+ 1 - 0
core/Common.h

@@ -49,6 +49,7 @@ AnsiString __fastcall FormatCommand(AnsiString Program, AnsiString Params);
 AnsiString __fastcall ExpandFileNameCommand(const AnsiString Command,
   const AnsiString FileName);
 void __fastcall ReformatFileNameCommand(AnsiString & Command);
+AnsiString __fastcall EscapePuttyCommandParam(AnsiString Param);
 AnsiString __fastcall ExpandEnvironmentVariables(const AnsiString & Str);
 bool __fastcall ComparePaths(const AnsiString & Path1, const AnsiString & Path2);
 bool __fastcall CompareFileName(const AnsiString & Path1, const AnsiString & Path2);

+ 25 - 3
core/FtpFileSystem.cpp

@@ -1763,6 +1763,7 @@ void __fastcall TFTPFileSystem::DoReadDirectory(TRemoteFileList * FileList)
 //---------------------------------------------------------------------------
 void __fastcall TFTPFileSystem::ReadDirectory(TRemoteFileList * FileList)
 {
+  bool GotNoFilesForAll = false;
   bool Repeat;
 
   do
@@ -1773,11 +1774,32 @@ void __fastcall TFTPFileSystem::ReadDirectory(TRemoteFileList * FileList)
       FDoListAll = (FListAll == asAuto) || (FListAll == asOn);
       DoReadDirectory(FileList);
 
-      if (FListAll == asAuto)
+      // We got no files with "-a", but again no files w/o "-a",
+      // so it was not "-a"'s problem, revert to auto and let it decide the next time
+      if (GotNoFilesForAll && (FileList->Count == 0))
       {
-        // reading first directory has succeeded, always use "-a"
-        FListAll = asOn;
+        assert(FListAll == asOff);
+        FListAll = asAuto;
       }
+      else if (FListAll == asAuto)
+      {
+        // some servers take "-a" as a mask and return empty directory listing
+        // (note that it's actually never empty here, there's always at least parent directory,
+        // added explicitly by DoReadDirectory)
+        if ((FileList->Count == 0) ||
+            ((FileList->Count == 1) && FileList->Files[0]->IsParentDirectory))
+        {
+          Repeat = true;
+          FListAll = asOff;
+          GotNoFilesForAll = true;
+        }
+        else
+        {
+          // reading first directory has succeeded, always use "-a"
+          FListAll = asOn;
+        }
+      }
+
       // use "-a" even for implicit directory reading by FZAPI?
       // (e.g. before file transfer)
       FDoListAll = (FListAll == asOn);

+ 1 - 1
core/Queue.cpp

@@ -423,7 +423,7 @@ void __fastcall TTerminalQueue::DeleteItem(TQueueItem * Item)
       Index = 0;
       while (Empty && (Index < FItems->Count))
       {
-        Empty = (GetItem(Index) != INVALID_HANDLE_VALUE);
+        Empty = (GetItem(Index)->CompleteEvent != INVALID_HANDLE_VALUE);
         Index++;
       }
     }

+ 4 - 1
core/RemoteFiles.cpp

@@ -2059,7 +2059,10 @@ void __fastcall TRights::SetText(const AnsiString & value)
           KeepText = true;
         }
         FSet |= static_cast<unsigned short>(Flag);
-        FUnset |= static_cast<unsigned short>(ExtendedFlag);
+        if (i % 3 == 0)
+        {
+          FUnset |= static_cast<unsigned short>(ExtendedFlag);
+        }
       }
 
       Flag <<= 1;

+ 1 - 1
core/Terminal.h

@@ -201,7 +201,6 @@ private:
 
   void __fastcall CommandError(Exception * E, const AnsiString Msg);
   int __fastcall CommandError(Exception * E, const AnsiString Msg, int Answers);
-  AnsiString __fastcall PeekCurrentDirectory();
   AnsiString __fastcall GetCurrentDirectory();
   bool __fastcall GetExceptionOnFail() const;
   const TRemoteTokenList * __fastcall GetGroups();
@@ -436,6 +435,7 @@ public:
   TUsableCopyParamAttrs __fastcall UsableCopyParamAttrs(int Params);
   bool __fastcall QueryReopen(Exception * E, int Params,
     TFileOperationProgressType * OperationProgress);
+  AnsiString __fastcall PeekCurrentDirectory();
 
   const TSessionInfo & __fastcall GetSessionInfo();
   const TFileSystemInfo & __fastcall GetFileSystemInfo(bool Retrieve = false);

+ 1 - 1
filezilla/FtpListResult.cpp

@@ -766,7 +766,7 @@ void CFtpListResult::AddLine(t_directory::t_direntry &direntry)
 		_int64 nFt2 = nFt;
 		nFt += ((_int64)m_server.nTimeZoneOffset) * 10000000 * 60;
 		ft.dwHighDateTime = static_cast<unsigned long>(nFt >> 32);
-		ft.dwLowDateTime = static_cast<unsigned long>(nFt % 0xFFFFFFFF);
+		ft.dwLowDateTime = static_cast<unsigned long>(nFt & 0xFFFFFFFF);
 		FileTimeToSystemTime(&ft, &st);
 		direntry.date.year = st.wYear;
 		direntry.date.month = st.wMonth;

+ 5 - 1
filezilla/TransferSocket.cpp

@@ -581,7 +581,11 @@ int CTransferSocket::CheckForTimeout(int delay)
 {
 	UpdateStatusBar(false);
 	if (!m_bCheckTimeout)
-		return 1;
+	{
+		// we are closed, so make sure the FTP control socket is itself checking for
+		// timeout as we are not
+		return 0;
+	}
 	CTimeSpan span = CTime::GetCurrentTime()-m_LastActiveTime;
 	if (span.GetTotalSeconds()>=delay)
 	{

+ 1 - 0
forms/Console.cpp

@@ -44,6 +44,7 @@ __fastcall TConsoleDialog::TConsoleDialog(TComponent* AOwner)
   FAnyCommandExecuted = false;
   OutputMemo->Color = clBlack;
   OutputMemo->Font->Color = (TColor)0x00BBBBBB; //clGray;
+  FixComboBoxResizeBug(CommandEdit);
   UseSystemSettings(this);
   try
   {

+ 17 - 2
forms/CustomScpExplorer.cpp

@@ -3904,7 +3904,14 @@ void __fastcall TCustomScpExplorerForm::UpdateTerminal(TTerminal * Terminal)
 
   // cannot use RemoteDirView->Path, because it is empty if connection
   // was already closed
-  ManagedTerminal->RemoteDirectory = Terminal->CurrentDirectory;
+  // also only peek, we may not be connected at all atm,
+  // so make sure we do not try retrieving current directory from the server
+  // (particularly with FTP)
+  AnsiString ACurrentDirectory = Terminal->PeekCurrentDirectory();
+  if (!ACurrentDirectory.IsEmpty())
+  {
+    ManagedTerminal->RemoteDirectory = ACurrentDirectory;
+  }
   ManagedTerminal->Color = SessionColor;
 }
 //---------------------------------------------------------------------------
@@ -3914,7 +3921,15 @@ void __fastcall TCustomScpExplorerForm::UpdateSessionData(TSessionData * Data)
 
   // cannot use RemoteDirView->Path, because it is empty if connection
   // was already closed
-  Data->RemoteDirectory = Terminal->CurrentDirectory;
+  // also only peek, we may not be connected at all atm
+  // (well this can hardly be true here, as opposite to UpdateTerminal above),
+  // so make sure we do not try retrieving current directory from the server
+  // (particularly with FTP)
+  AnsiString ACurrentDirectory = Terminal->PeekCurrentDirectory();
+  if (!ACurrentDirectory.IsEmpty())
+  {
+    Data->RemoteDirectory = ACurrentDirectory;
+  }
   Data->Color = SessionColor;
 }
 //---------------------------------------------------------------------------

+ 2 - 0
forms/OpenDirectory.cpp

@@ -58,7 +58,9 @@ __fastcall TOpenDirectoryDialog::TOpenDirectoryDialog(TComponent * AOwner):
   FSessionScrollOnDragOver = new TListBoxScrollOnDragOver(SessionBookmarksList, true);
   FSharedScrollOnDragOver = new TListBoxScrollOnDragOver(SharedBookmarksList, true);
 
+  FixComboBoxResizeBug(LocalDirectoryEdit);
   InstallPathWordBreakProc(LocalDirectoryEdit);
+  FixComboBoxResizeBug(RemoteDirectoryEdit);
   InstallPathWordBreakProc(RemoteDirectoryEdit);
 }
 //---------------------------------------------------------------------

+ 5 - 1
packages/filemng/DirView.pas

@@ -2224,11 +2224,15 @@ begin
               ForceByName := (FileIconForName <> FullName);
             end;
             if (not ForceByName) and Assigned(PIDL) then
+            begin
               SHGetFileInfo(PChar(PIDL), FILE_ATTRIBUTE_NORMAL, FileInfo, SizeOf(FileInfo),
                 SHGFI_TYPENAME or SHGFI_USEFILEATTRIBUTES or SHGFI_SYSICONINDEX or SHGFI_PIDL)
-            else
+            end
+              else
+            begin
               SHGetFileInfo(PChar(FileIconForName), FILE_ATTRIBUTE_NORMAL, FileInfo, SizeOf(FileInfo),
                 SHGFI_TYPENAME or SHGFI_USEFILEATTRIBUTES or SHGFI_SYSICONINDEX);
+            end;
 
             TypeName := FileInfo.szTypeName;
             ImageIndex := FileInfo.iIcon;

+ 57 - 13
packages/filemng/DriveView.pas

@@ -480,6 +480,9 @@ procedure Register;
 
 implementation
 
+uses
+  CompThread;
+
 resourcestring
    SErrorInvalidDirName = 'New name contains invalid characters %s';
 
@@ -1152,11 +1155,51 @@ begin
       Result := Result + Drive;
 end; {GetValidDriveStr}
 
-procedure TDriveView.GetNodeShellAttr(ParentFolder: iShellFolder;
-  NodeData: TNodeData; Path: string; ContentMask: Boolean = True);
+type
+  TFolderAttributesGetterThread = class(TCompThread)
+  private
+    FParentFolder: iShellFolder;
+    FPIDL: PItemIDList;
+    FshAttr: PUINT;
+
+  protected
+    procedure Execute; override;
+
+  public
+    constructor Create(ParentFolder: iShellFolder; PIDL: PItemIDList; shAttr: PUINT);
+  end;
+
+constructor TFolderAttributesGetterThread.Create(ParentFolder: iShellFolder; PIDL: PItemIDList; shAttr: PUINT);
+begin
+  inherited Create(True);
+  FParentFolder := ParentFolder;
+  FPIDL := PIDL;
+  FshAttr := shAttr;
+end;
+
+procedure TFolderAttributesGetterThread.Execute;
 var
   NotResult: Boolean;
   ErrorMode: Word;
+begin
+  ErrorMode := SetErrorMode(SEM_FAILCRITICALERRORS or SEM_NOOPENFILEERRORBOX);
+  try
+    try
+      NotResult := not Succeeded(FParentFolder.GetAttributesOf(1, FPIDL, FshAttr^));
+    finally
+      SetErrorMode(ErrorMode);
+    end;
+    if NotResult then FshAttr^ := 0;
+  except
+    FshAttr^ := 0;
+  end;
+end;
+
+procedure TDriveView.GetNodeShellAttr(ParentFolder: iShellFolder;
+  NodeData: TNodeData; Path: string; ContentMask: Boolean = True);
+var
+  Thread: TFolderAttributesGetterThread;
+  shAttr: ULONG;
 begin
   if (not Assigned(ParentFolder)) or (not Assigned(NodeData)) then
     Exit;
@@ -1166,19 +1209,20 @@ begin
   if Assigned(NodeData.PIDL) then
   begin
     if ContentMask then
-      NodeData.shAttr := SFGAO_DISPLAYATTRMASK or SFGAO_CONTENTSMASK
+      shAttr := SFGAO_DISPLAYATTRMASK or SFGAO_CONTENTSMASK
     else
-      NodeData.shAttr := SFGAO_DISPLAYATTRMASK;
+      shAttr := SFGAO_DISPLAYATTRMASK;
 
-    ErrorMode := SetErrorMode(SEM_FAILCRITICALERRORS or SEM_NOOPENFILEERRORBOX);
-    try
-      try
-        NotResult := not Succeeded(ParentFolder.GetAttributesOf(1, NodeData.PIDL, NodeData.shAttr));
-      finally
-        SetErrorMode(ErrorMode);
-      end;
-      if NotResult then NodeData.shAttr := 0;
-    except
+    Thread := TFolderAttributesGetterThread.Create(ParentFolder, NodeData.PIDL, @shAttr);
+    Thread.FreeOnTerminate := True;
+    Thread.Resume;
+    if Thread.WaitFor(1000) then
+    begin
+      NodeData.shAttr := shAttr;
+    end
+      else
+    begin
+      NodeData.shAttr := 0;
     end;
 
     if not ContentMask then

+ 1 - 1
packages/my/CompThread.hpp

@@ -54,7 +54,7 @@ public:
 	void __fastcall Resume(void);
 	void __fastcall Suspend(void);
 	virtual void __fastcall Terminate(void);
-	unsigned __fastcall WaitFor(void);
+	bool __fastcall WaitFor(unsigned Milliseconds = (unsigned)(0xffffffff));
 	__property bool FreeOnTerminate = {read=FFreeOnTerminate, write=FFreeOnTerminate, nodefault};
 	__property unsigned Handle = {read=FHandle, nodefault};
 	__property Classes::TThreadPriority Priority = {read=GetPriority, write=SetPriority, nodefault};

+ 19 - 6
packages/my/CompThread.pas

@@ -39,7 +39,7 @@ type
     procedure Resume;
     procedure Suspend;
     procedure Terminate; virtual;
-    function WaitFor: LongWord;
+    function WaitFor(Milliseconds: Cardinal = INFINITE): Boolean;
     property FreeOnTerminate: Boolean read FFreeOnTerminate write FFreeOnTerminate;
     property Handle: THandle read FHandle;
     property Priority: TThreadPriority read GetPriority write SetPriority;
@@ -50,6 +50,9 @@ type
 
 implementation
 
+uses
+  SysUtils, DateUtils;
+
 const
   CM_EXECPROC = $8FFF;
   CM_DESTROYWINDOW = $8FFE;
@@ -329,17 +332,27 @@ begin
   FTerminated := True;
 end;
 
-function TCompThread.WaitFor: LongWord;
+function TCompThread.WaitFor(Milliseconds: Cardinal): Boolean;
 var
   Msg: TMsg;
   H: THandle;
+  Start: TDateTime;
+  R: DWORD;
 begin
   H := FHandle;
   if GetCurrentThreadID = MainThreadID then
-    while MsgWaitForMultipleObjects(1, H, False, INFINITE,
-      QS_SENDMESSAGE) = WAIT_OBJECT_0 + 1 do PeekMessage(Msg, 0, 0, 0, PM_NOREMOVE)
-  else WaitForSingleObject(H, INFINITE);
-  GetExitCodeThread(H, Result);
+  begin
+    Start := Now;
+    repeat
+      R := MsgWaitForMultipleObjects(1, H, False, Milliseconds, QS_SENDMESSAGE);
+      if R = WAIT_OBJECT_0 + 1 then PeekMessage(Msg, 0, 0, 0, PM_NOREMOVE)
+    until (R <> WAIT_OBJECT_0 + 1) or ((Milliseconds <> INFINITE) and (MilliSecondsBetween(Now, Start) >= Milliseconds));
+  end
+    else
+  begin
+    R := WaitForSingleObject(H, Milliseconds);
+  end;
+  Result := (R = WAIT_OBJECT_0);
 end;
 
 initialization

+ 4 - 3
packages/my/TcpIp.pas

@@ -761,6 +761,7 @@ procedure THttp.SendRequest(const Method, Version: string);
 begin
   SendCommand(Method + ' ' + FPath + ' HTTP/' + Version);
   SendCommand('Host: ' + FHostname);
+  SendCommand('Connection: close');
   if FSender <> '' then
     SendCommand('From: ' + FSender);
   if FReference <> '' then
@@ -881,7 +882,7 @@ end;
 procedure THttp.GetHead;
 begin
   Login;
-  SendRequest('HEAD', '1.0');
+  SendRequest('HEAD', '1.1');
   GetAnswer;
   Logout;
 end;
@@ -892,7 +893,7 @@ var
   ok, ok2: Integer;
 begin
   Login;
-  SendRequest('GET', '1.0');
+  SendRequest('GET', '1.1');
   GetAnswer;
   // read the data
   TMemoryStream(FStream).Clear;
@@ -937,7 +938,7 @@ begin
   FSocketNumber := StrToInt(Port);
 
   Login;
-  SendRequest('POST', '1.0');
+  SendRequest('POST', '1.1');
   // Send the data
   TMemoryStream(FStream).Seek(0, 0);
   ok := 1;

+ 1 - 1
putty/LOGGING.C

@@ -43,7 +43,7 @@ static void logwrite(struct LogContext *ctx, void *data, int len)
 	bufchain_add(&ctx->queue, data, len);
     } else if (ctx->state == L_OPEN) {
 	assert(ctx->lgfp);
-	if (fwrite(data, 1, len, ctx->lgfp) < len) {
+	if (fwrite(data, 1, len, ctx->lgfp) < (size_t)len) {
 	    logfclose(ctx);
 	    ctx->state = L_ERROR;
 	    /* Log state is L_ERROR so this won't cause a loop */

+ 36 - 28
putty/SSH.C

@@ -3753,7 +3753,9 @@ static int do_ssh1_login(Ssh ssh, unsigned char *in, int inlen,
 		sfree(s->response);
 		if (s->publickey_blob && !s->tried_publickey)
 		    logevent("Configured key file not in Pageant");
-	    }
+	    } else {
+                logevent("Failed to get reply from Pageant");
+            }
 	    if (s->authed)
 		break;
 	}
@@ -6634,25 +6636,44 @@ static struct ssh_channel *ssh2_channel_msg(Ssh ssh, struct Packet *pktin)
     return c;
 }
 
+static int ssh2_handle_winadj_response(struct ssh_channel *c)
+{
+    struct winadj *wa = c->v.v2.winadj_head;
+    if (!wa)
+	return FALSE;
+    c->v.v2.winadj_head = wa->next;
+    c->v.v2.remlocwin += wa->size;
+    sfree(wa);
+    /*
+     * winadj messages are only sent when the window is fully open, so
+     * if we get an ack of one, we know any pending unthrottle is
+     * complete.
+     */
+    if (c->v.v2.throttle_state == UNTHROTTLING)
+	c->v.v2.throttle_state = UNTHROTTLED;
+    return TRUE;
+}
+
 static void ssh2_msg_channel_success(Ssh ssh, struct Packet *pktin)
 {
     /*
      * This should never get called.  All channel requests are either
-     * sent with want_reply false or are sent before this handler gets
-     * installed.
+     * sent with want_reply false, are sent before this handler gets
+     * installed, or are "winadj@putty" requests, which servers should
+     * never respond to with success.
+     *
+     * However, at least one server ("boks_sshd") is known to return
+     * SUCCESS for channel requests it's never heard of, such as
+     * "winadj@putty". Raised with foxt.com as bug 090916-090424, but
+     * for the sake of a quiet life, we handle it just the same as the
+     * expected FAILURE.
      */
     struct ssh_channel *c;
-    struct winadj *wa;
 
     c = ssh2_channel_msg(ssh, pktin);
     if (!c)
 	return;
-    wa = c->v.v2.winadj_head;
-    if (wa)
-	ssh_disconnect(ssh, NULL, "Received SSH_MSG_CHANNEL_SUCCESS for "
-		       "\"[email protected]\"",
-		       SSH2_DISCONNECT_PROTOCOL_ERROR, FALSE);
-    else
+    if (!ssh2_handle_winadj_response(c))
 	ssh_disconnect(ssh, NULL,
 		       "Received unsolicited SSH_MSG_CHANNEL_SUCCESS",
 		       SSH2_DISCONNECT_PROTOCOL_ERROR, FALSE);
@@ -6667,28 +6688,14 @@ static void ssh2_msg_channel_failure(Ssh ssh, struct Packet *pktin)
      * installed.
      */
     struct ssh_channel *c;
-    struct winadj *wa;
 
     c = ssh2_channel_msg(ssh, pktin);
     if (!c)
 	return;
-    wa = c->v.v2.winadj_head;
-    if (!wa) {
+    if (!ssh2_handle_winadj_response(c))
 	ssh_disconnect(ssh, NULL,
 		       "Received unsolicited SSH_MSG_CHANNEL_FAILURE",
 		       SSH2_DISCONNECT_PROTOCOL_ERROR, FALSE);
-	return;
-    }
-    c->v.v2.winadj_head = wa->next;
-    c->v.v2.remlocwin += wa->size;
-    sfree(wa);
-    /*
-     * winadj messages are only sent when the window is fully open, so
-     * if we get an ack of one, we know any pending unthrottle is
-     * complete.
-     */
-    if (c->v.v2.throttle_state == UNTHROTTLING)
-	c->v.v2.throttle_state = UNTHROTTLED;
 }
 
 static void ssh2_msg_channel_window_adjust(Ssh ssh, struct Packet *pktin)
@@ -7509,6 +7516,8 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen,
 			s->nkeys = 0;
 		    }
 		}
+	    } else {
+                logevent("Failed to get reply from Pageant");
 	    }
 	}
 
@@ -9143,10 +9152,9 @@ static void ssh2_msg_debug(Ssh ssh, struct Packet *pktin)
     /* log the debug message */
     char *msg;
     int msglen;
-    int always_display;
 
-    /* XXX maybe we should actually take notice of this */
-    always_display = ssh2_pkt_getbool(pktin);
+    /* XXX maybe we should actually take notice of the return value */
+    ssh2_pkt_getbool(pktin);
     ssh_pkt_getstring(pktin, &msg, &msglen);
 
     logeventf(ssh, "Remote debug message: %.*s", msglen, msg);

+ 5 - 5
putty/SSHBN.C

@@ -431,7 +431,7 @@ static void internal_mul(const BignumInt *a, const BignumInt *b,
             for (cp = cps, bp = b + len; cp--, bp-- > b ;) {
                 t = (MUL_WORD(*ap, *bp) + carry) + *cp;
                 *cp = (BignumInt) t;
-                carry = t >> BIGNUM_INT_BITS;
+                carry = (BignumInt)(t >> BIGNUM_INT_BITS);
             }
             *cp = carry;
         }
@@ -533,7 +533,7 @@ static void internal_mul_low(const BignumInt *a, const BignumInt *b,
             for (cp = cps, bp = b + len; bp--, cp-- > c ;) {
                 t = (MUL_WORD(*ap, *bp) + carry) + *cp;
                 *cp = (BignumInt) t;
-                carry = t >> BIGNUM_INT_BITS;
+                carry = (BignumInt)(t >> BIGNUM_INT_BITS);
             }
         }
     }
@@ -909,7 +909,7 @@ Bignum modpow(Bignum base_in, Bignum exp, Bignum mod)
 
     mninv = snewn(len, BignumInt);
     for (j = 0; j < len; j++)
-	mninv[len - 1 - j] = (j < inv[0] ? inv[j + 1] : 0);
+	mninv[len - 1 - j] = (j < (int)inv[0] ? inv[j + 1] : 0);
     freebn(inv);         /* we don't need this copy of it any more */
     /* Now negate mninv mod r, so it's the inverse of -n rather than +n. */
     x = snewn(len, BignumInt);
@@ -919,13 +919,13 @@ Bignum modpow(Bignum base_in, Bignum exp, Bignum mod)
 
     /* x = snewn(len, BignumInt); */ /* already done above */
     for (j = 0; j < len; j++)
-	x[len - 1 - j] = (j < base[0] ? base[j + 1] : 0);
+	x[len - 1 - j] = (j < (int)base[0] ? base[j + 1] : 0);
     freebn(base);        /* we don't need this copy of it any more */
 
     a = snewn(2*len, BignumInt);
     b = snewn(2*len, BignumInt);
     for (j = 0; j < len; j++)
-	a[2*len - 1 - j] = (j < rn[0] ? rn[j + 1] : 0);
+	a[2*len - 1 - j] = (j < (int)rn[0] ? rn[j + 1] : 0);
     freebn(rn);
 
     /* Scratch space for multiplies */

+ 43 - 3
putty/putty.h

@@ -353,12 +353,52 @@ enum {
  * Defined here so that backends can export their GSS library tables
  * to the cross-platform settings code.
  */
-struct keyval { char *s; int v; };
+struct keyvalwhere {
+    /*
+     * Two fields which define a string and enum value to be
+     * equivalent to each other.
+     */
+    char *s;
+    int v;
+
+    /*
+     * The next pair of fields are used by gprefs() in settings.c to
+     * arrange that when it reads a list of strings representing a
+     * preference list and translates it into the corresponding list
+     * of integers, strings not appearing in the list are entered in a
+     * configurable position rather than uniformly at the end.
+     */
+
+    /*
+     * 'vrel' indicates which other value in the list to place this
+     * element relative to. It should be a value that has occurred in
+     * a 'v' field of some other element of the array, or -1 to
+     * indicate that we simply place relative to one or other end of
+     * the list.
+     *
+     * gprefs will try to process the elements in an order which makes
+     * this field work (i.e. so that the element referenced has been
+     * added before processing this one).
+     */
+    int vrel;
+
+    /*
+     * 'where' indicates whether to place the new value before or
+     * after the one referred to by vrel. -1 means before; +1 means
+     * after.
+     *
+     * When vrel is -1, this also implicitly indicates which end of
+     * the array to use. So vrel=-1, where=-1 means to place _before_
+     * some end of the list (hence, at the last element); vrel=-1,
+     * where=+1 means to place _after_ an end (hence, at the first).
+     */
+    int where;
+};
 
 #ifndef NO_GSSAPI
 extern const int ngsslibs;
-extern const char *const gsslibnames[];/* for displaying in configuration */
-extern const struct keyval gsslibkeywords[];   /* for storing by settings.c */
+extern const char *const gsslibnames[]; /* for displaying in configuration */
+extern const struct keyvalwhere gsslibkeywords[]; /* for settings.c */
 #endif
 
 extern const char *const ttymodes[];

+ 4 - 4
putty/windows/WINGSS.C

@@ -18,10 +18,10 @@ const char *const gsslibnames[3] = {
     "Microsoft SSPI SECUR32.DLL",
     "User-specified GSSAPI DLL",
 };
-const struct keyval gsslibkeywords[] = {
-    { "gssapi32", 0 },
-    { "sspi", 1 },
-    { "custom", 2 },
+const struct keyvalwhere gsslibkeywords[] = {
+    { "gssapi32", 0, -1, -1 },
+    { "sspi", 1, -1, -1 },
+    { "custom", 2, -1, -1 },
 };
 
 DECL_WINDOWS_FUNCTION(static, SECURITY_STATUS,

+ 8 - 1
putty/windows/WINNET.C

@@ -1005,6 +1005,10 @@ static DWORD try_connect(Actual_Socket sock)
 	 * asynchronously.
 	 */
 	if ( err != WSAEWOULDBLOCK ) {
+#ifdef MPEXT
+    // unselect on error
+    do_select(sock->plug, s, 0);
+#endif
 	    sock->error = winsock_error_string(err);
 	    goto ret;
 	}
@@ -1089,6 +1093,9 @@ Socket sk_new(SockAddr addr, int port, int privport, int oobinline,
 
     err = 0;
     do {
+#ifdef MPEXT
+        ret->error = NULL;
+#endif
         err = try_connect(ret);
     } while (err && sk_nextaddr(ret->addr, &ret->step));
 
@@ -1756,7 +1763,7 @@ char *get_hostname(void)
 	    hostname = NULL;
 	    break;
 	}
-    } while (strlen(hostname) >= len-1);
+    } while (strlen(hostname) >= (size_t)(len-1));
     return hostname;
 }
 

+ 61 - 23
putty/windows/WINPGNTC.C

@@ -86,15 +86,70 @@ DECL_WINDOWS_FUNCTION(static, BOOL, InitializeSecurityDescriptor,
 		      (PSECURITY_DESCRIPTOR, DWORD));
 DECL_WINDOWS_FUNCTION(static, BOOL, SetSecurityDescriptorOwner,
 		      (PSECURITY_DESCRIPTOR, PSID, BOOL));
-static int init_advapi(void)
+DECL_WINDOWS_FUNCTION(, DWORD, GetSecurityInfo,
+		      (HANDLE, SE_OBJECT_TYPE, SECURITY_INFORMATION,
+		       PSID *, PSID *, PACL *, PACL *,
+		       PSECURITY_DESCRIPTOR *));
+int init_advapi(void)
 {
     advapi = load_system32_dll("advapi32.dll");
     return advapi &&
+	GET_WINDOWS_FUNCTION(advapi, GetSecurityInfo) &&
         GET_WINDOWS_FUNCTION(advapi, OpenProcessToken) &&
 	GET_WINDOWS_FUNCTION(advapi, GetTokenInformation) &&
 	GET_WINDOWS_FUNCTION(advapi, InitializeSecurityDescriptor) &&
 	GET_WINDOWS_FUNCTION(advapi, SetSecurityDescriptorOwner);
 }
+
+PSID get_user_sid(void)
+{
+    HANDLE proc = NULL, tok = NULL;
+    TOKEN_USER *user = NULL;
+    DWORD toklen, sidlen;
+    PSID sid = NULL, ret = NULL;
+
+    if ((proc = OpenProcess(MAXIMUM_ALLOWED, FALSE,
+                            GetCurrentProcessId())) == NULL)
+        goto cleanup;
+
+    if (!p_OpenProcessToken(proc, TOKEN_QUERY, &tok))
+        goto cleanup;
+
+    if (!p_GetTokenInformation(tok, TokenUser, NULL, 0, &toklen) &&
+        GetLastError() != ERROR_INSUFFICIENT_BUFFER)
+        goto cleanup;
+
+    if ((user = (TOKEN_USER *)LocalAlloc(LPTR, toklen)) == NULL)
+        goto cleanup;
+
+    if (!p_GetTokenInformation(tok, TokenUser, user, toklen, &toklen))
+        goto cleanup;
+
+    sidlen = GetLengthSid(user->User.Sid);
+
+    sid = (PSID)smalloc(sidlen);
+
+    if (!CopySid(sidlen, sid, user->User.Sid))
+        goto cleanup;
+
+    /* Success. Move sid into the return value slot, and null it out
+     * to stop the cleanup code freeing it. */
+    ret = sid;
+    sid = NULL;
+
+  cleanup:
+    if (proc != NULL)
+        CloseHandle(proc);
+    if (tok != NULL)
+        CloseHandle(tok);
+    if (user != NULL)
+        LocalFree(user);
+    if (sid != NULL)
+        sfree(sid);
+
+    return ret;
+}
+
 #endif
 
 int agent_query(void *in, int inlen, void **out, int *outlen,
@@ -108,8 +163,7 @@ int agent_query(void *in, int inlen, void **out, int *outlen,
     COPYDATASTRUCT cds;
     SECURITY_ATTRIBUTES sa, *psa;
     PSECURITY_DESCRIPTOR psd = NULL;
-    HANDLE proc, tok;
-    TOKEN_USER *user = NULL;
+    PSID usersid = NULL;
 
     *out = NULL;
     *outlen = 0;
@@ -134,31 +188,16 @@ int agent_query(void *in, int inlen, void **out, int *outlen,
          * run PSFTPs which refer back to the owning user's
          * unprivileged Pageant.
          */
-
-        if ((proc = OpenProcess(MAXIMUM_ALLOWED, FALSE,
-                                GetCurrentProcessId())) != NULL) {
-            if (p_OpenProcessToken(proc, TOKEN_QUERY, &tok)) {
-                DWORD retlen;
-                p_GetTokenInformation(tok, TokenUser, NULL, 0, &retlen);
-                user = (TOKEN_USER *)LocalAlloc(LPTR, retlen);
-                if (!p_GetTokenInformation(tok, TokenUser,
-                                           user, retlen, &retlen)) {
-                    LocalFree(user);
-                    user = NULL;
-                }
-                CloseHandle(tok);
-            }
-            CloseHandle(proc);
-        }
+        usersid = get_user_sid();
 
         psa = NULL;
-        if (user) {
+        if (usersid) {
             psd = (PSECURITY_DESCRIPTOR)
                 LocalAlloc(LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH);
             if (psd) {
                 if (p_InitializeSecurityDescriptor
                     (psd, SECURITY_DESCRIPTOR_REVISION) &&
-                    p_SetSecurityDescriptorOwner(psd, user->User.Sid, FALSE)) {
+                    p_SetSecurityDescriptorOwner(psd, usersid, FALSE)) {
                     sa.nLength = sizeof(sa);
                     sa.bInheritHandle = TRUE;
                     sa.lpSecurityDescriptor = psd;
@@ -225,8 +264,7 @@ int agent_query(void *in, int inlen, void **out, int *outlen,
     CloseHandle(filemap);
     if (psd)
         LocalFree(psd);
-    if (user)
-        LocalFree(user);
+    sfree(usersid);
 #ifdef MPEXT
     // fix memory leak
     sfree(mapname);

+ 9 - 1
putty/windows/WINSTUFF.H

@@ -503,7 +503,7 @@ int handle_backlog(struct handle *h);
 void *handle_get_privdata(struct handle *h);
 
 /*
- * pageantc.c needs to schedule callbacks for asynchronous agent
+ * winpgntc.c needs to schedule callbacks for asynchronous agent
  * requests. This has to be done differently in GUI and console, so
  * there's an exported function used for the purpose.
  * 
@@ -514,6 +514,14 @@ void agent_schedule_callback(void (*callback)(void *, void *, int),
 			     void *callback_ctx, void *data, int len);
 #define FLAG_SYNCAGENT 0x1000
 
+/*
+ * winpgntc.c also exports these two functions which are used by the
+ * server side of Pageant as well, to get the user SID for comparing
+ * with clients'.
+ */
+int init_advapi(void);  /* initialises everything needed by get_user_sid */
+PSID get_user_sid(void);
+
 /*
  * Exports from winser.c.
  */

+ 1 - 1
resource/TextsCore1.rc

@@ -336,7 +336,7 @@ BEGIN
 
   CORE_VARIABLE_STRINGS, "CORE_VARIABLE"
   PUTTY_BASED_ON, "SSH and SCP code based on PuTTY %s"
-  PUTTY_VERSION, "0.60"
+  PUTTY_VERSION, "0.61"
   PUTTY_COPYRIGHT, "Copyright © 1997-2011 Simon Tatham"
   PUTTY_URL, "http://www.chiark.greenend.org.uk/~sgtatham/putty/"
   FILEZILLA_BASED_ON, "FTP code based on FileZilla %s"

+ 2 - 2
windows/GUITools.cpp

@@ -117,9 +117,9 @@ void __fastcall OpenSessionInPutty(const AnsiString PuttyPath,
     }
     if (!Password.IsEmpty())
     {
-      Params += FORMAT("-pw \"%s\" ", (Password));
+      Params += FORMAT("-pw %s ", (EscapePuttyCommandParam(Password)));
     }
-    Params += FORMAT("-load \"%s\"", (SessionName));
+    Params += FORMAT("-load %s", (EscapePuttyCommandParam(SessionName)));
 
     if (!ExecuteShell(Program, Params))
     {

+ 2 - 2
windows/VCLCommon.cpp

@@ -934,7 +934,6 @@ HWND __fastcall GetCorrectFormParent()
   if ((Application->MainForm != NULL) &&
       (Application->MainForm != Screen->ActiveForm))
   {
-    AnsiString C = Screen->ActiveForm->Caption;
     if (Screen->ActiveForm != NULL)
     {
       // the case when we are invoking dialog from (e.g. prefences) dialog
@@ -1284,6 +1283,7 @@ void __fastcall HintLabelRestore(TStaticText * StaticText)
 //---------------------------------------------------------------------------
 static void __fastcall ComboBoxFixWindowProc(void * Data, TMessage & Message)
 {
+  // it is TCustomComboxBox, but the properties are published only by TComboBox
   TComboBox * ComboBox = static_cast<TComboBox *>(Data);
   if (Message.Msg == WM_SIZE)
   {
@@ -1311,7 +1311,7 @@ static void __fastcall ComboBoxFixWindowProc(void * Data, TMessage & Message)
   }
 }
 //---------------------------------------------------------------------------
-void __fastcall FixComboBoxResizeBug(TComboBox * ComboBox)
+void __fastcall FixComboBoxResizeBug(TCustomComboBox * ComboBox)
 {
   TWndMethod WindowProc;
   ((TMethod*)&WindowProc)->Data = ComboBox;

+ 1 - 1
windows/VCLCommon.h

@@ -22,7 +22,7 @@ void __fastcall LinkLabel(TStaticText * StaticText, AnsiString Url = "",
   TNotifyEvent OnEnter = NULL);
 void __fastcall HintLabel(TStaticText * StaticText, AnsiString Hint = "");
 void __fastcall HintLabelRestore(TStaticText * StaticText);
-void __fastcall FixComboBoxResizeBug(TComboBox * ComboBox);
+void __fastcall FixComboBoxResizeBug(TCustomComboBox * ComboBox);
 void __fastcall ShowAsModal(TForm * Form, void *& Storage);
 void __fastcall HideAsModal(TForm * Form, void *& Storage);
 void __fastcall ReleaseAsModal(TForm * Form, void *& Storage);