xref: /haiku/src/add-ons/network_settings/dialup/PPPoEAddon.cpp (revision fadb6952afef6d1d01f60b5c67a73ecced48c6f6)
1 /*
2  * Copyright 2003-2004 Waldemar Kornewald. All rights reserved.
3  * Copyright 2017 Haiku, Inc. All rights reserved.
4  * Distributed under the terms of the MIT License.
5  */
6 
7 //-----------------------------------------------------------------------
8 // PPPoEAddon saves the loaded settings.
9 // PPPoEView saves the current settings.
10 //-----------------------------------------------------------------------
11 
12 #include "PPPoEAddon.h"
13 
14 #include "InterfaceUtils.h"
15 #include "MessageDriverSettingsUtils.h"
16 #include "TextRequestDialog.h"
17 
18 #include <Box.h>
19 #include <MenuField.h>
20 #include <MenuItem.h>
21 #include <PopUpMenu.h>
22 #include <StringView.h>
23 
24 #include <PPPManager.h>
25 #include <PPPoE.h>
26 	// from PPPoE addon
27 
28 
29 // GUI constants
30 static const uint32 kDefaultButtonWidth = 80;
31 
32 // message constants
33 static const uint32 kMsgSelectInterface = 'SELI';
34 static const uint32 kMsgSelectOther = 'SELO';
35 static const uint32 kMsgFinishSelectOther = 'FISO';
36 static const uint32 kMsgShowServiceWindow = 'SHSW';
37 static const uint32 kMsgChangeService = 'CHGS';
38 static const uint32 kMsgResetService = 'RESS';
39 
40 // labels
41 static const char *kLabelInterfaceName = "Network Interface: ";
42 static const char *kLabelOptional = "(Optional)";
43 static const char *kLabelOtherInterface = "Other:";
44 static const char *kLabelSelectInterface = "Select Interface...";
45 static const char *kLabelServiceName = "Service: ";
46 
47 // requests
48 static const char *kRequestInterfaceName = "Network Interface Name: ";
49 
50 // add-on descriptions
51 static const char *kFriendlyName = "Broadband: DSL, Cable, etc.";
52 static const char *kTechnicalName = "PPPoE";
53 static const char *kKernelModuleName = "pppoe";
54 
55 
PPPoEAddon(BMessage * addons)56 PPPoEAddon::PPPoEAddon(BMessage *addons)
57 	: DialUpAddon(addons),
58 	fSettings(NULL),
59 	fProfile(NULL),
60 	fPPPoEView(NULL)
61 {
62 	fHeight = 20 // interface name control
63 		+ 20 // service control
64 		+ 5 + 2; // space between controls and bottom
65 }
66 
67 
~PPPoEAddon()68 PPPoEAddon::~PPPoEAddon()
69 {
70 	delete fPPPoEView;
71 		// this may have been set to NULL from the view's destructor!
72 }
73 
74 
75 const char*
FriendlyName() const76 PPPoEAddon::FriendlyName() const
77 {
78 	return kFriendlyName;
79 }
80 
81 
82 const char*
TechnicalName() const83 PPPoEAddon::TechnicalName() const
84 {
85 	return kTechnicalName;
86 }
87 
88 
89 const char*
KernelModuleName() const90 PPPoEAddon::KernelModuleName() const
91 {
92 	return kKernelModuleName;
93 }
94 
95 
96 bool
LoadSettings(BMessage * settings,BMessage * profile,bool isNew)97 PPPoEAddon::LoadSettings(BMessage *settings, BMessage *profile, bool isNew)
98 {
99 	fIsNew = isNew;
100 	fInterfaceName = fServiceName = "";
101 	fSettings = settings;
102 	fProfile = profile;
103 
104 	if(fPPPoEView)
105 		fPPPoEView->Reload();
106 
107 	if(!settings || !profile || isNew)
108 		return true;
109 
110 	BMessage device;
111 	int32 deviceIndex = 0;
112 	if(!FindMessageParameter(PPP_DEVICE_KEY, *fSettings, &device, &deviceIndex))
113 		return false;
114 			// error: no device
115 
116 	BString name;
117 	if(device.FindString(MDSU_VALUES, &name) != B_OK || name != kKernelModuleName)
118 		return false;
119 			// error: no device
120 
121 	BMessage parameter;
122 	int32 index = 0;
123 	if(!FindMessageParameter(PPPoE_INTERFACE_KEY, device, &parameter, &index)
124 			|| parameter.FindString(MDSU_VALUES, &fInterfaceName) != B_OK)
125 		return false;
126 			// error: no interface
127 	else {
128 		parameter.AddBool(MDSU_VALID, true);
129 		device.ReplaceMessage(MDSU_PARAMETERS, index, &parameter);
130 	}
131 
132 	index = 0;
133 	if(!FindMessageParameter(PPPoE_SERVICE_NAME_KEY, device, &parameter, &index)
134 			|| parameter.FindString(MDSU_VALUES, &fServiceName) != B_OK)
135 		fServiceName = "";
136 	else {
137 		parameter.AddBool(MDSU_VALID, true);
138 		device.ReplaceMessage(MDSU_PARAMETERS, index, &parameter);
139 	}
140 
141 	device.AddBool(MDSU_VALID, true);
142 	fSettings->ReplaceMessage(MDSU_PARAMETERS, deviceIndex, &device);
143 
144 	if(fPPPoEView)
145 		fPPPoEView->Reload();
146 
147 	return true;
148 }
149 
150 
151 void
IsModified(bool * settings,bool * profile) const152 PPPoEAddon::IsModified(bool *settings, bool *profile) const
153 {
154 	*profile = false;
155 
156 	if(!fSettings) {
157 		*settings = false;
158 		return;
159 	}
160 
161 	*settings = (fInterfaceName != fPPPoEView->InterfaceName()
162 		|| fServiceName != fPPPoEView->ServiceName());
163 }
164 
165 
166 bool
SaveSettings(BMessage * settings,BMessage * profile,bool saveTemporary)167 PPPoEAddon::SaveSettings(BMessage *settings, BMessage *profile, bool saveTemporary)
168 {
169 	if(!fSettings || !settings || !fPPPoEView->InterfaceName()
170 			|| strlen(fPPPoEView->InterfaceName()) == 0)
171 		return false;
172 			// TODO: tell user that an interface is needed (if we fail because of this)
173 
174 	BMessage device, interface;
175 	device.AddString(MDSU_NAME, PPP_DEVICE_KEY);
176 	device.AddString(MDSU_VALUES, kKernelModuleName);
177 
178 	interface.AddString(MDSU_NAME, PPPoE_INTERFACE_KEY);
179 	interface.AddString(MDSU_VALUES, fPPPoEView->InterfaceName());
180 	device.AddMessage(MDSU_PARAMETERS, &interface);
181 
182 	if(fPPPoEView->ServiceName() && strlen(fPPPoEView->ServiceName()) > 0) {
183 		// save service name, too
184 		BMessage service;
185 		service.AddString(MDSU_NAME, PPPoE_SERVICE_NAME_KEY);
186 		service.AddString(MDSU_VALUES, fPPPoEView->ServiceName());
187 		device.AddMessage(MDSU_PARAMETERS, &service);
188 	}
189 
190 	settings->AddMessage(MDSU_PARAMETERS, &device);
191 
192 	return true;
193 }
194 
195 
196 bool
GetPreferredSize(float * width,float * height) const197 PPPoEAddon::GetPreferredSize(float *width, float *height) const
198 {
199 	float viewWidth;
200 	if(Addons()->FindFloat(DUN_DEVICE_VIEW_WIDTH, &viewWidth) != B_OK)
201 		viewWidth = 270;
202 			// default value
203 
204 	if(width)
205 		*width = viewWidth;
206 	if(height)
207 		*height = fHeight;
208 
209 	return true;
210 }
211 
212 
213 BView*
CreateView()214 PPPoEAddon::CreateView()
215 {
216 	if(!fPPPoEView) {
217 		float width;
218 		if(!Addons()->FindFloat(DUN_DEVICE_VIEW_WIDTH, &width))
219 			width = 270;
220 				// default value
221 
222 		BRect rect(0, 0, width, fHeight);
223 		fPPPoEView = new PPPoEView(this, rect);
224 		fPPPoEView->Reload();
225 	}
226 
227 	return fPPPoEView;
228 }
229 
230 
PPPoEView(PPPoEAddon * addon,BRect frame)231 PPPoEView::PPPoEView(PPPoEAddon *addon, BRect frame)
232 	: BView(frame, "PPPoEView", B_FOLLOW_NONE, 0),
233 	fAddon(addon)
234 {
235 	BRect rect = Bounds();
236 	rect.InsetBy(5, 0);
237 	rect.bottom = 20;
238 	fInterface = new BMenuField(rect, "interface", kLabelInterfaceName,
239 		new BPopUpMenu(kLabelSelectInterface));
240 	fInterface->SetDivider(StringWidth(fInterface->Label()) + 5);
241 	fInterface->Menu()->AddSeparatorItem();
242 	fOtherInterface = new BMenuItem(kLabelOtherInterface,
243 		new BMessage(kMsgSelectOther));
244 	fInterface->Menu()->AddItem(fOtherInterface);
245 	rect.top = rect.bottom + 5;
246 	rect.bottom = rect.top + 20;
247 	rect.right -= 75;
248 	fServiceName = new BTextControl(rect, "service", kLabelServiceName, NULL, NULL);
249 	fServiceName->SetDivider(StringWidth(fServiceName->Label()) + 5);
250 	rect.left = rect.right + 5;
251 	rect.right += 75;
252 	rect.bottom = rect.top + 15;
253 	AddChild(new BStringView(rect, "optional", kLabelOptional));
254 
255 	AddChild(fInterface);
256 	AddChild(fServiceName);
257 }
258 
259 
~PPPoEView()260 PPPoEView::~PPPoEView()
261 {
262 	Addon()->UnregisterView();
263 }
264 
265 
266 void
Reload()267 PPPoEView::Reload()
268 {
269 	ReloadInterfaces();
270 	fServiceName->SetText(Addon()->ServiceName());
271 }
272 
273 
274 void
AttachedToWindow()275 PPPoEView::AttachedToWindow()
276 {
277 	SetViewColor(Parent()->ViewColor());
278 	fInterface->Menu()->SetTargetForItems(this);
279 	fServiceName->SetTarget(this);
280 }
281 
282 
283 void
MessageReceived(BMessage * message)284 PPPoEView::MessageReceived(BMessage *message)
285 {
286 	switch(message->what) {
287 		case kMsgSelectInterface: {
288 			BMenuItem *item = fInterface->Menu()->FindMarked();
289 			if(item)
290 				fInterfaceName = item->Label();
291 		} break;
292 
293 		case kMsgSelectOther:
294 			(new TextRequestDialog("InterfaceName", NULL, kRequestInterfaceName,
295 				fInterfaceName.String()))->Go(new BInvoker(
296 				new BMessage(kMsgFinishSelectOther), this));
297 		break;
298 
299 		case kMsgFinishSelectOther: {
300 			int32 which;
301 			message->FindInt32("which", &which);
302 
303 			const char *name = message->FindString("text");
304 			BMenu *menu = fInterface->Menu();
305 			BMenuItem *item;
306 			if(which != 1 || !name || strlen(name) == 0) {
307 				item = menu->FindItem(fInterfaceName.String());
308 				if(item && menu->IndexOf(item) <= menu->CountItems() - 2)
309 					item->SetMarked(true);
310 				else
311 					fOtherInterface->SetMarked(true);
312 
313 				return;
314 			}
315 
316 			fInterfaceName = name;
317 
318 			item = menu->FindItem(fInterfaceName.String());
319 			if(item && menu->IndexOf(item) <= menu->CountItems() - 2) {
320 				item->SetMarked(true);
321 				return;
322 			}
323 
324 			BString label(kLabelOtherInterface);
325 			label << " " << name;
326 			fOtherInterface->SetLabel(label.String());
327 			fOtherInterface->SetMarked(true);
328 				// XXX: this is needed to tell the owning menu to update its label
329 		} break;
330 
331 		default:
332 			BView::MessageReceived(message);
333 	}
334 }
335 
336 
337 void
ReloadInterfaces()338 PPPoEView::ReloadInterfaces()
339 {
340 	// delete all items and request a new bunch from the pppoe kernel module
341 	BMenu *menu = fInterface->Menu();
342 	while(menu->CountItems() > 2)
343 		delete menu->RemoveItem((int32) 0);
344 	fOtherInterface->SetLabel(kLabelOtherInterface);
345 
346 	PPPManager manager;
347 	char *interfaces = new char[8192];
348 		// reserve enough space for approximately 512 entries
349 	int32 count = manager.ControlModule("pppoe", PPPoE_GET_INTERFACES, interfaces,
350 		8192);
351 
352 	BMenuItem *item;
353 	char *name = interfaces;
354 	int32 insertAt;
355 	for(int32 index = 0; index < count; index++) {
356 		item = new BMenuItem(name, new BMessage(kMsgSelectInterface));
357 		insertAt = FindNextMenuInsertionIndex(menu, name);
358 		if(insertAt > menu->CountItems() - 2)
359 			insertAt = menu->CountItems() - 2;
360 
361 		item->SetTarget(this);
362 		menu->AddItem(item, insertAt);
363 		name += strlen(name) + 1;
364 	}
365 
366 	// set interface or some default value if nothing was found
367 	if(Addon()->InterfaceName() && strlen(Addon()->InterfaceName()) > 0)
368 		fInterfaceName = Addon()->InterfaceName();
369 	else if(count > 0)
370 		fInterfaceName = interfaces;
371 	else
372 		fInterfaceName = "";
373 
374 	delete interfaces;
375 
376 	item = menu->FindItem(fInterfaceName.String());
377 	if(item && menu->IndexOf(item) <= menu->CountItems() - 2)
378 		item->SetMarked(true);
379 	else if(Addon()->InterfaceName()) {
380 		BString label(kLabelOtherInterface);
381 		label << " " << fInterfaceName;
382 		fOtherInterface->SetLabel(label.String());
383 		fOtherInterface->SetMarked(true);
384 	}
385 }
386