3 /// Dialog class to handle modem functionality
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.
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>
41 // begin wxGlade: ::extracode
45 ModemDlg::ModemDlg(wxWindow
* parent
,
46 const std::vector
<std::string
> &peers
,
47 const std::string
&default_peer
)
48 : wxDialog(parent
, Dialog_Modem
, _T("Modem Kickstart"))
50 bottom_buttons
= CreateButtonSizer(wxOK
| wxCANCEL
);
52 // begin wxGlade: ModemDlg::ModemDlg
53 sizer_5_staticbox
= new wxStaticBox(this, -1, wxT("Device"));
54 sizer_1_staticbox
= new wxStaticBox(this, -1, wxT("Providers"));
55 const wxString list_box_1_choices
[] = {
60 list_box_1
= new wxListBox(this, wxID_ANY
, wxDefaultPosition
, wxDefaultSize
, 3, list_box_1_choices
, wxLB_SINGLE
);
61 label_1
= new wxStaticText(this, wxID_ANY
, wxT("Password:"));
62 text_ctrl_1
= new wxTextCtrl(this, wxID_ANY
, wxEmptyString
, wxDefaultPosition
, wxDefaultSize
, wxTE_PASSWORD
);
68 // add all peers to the listbox
70 int default_index
= -1, index
= 0;
71 for( std::vector
<std::string
>::const_iterator i
= peers
.begin();
72 i
!= peers
.end(); ++i
, ++index
)
74 if( default_peer
== *i
)
75 default_index
= index
;
76 list_box_1
->Append(wxString(i
->c_str(), wxConvUTF8
));
79 if( default_index
>= 0 ) {
80 list_box_1
->SetSelection(default_index
);
83 list_box_1
->SetSelection(0);
87 void ModemDlg::set_properties()
89 // begin wxGlade: ModemDlg::set_properties
90 SetTitle(wxT("Modem Starter"));
91 list_box_1
->SetMinSize(wxSize(-1, 150));
92 list_box_1
->SetSelection(0);
93 text_ctrl_1
->SetMinSize(wxSize(150, -1));
98 void ModemDlg::do_layout()
100 // begin wxGlade: ModemDlg::do_layout
101 wxBoxSizer
* sizer_2
= new wxBoxSizer(wxHORIZONTAL
);
102 wxBoxSizer
* sizer_3
= new wxBoxSizer(wxVERTICAL
);
103 wxStaticBoxSizer
* sizer_5
= new wxStaticBoxSizer(sizer_5_staticbox
, wxHORIZONTAL
);
104 wxStaticBoxSizer
* sizer_1
= new wxStaticBoxSizer(sizer_1_staticbox
, wxVERTICAL
);
105 sizer_1
->Add(list_box_1
, 0, wxEXPAND
, 0);
106 sizer_3
->Add(sizer_1
, 0, wxEXPAND
, 0);
107 sizer_5
->Add(label_1
, 0, wxRIGHT
|wxALIGN_CENTER_VERTICAL
, 2);
108 sizer_5
->Add(text_ctrl_1
, 0, 0, 0);
109 sizer_3
->Add(sizer_5
, 1, wxEXPAND
, 0);
110 sizer_2
->Add(sizer_3
, 0, wxALL
|wxEXPAND
, 7);
113 sizer_3
->Add(bottom_buttons
, 0, wxTOP
|wxEXPAND
, 5);
123 /// Searches for the given program name, in various directories, and
124 /// stores the following info:
125 /// Exists() - file exists, and if true, then:
126 /// GetPath() - returns full path of file, and:
127 /// IsExecutable() - returns true if file is a runnable program
128 /// IsSuid() - returns true if file is suid
129 /// GetGroup() - returns the group name of the file
131 /// For pppd, for example, this may return on Debian:
133 /// path? /usr/sbin/pppd
134 /// executable? true if user in group, false if not
135 /// suid? true, suid root on Debian
136 /// group? uses the 'dip' group on Debian
140 /// path? /usr/sbin/pppd
153 void Dump(std::ostream
&os
)
155 os
<< "Path: " << m_path
<< "\n";
156 os
<< "Group: " << m_group
<< "\n";
157 os
<< "Exec: " << (m_executable
? "true" : "false") << "\n";
158 os
<< "Suid: " << (m_suid
? "true" : "false") << "\n";
161 const std::string
& GetPath() const { return m_path
; }
162 const std::string
& GetGroup() const { return m_group
; }
163 bool Exists() const { return m_path
.size() > 0; }
164 bool IsExecutable() const { return m_executable
; }
165 bool IsSuid() const { return m_suid
; }
167 bool CheckPath(const std::string
&path
)
169 if( access(path
.c_str(), F_OK
) == 0 ) {
176 void CheckAll(const char *prog
, const std::string
&path
)
178 istringstream
iss(path
);
181 while( getline(iss
, p
, ':') ) {
182 string f
= p
+ "/" + prog
;
188 ProgramDetect(const char *prog
, const std::string
&path
)
189 : m_executable(false)
192 // find the program first
193 CheckAll(prog
, path
);
200 if( access(m_path
.c_str(), X_OK
) == 0 ) {
206 if( stat(m_path
.c_str(), &s
) == 0 ) {
207 if( s
.st_mode
& S_ISUID
) {
212 struct group
*g
= getgrgid(s
.st_gid
);
214 m_group
= g
->gr_name
;
220 std::string
ModemDlg::GetPeerName() const
222 return string(list_box_1
->GetStringSelection().utf8_str());
225 std::string
ModemDlg::GetPassword() const
227 return string(text_ctrl_1
->GetValue().utf8_str());
230 void ModemDlg::DoModem(wxWindow
*parent
, const Barry::Pin
&pin
)
232 // test whether xterm is in the path
233 ProgramDetect
xterm("xterm", getenv("PATH"));
234 if( !xterm
.Exists() || !xterm
.IsExecutable() ) {
235 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
);
239 // in preparation for pppob search, find sbin, relative to our
240 // current application path
241 wxFileName
app_path(wxTheApp
->argv
[0]);
242 string
app_sbin(app_path
.GetPath().utf8_str());
243 app_sbin
+= "/../sbin";
244 if( app_sbin
[0] != '/' ) {
245 char cwdbuf
[PATH_MAX
];
246 getcwd(cwdbuf
, PATH_MAX
);
248 // insert current directory
249 app_sbin
.insert(0, string(cwdbuf
) + "/");
251 char *app_real
= realpath(app_sbin
.c_str(), NULL
);
254 cout
<< "app_sbin = " << app_sbin
<< endl
;
256 // test whether pppob is available... use app directory as
257 // part of search as well, in case Barry is installed in an
259 ProgramDetect
pppob("pppob", app_sbin
+ ":/usr/sbin:" + getenv("PATH"));
260 if( !pppob
.Exists() || !pppob
.IsExecutable() ) {
261 wxMessageBox(_T("Cannot find pppob. Please make sure Barry's command line utilities are installed."), _T("pppob Not Found"), wxOK
| wxICON_ERROR
, parent
);
264 cout
<< pppob
.GetPath() << endl
;
266 // test whether we can run pppd, probably need to use full
267 // /usr/sbin/pppd path to reach it... check for return code
269 ProgramDetect
pppd("pppd", "/usr/sbin:/usr/bin");
270 if( !pppd
.Exists() ) {
271 wxMessageBox(_T("Cannot find pppd. Please install it for modem use."), _T("pppd Not Found"), wxOK
| wxICON_ERROR
, parent
);
277 if( !(pppd
.IsSuid() && pppd
.GetGroup() != "root") ) {
278 // No group / suid setup, so need sudo
279 // Use gtk's gui sudo, since we're using GTK's wxwidgets
280 // and probably safe here
281 // FIXME - need a portable method for all of this someday :-(
286 wxString
cmd((need_sudo
+ pppd
.GetPath() + " help").c_str(), wxConvUTF8
);
287 if( !eh
.Run(0, "", cmd
) ) {
288 if( need_sudo
.size() ) {
289 wxMessageBox(_T("Unable to run pppd. Please make sure you have it enabled in your sudo config, or put pppd in a group of its own."), _T("Cannot Run pppd"), wxOK
| wxICON_ERROR
, parent
);
292 wxString msg
= wxString::Format(_T("Unable to run pppd. Please make sure your user account is included in the '%s' group."), wxString(pppd
.GetGroup().c_str(), wxConvUTF8
).c_str());
294 wxMessageBox(msg
, _T("Cannot Run pppd"), wxOK
| wxICON_ERROR
, parent
);
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
);
307 // do a search in /etc/ppp/peers for all barry-* files and
309 std::vector
<std::string
> peers
;
310 wxDir
dir(wxString("/etc/ppp/peers", wxConvUTF8
));
311 if( !dir
.IsOpened() ) {
312 wxMessageBox(_T("Unable to access files in /etc/ppp/peers. Do you have the correct permissions?"), _T("Cannot Open Peers"), wxOK
| wxICON_ERROR
, parent
);
316 bool cont
= dir
.GetFirst(&filename
, _T("barry-*"), wxDIR_FILES
);
318 peers
.push_back( string(filename
.utf8_str()) );
319 cont
= dir
.GetNext(&filename
);
322 // anything available?
323 if( !peers
.size() ) {
324 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
);
329 sort(peers
.begin(), peers
.end());
331 // do an access or file open test on the first barry-* file
332 // to make sure that we have access to peers/
333 string testfile
= "/etc/ppp/peers/" + peers
[0];
334 if( access(testfile
.c_str(), R_OK
) != 0 ) {
335 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());
336 wxMessageBox(msg
, _T("Permissions Error"), wxOK
| wxICON_ERROR
, parent
);
340 // fetch default peer choice
341 Barry::GlobalConfigFile
&config
= wxGetApp().GetGlobalConfig();
342 string key
= pin
.Str() + "-DefaultPeer";
343 string default_peer
= config
.GetKey(key
);
346 ModemDlg
dlg(parent
, peers
, default_peer
);
347 if( dlg
.ShowModal() == wxID_OK
) {
348 string password
= dlg
.GetPassword();
349 string peer
= dlg
.GetPeerName();
350 string peerfile
= "/etc/ppp/peers/" + peer
;
351 if( !peer
.size() || access(peerfile
.c_str(), R_OK
) != 0 ) {
352 wxString msg
= wxString::Format(_T("Unable to open peer file: %s"), wxString(peerfile
.c_str(), wxConvUTF8
).c_str());
353 wxMessageBox(msg
, _T("Invalid Peer"), wxOK
| wxICON_ERROR
, parent
);
357 // save peer selection as default for this device
358 config
.SetKey(key
, peer
);
360 // create shell script which calls pppd with proper
361 // pty pppob override, and password if needed
362 TempDir
tempdir("BarryDesktopModem");
363 string tmp_path
= tempdir
.GetNewFilename();
365 ofstream
otmp(tmp_path
.c_str());
366 otmp
<< "#!/bin/sh" << endl
;
367 otmp
<< "echo Starting pppd for device PIN "
368 << pin
.Str() << "... " << endl
;
369 // otmp << need_sudo << pppd.GetPath()
370 // FIXME - need gksu here, for the pty override :-( Need method to
371 // pass options to pppob without root
372 otmp
<< "gksu " << pppd
.GetPath()
374 << " pty \"" << pppob
.GetPath()
375 << " -p " << pin
.Str();
376 if( password
.size() )
377 otmp
<< " -P " << password
;
379 otmp
<< "echo Press enter to close window..." << endl
;
380 otmp
<< "read" << endl
;
383 chmod(tmp_path
.c_str(), S_IRUSR
| S_IRGRP
| S_IROTH
|
384 S_IXUSR
| S_IXGRP
| S_IXOTH
);
386 // create command line using xterm as display
387 wxString
xterm_cmd((xterm
.GetPath() + " " + tmp_path
).c_str(),
390 // run! and go back to main screen
392 run
.Run(parent
, "modem", xterm_cmd
);
394 // let run, then let TempDir cleanup