~ubuntu-branches/debian/sid/filezilla/sid

« back to all changes in this revision

Viewing changes to src/engine/ControlSocket.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Adam Cécile (Le_Vert)
  • Date: 2008-07-05 21:00:24 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20080705210024-mvzp21zlyheschi6
Tags: 3.0.11.1-1
* wxWidgets 2.8 just entered unstable ! Upload to unstable.
* New upstream release.
* Bump Standards-Version to 3.8.0.

Show diffs side-by-side

added added

removed removed

Lines of Context:
4
4
#include <idna.h>
5
5
#include "asynchostresolver.h"
6
6
#include "directorycache.h"
 
7
#include "servercapabilities.h"
7
8
 
8
9
DECLARE_EVENT_TYPE(fzOBTAINLOCK, -1)
9
10
DEFINE_EVENT_TYPE(fzOBTAINLOCK)
15
16
std::list<CControlSocket::t_lockInfo> CControlSocket::m_lockInfoList;
16
17
 
17
18
BEGIN_EVENT_TABLE(CControlSocket, wxEvtHandler)
18
 
        EVT_SOCKET(wxID_ANY, CControlSocket::OnSocketEvent)
19
19
        EVT_TIMER(wxID_ANY, CControlSocket::OnTimer)
20
20
        EVT_COMMAND(wxID_ANY, fzOBTAINLOCK, CControlSocket::OnObtainLock)
21
21
END_EVENT_TABLE();
28
28
        pNextOpData = 0;
29
29
 
30
30
        waitForAsyncRequest = false;
 
31
 
 
32
        holdsLock = false;
31
33
}
32
34
 
33
35
COpData::~COpData()
36
38
}
37
39
 
38
40
CControlSocket::CControlSocket(CFileZillaEnginePrivate *pEngine)
39
 
        : wxSocketClient(wxSOCKET_NOWAIT), CLogging(pEngine)
 
41
        : CLogging(pEngine)
40
42
{
41
 
        m_socketId = 0;
42
43
        m_pEngine = pEngine;
43
44
        m_pCurOpData = 0;
44
 
        m_pSendBuffer = 0;
45
 
        m_nSendBufferLen = 0;
46
45
        m_pCurrentServer = 0;
47
46
        m_pTransferStatus = 0;
48
47
        m_transferStatusSendState = 0;
49
 
        m_onConnectCalled = false;
50
 
 
51
 
        SetEvtHandlerEnabled(true);
52
 
        SetEventHandler(*this, m_socketId);
53
 
        SetNotify(wxSOCKET_INPUT_FLAG | wxSOCKET_OUTPUT_FLAG | wxSOCKET_CONNECTION_FLAG | wxSOCKET_LOST_FLAG);
54
 
        Notify(true);
55
48
 
56
49
        m_pCSConv = 0;
57
50
        m_useUTF8 = false;
58
51
 
59
52
        m_timer.SetOwner(this);
 
53
 
 
54
        m_closed = false;
 
55
 
 
56
        m_invalidateCurrentPath = false;
60
57
}
61
58
 
62
59
CControlSocket::~CControlSocket()
63
60
{
 
61
        DoClose();
 
62
 
64
63
        delete m_pCSConv;
65
 
 
66
 
        DoClose();
67
 
}
68
 
 
69
 
void CControlSocket::OnConnect(wxSocketEvent &event)
70
 
{
71
 
}
72
 
 
73
 
void CControlSocket::OnReceive(wxSocketEvent &event)
74
 
{
75
 
}
76
 
 
77
 
void CControlSocket::OnSend(wxSocketEvent &event)
78
 
{
79
 
        if (m_pSendBuffer)
80
 
        {
81
 
                if (!m_nSendBufferLen)
82
 
                {
83
 
                        delete [] m_pSendBuffer;
84
 
                        m_pSendBuffer = 0;
85
 
                        return;
86
 
                }
87
 
 
88
 
                Write(m_pSendBuffer, m_nSendBufferLen);
89
 
                if (Error())
90
 
                {
91
 
                        if (LastError() != wxSOCKET_WOULDBLOCK)
92
 
                                DoClose();
93
 
                        return;
94
 
                }
95
 
 
96
 
                int numsent = LastCount();
97
 
 
98
 
                if (numsent)
99
 
                {
100
 
                        SetAlive();
101
 
                        m_pEngine->SetActive(false);
102
 
                }
103
 
 
104
 
                if (numsent == m_nSendBufferLen)
105
 
                {
106
 
                        m_nSendBufferLen = 0;
107
 
                        delete [] m_pSendBuffer;
108
 
                        m_pSendBuffer = 0;
109
 
                }
110
 
                else
111
 
                {
112
 
                        memmove(m_pSendBuffer, m_pSendBuffer + numsent, m_nSendBufferLen - numsent);
113
 
                        m_nSendBufferLen -= numsent;
114
 
                }
115
 
        }
116
 
}
117
 
 
118
 
void CControlSocket::OnClose(wxSocketEvent &event)
119
 
{
120
 
        LogMessage(Debug_Verbose, _T("CControlSocket::OnClose()"));
121
 
 
122
 
        if (GetCurrentCommandId() != cmd_connect)
123
 
                LogMessage(::Error, _("Disconnected from server"));
124
 
        DoClose();
125
 
}
126
 
 
127
 
int CControlSocket::Connect(const CServer &server)
128
 
{
129
 
        SetWait(true);
130
 
 
131
 
        if (server.GetEncodingType() == ENCODING_CUSTOM)
132
 
                m_pCSConv = new wxCSConv(server.GetCustomEncoding());
133
 
 
134
 
        if (m_pCurrentServer)
135
 
                delete m_pCurrentServer;
136
 
        m_pCurrentServer = new CServer(server);
137
 
 
138
 
        const wxString & host = server.GetHost();
139
 
        if (!IsIpAddress(host))
140
 
        {
141
 
                LogMessage(Status, _("Resolving IP-Address for %s"), host.c_str());
142
 
                CAsyncHostResolver *resolver = new CAsyncHostResolver(m_pEngine, ConvertDomainName(host));
143
 
                m_pEngine->AddNewAsyncHostResolver(resolver);
144
 
 
145
 
                resolver->Create();
146
 
                resolver->Run();
147
 
        }
148
 
        else
149
 
        {
150
 
                wxIPV4address addr;
151
 
                addr.Hostname(host);
152
 
                return ContinueConnect(&addr);
153
 
        }
154
 
 
155
 
        return FZ_REPLY_WOULDBLOCK;
156
 
}
157
 
 
158
 
int CControlSocket::ContinueConnect(const wxIPV4address *address)
159
 
{
160
 
        LogMessage(__TFILE__, __LINE__, this, Debug_Verbose, _T("CControlSocket::ContinueConnect(%p) m_pEngine=%p"), address, m_pEngine);
161
 
        if (GetCurrentCommandId() != cmd_connect ||
162
 
                !m_pCurrentServer)
163
 
        {
164
 
                LogMessage(Debug_Warning, _T("Invalid context for call to ContinueConnect(), cmd=%d, m_pCurrentServer=%p"), GetCurrentCommandId(), m_pCurrentServer);
165
 
                return DoClose(FZ_REPLY_INTERNALERROR);
166
 
        }
167
 
        
168
 
        if (!address)
169
 
        {
170
 
                LogMessage(::Error, _("Invalid hostname or host not found"));
171
 
                return ResetOperation(FZ_REPLY_ERROR | FZ_REPLY_CRITICALERROR);
172
 
        }
173
 
 
174
 
        const unsigned int port = m_pCurrentServer->GetPort();
175
 
        LogMessage(Status, _("Connecting to %s:%d..."), address->IPAddress().c_str(), port);
176
 
 
177
 
        wxIPV4address addr = *address;
178
 
        addr.Service(port);
179
 
 
180
 
        bool res = wxSocketClient::Connect(addr, false);
181
 
 
182
 
        if (!res && LastError() != wxSOCKET_WOULDBLOCK)
183
 
                return ResetOperation(FZ_REPLY_ERROR);
184
 
 
185
 
        return FZ_REPLY_WOULDBLOCK;
 
64
        m_pCSConv = 0;
186
65
}
187
66
 
188
67
int CControlSocket::Disconnect()
193
72
        return FZ_REPLY_OK;
194
73
}
195
74
 
196
 
void CControlSocket::OnSocketEvent(wxSocketEvent &event)
197
 
{
198
 
        if (event.GetId() != m_socketId)
199
 
                return;
200
 
 
201
 
        switch (event.GetSocketEvent())
202
 
        {
203
 
        case wxSOCKET_CONNECTION:
204
 
                m_onConnectCalled = true;
205
 
                OnConnect(event);
206
 
                break;
207
 
        case wxSOCKET_INPUT:
208
 
                if (!m_onConnectCalled)
209
 
                {
210
 
                        m_onConnectCalled = true;
211
 
                        OnConnect(event);
212
 
                }
213
 
                OnReceive(event);
214
 
                break;
215
 
        case wxSOCKET_OUTPUT:
216
 
                OnSend(event);
217
 
                break;
218
 
        case wxSOCKET_LOST:
219
 
                OnClose(event);
220
 
                break;
221
 
        }
222
 
}
223
 
 
224
75
enum Command CControlSocket::GetCurrentCommandId() const
225
76
{
226
77
        if (m_pCurOpData)
238
89
                LogMessage(::Debug_Warning, _T("ResetOperation with FZ_REPLY_WOULDBLOCK in nErrorCode (%d)"), nErrorCode);
239
90
        }
240
91
 
241
 
        if (m_pCurOpData && m_pCurOpData->opId != cmd_rawtransfer)
242
 
        {
 
92
        if (m_pCurOpData && m_pCurOpData->holdsLock)
243
93
                UnlockCache();
244
 
        }
245
94
 
246
 
        if (m_pCurOpData && m_pCurOpData->pNextOpData && (nErrorCode & FZ_REPLY_INTERNALERROR) != FZ_REPLY_INTERNALERROR)
 
95
        if (m_pCurOpData && m_pCurOpData->pNextOpData)
247
96
        {
248
97
                COpData *pNext = m_pCurOpData->pNextOpData;
249
98
                m_pCurOpData->pNextOpData = 0;
250
99
                delete m_pCurOpData;
251
100
                m_pCurOpData = pNext;
252
 
                return SendNextCommand(nErrorCode);
253
 
        }
254
 
        
255
 
        if (m_pCurOpData)
256
 
        {
257
 
                if (m_pCurOpData->opId == cmd_transfer)
 
101
                if (nErrorCode == FZ_REPLY_OK ||
 
102
                        nErrorCode == FZ_REPLY_ERROR ||
 
103
                        nErrorCode == FZ_REPLY_CRITICALERROR)
258
104
                {
259
 
                        CFileTransferOpData *pData = static_cast<CFileTransferOpData *>(m_pCurOpData);
260
 
                        if (!pData->download && pData->transferInitiated)
261
 
                        {
262
 
                                CDirectoryCache cache;
263
 
                                cache.InvalidateFile(*m_pCurrentServer, pData->remotePath, pData->remoteFile, true, CDirectoryCache::file, (nErrorCode == FZ_REPLY_OK) ? pData->localFileSize : -1);
264
 
 
265
 
                                m_pEngine->SendDirectoryListingNotification(pData->remotePath, false, true, false);
266
 
                        }
 
105
                        return ParseSubcommandResult(nErrorCode);
267
106
                }
268
 
 
269
 
                delete m_pCurOpData;
270
 
                m_pCurOpData = 0;
 
107
                else
 
108
                        return ResetOperation(nErrorCode);
271
109
        }
272
110
 
273
 
        if (nErrorCode != FZ_REPLY_OK)
 
111
        if ((nErrorCode & FZ_REPLY_CRITICALERROR) == FZ_REPLY_CRITICALERROR)
 
112
                LogMessage(::Error, _("Critical error"));
 
113
 
 
114
        if (m_pCurOpData)
274
115
        {
275
 
                if ((nErrorCode & FZ_REPLY_CRITICALERROR) == FZ_REPLY_CRITICALERROR)
276
 
                        LogMessage(::Error, _("Critical error"));
277
 
                const enum Command commandId = GetCurrentCommandId();
 
116
                const enum Command commandId = m_pCurOpData->opId;
278
117
                switch (commandId)
279
118
                {
 
119
                case cmd_none:
 
120
                        break;
280
121
                case cmd_connect:
281
122
                        if ((nErrorCode & FZ_REPLY_CANCELED) == FZ_REPLY_CANCELED)
282
123
                                LogMessage(::Error, _("Connection attempt interrupted by user"));
283
 
                        else
 
124
                        else if (nErrorCode != FZ_REPLY_OK)
284
125
                                LogMessage(::Error, _("Could not connect to server"));
285
126
                        break;
286
127
                case cmd_list:
287
128
                        if ((nErrorCode & FZ_REPLY_CANCELED) == FZ_REPLY_CANCELED)
288
129
                                LogMessage(::Error, _("Directory listing aborted by user"));
289
 
                        else
 
130
                        else if (nErrorCode != FZ_REPLY_OK)
290
131
                                LogMessage(::Error, _("Failed to retrieve directory listing"));
 
132
                        else
 
133
                                LogMessage(Status, _("Directory listing successful"));
291
134
                        break;
292
 
                case cmd_none:
 
135
                case cmd_transfer:
 
136
                        {
 
137
                                CFileTransferOpData *pData = static_cast<CFileTransferOpData *>(m_pCurOpData);
 
138
                                if (!pData->download && pData->transferInitiated)
 
139
                                {
 
140
                                        if (!m_pCurrentServer)
 
141
                                                LogMessage(__TFILE__, __LINE__, this, Debug_Warning, _T("m_pCurrentServer is 0"));
 
142
                                        else
 
143
                                        {
 
144
                                                CDirectoryCache cache;
 
145
                                                bool updated = cache.UpdateFile(*m_pCurrentServer, pData->remotePath, pData->remoteFile, true, CDirectoryCache::file, (nErrorCode == FZ_REPLY_OK) ? pData->localFileSize : -1);
 
146
 
 
147
                                                if (updated)
 
148
                                                        m_pEngine->SendDirectoryListingNotification(pData->remotePath, false, true, false);
 
149
                                        }
 
150
                                }
 
151
                                if ((nErrorCode & FZ_REPLY_CANCELED) == FZ_REPLY_CANCELED)
 
152
                                        LogMessage(::Error, _("Transfer aborted by user"));
 
153
                                else if (nErrorCode == FZ_REPLY_OK)
 
154
                                        LogMessage(Status, _("File transfer successful"));
 
155
                        }
293
156
                        break;
294
157
                default:
295
158
                        if ((nErrorCode & FZ_REPLY_CANCELED) == FZ_REPLY_CANCELED)
296
159
                                LogMessage(::Error, _("Interrupted by user"));
297
160
                        break;
298
161
                }
299
 
        }
300
 
        else
301
 
        {
302
 
                switch (GetCurrentCommandId())
303
 
                {
304
 
                case cmd_list:
305
 
                        LogMessage(Status, _("Directory listing successful"));
306
 
                        break;
307
 
                case cmd_transfer:
308
 
                        LogMessage(Status, _("File transfer successful"));
309
 
                        break;
310
 
                default:
311
 
                        break;
312
 
                }
 
162
 
 
163
                delete m_pCurOpData;
 
164
                m_pCurOpData = 0;
313
165
        }
314
166
 
315
167
        ResetTransferStatus();
316
168
 
317
169
        SetWait(false);
318
170
 
 
171
        if (m_invalidateCurrentPath)
 
172
        {
 
173
                m_CurrentPath.Clear();
 
174
                m_invalidateCurrentPath = false;
 
175
        }
 
176
 
319
177
        return m_pEngine->ResetOperation(nErrorCode);
320
178
}
321
179
 
322
180
int CControlSocket::DoClose(int nErrorCode /*=FZ_REPLY_DISCONNECTED*/)
323
181
{
 
182
        if (m_closed)
 
183
        {
 
184
                wxASSERT(!m_pCurOpData);
 
185
                return nErrorCode;
 
186
        }
 
187
 
 
188
        m_closed = true;
 
189
 
324
190
        nErrorCode = ResetOperation(FZ_REPLY_ERROR | FZ_REPLY_DISCONNECTED | nErrorCode);
325
 
        
326
 
        ResetSocket();
327
191
 
328
192
        delete m_pCurrentServer;
329
193
        m_pCurrentServer = 0;
330
194
 
331
 
        m_pEngine->SendDisconnectNotification();
332
 
 
333
195
        return nErrorCode;
334
196
}
335
197
 
336
 
void CControlSocket::ResetSocket()
337
 
{
338
 
        Close();
339
 
 
340
 
        delete [] m_pSendBuffer;
341
 
        m_pSendBuffer = 0;
342
 
        m_nSendBufferLen = 0;
343
 
 
344
 
        m_onConnectCalled = false;
345
 
 
346
 
        SetEventHandler(*this, ++m_socketId);
347
 
}
348
 
 
349
 
bool CControlSocket::Send(const char *buffer, int len)
350
 
{
351
 
        SetWait(true);
352
 
        if (m_pSendBuffer)
353
 
        {
354
 
                char *tmp = m_pSendBuffer;
355
 
                m_pSendBuffer = new char[m_nSendBufferLen + len];
356
 
                memcpy(m_pSendBuffer, tmp, m_nSendBufferLen);
357
 
                memcpy(m_pSendBuffer + m_nSendBufferLen, buffer, len);
358
 
                m_nSendBufferLen += len;
359
 
                delete [] tmp;
360
 
        }
361
 
        else
362
 
        {
363
 
                Write(buffer, len);
364
 
                int numsent = 0;
365
 
                if (Error())
366
 
                {
367
 
                        if (LastError() != wxSOCKET_WOULDBLOCK)
368
 
                        {
369
 
                                DoClose();
370
 
                                return false;
371
 
                        }
372
 
                }
373
 
                else
374
 
                        numsent = LastCount();
375
 
 
376
 
                if (numsent)
377
 
                        m_pEngine->SetActive(false);
378
 
 
379
 
                if (numsent < len)
380
 
                {
381
 
                        char *tmp = m_pSendBuffer;
382
 
                        m_pSendBuffer = new char[m_nSendBufferLen + len - numsent];
383
 
                        memcpy(m_pSendBuffer, tmp, m_nSendBufferLen);
384
 
                        memcpy(m_pSendBuffer + m_nSendBufferLen, buffer, len - numsent);
385
 
                        m_nSendBufferLen += len - numsent;
386
 
                        delete [] tmp;
387
 
                }
388
 
        }
389
 
 
390
 
        return true;
391
 
}
392
 
 
393
198
wxString CControlSocket::ConvertDomainName(wxString domain)
394
199
{
395
200
        const wxWCharBuffer buffer = wxConvCurrent->cWX2WC(domain);
437
242
        m_transferStatusSendState = 0;
438
243
}
439
244
 
440
 
void CControlSocket::InitTransferStatus(wxFileOffset totalSize, wxFileOffset startOffset)
 
245
void CControlSocket::InitTransferStatus(wxFileOffset totalSize, wxFileOffset startOffset, bool list)
441
246
{
442
247
        if (startOffset < 0)
443
248
                startOffset = 0;
445
250
        delete m_pTransferStatus;
446
251
        m_pTransferStatus = new CTransferStatus();
447
252
 
 
253
        m_pTransferStatus->list = list;
448
254
        m_pTransferStatus->totalSize = totalSize;
449
255
        m_pTransferStatus->startOffset = startOffset;
450
256
        m_pTransferStatus->currentOffset = startOffset;
 
257
        m_pTransferStatus->madeProgress = false;
451
258
}
452
259
 
453
260
void CControlSocket::SetTransferStatusStartTime()
458
265
        m_pTransferStatus->started = wxDateTime::Now();
459
266
}
460
267
 
 
268
void CControlSocket::SetTransferStatusMadeProgress()
 
269
{
 
270
        if (!m_pTransferStatus)
 
271
                return;
 
272
 
 
273
        m_pTransferStatus->madeProgress = true;
 
274
}
 
275
 
461
276
void CControlSocket::UpdateTransferStatus(wxFileOffset transferredBytes)
462
277
{
463
278
        if (!m_pTransferStatus)
500
315
        return m_pCurrentServer;
501
316
}
502
317
 
503
 
bool CControlSocket::ParsePwdReply(wxString reply, bool unquoted /*=false*/)
 
318
bool CControlSocket::ParsePwdReply(wxString reply, bool unquoted /*=false*/, const CServerPath& defaultPath /*=CServerPath()*/)
504
319
{
505
320
        if (!unquoted)
506
321
        {
508
323
                int pos2 = reply.Find('"', true);
509
324
                if (pos1 == -1 || pos1 >= pos2)
510
325
                {
511
 
                        LogMessage(__TFILE__, __LINE__, this, Debug_Info, _T("No quoted path found in pwd reply, trying first token as path"));
 
326
                        pos1 = reply.Find('\'');
 
327
                        pos2 = reply.Find('\'', true);
 
328
 
 
329
                        if (pos1 != -1 && pos1 < pos2)
 
330
                                LogMessage(__TFILE__, __LINE__, this, Debug_Info, _T("Broken server sending single-quoted path instead of double-quoted path."));
 
331
                }
 
332
                if (pos1 == -1 || pos1 >= pos2)
 
333
                {
 
334
                        LogMessage(__TFILE__, __LINE__, this, Debug_Info, _T("Broken server, no quoted path found in pwd reply, trying first token as path"));
512
335
                        pos1 = reply.Find(' ');
513
 
                        if (pos1 == -1)
 
336
                        if (pos1 != -1)
514
337
                        {
515
 
                                LogMessage(__TFILE__, __LINE__, this, Debug_Warning, _T("Can't parse path"));
516
 
                                return false;
 
338
                                reply = reply.Mid(pos1 + 1);
 
339
                                pos2 = reply.Find(' ');
 
340
                                if (pos2 != -1)
 
341
                                        reply = reply.Left(pos2);
517
342
                        }
518
 
 
519
 
                        pos2 = reply.Mid(pos1 + 1).Find(' ');
520
 
                        if (pos2 == -1)
521
 
                                pos2 = (int)reply.Length();
 
343
                        else
 
344
                                reply = _T("");
522
345
                }
523
 
                reply = reply.Mid(pos1 + 1, pos2 - pos1 - 1);
 
346
                else
 
347
                        reply = reply.Mid(pos1 + 1, pos2 - pos1 - 1);
524
348
        }
525
349
 
526
350
        m_CurrentPath.SetType(m_pCurrentServer->GetType());
527
 
        if (!m_CurrentPath.SetPath(reply))
 
351
        if (reply == _T("") || !m_CurrentPath.SetPath(reply))
528
352
        {
529
 
                LogMessage(__TFILE__, __LINE__, this, Debug_Warning, _T("Can't parse path"));
 
353
                if (reply != _T(""))
 
354
                        LogMessage(__TFILE__, __LINE__, this, Debug_Warning, _T("Failed to parse returned path."));
 
355
                else
 
356
                        LogMessage(__TFILE__, __LINE__, this, Debug_Warning, _T("Server returned empty path."));
 
357
 
 
358
                if (!defaultPath.IsEmpty())
 
359
                {
 
360
                        LogMessage(Debug_Warning, _T("Assuming path is '%s'."), defaultPath.GetPath().c_str());
 
361
                        m_CurrentPath = defaultPath;
 
362
                        return true;
 
363
                }
530
364
                return false;
531
365
        }
532
366
 
554
388
        bool dirDidExist;
555
389
        bool matchedCase;
556
390
        CDirectoryCache cache;
557
 
        bool found = cache.LookupFile(entry, *m_pCurrentServer, pData->tryAbsolutePath ? pData->remotePath : m_CurrentPath, pData->remoteFile, dirDidExist, matchedCase);
 
391
        CServerPath remotePath;
 
392
        if (pData->tryAbsolutePath || m_CurrentPath.IsEmpty())
 
393
                remotePath = pData->remotePath;
 
394
        else
 
395
                remotePath = m_CurrentPath;
 
396
        bool found = cache.LookupFile(entry, *m_pCurrentServer, remotePath, pData->remoteFile, dirDidExist, matchedCase);
558
397
 
559
398
        // Ignore entries with wrong case
560
 
        if (!matchedCase)
 
399
        if (found && !matchedCase)
561
400
                found = false;
562
401
 
563
402
        if (!pData->download)
576
415
        pNotification->remoteSize = pData->remoteFileSize;
577
416
        pNotification->ascii = !pData->transferSettings.binary;
578
417
 
 
418
        if (pData->download && pNotification->localSize != -1)
 
419
                pNotification->canResume = true;
 
420
        else if (!pData->download && pNotification->remoteSize != -1)
 
421
                pNotification->canResume = true;
 
422
        else
 
423
                pNotification->canResume = false;
 
424
 
579
425
        wxStructStat buf;
580
426
        int result;
581
427
        result = wxStat(pData->localFile, &buf);
601
447
                }
602
448
        }
603
449
 
604
 
        pNotification->requestNumber = m_pEngine->GetNextAsyncRequestNumber();
605
 
        pData->waitForAsyncRequest = true;
606
 
 
607
 
        m_pEngine->AddNotification(pNotification);
 
450
        SendAsyncRequest(pNotification);
608
451
 
609
452
        return FZ_REPLY_WOULDBLOCK;
610
453
}
625
468
        if (m_useUTF8)
626
469
        {
627
470
                wxChar* out = ConvToLocalBuffer(buffer, wxConvUTF8);
628
 
                if (buffer)
 
471
                if (out)
629
472
                {
630
473
                        wxString str = out;
631
474
                        delete [] out;
639
482
                        m_useUTF8 = false;
640
483
                }
641
484
        }
642
 
        
 
485
 
643
486
        if (m_pCSConv)
644
487
        {
645
488
                wxChar* out = ConvToLocalBuffer(buffer, *m_pCSConv);
646
 
                if (buffer)
 
489
                if (out)
647
490
                {
648
491
                        wxString str = out;
649
492
                        delete [] out;
651
494
                }
652
495
        }
653
496
 
654
 
        wxString str = wxConvCurrent->cMB2WX(buffer);
 
497
        wxCSConv conv(_T("ISO-8859-1"));
 
498
        wxString str = conv.cMB2WX(buffer);
 
499
        if (str == _T(""))
 
500
                str = wxConvCurrent->cMB2WX(buffer);
655
501
 
656
502
        return str;
657
503
}
716
562
        return res;
717
563
}
718
564
 
719
 
wxCharBuffer CControlSocket::ConvToServer(const wxString& str)
 
565
wxCharBuffer CControlSocket::ConvToServer(const wxString& str, bool force_utf8 /*=false*/)
720
566
{
721
 
        if (m_useUTF8)
 
567
        if (m_useUTF8 || force_utf8)
722
568
        {
723
569
#if wxUSE_UNICODE
724
570
                wxCharBuffer buffer = wxConvUTF8.cWX2MB(str);
729
575
                         buffer = wxConvUTF8.cWC2MB(unicode);
730
576
#endif
731
577
 
732
 
                if (buffer)
 
578
                if (buffer || force_utf8)
733
579
                        return buffer;
734
580
        }
735
581
 
755
601
        return buffer;
756
602
}
757
603
 
758
 
wxString CControlSocket::GetLocalIP() const
759
 
{
760
 
        wxIPV4address addr;
761
 
        if (!GetLocal(addr))
762
 
                return _T("");
763
 
 
764
 
        return addr.IPAddress();
765
 
}
766
 
 
767
 
wxString CControlSocket::GetPeerIP() const
768
 
{
769
 
        wxIPV4address addr;
770
 
        if (!GetPeer(addr))
771
 
                return _T("");
772
 
 
773
 
        return addr.IPAddress();
774
 
}
775
 
 
776
604
void CControlSocket::OnTimer(wxTimerEvent& event)
777
605
{
778
606
        int timeout = m_pEngine->GetOptions()->GetOptionVal(OPTION_TIMEOUT);
779
607
        if (!timeout)
780
608
                return;
781
609
 
 
610
        if (m_pCurOpData && m_pCurOpData->waitForAsyncRequest)
 
611
                return;
 
612
 
782
613
        if (m_stopWatch.Time() > (timeout * 1000))
783
614
        {
784
 
                
785
615
                LogMessage(::Error, _("Connection timed out"));
786
616
                DoClose(FZ_REPLY_TIMEOUT);
 
617
                wxASSERT(!m_timer.IsRunning());
787
618
        }
788
619
}
789
620
 
806
637
                m_timer.Stop();
807
638
}
808
639
 
809
 
int CControlSocket::SendNextCommand(int prevResult /*=FZ_REPLY_OK*/)
810
 
{
811
 
        ResetOperation(prevResult);
 
640
int CControlSocket::SendNextCommand()
 
641
{
 
642
        ResetOperation(FZ_REPLY_INTERNALERROR);
 
643
        return FZ_REPLY_ERROR;
 
644
}
 
645
 
 
646
int CControlSocket::ParseSubcommandResult(int prevResult)
 
647
{
 
648
        ResetOperation(FZ_REPLY_INTERNALERROR);
812
649
        return FZ_REPLY_ERROR;
813
650
}
814
651
 
822
659
        return iter;
823
660
}
824
661
 
825
 
bool CControlSocket::TryLockCache(const CServerPath& directory)
 
662
bool CControlSocket::TryLockCache(enum locking_reason reason, const CServerPath& directory)
826
663
{
827
 
        wxASSERT(GetLockStatus() == m_lockInfoList.end());
828
664
        wxASSERT(m_pCurrentServer);
829
 
 
830
 
        t_lockInfo info;
831
 
        info.directory = directory;
832
 
        info.pControlSocket = this;
833
 
        info.waiting = false;
834
 
 
835
 
        // Try to find other instance holding the lock
836
 
        for (std::list<t_lockInfo>::const_iterator iter = m_lockInfoList.begin(); iter != m_lockInfoList.end(); iter++)
837
 
        {
838
 
                if (*m_pCurrentServer != *iter->pControlSocket->m_pCurrentServer)
839
 
                        continue;
840
 
 
841
 
                if (directory == iter->directory)
 
665
        wxASSERT(m_pCurOpData);
 
666
 
 
667
        std::list<t_lockInfo>::iterator own = GetLockStatus();
 
668
        if (own == m_lockInfoList.end())
 
669
        {
 
670
                t_lockInfo info;
 
671
                info.directory = directory;
 
672
                info.pControlSocket = this;
 
673
                info.waiting = true;
 
674
                info.reason = reason;
 
675
                info.lockcount = 0;
 
676
                m_lockInfoList.push_back(info);
 
677
                own = --m_lockInfoList.end();
 
678
        }
 
679
        else
 
680
        {
 
681
                if (own->lockcount)
842
682
                {
843
 
                        // Some other instance is holding the lock
844
 
                        info.waiting = true;
845
 
                        break;
 
683
                        if (!m_pCurOpData->holdsLock)
 
684
                        {
 
685
                                m_pCurOpData->holdsLock = true;
 
686
                                own->lockcount++;
 
687
                        }
 
688
                        return true;
846
689
                }
847
 
        }
848
 
 
849
 
        m_lockInfoList.push_back(info);
850
 
        return !info.waiting;
 
690
                wxASSERT(own->waiting);
 
691
                wxASSERT(own->reason == reason);
 
692
        }
 
693
 
 
694
        // Needs to be set in any case so that ResetOperation 
 
695
        // unlocks or cancels the lock wait
 
696
        m_pCurOpData->holdsLock = true;
 
697
 
 
698
        // Try to find other instance holding the lock
 
699
        for (std::list<t_lockInfo>::const_iterator iter = m_lockInfoList.begin(); iter != own; iter++)
 
700
        {
 
701
                if (*m_pCurrentServer != *iter->pControlSocket->m_pCurrentServer)
 
702
                        continue;
 
703
                if (directory != iter->directory)
 
704
                        continue;
 
705
                if (reason != iter->reason)
 
706
                        continue;
 
707
 
 
708
                // Some other instance is holding the lock
 
709
                return false;
 
710
        }
 
711
 
 
712
        own->lockcount++;
 
713
        own->waiting = false;
 
714
        return true;
 
715
}
 
716
 
 
717
bool CControlSocket::IsLocked(enum locking_reason reason, const CServerPath& directory)
 
718
{
 
719
        wxASSERT(m_pCurrentServer);
 
720
 
 
721
        std::list<t_lockInfo>::iterator own = GetLockStatus();
 
722
        if (own != m_lockInfoList.end())
 
723
                return true;
 
724
 
 
725
        // Try to find other instance holding the lock
 
726
        for (std::list<t_lockInfo>::const_iterator iter = m_lockInfoList.begin(); iter != own; iter++)
 
727
        {
 
728
                if (*m_pCurrentServer != *iter->pControlSocket->m_pCurrentServer)
 
729
                        continue;
 
730
                if (directory != iter->directory)
 
731
                        continue;
 
732
                if (reason != iter->reason)
 
733
                        continue;
 
734
 
 
735
                // Some instance is holding the lock
 
736
                return true;
 
737
        }
 
738
 
 
739
        return false;
851
740
}
852
741
 
853
742
void CControlSocket::UnlockCache()
854
743
{
 
744
        if (!m_pCurOpData || !m_pCurOpData->holdsLock)
 
745
                return;
 
746
        m_pCurOpData->holdsLock = false;
 
747
 
855
748
        std::list<t_lockInfo>::iterator iter = GetLockStatus();
856
749
        if (iter == m_lockInfoList.end())
857
750
                return;
858
751
 
 
752
        iter->lockcount--;
 
753
        if (iter->lockcount)
 
754
                return;
 
755
 
859
756
        CServerPath directory = iter->directory;
 
757
        enum locking_reason reason = iter->reason;
 
758
 
860
759
        m_lockInfoList.erase(iter);
861
760
 
862
761
        // Find other instance waiting for the lock
868
767
                if (iter->directory != directory)
869
768
                        continue;
870
769
 
 
770
                if (iter->reason != reason)
 
771
                        continue;
 
772
 
871
773
                // Send notification
872
774
                wxCommandEvent evt(fzOBTAINLOCK);
873
775
                iter->pControlSocket->AddPendingEvent(evt);
875
777
        }
876
778
}
877
779
 
878
 
bool CControlSocket::ObtainLockFromEvent()
 
780
enum CControlSocket::locking_reason CControlSocket::ObtainLockFromEvent()
879
781
{
 
782
        wxASSERT(m_pCurOpData);
 
783
 
880
784
        std::list<t_lockInfo>::iterator own = GetLockStatus();
881
785
        if (own == m_lockInfoList.end())
882
 
                return false;
 
786
                return lock_unknown;
883
787
 
884
788
        if (!own->waiting)
885
 
                return false;
 
789
                return lock_unknown;
886
790
 
887
791
        for (std::list<t_lockInfo>::const_iterator iter = m_lockInfoList.begin(); iter != own; iter++)
888
792
        {
889
793
                if (*m_pCurrentServer != *iter->pControlSocket->m_pCurrentServer)
890
794
                        continue;
891
795
 
892
 
                if (iter->directory == own->directory)
893
 
                        return false;
 
796
                if (iter->directory != own->directory)
 
797
                        continue;
 
798
 
 
799
                if (iter->reason != own->reason)
 
800
                        continue;
 
801
 
 
802
                // Another instance comes before us
 
803
                return lock_unknown;
894
804
        }
895
805
 
896
806
        own->waiting = false;
 
807
        own->lockcount++;
897
808
 
898
 
        return true;
 
809
        return own->reason;
899
810
}
900
811
 
901
812
void CControlSocket::OnObtainLock(wxCommandEvent& event)
902
813
{
903
 
        if (!ObtainLockFromEvent())
 
814
        if (ObtainLockFromEvent() == lock_unknown)
904
815
                return;
905
816
 
906
817
        SendNextCommand();
907
818
 
908
819
        UnlockCache();
909
820
}
 
821
 
 
822
void CControlSocket::InvalidateCurrentWorkingDir(const CServerPath& path)
 
823
{
 
824
        wxASSERT(!path.IsEmpty());
 
825
        if (m_CurrentPath.IsEmpty())
 
826
                return;
 
827
 
 
828
        if (m_CurrentPath == path || path.IsParentOf(m_CurrentPath, false))
 
829
        {
 
830
                if (m_pCurOpData)
 
831
                        m_invalidateCurrentPath = true;
 
832
                else
 
833
                        m_CurrentPath.Clear();
 
834
        }
 
835
}
 
836
 
 
837
wxTimeSpan CControlSocket::GetTimezoneOffset()
 
838
{
 
839
        if (!m_pCurrentServer)
 
840
                return wxTimeSpan();
 
841
 
 
842
        int seconds = 0;
 
843
        if (CServerCapabilities::GetCapability(*m_pCurrentServer, timezone_offset, &seconds) != yes)
 
844
                return wxTimeSpan();
 
845
 
 
846
        return wxTimeSpan(0, 0, seconds);
 
847
}
 
848
 
 
849
void CControlSocket::SendAsyncRequest(CAsyncRequestNotification* pNotification)
 
850
{
 
851
        wxASSERT(pNotification);
 
852
 
 
853
        pNotification->requestNumber = m_pEngine->GetNextAsyncRequestNumber();
 
854
 
 
855
        if (m_pCurOpData)
 
856
                m_pCurOpData->waitForAsyncRequest = true;
 
857
        m_pEngine->AddNotification(pNotification);
 
858
}
 
859
 
 
860
// ------------------
 
861
// CRealControlSocket
 
862
// ------------------
 
863
 
 
864
BEGIN_EVENT_TABLE(CRealControlSocket, CControlSocket)
 
865
        EVT_SOCKET(wxID_ANY, CRealControlSocket::OnSocketEvent)
 
866
END_EVENT_TABLE()
 
867
 
 
868
CRealControlSocket::CRealControlSocket(CFileZillaEnginePrivate *pEngine)
 
869
        : CControlSocket(pEngine), wxSocketClient(wxSOCKET_NOWAIT)
 
870
{
 
871
        m_pBackend = new CSocketBackend(this, this);
 
872
 
 
873
        m_pSendBuffer = 0;
 
874
        m_nSendBufferLen = 0;
 
875
        m_onConnectCalled = false;
 
876
}
 
877
 
 
878
CRealControlSocket::~CRealControlSocket()
 
879
{
 
880
        delete m_pBackend;
 
881
        m_pBackend = 0;
 
882
}
 
883
 
 
884
bool CRealControlSocket::Send(const char *buffer, int len)
 
885
{
 
886
        SetWait(true);
 
887
        if (m_pSendBuffer)
 
888
        {
 
889
                char *tmp = m_pSendBuffer;
 
890
                m_pSendBuffer = new char[m_nSendBufferLen + len];
 
891
                memcpy(m_pSendBuffer, tmp, m_nSendBufferLen);
 
892
                memcpy(m_pSendBuffer + m_nSendBufferLen, buffer, len);
 
893
                m_nSendBufferLen += len;
 
894
                delete [] tmp;
 
895
        }
 
896
        else
 
897
        {
 
898
                m_pBackend->Write(buffer, len);
 
899
                int numsent = 0;
 
900
                if (m_pBackend->Error())
 
901
                {
 
902
                        if (m_pBackend->LastError() != wxSOCKET_WOULDBLOCK)
 
903
                        {
 
904
                                DoClose();
 
905
                                return false;
 
906
                        }
 
907
                }
 
908
                else
 
909
                        numsent = m_pBackend->LastCount();
 
910
 
 
911
                if (numsent)
 
912
                        m_pEngine->SetActive(false);
 
913
 
 
914
                if (numsent < len)
 
915
                {
 
916
                        char *tmp = m_pSendBuffer;
 
917
                        m_pSendBuffer = new char[m_nSendBufferLen + len - numsent];
 
918
                        memcpy(m_pSendBuffer, tmp, m_nSendBufferLen);
 
919
                        memcpy(m_pSendBuffer + m_nSendBufferLen, buffer, len - numsent);
 
920
                        m_nSendBufferLen += len - numsent;
 
921
                        delete [] tmp;
 
922
                }
 
923
        }
 
924
 
 
925
        return true;
 
926
}
 
927
 
 
928
void CRealControlSocket::OnSocketEvent(wxSocketEvent &event)
 
929
{
 
930
        if (!m_pBackend)
 
931
                return;
 
932
 
 
933
        if (event.GetId() != m_pBackend->GetId())
 
934
                return;
 
935
 
 
936
        switch (event.GetSocketEvent())
 
937
        {
 
938
        case wxSOCKET_CONNECTION:
 
939
                m_onConnectCalled = true;
 
940
                OnConnect();
 
941
                break;
 
942
        case wxSOCKET_INPUT:
 
943
                if (!m_onConnectCalled)
 
944
                {
 
945
                        m_onConnectCalled = true;
 
946
                        OnConnect();
 
947
                }
 
948
                OnReceive();
 
949
                break;
 
950
        case wxSOCKET_OUTPUT:
 
951
                OnSend();
 
952
                break;
 
953
        case wxSOCKET_LOST:
 
954
                OnClose();
 
955
                break;
 
956
        }
 
957
}
 
958
 
 
959
void CRealControlSocket::OnConnect()
 
960
{
 
961
}
 
962
 
 
963
void CRealControlSocket::OnReceive()
 
964
{
 
965
}
 
966
 
 
967
void CRealControlSocket::OnSend()
 
968
{
 
969
        if (m_pSendBuffer)
 
970
        {
 
971
                if (!m_nSendBufferLen)
 
972
                {
 
973
                        delete [] m_pSendBuffer;
 
974
                        m_pSendBuffer = 0;
 
975
                        return;
 
976
                }
 
977
 
 
978
                m_pBackend->Write(m_pSendBuffer, m_nSendBufferLen);
 
979
                if (m_pBackend->Error())
 
980
                {
 
981
                        if (m_pBackend->LastError() != wxSOCKET_WOULDBLOCK)
 
982
                                DoClose();
 
983
                        return;
 
984
                }
 
985
 
 
986
                int numsent = m_pBackend->LastCount();
 
987
 
 
988
                if (numsent)
 
989
                {
 
990
                        SetAlive();
 
991
                        m_pEngine->SetActive(false);
 
992
                }
 
993
 
 
994
                if (numsent == m_nSendBufferLen)
 
995
                {
 
996
                        m_nSendBufferLen = 0;
 
997
                        delete [] m_pSendBuffer;
 
998
                        m_pSendBuffer = 0;
 
999
                }
 
1000
                else
 
1001
                {
 
1002
                        memmove(m_pSendBuffer, m_pSendBuffer + numsent, m_nSendBufferLen - numsent);
 
1003
                        m_nSendBufferLen -= numsent;
 
1004
                }
 
1005
        }
 
1006
}
 
1007
 
 
1008
void CRealControlSocket::OnClose()
 
1009
{
 
1010
        LogMessage(Debug_Verbose, _T("CRealControlSocket::OnClose()"));
 
1011
 
 
1012
        if (GetCurrentCommandId() != cmd_connect)
 
1013
                LogMessage(::Error, _("Disconnected from server"));
 
1014
        DoClose();
 
1015
}
 
1016
 
 
1017
int CRealControlSocket::Connect(const CServer &server)
 
1018
{
 
1019
        SetWait(true);
 
1020
 
 
1021
        if (server.GetEncodingType() == ENCODING_CUSTOM)
 
1022
                m_pCSConv = new wxCSConv(server.GetCustomEncoding());
 
1023
 
 
1024
        if (m_pCurrentServer)
 
1025
                delete m_pCurrentServer;
 
1026
        m_pCurrentServer = new CServer(server);
 
1027
 
 
1028
        CConnectOpData* pData;
 
1029
        if (!m_pCurOpData || m_pCurOpData->opId != cmd_connect)
 
1030
                pData = 0;
 
1031
        else
 
1032
                pData = static_cast<CConnectOpData *>(m_pCurOpData);
 
1033
 
 
1034
        const wxString& host = pData ? pData->host : server.GetHost();
 
1035
        if (!IsIpAddress(host))
 
1036
        {
 
1037
                LogMessage(Status, _("Resolving IP-Address for %s"), host.c_str());
 
1038
                CAsyncHostResolver *resolver = new CAsyncHostResolver(m_pEngine, ConvertDomainName(host));
 
1039
                m_pEngine->AddNewAsyncHostResolver(resolver);
 
1040
 
 
1041
                resolver->Create();
 
1042
                resolver->Run();
 
1043
        }
 
1044
        else
 
1045
        {
 
1046
                wxIPV4address addr;
 
1047
                addr.Hostname(host);
 
1048
                return ContinueConnect(&addr);
 
1049
        }
 
1050
 
 
1051
        return FZ_REPLY_WOULDBLOCK;
 
1052
}
 
1053
 
 
1054
int CRealControlSocket::ContinueConnect(const wxIPV4address *address)
 
1055
{
 
1056
        LogMessage(__TFILE__, __LINE__, this, Debug_Verbose, _T("CRealControlSocket::ContinueConnect(%p) m_pEngine=%p"), address, m_pEngine);
 
1057
        if (GetCurrentCommandId() != cmd_connect ||
 
1058
                !m_pCurrentServer)
 
1059
        {
 
1060
                LogMessage(Debug_Warning, _T("Invalid context for call to ContinueConnect(), cmd=%d, m_pCurrentServer=%p"), GetCurrentCommandId(), m_pCurrentServer);
 
1061
                return DoClose(FZ_REPLY_INTERNALERROR);
 
1062
        }
 
1063
 
 
1064
        if (!address)
 
1065
        {
 
1066
                LogMessage(::Error, _("Invalid hostname or host not found"));
 
1067
                return DoClose(FZ_REPLY_ERROR | FZ_REPLY_CRITICALERROR);
 
1068
        }
 
1069
 
 
1070
        CConnectOpData* pData;
 
1071
        if (!m_pCurOpData || m_pCurOpData->opId != cmd_connect)
 
1072
                pData = 0;
 
1073
        else
 
1074
                pData = static_cast<CConnectOpData *>(m_pCurOpData);
 
1075
 
 
1076
        const unsigned int port = pData ? pData->port : m_pCurrentServer->GetPort();
 
1077
        LogMessage(Status, _("Connecting to %s:%d..."), address->IPAddress().c_str(), port);
 
1078
 
 
1079
        wxIPV4address addr = *address;
 
1080
        addr.Service(port);
 
1081
 
 
1082
        bool res = wxSocketClient::Connect(addr, false);
 
1083
 
 
1084
        if (!res && LastError() != wxSOCKET_WOULDBLOCK)
 
1085
                return DoClose();
 
1086
 
 
1087
        return FZ_REPLY_WOULDBLOCK;
 
1088
}
 
1089
 
 
1090
int CRealControlSocket::DoClose(int nErrorCode /*=FZ_REPLY_DISCONNECTED*/)
 
1091
{
 
1092
        ResetSocket();
 
1093
 
 
1094
        return CControlSocket::DoClose(nErrorCode);
 
1095
}
 
1096
 
 
1097
void CRealControlSocket::ResetSocket()
 
1098
{
 
1099
        Close();
 
1100
 
 
1101
        if (m_pSendBuffer)
 
1102
        {
 
1103
                delete [] m_pSendBuffer;
 
1104
                m_pSendBuffer = 0;
 
1105
                m_nSendBufferLen = 0;
 
1106
        }
 
1107
 
 
1108
        m_onConnectCalled = false;
 
1109
 
 
1110
        delete m_pBackend;
 
1111
        m_pBackend = 0;
 
1112
}
 
1113
 
 
1114
wxString CRealControlSocket::GetLocalIP() const
 
1115
{
 
1116
        wxIPV4address addr;
 
1117
        if (!GetLocal(addr))
 
1118
                return _T("");
 
1119
 
 
1120
        return addr.IPAddress();
 
1121
}
 
1122
 
 
1123
wxString CRealControlSocket::GetPeerIP() const
 
1124
{
 
1125
        wxIPV4address addr;
 
1126
        if (!GetPeer(addr))
 
1127
                return _T("");
 
1128
 
 
1129
        return addr.IPAddress();
 
1130
}