1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198
|
#include <iostream>
#include <iomanip>
#include <locale>
#include <sstream>
#include <sigxconfig.h>
#ifdef SIGC_MSC
// windows and msvc++
# if (_WIN32_WINNT >= 0x0501)
# include <winsock2.h>
# else
// must include for versions earlier than win xp
# include <Wspiapi.h>
# endif
#else
#include <arpa/inet.h>
#include <netdb.h>
#endif
#include <sigc++/sigc++.h>
#include "thegui.h"
using namespace std;
TheGUI::InfoDialog::InfoDialog(Gtk::Window& parent):
Gtk::Dialog("", parent, true)
{
Gtk::HBox* hbox = Gtk::manage(new Gtk::HBox(false, 5));
Gtk::Image* ico = Gtk::manage(new Gtk::Image(Gtk::Stock::DIALOG_INFO, Gtk::ICON_SIZE_DIALOG));
Gtk::Label* lbl = Gtk::manage(new Gtk::Label("The IP address resolver is still working.\nThis could take up to some minutes..."));
hbox->pack_start(*ico, Gtk::PACK_SHRINK);
hbox->pack_start(*lbl, Gtk::PACK_SHRINK);
get_vbox()->add(*hbox);
add_button(Gtk::Stock::STOP, Gtk::RESPONSE_OK);
set_has_separator();
show_all_children();
}
TheGUI::TheGUI():
Gtk::Window(),
sigx::glib_auto_dispatchable(),
m_resolver(),
m_connResolved(),
m_connResolvingStopped(),
m_pentryIP(),
m_pentryHostname(),
m_ptvError()
{
Gtk::Label* pLabelIP = Gtk::manage(new Gtk::Label("IP Address:", Gtk::ALIGN_LEFT));
m_pentryIP = Gtk::manage(new Gtk::Entry);
m_pentryIP->set_activates_default();
m_pentryIP->set_editable(false);
Gtk::Label* plabelHostname = Gtk::manage(new Gtk::Label("Hostname:", Gtk::ALIGN_LEFT));
m_pentryHostname = Gtk::manage(new Gtk::Entry);
m_pentryHostname->set_editable(false);
Gtk::Label* plabelError = Gtk::manage(new Gtk::Label("Error:", Gtk::ALIGN_LEFT));
m_ptvError = Gtk::manage(new Gtk::TextView);
m_ptvError->set_editable(false);
Gtk::Button* pbtnResolve = Gtk::manage(new Gtk::Button(Gtk::Stock::CONVERT));
pbtnResolve->property_can_default() = true;
Gtk::HBox* phboxIP = Gtk::manage(new Gtk::HBox(false, 5));
phboxIP->pack_start(*pLabelIP, Gtk::PACK_SHRINK);
phboxIP->pack_start(*m_pentryIP);
phboxIP->pack_start(*pbtnResolve, Gtk::PACK_SHRINK);
Gtk::HBox* phboxHostname = Gtk::manage(new Gtk::HBox(false, 5));
phboxHostname->pack_start(*plabelHostname, Gtk::PACK_SHRINK);
phboxHostname->pack_start(*m_pentryHostname);
Gtk::HBox* phboxError = Gtk::manage(new Gtk::HBox(false, 5));
phboxError->pack_start(*plabelError, Gtk::PACK_SHRINK);
phboxError->pack_start(*m_ptvError);
Gtk::VBox* pvboxAll = Gtk::manage(new Gtk::VBox);
pvboxAll->pack_start(*phboxIP, Gtk::PACK_SHRINK, 5);
pvboxAll->pack_start(*phboxHostname, Gtk::PACK_SHRINK, 5);
pvboxAll->pack_start(*phboxError, Gtk::PACK_SHRINK, 5);
add(*pvboxAll);
set_default(*pbtnResolve);
show_all_children();
pbtnResolve->signal_clicked().connect(sigc::mem_fun(this, &TheGUI::on_resolve));
// one-shot idle handler
Glib::signal_idle().connect(sigc::bind_return(sigc::mem_fun(this, &TheGUI::on_gui_ready), false));
// we connect to the resolver's signals in on_gui_ready() when the
// resolver thread is started and ready
}
bool TheGUI::on_delete_event(GdkEventAny*)
{
m_pentryIP->property_editable() = false;
// display an info dialog after 3 seconds if the program does not
// end because the resolver is still resolving
InfoDialog::threadsafe_type dlg(new InfoDialog(*this));
Glib::signal_timeout().connect(
sigc::bind_return(
sigc::bind(
sigc::mem_fun(this, &TheGUI::on_display_infomessage),
dlg
),
false
),
3000
);
m_connResolved.disconnect();
cout << "waiting for resolver to stop resolving.." << endl;
m_connResolvingStopped = m_resolver.signal_resolving_stopped().connect(
sigc::bind(
sigc::mem_fun(this, &TheGUI::on_resolving_stopped),
dlg
)
);
m_resolver.stop_resolving();
return true; // do not proceed
}
void TheGUI::on_gui_ready()
{
cout << "waiting for resolver to be ready" << endl;
m_resolver.run();
m_connResolved = m_resolver.signal_resolved().connect(
sigc::mem_fun(this, &TheGUI::on_resolved)
);
cout << "connected to the resolver: " << boolalpha << m_connResolved.connected() << endl;
m_pentryIP->set_editable(true);
}
void TheGUI::on_resolved(const std::string& strHost, guint32 nIP, int nErr)
{
m_pentryHostname->set_text(strHost);
if (nErr)
{
const Glib::RefPtr<Gtk::TextBuffer> pTextBuf = m_ptvError->get_buffer();
#ifdef SIGC_MSC
char* pBuf(0);
// FormatMessage returns the number of characters stored in the output buffer, excluding the terminating null character
const DWORD nLen = FormatMessageA(
FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM,
0, nErr, 0,
// must be a char** if FORMAT_MESSAGE_ALLOCATE_BUFFER is specified above
reinterpret_cast<char*>(&pBuf), 0,
0
);
pTextBuf->set_text(Glib::locale_to_utf8(pBuf));
LocalFree(pBuf);
#else
pTextBuf->set_text(Glib::locale_to_utf8(hstrerror(nErr)));
#endif
}
}
void TheGUI::on_display_infomessage(InfoDialog::threadsafe_type pDlg)
{
if (pDlg->run() == Gtk::RESPONSE_OK)
// user clicked "stop", don't wait for resolver thread
hide();
}
void TheGUI::on_resolving_stopped(InfoDialog::threadsafe_type pDlg)
{
cout << "resolver stopped resolving" << endl;
// quit the info dialog eventually
pDlg->response(Gtk::RESPONSE_DELETE_EVENT);
m_connResolvingStopped.disconnect();
m_resolver.finish();
// now quit the main loop
hide();
}
void TheGUI::on_resolve()
{
m_pentryHostname->set_text(Glib::ustring());
m_ptvError->get_buffer()->set_text(Glib::ustring());
const Glib::ustring& strIP = m_pentryIP->get_text();
#ifdef SIGC_MSC
const in_addr_t nIP = inet_addr(strIP.c_str());
if (nIP != INADDR_NONE)
m_resolver.resolve(nIP);
#else
in_addr addr = {};
if (inet_aton(strIP.c_str(), &addr) != 0)
m_resolver.resolve(addr.s_addr);
#endif
else
{
m_ptvError->get_buffer()->set_text("\"" + strIP + "\" is not a valid ip address");
cerr << ("\"" + strIP + "\" is not a valid ip address") << endl;
}
}
|