source: filezilla/trunk/fuentes/src/interface/netconfwizard.cpp @ 130

Last change on this file since 130 was 130, checked in by jrpelegrina, 4 years ago

First release to xenial

File size: 28.2 KB
Line 
1#include <filezilla.h>
2
3#include "event_loop.h"
4#include "engine_context.h"
5#include "netconfwizard.h"
6#include "Options.h"
7#include "dialogex.h"
8#include "filezillaapp.h"
9#include "externalipresolver.h"
10
11DECLARE_EVENT_TYPE(fzEVT_ON_EXTERNAL_IP_ADDRESS, -1)
12DEFINE_EVENT_TYPE(fzEVT_ON_EXTERNAL_IP_ADDRESS)
13
14BEGIN_EVENT_TABLE(CNetConfWizard, wxWizard)
15EVT_WIZARD_PAGE_CHANGING(wxID_ANY, CNetConfWizard::OnPageChanging)
16EVT_WIZARD_PAGE_CHANGED(wxID_ANY, CNetConfWizard::OnPageChanged)
17EVT_SOCKET(wxID_ANY, CNetConfWizard::OnSocketEvent)
18EVT_BUTTON(XRCID("ID_RESTART"), CNetConfWizard::OnRestart)
19EVT_WIZARD_FINISHED(wxID_ANY, CNetConfWizard::OnFinish)
20EVT_TIMER(wxID_ANY, CNetConfWizard::OnTimer)
21EVT_COMMAND(wxID_ANY, fzEVT_ON_EXTERNAL_IP_ADDRESS, CNetConfWizard::OnExternalIPAddress2)
22END_EVENT_TABLE()
23
24// Mark some strings used by wx as translatable
25#if 0
26TRANSLATE_T("&Next >");
27TRANSLATE_T("< &Back");
28#endif
29
30CNetConfWizard::CNetConfWizard(wxWindow* parent, COptions* pOptions, CFileZillaEngineContext & engine_context)
31        : CEventHandler(engine_context.GetEventLoop())
32        , m_parent(parent), m_pOptions(pOptions), m_pSocketServer(0)
33{
34        m_socket = 0;
35        m_pIPResolver = 0;
36        m_pSendBuffer = 0;
37        m_pSocketServer = 0;
38        m_pDataSocket = 0;
39
40        m_timer.SetOwner(this);
41
42        ResetTest();
43}
44
45CNetConfWizard::~CNetConfWizard()
46{
47        RemoveHandler();
48
49        delete m_socket;
50        delete m_pIPResolver;
51        delete [] m_pSendBuffer;
52        delete m_pSocketServer;
53}
54
55bool CNetConfWizard::Load()
56{
57        if (!Create(m_parent, wxID_ANY, _("Firewall and router configuration wizard"), wxNullBitmap, wxPoint(0, 0)))
58                return false;
59
60        wxSize minPageSize = GetPageAreaSizer()->GetMinSize();
61
62        for (int i = 1; i <= 7; i++)
63        {
64                wxWizardPageSimple* page = new wxWizardPageSimple();
65                bool res = wxXmlResource::Get()->LoadPanel(page, this, wxString::Format(_T("NETCONF_PANEL%d"), i));
66                if (!res)
67                        return false;
68                page->Show(false);
69
70                m_pages.push_back(page);
71        }
72        for (unsigned int i = 0; i < (m_pages.size() - 1); i++)
73                m_pages[i]->Chain(m_pages[i], m_pages[i + 1]);
74
75        GetPageAreaSizer()->Add(m_pages[0]);
76
77        std::vector<wxWindow*> windows;
78        for (unsigned int i = 0; i < m_pages.size(); i++)
79                windows.push_back(m_pages[i]);
80        wxGetApp().GetWrapEngine()->WrapRecursive(windows, 1.7, "Netconf", wxSize(), minPageSize);
81
82        CenterOnParent();
83
84        // Load values
85
86        switch (m_pOptions->GetOptionVal(OPTION_USEPASV))
87        {
88        default:
89        case 1:
90                XRCCTRL(*this, "ID_PASSIVE", wxRadioButton)->SetValue(true);
91                break;
92        case 0:
93                XRCCTRL(*this, "ID_ACTIVE", wxRadioButton)->SetValue(true);
94                break;
95        }
96
97        XRCCTRL(*this, "ID_FALLBACK", wxCheckBox)->SetValue(m_pOptions->GetOptionVal(OPTION_ALLOW_TRANSFERMODEFALLBACK) != 0);
98
99        switch (m_pOptions->GetOptionVal(OPTION_PASVREPLYFALLBACKMODE))
100        {
101        default:
102        case 0:
103                XRCCTRL(*this, "ID_PASSIVE_FALLBACK1", wxRadioButton)->SetValue(true);
104                break;
105        case 1:
106                XRCCTRL(*this, "ID_PASSIVE_FALLBACK2", wxRadioButton)->SetValue(true);
107                break;
108        }
109        switch (m_pOptions->GetOptionVal(OPTION_EXTERNALIPMODE))
110        {
111        default:
112        case 0:
113                XRCCTRL(*this, "ID_ACTIVEMODE1", wxRadioButton)->SetValue(true);
114                break;
115        case 1:
116                XRCCTRL(*this, "ID_ACTIVEMODE2", wxRadioButton)->SetValue(true);
117                break;
118        case 2:
119                XRCCTRL(*this, "ID_ACTIVEMODE3", wxRadioButton)->SetValue(true);
120                break;
121        }
122        switch (m_pOptions->GetOptionVal(OPTION_LIMITPORTS))
123        {
124        default:
125        case 0:
126                XRCCTRL(*this, "ID_ACTIVE_PORTMODE1", wxRadioButton)->SetValue(true);
127                break;
128        case 1:
129                XRCCTRL(*this, "ID_ACTIVE_PORTMODE2", wxRadioButton)->SetValue(true);
130                break;
131        }
132        XRCCTRL(*this, "ID_ACTIVE_PORTMIN", wxTextCtrl)->SetValue(wxString::Format(_T("%d"), m_pOptions->GetOptionVal(OPTION_LIMITPORTS_LOW)));
133        XRCCTRL(*this, "ID_ACTIVE_PORTMAX", wxTextCtrl)->SetValue(wxString::Format(_T("%d"), m_pOptions->GetOptionVal(OPTION_LIMITPORTS_HIGH)));
134        XRCCTRL(*this, "ID_ACTIVEIP", wxTextCtrl)->SetValue(m_pOptions->GetOption(OPTION_EXTERNALIP));
135        XRCCTRL(*this, "ID_ACTIVERESOLVER", wxTextCtrl)->SetValue(m_pOptions->GetOption(OPTION_EXTERNALIPRESOLVER));
136        XRCCTRL(*this, "ID_NOEXTERNALONLOCAL", wxCheckBox)->SetValue(m_pOptions->GetOptionVal(OPTION_NOEXTERNALONLOCAL) != 0);
137
138        return true;
139}
140
141bool CNetConfWizard::Run()
142{
143        return RunWizard(m_pages.front());
144}
145
146void CNetConfWizard::OnPageChanging(wxWizardEvent& event)
147{
148        if (event.GetPage() == m_pages[3])
149        {
150                int mode = XRCCTRL(*this, "ID_ACTIVEMODE1", wxRadioButton)->GetValue() ? 0 : (XRCCTRL(*this, "ID_ACTIVEMODE2", wxRadioButton)->GetValue() ? 1 : 2);
151                if (mode == 1)
152                {
153                        wxTextCtrl* control = XRCCTRL(*this, "ID_ACTIVEIP", wxTextCtrl);
154                        wxString ip = control->GetValue();
155                        if (ip.empty())
156                        {
157                                wxMessageBoxEx(_("Please enter your external IP address"));
158                                control->SetFocus();
159                                event.Veto();
160                                return;
161                        }
162                        if (!IsIpAddress(ip))
163                        {
164                                wxMessageBoxEx(_("You have to enter a valid IP address."));
165                                control->SetFocus();
166                                event.Veto();
167                                return;
168                        }
169                }
170                else if (mode == 2)
171                {
172                        wxTextCtrl* pResolver = XRCCTRL(*this, "ID_ACTIVERESOLVER", wxTextCtrl);
173                        wxString address = pResolver->GetValue();
174                        if (address.empty())
175                        {
176                                wxMessageBoxEx(_("Please enter an URL where to get your external address from"));
177                                pResolver->SetFocus();
178                                event.Veto();
179                                return;
180                        }
181                }
182        }
183        else if (event.GetPage() == m_pages[4])
184        {
185                int mode = XRCCTRL(*this, "ID_ACTIVE_PORTMODE1", wxRadioButton)->GetValue() ? 0 : 1;
186                if (mode)
187                {
188                        wxTextCtrl* pPortMin = XRCCTRL(*this, "ID_ACTIVE_PORTMIN", wxTextCtrl);
189                        wxTextCtrl* pPortMax = XRCCTRL(*this, "ID_ACTIVE_PORTMAX", wxTextCtrl);
190                        wxString portMin = pPortMin->GetValue();
191                        wxString portMax = pPortMax->GetValue();
192
193                        long min = 0, max = 0;
194                        if (!portMin.ToLong(&min) || !portMax.ToLong(&max) ||
195                                min < 1024 || max > 65535 || min > max)
196                        {
197                                wxMessageBoxEx(_("Please enter a valid portrange."));
198                                pPortMin->SetFocus();
199                                event.Veto();
200                                return;
201                        }
202                }
203        }
204        else if (event.GetPage() == m_pages[5] && !event.GetDirection())
205        {
206                wxButton* pNext = wxDynamicCast(FindWindow(wxID_FORWARD), wxButton);
207                pNext->SetLabel(m_nextLabelText);
208        }
209        else if (event.GetPage() == m_pages[5] && event.GetDirection())
210        {
211                if (m_testDidRun)
212                        return;
213
214                m_testDidRun = true;
215
216                wxButton* pNext = wxDynamicCast(FindWindow(wxID_FORWARD), wxButton);
217                pNext->Disable();
218                wxButton* pPrev = wxDynamicCast(FindWindow(wxID_BACKWARD), wxButton);
219                pPrev->Disable();
220                event.Veto();
221
222                PrintMessage(wxString::Format(_("Connecting to %s"), _T("probe.filezilla-project.org")), 0);
223                m_socket = new wxSocketClient(wxSOCKET_NOWAIT);
224                m_socket->SetEventHandler(*this, 0);
225                m_socket->SetNotify(wxSOCKET_INPUT_FLAG | wxSOCKET_OUTPUT_FLAG | wxSOCKET_CONNECTION_FLAG | wxSOCKET_LOST_FLAG);
226                m_socket->Notify(true);
227                m_recvBufferPos = 0;
228
229                wxIPV4address addr;
230                addr.Hostname(_T("probe.filezilla-project.org"));
231                addr.Service(21);
232
233                m_socket->Connect(addr, false);
234        }
235}
236
237void CNetConfWizard::OnPageChanged(wxWizardEvent& event)
238{
239        if (event.GetPage() == m_pages[5])
240        {
241                wxButton* pNext = wxDynamicCast(FindWindow(wxID_FORWARD), wxButton);
242                m_nextLabelText = pNext->GetLabel();
243                pNext->SetLabel(_("&Test"));
244        }
245        else if (event.GetPage() == m_pages[6])
246        {
247                wxButton* pPrev = wxDynamicCast(FindWindow(wxID_BACKWARD), wxButton);
248                pPrev->Disable();
249                wxButton* pNext = wxDynamicCast(FindWindow(wxID_FORWARD), wxButton);
250                pNext->SetFocus();
251        }
252}
253
254void CNetConfWizard::OnSocketEvent(wxSocketEvent& event)
255{
256        if (!m_socket)
257                return;
258
259        if (event.GetSocket() == m_socket)
260        {
261                switch (event.GetSocketEvent())
262                {
263                case wxSOCKET_INPUT:
264                        OnReceive();
265                        break;
266                case wxSOCKET_OUTPUT:
267                        OnSend();
268                        break;
269                case wxSOCKET_LOST:
270                        OnClose();
271                        break;
272                case wxSOCKET_CONNECTION:
273                        OnConnect();
274                        break;
275                }
276        }
277        else if (event.GetSocket() == m_pSocketServer)
278        {
279                switch (event.GetSocketEvent())
280                {
281                case wxSOCKET_LOST:
282                        PrintMessage(_("Listen socket closed"), 1);
283                        CloseSocket();
284                        break;
285                case wxSOCKET_CONNECTION:
286                        OnAccept();
287                        break;
288                default:
289                        break;
290                }
291        }
292        else if (event.GetSocket() == m_pDataSocket)
293        {
294                switch (event.GetSocketEvent())
295                {
296                case wxSOCKET_LOST:
297                        OnDataClose();
298                        break;
299                case wxSOCKET_INPUT:
300                        OnDataReceive();
301                        break;
302                default:
303                        break;
304                }
305        }
306}
307
308void CNetConfWizard::OnSend()
309{
310        if (!m_pSendBuffer)
311                return;
312
313        if (!m_socket)
314                return;
315
316        int len = strlen(m_pSendBuffer);
317        m_socket->Write(m_pSendBuffer, len);
318        if (m_socket->Error())
319        {
320                if (m_socket->LastError() != wxSOCKET_WOULDBLOCK)
321                {
322                        PrintMessage(_("Failed to send command."), 1);
323                        CloseSocket();
324                }
325                return;
326        }
327        int written = m_socket->LastCount();
328        if (written == len)
329        {
330                delete [] m_pSendBuffer;
331                m_pSendBuffer = 0;
332        }
333        else
334                memmove(m_pSendBuffer, m_pSendBuffer + written, len - written + 1);
335}
336
337void CNetConfWizard::OnClose()
338{
339        CloseSocket();
340}
341
342void CNetConfWizard::OnConnect()
343{
344        m_connectSuccessful = true;
345}
346
347void CNetConfWizard::OnReceive()
348{
349        m_socket->Read(m_recvBuffer + m_recvBufferPos, NETCONFBUFFERSIZE - m_recvBufferPos);
350        unsigned int len;
351        if (m_socket->Error() || !(len = m_socket->LastCount()))
352        {
353                PrintMessage(_("Connection lost"), 1);
354                CloseSocket();
355                return;
356        }
357
358        m_recvBufferPos += len;
359
360        if (m_recvBufferPos < 3)
361                return;
362
363        for (int i = 0; i < m_recvBufferPos - 1; i++)
364        {
365                if (m_recvBuffer[i] == '\n')
366                {
367                        m_testResult = servererror;
368                        PrintMessage(_("Invalid data received"), 1);
369                        CloseSocket();
370                        return;
371                }
372                if (m_recvBuffer[i] != '\r')
373                        continue;
374
375                if (m_recvBuffer[i + 1] != '\n')
376                {
377                        m_testResult = servererror;
378                        PrintMessage(_("Invalid data received"), 1);
379                        CloseSocket();
380                        return;
381                }
382                m_recvBuffer[i] = 0;
383
384                if (!*m_recvBuffer)
385                {
386                        m_testResult = servererror;
387                        PrintMessage(_("Invalid data received"), 1);
388                        CloseSocket();
389                        return;
390                }
391
392                ParseResponse(m_recvBuffer);
393
394                if (!m_socket)
395                        return;
396
397                memmove(m_recvBuffer, m_recvBuffer + i + 2, m_recvBufferPos - i - 2);
398                m_recvBufferPos -= i + 2;
399                i = -1;
400        }
401}
402
403void CNetConfWizard::ParseResponse(const char* line)
404{
405        if (m_timer.IsRunning())
406                m_timer.Stop();
407
408        const int len = strlen(line);
409        wxString msg(line, wxConvLocal);
410        wxString str = _("Response:");
411        str += _T(" ");
412        str += msg;
413        PrintMessage(str, 3);
414
415        if (len < 3)
416        {
417                m_testResult = servererror;
418                PrintMessage(_("Server sent unexpected reply."), 1);
419                CloseSocket();
420                return;
421        }
422        if (line[3] && line[3] != ' ')
423        {
424                m_testResult = servererror;
425                PrintMessage(_("Server sent unexpected reply."), 1);
426                CloseSocket();
427                return;
428        }
429
430        if (line[0] == '1')
431                return;
432
433        switch (m_state)
434        {
435        case 3:
436                if (line[0] == '2')
437                        break;
438
439                if (line[1] == '0' && line[2] == '1')
440                {
441                        PrintMessage(_("Communication tainted by router or firewall"), 1);
442                        m_testResult = tainted;
443                        CloseSocket();
444                        return;
445                }
446                else if (line[1] == '1' && line[2] == '0')
447                {
448                        PrintMessage(_("Wrong external IP address"), 1);
449                        m_testResult = mismatch;
450                        CloseSocket();
451                        return;
452                }
453                else if (line[1] == '1' && line[2] == '1')
454                {
455                        PrintMessage(_("Wrong external IP address"), 1);
456                        PrintMessage(_("Communication tainted by router or firewall"), 1);
457                        m_testResult = mismatchandtainted;
458                        CloseSocket();
459                        return;
460                }
461                else
462                {
463                        m_testResult = servererror;
464                        PrintMessage(_("Server sent unexpected reply."), 1);
465                        CloseSocket();
466                        return;
467                }
468                break;
469        case 4:
470                if (line[0] != '2')
471                {
472                        m_testResult = servererror;
473                        PrintMessage(_("Server sent unexpected reply."), 1);
474                        CloseSocket();
475                        return;
476                }
477                else
478                {
479                        const char* p = line + len;
480                        while (*(--p) != ' ')
481                        {
482                                if (*p < '0' || *p > '9')
483                                {
484                                        m_testResult = servererror;
485                                        PrintMessage(_("Server sent unexpected reply."), 1);
486                                        CloseSocket();
487                                        return;
488                                }
489                        }
490                        m_data = 0;
491                        while (*++p)
492                                m_data = m_data * 10 + *p - '0';
493                }
494                break;
495        case 5:
496                if (line[0] == '2')
497                        break;
498
499
500                if (line[0] == '5' && line[1] == '0' && (line[2] == '1' || line[2] == '2'))
501                {
502                        m_testResult = tainted;
503                        PrintMessage(_("PORT command tainted by router or firewall."), 1);
504                        CloseSocket();
505                        return;
506                }
507
508                m_testResult = servererror;
509                PrintMessage(_("Server sent unexpected reply."), 1);
510                CloseSocket();
511                return;
512        case 6:
513                if (line[0] != '2' && line[0] != '3')
514                {
515                        m_testResult = servererror;
516                        PrintMessage(_("Server sent unexpected reply."), 1);
517                        CloseSocket();
518                        return;
519                }
520                if (m_pDataSocket)
521                {
522                        if (gotListReply)
523                        {
524                                m_testResult = servererror;
525                                PrintMessage(_("Server sent unexpected reply."), 1);
526                                CloseSocket();
527                        }
528                        gotListReply = true;
529                        return;
530                }
531                break;
532        default:
533                if (line[0] != '2' && line[0] != '3')
534                {
535                        m_testResult = servererror;
536                        PrintMessage(_("Server sent unexpected reply."), 1);
537                        CloseSocket();
538                        return;
539                }
540                break;
541        }
542
543        m_state++;
544
545        SendNextCommand();
546}
547
548void CNetConfWizard::PrintMessage(const wxString& msg, int type)
549{
550        XRCCTRL(*this, "ID_RESULTS", wxTextCtrl)->AppendText(msg + _T("\n"));
551}
552
553void CNetConfWizard::CloseSocket()
554{
555        if (!m_socket)
556                return;
557
558        PrintMessage(_("Connection closed"), 0);
559
560        wxButton* pNext = wxDynamicCast(FindWindow(wxID_FORWARD), wxButton);
561        pNext->Enable();
562        pNext->SetLabel(m_nextLabelText);
563
564        wxString text[5];
565        if (!m_connectSuccessful)
566        {
567                text[0] = _("Connection with the test server failed.");
568                text[1] = _("Please check on https://filezilla-project.org/probe.php that the server is running and carefully check your settings again.");
569                text[2] = _("If the problem persists, some router and/or firewall keeps blocking FileZilla.");
570        }
571        else
572        {
573                switch (m_testResult)
574                {
575                case unknown:
576                        text[0] = _("Connection with server got closed prematurely.");
577                        text[1] = _("Please ensure you have a stable internet connection and carefully check your settings again.");
578                        text[2] = _("If the problem persists, some router and/or firewall keeps interrupting the connection.");
579                        text[3] = _("See also: https://wiki.filezilla-project.org/Network_Configuration");
580                        break;
581                case successful:
582                        text[0] = _("Congratulations, your configuration seems to be working.");
583                        text[1] = _("You should have no problems connecting to other servers, file transfers should work properly.");
584                        text[2] = _("If you keep having problems with a specific server, the server itself or a remote router or firewall might be misconfigured. In this case try to toggle passive mode and contact the server administrator for help.");
585                        text[3] = _("Please run this wizard again should you change your network environment or in case you suddenly encounter problems with servers that did work previously.");
586                        text[4] = _("Click on Finish to save your configuration.");
587                        break;
588                case servererror:
589                        text[0] = _("The server sent an unexpected or unrecognized reply.");
590                        text[1] = _("This means that some router and/or firewall is still interfering with FileZilla.");
591                        text[2] = _("Re-run the wizard and carefully check your settings and configure all routers and firewalls accordingly.");
592                        text[3] = _("See also: https://wiki.filezilla-project.org/Network_Configuration");
593                        break;
594                case tainted:
595                        text[0] = _("Active mode FTP test failed. FileZilla knows the correct external IP address, but your router or firewall has misleadingly modified the sent address.");
596                        text[1] = _("Please update your firewall and make sure your router is using the latest available firmware. Furthermore, your router has to be configured properly. You will have to use manual port forwarding. Don't run your router in the so called 'DMZ mode' or 'game mode'. Things like protocol inspection or protocol specific 'fixups' have to be disabled");
597                        text[2] = _("If this problem stays, please contact your router manufacturer.");
598                        text[3] = _("Unless this problem gets fixed, active mode FTP will not work and passive mode has to be used.");
599                        if (XRCCTRL(*this, "ID_ACTIVE", wxRadioButton)->GetValue())
600                        {
601                                XRCCTRL(*this, "ID_PASSIVE", wxRadioButton)->SetValue(true);
602                                text[3] += _T(" ");
603                                text[3] += _("Passive mode has been set as default transfer mode.");
604                        }
605                        break;
606                case mismatchandtainted:
607                        text[0] = _("Active mode FTP test failed. FileZilla does not know the correct external IP address. In addition to that, your router has modified the sent address.");
608                        text[1] = _("Please enter your external IP address on the active mode page of this wizard. In case you have a dynamic address or don't know your external address, use the external resolver option.");
609                        text[2] = _("Please make sure your router is using the latest available firmware. Furthermore, your router has to be configured properly. You will have to use manual port forwarding. Don't run your router in the so called 'DMZ mode' or 'game mode'.");
610                        text[3] = _("If your router keeps changing the IP address, please contact your router manufacturer.");
611                        text[4] = _("Unless these problems get fixed, active mode FTP will not work and passive mode has to be used.");
612                        if (XRCCTRL(*this, "ID_ACTIVE", wxRadioButton)->GetValue())
613                        {
614                                XRCCTRL(*this, "ID_PASSIVE", wxRadioButton)->SetValue(true);
615                                text[4] += _T(" ");
616                                text[4] += _("Passive mode has been set as default transfer mode.");
617                        }
618                        break;
619                case mismatch:
620                        text[0] = _("Active mode FTP test failed. FileZilla does not know the correct external IP address.");
621                        text[1] = _("Please enter your external IP address on the active mode page of this wizard. In case you have a dynamic address or don't know your external address, use the external resolver option.");
622                        text[2] = _("Unless these problems get fixed, active mode FTP will not work and passive mode has to be used.");
623                        if (XRCCTRL(*this, "ID_ACTIVE", wxRadioButton)->GetValue())
624                        {
625                                XRCCTRL(*this, "ID_PASSIVE", wxRadioButton)->SetValue(true);
626                                text[2] += _T(" ");
627                                text[2] += _("Passive mode has been set as default transfer mode.");
628                        }
629                        break;
630                case externalfailed:
631                        text[0] = _("Failed to retrieve the external IP address.");
632                        text[1] = _("Please make sure FileZilla is allowed to establish outgoing connections and make sure you typed the address of the address resolver correctly.");
633                        text[2] = wxString::Format(_("The address you entered was: %s"), XRCCTRL(*this, "ID_ACTIVERESOLVER", wxTextCtrl)->GetValue());
634                        break;
635                case datatainted:
636                        text[0] = _("Transferred data got tainted.");
637                        text[1] = _("You likely have a router or firewall which erroneously modified the transferred data.");
638                        text[2] = _("Please disable settings like 'DMZ mode' or 'Game mode' on your router.");
639                        text[3] = _("If this problem persists, please contact your router or firewall manufacturer for a solution.");
640                        break;
641                }
642        }
643        for (unsigned int i = 0; i < 5; i++)
644        {
645                wxString name = wxString::Format(_T("ID_SUMMARY%d"), i + 1);
646                int id = wxXmlResource::GetXRCID(name);
647                wxDynamicCast(FindWindowById(id, this), wxStaticText)->SetLabel(text[i]);
648        }
649        m_pages[6]->GetSizer()->Layout();
650        m_pages[6]->GetSizer()->Fit(m_pages[6]);
651        wxGetApp().GetWrapEngine()->WrapRecursive(m_pages[6], m_pages[6]->GetSizer(), wxGetApp().GetWrapEngine()->GetWidthFromCache("Netconf"));
652
653        // Focus one so enter key hits finish and not the restart button by default
654        XRCCTRL(*this, "ID_SUMMARY1", wxStaticText)->SetFocus();
655
656        delete m_socket;
657        m_socket = 0;
658
659        delete [] m_pSendBuffer;
660        m_pSendBuffer = 0;
661
662        delete m_pSocketServer;
663        m_pSocketServer = 0;
664
665        delete m_pDataSocket;
666        m_pDataSocket = 0;
667
668        if (m_timer.IsRunning())
669                m_timer.Stop();
670}
671
672bool CNetConfWizard::Send(wxString cmd)
673{
674        wxASSERT(!m_pSendBuffer);
675
676        if (!m_socket)
677                return false;
678
679        PrintMessage(cmd, 2);
680
681        cmd += _T("\r\n");
682        wxCharBuffer buffer = cmd.mb_str();
683        unsigned int len = strlen(buffer);
684        m_pSendBuffer = new char[len + 1];
685        memcpy(m_pSendBuffer, buffer, len + 1);
686
687        m_timer.Start(15000, true);
688        OnSend();
689
690        return m_socket != 0;
691}
692
693wxString CNetConfWizard::GetExternalIPAddress()
694{
695        wxString ret;
696
697        wxASSERT(m_socket);
698
699        int mode = XRCCTRL(*this, "ID_ACTIVEMODE1", wxRadioButton)->GetValue() ? 0 : (XRCCTRL(*this, "ID_ACTIVEMODE2", wxRadioButton)->GetValue() ? 1 : 2);
700        if (!mode) {
701                wxIPV4address addr;
702                if (m_socket->GetLocal(addr)) {
703                        ret = addr.IPAddress();
704                }
705                else {
706                        PrintMessage(_("Failed to retrieve local ip address. Aborting"), 1);
707                        CloseSocket();
708                }
709        }
710        else if (mode == 1) {
711                wxTextCtrl* control = XRCCTRL(*this, "ID_ACTIVEIP", wxTextCtrl);
712                ret = control->GetValue();
713        }
714        else if (mode == 2) {
715                if (!m_pIPResolver) {
716                        wxTextCtrl* pResolver = XRCCTRL(*this, "ID_ACTIVERESOLVER", wxTextCtrl);
717                        wxString address = pResolver->GetValue();
718
719                        PrintMessage(wxString::Format(_("Retrieving external IP address from %s"), address), 0);
720
721                        m_pIPResolver = new CExternalIPResolver(*this);
722                        m_pIPResolver->GetExternalIP(address, CSocket::ipv4, true);
723                        if (!m_pIPResolver->Done())
724                                return wxString();
725                }
726                if (m_pIPResolver->Successful()) {
727                        ret = m_pIPResolver->GetIP();
728                }
729                else {
730                        PrintMessage(_("Failed to retrieve external ip address, aborting"), 1);
731
732                        m_testResult = externalfailed;
733                        CloseSocket();
734                }
735                delete m_pIPResolver;
736                m_pIPResolver = 0;
737        }
738
739        return ret;
740}
741
742void CNetConfWizard::OnExternalIPAddress2(wxCommandEvent&)
743{
744        if (!m_pIPResolver)
745                return;
746
747        if (m_state != 3)
748                return;
749
750        if (!m_pIPResolver->Done())
751                return;
752
753        SendNextCommand();
754}
755
756void CNetConfWizard::SendNextCommand()
757{
758        switch (m_state)
759        {
760        case 1:
761                if (!Send(_T("USER ") + wxString(PACKAGE_NAME, wxConvLocal)))
762                        return;
763                break;
764        case 2:
765                if (!Send(_T("PASS ") + wxString(PACKAGE_VERSION, wxConvLocal)))
766                        return;
767                break;
768        case 3:
769                {
770                        PrintMessage(_("Checking for correct external IP address"), 0);
771                        wxString ip = GetExternalIPAddress();
772                        if (ip.empty())
773                                return;
774                        if (!GetIPV6LongForm(ip).empty())
775                        {
776                                PrintMessage(_("You appear to be using an IPv6-only host. This wizard does not support this environment."), 1);
777                                CloseSocket();
778                                return;
779                        }
780                        m_externalIP = ip;
781
782                        wxString hexIP = ip;
783                        for (unsigned int i = 0; i < hexIP.Length(); i++) {
784                                wxChar c = hexIP[i];
785                                if (c == '.')
786                                        c = '-';
787                                else
788                                        c = c - '0' + 'a';
789                                hexIP.SetChar(i, c);
790                        }
791
792                        if (!Send(_T("IP ") + ip + _T(" ") + hexIP))
793                                return;
794
795                }
796                break;
797        case 4:
798                {
799                        int port = CreateListenSocket();
800                        if (!port)
801                        {
802                                PrintMessage(_("Failed to create listen socket, aborting"), 1);
803                                CloseSocket();
804                                return;
805                        }
806                        m_listenPort = port;
807                        Send(wxString::Format(_T("PREP %d"), port));
808                        break;
809                }
810        case 5:
811                {
812                        wxString cmd = wxString::Format(_T("PORT %s,%d,%d"), m_externalIP, m_listenPort / 256, m_listenPort % 256);
813                        cmd.Replace(_T("."), _T(","));
814                        Send(cmd);
815                }
816                break;
817        case 6:
818                Send(_T("LIST"));
819                break;
820        case 7:
821                m_testResult = successful;
822                Send(_T("QUIT"));
823                break;
824        case 8:
825                CloseSocket();
826                break;
827        }
828}
829
830void CNetConfWizard::OnRestart(wxCommandEvent& event)
831{
832        ResetTest();
833        ShowPage(m_pages[0], false);
834}
835
836void CNetConfWizard::ResetTest()
837{
838        if (m_timer.IsRunning())
839                m_timer.Stop();
840
841        m_state = 0;
842        m_connectSuccessful = false;
843
844        m_testDidRun = false;
845        m_testResult = unknown;
846        m_recvBufferPos = 0;
847        gotListReply = false;
848
849        if (!m_pages.empty())
850                XRCCTRL(*this, "ID_RESULTS", wxTextCtrl)->SetLabel(_T(""));
851}
852
853void CNetConfWizard::OnFinish(wxWizardEvent& event)
854{
855        if (m_testResult != successful)
856        {
857                if (wxMessageBoxEx(_("The test did not succeed. Do you really want to save the settings?"), _("Save settings?"), wxYES_NO | wxICON_QUESTION) != wxYES)
858                        return;
859        }
860
861        m_pOptions->SetOption(OPTION_USEPASV, XRCCTRL(*this, "ID_PASSIVE", wxRadioButton)->GetValue() ? 1 : 0);
862        m_pOptions->SetOption(OPTION_ALLOW_TRANSFERMODEFALLBACK, XRCCTRL(*this, "ID_FALLBACK", wxCheckBox)->GetValue() ? 1 : 0);
863
864        m_pOptions->SetOption(OPTION_PASVREPLYFALLBACKMODE, XRCCTRL(*this, "ID_PASSIVE_FALLBACK1", wxRadioButton)->GetValue() ? 0 : 1);
865
866        if (XRCCTRL(*this, "ID_ACTIVEMODE1", wxRadioButton)->GetValue())
867                m_pOptions->SetOption(OPTION_EXTERNALIPMODE, 0);
868        else
869                m_pOptions->SetOption(OPTION_EXTERNALIPMODE, XRCCTRL(*this, "ID_ACTIVEMODE2", wxRadioButton)->GetValue() ? 1 : 2);
870
871        m_pOptions->SetOption(OPTION_LIMITPORTS, XRCCTRL(*this, "ID_ACTIVE_PORTMODE1", wxRadioButton)->GetValue() ? 0 : 1);
872
873        long tmp;
874        XRCCTRL(*this, "ID_ACTIVE_PORTMIN", wxTextCtrl)->GetValue().ToLong(&tmp); m_pOptions->SetOption(OPTION_LIMITPORTS_LOW, tmp);
875        XRCCTRL(*this, "ID_ACTIVE_PORTMAX", wxTextCtrl)->GetValue().ToLong(&tmp); m_pOptions->SetOption(OPTION_LIMITPORTS_HIGH, tmp);
876
877        m_pOptions->SetOption(OPTION_EXTERNALIP, XRCCTRL(*this, "ID_ACTIVEIP", wxTextCtrl)->GetValue());
878        m_pOptions->SetOption(OPTION_EXTERNALIPRESOLVER, XRCCTRL(*this, "ID_ACTIVERESOLVER", wxTextCtrl)->GetValue());
879        m_pOptions->SetOption(OPTION_NOEXTERNALONLOCAL, XRCCTRL(*this, "ID_NOEXTERNALONLOCAL", wxCheckBox)->GetValue());
880}
881
882int CNetConfWizard::CreateListenSocket()
883{
884        if (m_pSocketServer)
885                return 0;
886
887        if (XRCCTRL(*this, "ID_ACTIVE_PORTMODE1", wxRadioButton)->GetValue())
888        {
889                return CreateListenSocket(0);
890        }
891        else
892        {
893                long low;
894                long high;
895                XRCCTRL(*this, "ID_ACTIVE_PORTMIN", wxTextCtrl)->GetValue().ToLong(&low);
896                XRCCTRL(*this, "ID_ACTIVE_PORTMAX", wxTextCtrl)->GetValue().ToLong(&high);
897
898                int mid = GetRandomNumber(low, high);
899                wxASSERT(mid >= low && mid <= high);
900
901                for (int port = mid; port <= high; port++)
902                        if (CreateListenSocket(port))
903                                return port;
904                for (int port = low; port < mid; port++)
905                        if (CreateListenSocket(port))
906                                return port;
907
908                return 0;
909        }
910}
911
912int CNetConfWizard::CreateListenSocket(unsigned int port)
913{
914        wxIPV4address addr;
915        if (!addr.AnyAddress())
916                return 0;
917
918        if (!addr.Service(port))
919                return 0;
920
921        m_pSocketServer = new wxSocketServer(addr, wxSOCKET_NOWAIT);
922        if (!m_pSocketServer->Ok())
923        {
924                delete m_pSocketServer;
925                m_pSocketServer = 0;
926                return 0;
927        }
928
929        m_pSocketServer->SetEventHandler(*this);
930        m_pSocketServer->SetFlags(wxSOCKET_NOWAIT);
931        m_pSocketServer->SetNotify(wxSOCKET_CONNECTION_FLAG | wxSOCKET_LOST_FLAG);
932        m_pSocketServer->Notify(true);
933
934
935        if (port)
936                return port;
937
938        // Get port number from socket
939        if (!m_pSocketServer->GetLocal(addr))
940        {
941                delete m_pSocketServer;
942                m_pSocketServer = 0;
943                return 0;
944        }
945        return addr.Service();
946}
947
948void CNetConfWizard::OnAccept()
949{
950        if (m_pDataSocket)
951                return;
952        m_pDataSocket = m_pSocketServer->Accept(false);
953        if (!m_pDataSocket)
954                return;
955
956        wxIPV4address peerAddr, dataPeerAddr;
957        if (!m_socket->GetPeer(peerAddr)) {
958                delete m_pDataSocket;
959                m_pDataSocket = 0;
960                PrintMessage(_("Failed to get peer address of control connection, connection closed."), 1);
961                CloseSocket();
962                return;
963        }
964        if (!m_pDataSocket->GetPeer(dataPeerAddr)) {
965                delete m_pDataSocket;
966                m_pDataSocket = 0;
967                PrintMessage(_("Failed to get peer address of data connection, connection closed."), 1);
968                CloseSocket();
969                return;
970        }
971        if (peerAddr.IPAddress() != dataPeerAddr.IPAddress()) {
972                delete m_pDataSocket;
973                m_pDataSocket = 0;
974                PrintMessage(_("Warning, ignoring data connection from wrong IP."), 0);
975                return;
976        }
977        delete m_pSocketServer;
978        m_pSocketServer = 0;
979
980        m_pDataSocket->SetEventHandler(*this);
981        m_pDataSocket->SetFlags(wxSOCKET_NOWAIT);
982        m_pDataSocket->SetNotify(wxSOCKET_INPUT_FLAG | wxSOCKET_LOST_FLAG);
983        m_pDataSocket->Notify(true);
984}
985
986void CNetConfWizard::OnDataReceive()
987{
988        char buffer[100];
989        m_pDataSocket->Read(buffer, 99);
990        unsigned int len;
991        if (m_pDataSocket->Error() || !(len = m_pDataSocket->LastCount()))
992        {
993                PrintMessage(_("Data socket closed too early."), 1);
994                CloseSocket();
995                return;
996        }
997        buffer[len] = 0;
998
999        int data = 0;
1000        const char* p = buffer;
1001        while (*p && *p != ' ')
1002        {
1003                if (*p < '0' || *p > '9')
1004                {
1005                        m_testResult = datatainted;
1006                        PrintMessage(_("Received data tainted"), 1);
1007                        CloseSocket();
1008                        return;
1009                }
1010                data = data * 10 + *p++ - '0';
1011        }
1012        if (data != m_data)
1013        {
1014                m_testResult = datatainted;
1015                PrintMessage(_("Received data tainted"), 1);
1016                CloseSocket();
1017                return;
1018        }
1019        p++;
1020        if (p - buffer != (int)len - 4)
1021        {
1022                PrintMessage(_("Failed to receive data"), 1);
1023                CloseSocket();
1024                return;
1025        }
1026
1027        wxUint32 ip = 0;
1028        for (const wxChar* q = m_externalIP.c_str(); *q; q++)
1029        {
1030                if (*q == '.')
1031                        ip *= 256;
1032                else
1033                        ip = ip - (ip % 256) + (ip % 256) * 10 + *q - '0';
1034        }
1035        ip = wxUINT32_SWAP_ON_LE(ip);
1036        if (memcmp(&ip, p, 4)) {
1037                m_testResult = datatainted;
1038                PrintMessage(_("Received data tainted"), 1);
1039                CloseSocket();
1040                return;
1041        }
1042
1043        delete m_pDataSocket;
1044        m_pDataSocket = 0;
1045
1046        if (gotListReply) {
1047                m_state++;
1048                SendNextCommand();
1049        }
1050}
1051
1052void CNetConfWizard::OnDataClose()
1053{
1054        OnDataReceive();
1055        if (m_pDataSocket)
1056        {
1057                PrintMessage(_("Data socket closed too early."), 0);
1058                CloseSocket();
1059                return;
1060        }
1061        delete m_pDataSocket;
1062        m_pDataSocket = 0;
1063
1064        if (gotListReply)
1065        {
1066                m_state++;
1067                SendNextCommand();
1068        }
1069}
1070
1071void CNetConfWizard::OnTimer(wxTimerEvent& event)
1072{
1073        if (event.GetId() != m_timer.GetId())
1074                return;
1075
1076        PrintMessage(_("Connection timed out."), 0);
1077        CloseSocket();
1078}
1079
1080void CNetConfWizard::operator()(CEventBase const& ev)
1081{
1082        if (Dispatch<CExternalIPResolveEvent>(ev, this, &CNetConfWizard::OnExternalIPAddress))
1083                return;
1084}
1085
1086void CNetConfWizard::OnExternalIPAddress()
1087{
1088        QueueEvent(new wxCommandEvent(fzEVT_ON_EXTERNAL_IP_ADDRESS));
1089}
Note: See TracBrowser for help on using the repository browser.