3 /// Dialog class to handle modem functionality
7 Copyright (C) 2012-2013, 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.
23 #include "windowids.h"
24 #include "exechelper.h"
25 #include "barrydesktop.h"
31 #include <sys/types.h>
36 #include <wx/filename.h>
37 #include <barry/barry.h>
42 // begin wxGlade: ::extracode
46 ModemDlg::ModemDlg(wxWindow
* parent
,
47 const std::vector
<std::string
> &peers
,
48 const std::string
&default_peer
,
49 const Barry::Pin
&pin
)
50 : wxDialog(parent
, Dialog_Modem
, _W("Modem Kickstart"))
52 bottom_buttons
= CreateButtonSizer(wxOK
| wxCANCEL
);
54 // begin wxGlade: ModemDlg::ModemDlg
55 sizer_5_staticbox
= new wxStaticBox(this, -1, _W("Device"));
56 sizer_1_staticbox
= new wxStaticBox(this, -1, _W("Providers"));
57 label_2
= new wxStaticText(this, wxID_ANY
, _W("For device pin:"));
58 device_label
= new wxStaticText(this, wxID_ANY
, wxT("3009efe3"));
59 const wxString list_box_1_choices
[] = {
64 list_box_1
= new wxListBox(this, wxID_ANY
, wxDefaultPosition
, wxDefaultSize
, 3, list_box_1_choices
, wxLB_SINGLE
);
65 label_1
= new wxStaticText(this, wxID_ANY
, _W("Password:"));
66 text_ctrl_1
= new wxTextCtrl(this, wxID_ANY
, wxEmptyString
, wxDefaultPosition
, wxDefaultSize
, wxTE_PASSWORD
);
72 // add all peers to the listbox
74 int default_index
= -1, index
= 0;
75 for( std::vector
<std::string
>::const_iterator i
= peers
.begin();
76 i
!= peers
.end(); ++i
, ++index
)
78 if( default_peer
== *i
)
79 default_index
= index
;
80 list_box_1
->Append(wxString(i
->c_str(), wxConvUTF8
));
83 if( default_index
>= 0 ) {
84 list_box_1
->SetSelection(default_index
);
87 list_box_1
->SetSelection(0);
91 device_label
->SetLabel(wxString(pin
.Str().c_str(), wxConvUTF8
));
94 void ModemDlg::set_properties()
96 // begin wxGlade: ModemDlg::set_properties
97 SetTitle(_W("Modem Starter"));
98 device_label
->SetMinSize(wxSize(100, -1));
99 list_box_1
->SetMinSize(wxSize(-1, 150));
100 list_box_1
->SetToolTip(_W("Available provider scripts on your system. Must pick one."));
101 list_box_1
->SetSelection(0);
102 label_1
->SetToolTip(_W("Optional device password"));
103 text_ctrl_1
->SetMinSize(wxSize(150, -1));
104 text_ctrl_1
->SetToolTip(_W("Optional device password"));
109 void ModemDlg::do_layout()
111 // begin wxGlade: ModemDlg::do_layout
112 wxBoxSizer
* sizer_2
= new wxBoxSizer(wxHORIZONTAL
);
113 wxBoxSizer
* sizer_3
= new wxBoxSizer(wxVERTICAL
);
114 wxStaticBoxSizer
* sizer_5
= new wxStaticBoxSizer(sizer_5_staticbox
, wxHORIZONTAL
);
115 wxStaticBoxSizer
* sizer_1
= new wxStaticBoxSizer(sizer_1_staticbox
, wxVERTICAL
);
116 wxBoxSizer
* sizer_4
= new wxBoxSizer(wxHORIZONTAL
);
117 sizer_4
->Add(label_2
, 0, wxRIGHT
|wxALIGN_CENTER_VERTICAL
, 2);
118 sizer_4
->Add(device_label
, 0, wxLEFT
|wxALIGN_CENTER_VERTICAL
, 10);
119 sizer_3
->Add(sizer_4
, 0, wxBOTTOM
|wxEXPAND
, 5);
120 sizer_1
->Add(list_box_1
, 0, wxEXPAND
, 0);
121 sizer_3
->Add(sizer_1
, 0, wxEXPAND
, 0);
122 sizer_5
->Add(label_1
, 0, wxRIGHT
|wxALIGN_CENTER_VERTICAL
, 2);
123 sizer_5
->Add(text_ctrl_1
, 0, 0, 0);
124 sizer_3
->Add(sizer_5
, 1, wxEXPAND
, 0);
125 sizer_2
->Add(sizer_3
, 0, wxALL
|wxEXPAND
, 7);
128 sizer_3
->Add(bottom_buttons
, 0, wxTOP
|wxEXPAND
, 5);
138 /// Searches for the given program name, in various directories, and
139 /// stores the following info:
140 /// Exists() - file exists, and if true, then:
141 /// GetPath() - returns full path of file, and:
142 /// IsExecutable() - returns true if file is a runnable program
143 /// IsSuid() - returns true if file is suid
144 /// GetGroup() - returns the group name of the file
146 /// For pppd, for example, this may return on Debian:
148 /// path? /usr/sbin/pppd
149 /// executable? true if user in group, false if not
150 /// suid? true, suid root on Debian
151 /// group? uses the 'dip' group on Debian
155 /// path? /usr/sbin/pppd
168 void Dump(std::ostream
&os
)
170 os
<< "Path: " << m_path
<< "\n";
171 os
<< "Group: " << m_group
<< "\n";
172 os
<< "Exec: " << (m_executable
? "true" : "false") << "\n";
173 os
<< "Suid: " << (m_suid
? "true" : "false") << "\n";
176 const std::string
& GetPath() const { return m_path
; }
177 const std::string
& GetGroup() const { return m_group
; }
178 bool Exists() const { return m_path
.size() > 0; }
179 bool IsExecutable() const { return m_executable
; }
180 bool IsSuid() const { return m_suid
; }
182 bool CheckPath(const std::string
&path
)
184 if( access(path
.c_str(), F_OK
) == 0 ) {
191 void CheckAll(const char *prog
, const std::string
&path
)
193 istringstream
iss(path
);
196 while( getline(iss
, p
, ':') ) {
197 string f
= p
+ "/" + prog
;
203 ProgramDetect(const char *prog
, const std::string
&path
)
204 : m_executable(false)
207 // find the program first
208 CheckAll(prog
, path
);
215 if( access(m_path
.c_str(), X_OK
) == 0 ) {
221 if( stat(m_path
.c_str(), &s
) == 0 ) {
222 if( s
.st_mode
& S_ISUID
) {
227 struct group
*g
= getgrgid(s
.st_gid
);
229 m_group
= g
->gr_name
;
235 std::string
ModemDlg::GetPeerName() const
237 return string(list_box_1
->GetStringSelection().utf8_str());
240 std::string
ModemDlg::GetPassword() const
242 return string(text_ctrl_1
->GetValue().utf8_str());
245 void ModemDlg::DoModem(wxWindow
*parent
, const Barry::Pin
&pin
)
248 // Search for dependency programs: xterm, pppd, gksu, etc.
251 // test whether xterm is in the path
252 ProgramDetect
xterm("xterm", getenv("PATH"));
253 if( !xterm
.Exists() || !xterm
.IsExecutable() ) {
254 wxMessageBox(_W("Cannot locate the xterm program. This is used to display modem connection output. Please install it and try again."), _W("Xterm Not Found"), wxOK
| wxICON_ERROR
, parent
);
258 // test whether we can run pppd, probably need to use full
259 // /usr/sbin/pppd path to reach it... check for return code
261 ProgramDetect
pppd("pppd", "/usr/sbin:/usr/bin");
262 if( !pppd
.Exists() ) {
263 wxMessageBox(_W("Cannot find pppd. Please install it for modem use."), _W("pppd Not Found"), wxOK
| wxICON_ERROR
, parent
);
269 // Check if we need root access to run pppd
273 if( pppd
.IsExecutable() && pppd
.IsSuid() ) {
276 else if( !pppd
.IsExecutable() && pppd
.IsSuid() && pppd
.GetGroup() != "root" ) {
277 wxString
gname(pppd
.GetGroup().c_str(), wxConvUTF8
);
278 wxString msg
= wxString::Format(_W("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());
279 int choice
= wxMessageBox(msg
, _W("System Group"), wxYES_NO
,
281 if( choice
!= wxYES
)
284 need_sudo
= BARRYDESKTOP_SYSTEM_GUI_SU
+ string(" ");
286 else if( pppd
.IsExecutable() && !pppd
.IsSuid() ) {
287 need_sudo
= BARRYDESKTOP_SYSTEM_GUI_SU
+ string(" ");
291 // Check if we can run pppd, in the non-root case
293 if( need_sudo
.size() == 0 ) {
295 wxString
cmd((pppd
.GetPath() + " permission_test").c_str(), wxConvUTF8
);
296 if( !eh
.Run(0, "", cmd
) ) {
297 wxMessageBox(_W("Internal fork error. Should never happen."), _W("Cannot Run pppd"), wxOK
| wxICON_ERROR
, parent
);
302 if( !(eh
.GetChildExitCode() == 0 || eh
.GetChildExitCode() == 2) ) {
303 wxString msg
= wxString::Format(_W("Unable to run pppd correctly. Unexpected error code: %d, %s"), eh
.GetChildExitCode(), cmd
.c_str());
304 wxMessageBox(msg
, _W("Error Code"), wxOK
| wxICON_ERROR
, parent
);
310 // Load all peer files.
312 // do a search in /etc/ppp/peers for all barry-* files and
315 std::vector
<std::string
> peers
;
316 wxDir
dir(wxString("/etc/ppp/peers", wxConvUTF8
));
317 if( !dir
.IsOpened() ) {
318 wxMessageBox(_W("Unable to access files in /etc/ppp/peers. Do you have the correct permissions?"), _W("Cannot Open Peers"), wxOK
| wxICON_ERROR
, parent
);
322 bool cont
= dir
.GetFirst(&filename
, _T("barry-*"), wxDIR_FILES
);
324 peers
.push_back( string(filename
.utf8_str()) );
325 cont
= dir
.GetNext(&filename
);
328 // anything available?
329 if( !peers
.size() ) {
330 wxMessageBox(_W("No providers found. Make sure Barry was properly installed, with peer files in /etc/ppp/peers."), _W("No Providers"), wxOK
| wxICON_ERROR
, parent
);
335 sort(peers
.begin(), peers
.end());
339 // Double check that we can read the peer files
342 // do an access or file open test on the first barry-* file
343 // to make sure that we have access to peers/
344 string testfile
= "/etc/ppp/peers/" + peers
[0];
345 if( access(testfile
.c_str(), R_OK
) != 0 ) {
346 wxString msg
= wxString::Format(_W("Cannot read provider files under /etc/ppp/peers. Please check your file permissions. (Access failed for %s)"), wxString(testfile
.c_str(), wxConvUTF8
).c_str());
347 wxMessageBox(msg
, _W("Permissions Error"), wxOK
| wxICON_ERROR
, parent
);
353 // Fetch default peer choice
355 Barry::GlobalConfigFile
&config
= wxGetApp().GetGlobalConfig();
356 string key
= pin
.Str() + "-DefaultPeer";
357 string default_peer
= config
.GetKey(key
);
363 ModemDlg
dlg(parent
, peers
, default_peer
, pin
);
364 if( dlg
.ShowModal() == wxID_OK
) {
365 string peer
= dlg
.GetPeerName();
366 string peerfile
= "/etc/ppp/peers/" + peer
;
367 if( !peer
.size() || access(peerfile
.c_str(), R_OK
) != 0 ) {
368 wxString msg
= wxString::Format(_W("Unable to open peer file: %s"), wxString(peerfile
.c_str(), wxConvUTF8
).c_str());
369 wxMessageBox(msg
, _W("Invalid Peer"), wxOK
| wxICON_ERROR
, parent
);
373 // save peer selection as default for this device
374 config
.SetKey(key
, peer
);
376 // create shell script which calls pppd
377 TempDir
tempdir("BarryDesktopModem");
378 string tmp_path
= tempdir
.GetNewFilename();
380 ofstream
otmp(tmp_path
.c_str());
381 otmp
<< "#!/bin/sh" << endl
;
382 otmp
<< "echo " << _C("Starting pppd for device PIN ")
383 << pin
.Str() << "... " << endl
;
385 ostringstream cmdoss
;
386 cmdoss
<< need_sudo
<< pppd
.GetPath() << " call " << peer
;
388 // show command with echo too
389 otmp
<< "echo" << endl
;
390 otmp
<< "echo '" << cmdoss
.str() << "'" << endl
;
391 otmp
<< cmdoss
.str() << endl
;
393 otmp
<< "echo " << _C("Press enter to close window...") << endl
;
394 otmp
<< "read" << endl
;
397 chmod(tmp_path
.c_str(), S_IRUSR
| S_IRGRP
| S_IROTH
|
398 S_IXUSR
| S_IXGRP
| S_IXOTH
);
400 // create command line using xterm as display
401 wxString
xterm_cmd((xterm
.GetPath() + " " + tmp_path
).c_str(),
404 // setup argument fifo
405 Barry::FifoArgs args
;
406 args
.m_password
= dlg
.GetPassword();
408 Barry::FifoServer
fifo(args
);
410 // run! and go back to main screen
412 run
.Run(parent
, "modem", xterm_cmd
);