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

Last change on this file since 3185 was 3185, checked in by jrpelegrina, 2 years ago

Update new version: 3.15.02

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