lib: added implicit ctor converter from DatabaseDatabase to DBListType
[barry/progweb.git] / desktop / src / ModemDlg.cc
blobab1e5f0a4735d9e4615e98a3b9863b9e58e2329e
1 ///
2 /// \file ModemDlg.cc
3 /// Dialog class to handle modem functionality
4 ///
6 /*
7 Copyright (C) 2012, Net Direct Inc. (http://www.netdirect.ca/)
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
18 See the GNU General Public License in the COPYING file at the
19 root directory of this project for more details.
22 #include "ModemDlg.h"
23 #include "windowids.h"
24 #include "exechelper.h"
25 #include "barrydesktop.h"
26 #include "tempdir.h"
27 #include <iostream>
28 #include <sstream>
29 #include <algorithm>
30 #include <unistd.h>
31 #include <sys/types.h>
32 #include <grp.h>
33 #include <limits.h>
34 #include <stdlib.h>
35 #include <wx/dir.h>
36 #include <wx/filename.h>
37 #include <barry/barry.h>
39 using namespace std;
41 // begin wxGlade: ::extracode
42 // end wxGlade
45 ModemDlg::ModemDlg(wxWindow* parent,
46 const std::vector<std::string> &peers,
47 const std::string &default_peer,
48 const Barry::Pin &pin)
49 : wxDialog(parent, Dialog_Modem, _T("Modem Kickstart"))
51 bottom_buttons = CreateButtonSizer(wxOK | wxCANCEL);
53 // begin wxGlade: ModemDlg::ModemDlg
54 sizer_5_staticbox = new wxStaticBox(this, -1, wxT("Device"));
55 sizer_1_staticbox = new wxStaticBox(this, -1, wxT("Providers"));
56 label_2 = new wxStaticText(this, wxID_ANY, wxT("For device pin:"));
57 device_label = new wxStaticText(this, wxID_ANY, wxT("3009efe3"));
58 const wxString list_box_1_choices[] = {
59 wxT("barry-minimal"),
60 wxT("barry-rogers"),
61 wxT("barry-testing")
63 list_box_1 = new wxListBox(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, 3, list_box_1_choices, wxLB_SINGLE);
64 label_1 = new wxStaticText(this, wxID_ANY, wxT("Password:"));
65 text_ctrl_1 = new wxTextCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_PASSWORD);
67 set_properties();
68 do_layout();
69 // end wxGlade
71 // add all peers to the listbox
72 list_box_1->Clear();
73 int default_index = -1, index = 0;
74 for( std::vector<std::string>::const_iterator i = peers.begin();
75 i != peers.end(); ++i, ++index )
77 if( default_peer == *i )
78 default_index = index;
79 list_box_1->Append(wxString(i->c_str(), wxConvUTF8));
82 if( default_index >= 0 ) {
83 list_box_1->SetSelection(default_index);
85 else {
86 list_box_1->SetSelection(0);
89 // set the PIN value
90 device_label->SetLabel(wxString(pin.Str().c_str(), wxConvUTF8));
93 void ModemDlg::set_properties()
95 // begin wxGlade: ModemDlg::set_properties
96 SetTitle(wxT("Modem Starter"));
97 device_label->SetMinSize(wxSize(100, -1));
98 list_box_1->SetMinSize(wxSize(-1, 150));
99 list_box_1->SetToolTip(wxT("Available provider scripts on your system. Must pick one."));
100 list_box_1->SetSelection(0);
101 label_1->SetToolTip(wxT("Optional device password"));
102 text_ctrl_1->SetMinSize(wxSize(150, -1));
103 text_ctrl_1->SetToolTip(wxT("Optional device password"));
104 // end wxGlade
108 void ModemDlg::do_layout()
110 // begin wxGlade: ModemDlg::do_layout
111 wxBoxSizer* sizer_2 = new wxBoxSizer(wxHORIZONTAL);
112 wxBoxSizer* sizer_3 = new wxBoxSizer(wxVERTICAL);
113 wxStaticBoxSizer* sizer_5 = new wxStaticBoxSizer(sizer_5_staticbox, wxHORIZONTAL);
114 wxStaticBoxSizer* sizer_1 = new wxStaticBoxSizer(sizer_1_staticbox, wxVERTICAL);
115 wxBoxSizer* sizer_4 = new wxBoxSizer(wxHORIZONTAL);
116 sizer_4->Add(label_2, 0, wxRIGHT|wxALIGN_CENTER_VERTICAL, 2);
117 sizer_4->Add(device_label, 0, wxLEFT|wxALIGN_CENTER_VERTICAL, 10);
118 sizer_3->Add(sizer_4, 0, wxBOTTOM|wxEXPAND, 5);
119 sizer_1->Add(list_box_1, 0, wxEXPAND, 0);
120 sizer_3->Add(sizer_1, 0, wxEXPAND, 0);
121 sizer_5->Add(label_1, 0, wxRIGHT|wxALIGN_CENTER_VERTICAL, 2);
122 sizer_5->Add(text_ctrl_1, 0, 0, 0);
123 sizer_3->Add(sizer_5, 1, wxEXPAND, 0);
124 sizer_2->Add(sizer_3, 0, wxALL|wxEXPAND, 7);
125 // end wxGlade
127 sizer_3->Add(bottom_buttons, 0, wxTOP|wxEXPAND, 5);
129 SetSizer(sizer_2);
130 sizer_2->Fit(this);
131 Layout();
135 // ProgramDetect
137 /// Searches for the given program name, in various directories, and
138 /// stores the following info:
139 /// Exists() - file exists, and if true, then:
140 /// GetPath() - returns full path of file, and:
141 /// IsExecutable() - returns true if file is a runnable program
142 /// IsSuid() - returns true if file is suid
143 /// GetGroup() - returns the group name of the file
145 /// For pppd, for example, this may return on Debian:
146 /// exists? true
147 /// path? /usr/sbin/pppd
148 /// executable? true if user in group, false if not
149 /// suid? true, suid root on Debian
150 /// group? uses the 'dip' group on Debian
152 /// On Fedora:
153 /// exists? true
154 /// path? /usr/sbin/pppd
155 /// exec? true
156 /// suid? false
157 /// group? root
159 class ProgramDetect
161 std::string m_path;
162 std::string m_group;
163 bool m_executable;
164 bool m_suid;
166 public:
167 void Dump(std::ostream &os)
169 os << "Path: " << m_path << "\n";
170 os << "Group: " << m_group << "\n";
171 os << "Exec: " << (m_executable ? "true" : "false") << "\n";
172 os << "Suid: " << (m_suid ? "true" : "false") << "\n";
175 const std::string& GetPath() const { return m_path; }
176 const std::string& GetGroup() const { return m_group; }
177 bool Exists() const { return m_path.size() > 0; }
178 bool IsExecutable() const { return m_executable; }
179 bool IsSuid() const { return m_suid; }
181 bool CheckPath(const std::string &path)
183 if( access(path.c_str(), F_OK) == 0 ) {
184 m_path = path;
185 return true;
187 return false;
190 void CheckAll(const char *prog, const std::string &path)
192 istringstream iss(path);
193 string p;
195 while( getline(iss, p, ':') ) {
196 string f = p + "/" + prog;
197 if( CheckPath(f) )
198 return;
202 ProgramDetect(const char *prog, const std::string &path)
203 : m_executable(false)
204 , m_suid(false)
206 // find the program first
207 CheckAll(prog, path);
209 // does it exist?
210 if( !m_path.size() )
211 return; // nope
213 // executable?
214 if( access(m_path.c_str(), X_OK) == 0 ) {
215 m_executable = true;
218 // suid?
219 struct stat s;
220 if( stat(m_path.c_str(), &s) == 0 ) {
221 if( s.st_mode & S_ISUID ) {
222 m_suid = true;
226 struct group *g = getgrgid(s.st_gid);
227 if( g ) {
228 m_group = g->gr_name;
234 std::string ModemDlg::GetPeerName() const
236 return string(list_box_1->GetStringSelection().utf8_str());
239 std::string ModemDlg::GetPassword() const
241 return string(text_ctrl_1->GetValue().utf8_str());
244 void ModemDlg::DoModem(wxWindow *parent, const Barry::Pin &pin)
247 // Search for dependency programs: xterm, pppd, gksu, etc.
250 // test whether xterm is in the path
251 ProgramDetect xterm("xterm", getenv("PATH"));
252 if( !xterm.Exists() || !xterm.IsExecutable() ) {
253 wxMessageBox(_T("Cannot locate the xterm program. This is used to display modem connection output. Please install it and try again."), _T("Xterm Not Found"), wxOK | wxICON_ERROR, parent);
254 return;
257 // test whether we can run pppd, probably need to use full
258 // /usr/sbin/pppd path to reach it... check for return code
259 // of 0 or 2
260 ProgramDetect pppd("pppd", "/usr/sbin:/usr/bin");
261 if( !pppd.Exists() ) {
262 wxMessageBox(_T("Cannot find pppd. Please install it for modem use."), _T("pppd Not Found"), wxOK | wxICON_ERROR, parent);
263 return;
268 // Check if we need root access to run pppd
270 string need_sudo;
272 if( pppd.IsExecutable() && pppd.IsSuid() ) {
273 // all good!
275 else if( !pppd.IsExecutable() && pppd.IsSuid() && pppd.GetGroup() != "root" ) {
276 wxString gname(pppd.GetGroup().c_str(), wxConvUTF8);
277 wxString msg = wxString::Format(_T("Your system's PPP has the suid bit set, with a group of '%s'. You should add your account to the '%s' group, to avoid the need to enter the root password every time you use the modem.\n\nContinue anyway?"), gname.c_str(), gname.c_str());
278 int choice = wxMessageBox(msg, _T("System Group"), wxYES_NO,
279 parent);
280 if( choice != wxYES )
281 return;
283 need_sudo = BARRYDESKTOP_SYSTEM_GUI_SU + string(" ");
285 else if( pppd.IsExecutable() && !pppd.IsSuid() ) {
286 need_sudo = BARRYDESKTOP_SYSTEM_GUI_SU + string(" ");
290 // Check if we can run pppd, in the non-root case
292 if( need_sudo.size() == 0 ) {
293 ExecHelper eh(0);
294 wxString cmd((pppd.GetPath() + " permission_test").c_str(), wxConvUTF8);
295 if( !eh.Run(0, "", cmd) ) {
296 wxMessageBox(_T("Internal fork error. Should never happen."), _T("Cannot Run pppd"), wxOK | wxICON_ERROR, parent);
297 return;
300 eh.WaitForChild();
301 if( !(eh.GetChildExitCode() == 0 || eh.GetChildExitCode() == 2) ) {
302 wxString msg = wxString::Format(_T("Unable to run pppd correctly. Unexpected error code: %d, %s"), eh.GetChildExitCode(), cmd.c_str());
303 wxMessageBox(msg, _T("Error Code"), wxOK | wxICON_ERROR, parent);
304 return;
309 // Load all peer files.
311 // do a search in /etc/ppp/peers for all barry-* files and
312 // store in a vector
314 std::vector<std::string> peers;
315 wxDir dir(wxString("/etc/ppp/peers", wxConvUTF8));
316 if( !dir.IsOpened() ) {
317 wxMessageBox(_T("Unable to access files in /etc/ppp/peers. Do you have the correct permissions?"), _T("Cannot Open Peers"), wxOK | wxICON_ERROR, parent);
318 return;
320 wxString filename;
321 bool cont = dir.GetFirst(&filename, _T("barry-*"), wxDIR_FILES);
322 while( cont ) {
323 peers.push_back( string(filename.utf8_str()) );
324 cont = dir.GetNext(&filename);
327 // anything available?
328 if( !peers.size() ) {
329 wxMessageBox(_T("No providers found. Make sure Barry was properly installed, with peer files in /etc/ppp/peers."), _T("No Providers"), wxOK | wxICON_ERROR, parent);
330 return;
333 // sort the vector
334 sort(peers.begin(), peers.end());
338 // Double check that we can read the peer files
341 // do an access or file open test on the first barry-* file
342 // to make sure that we have access to peers/
343 string testfile = "/etc/ppp/peers/" + peers[0];
344 if( access(testfile.c_str(), R_OK) != 0 ) {
345 wxString msg = wxString::Format(_T("Cannot read provider files under /etc/ppp/peers. Please check your file permissions. (Access failed for %s)"), wxString(testfile.c_str(), wxConvUTF8).c_str());
346 wxMessageBox(msg, _T("Permissions Error"), wxOK | wxICON_ERROR, parent);
347 return;
352 // Fetch default peer choice
354 Barry::GlobalConfigFile &config = wxGetApp().GetGlobalConfig();
355 string key = pin.Str() + "-DefaultPeer";
356 string default_peer = config.GetKey(key);
360 // Show the dialog
362 ModemDlg dlg(parent, peers, default_peer, pin);
363 if( dlg.ShowModal() == wxID_OK ) {
364 string peer = dlg.GetPeerName();
365 string peerfile = "/etc/ppp/peers/" + peer;
366 if( !peer.size() || access(peerfile.c_str(), R_OK) != 0 ) {
367 wxString msg = wxString::Format(_T("Unable to open peer file: %s"), wxString(peerfile.c_str(), wxConvUTF8).c_str());
368 wxMessageBox(msg, _T("Invalid Peer"), wxOK | wxICON_ERROR, parent);
369 return;
372 // save peer selection as default for this device
373 config.SetKey(key, peer);
375 // create shell script which calls pppd
376 TempDir tempdir("BarryDesktopModem");
377 string tmp_path = tempdir.GetNewFilename();
379 ofstream otmp(tmp_path.c_str());
380 otmp << "#!/bin/sh" << endl;
381 otmp << "echo Starting pppd for device PIN "
382 << pin.Str() << "... " << endl;
384 ostringstream cmdoss;
385 cmdoss << need_sudo << pppd.GetPath() << " call " << peer;
387 // show command with echo too
388 otmp << "echo" << endl;
389 otmp << "echo '" << cmdoss.str() << "'" << endl;
390 otmp << cmdoss.str() << endl;
392 otmp << "echo Press enter to close window..." << endl;
393 otmp << "read" << endl;
394 otmp.close();
396 chmod(tmp_path.c_str(), S_IRUSR | S_IRGRP | S_IROTH |
397 S_IXUSR | S_IXGRP | S_IXOTH);
399 // create command line using xterm as display
400 wxString xterm_cmd((xterm.GetPath() + " " + tmp_path).c_str(),
401 wxConvUTF8);
403 // setup argument fifo
404 Barry::FifoArgs args;
405 args.m_password = dlg.GetPassword();
406 args.m_pin = pin;
407 Barry::FifoServer fifo(args);
409 // run! and go back to main screen
410 ExecHelper run(0);
411 run.Run(parent, "modem", xterm_cmd);
413 fifo.Serve(5);