vfs: check userland buffers before reading them.
[haiku.git] / src / add-ons / network_settings / dialup / PPPoEAddon.cpp
blob6ecb7826f4716d88f174c1e9133cd886c407f692
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 */
7 //-----------------------------------------------------------------------
8 // PPPoEAddon saves the loaded settings.
9 // PPPoEView saves the current settings.
10 //-----------------------------------------------------------------------
12 #include "PPPoEAddon.h"
14 #include "InterfaceUtils.h"
15 #include "MessageDriverSettingsUtils.h"
16 #include "TextRequestDialog.h"
18 #include <Box.h>
19 #include <MenuField.h>
20 #include <MenuItem.h>
21 #include <PopUpMenu.h>
22 #include <StringView.h>
24 #include <PPPManager.h>
25 #include <PPPoE.h>
26 // from PPPoE addon
29 // GUI constants
30 static const uint32 kDefaultButtonWidth = 80;
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';
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: ";
47 // requests
48 static const char *kRequestInterfaceName = "Network Interface Name: ";
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";
56 PPPoEAddon::PPPoEAddon(BMessage *addons)
57 : DialUpAddon(addons),
58 fSettings(NULL),
59 fProfile(NULL),
60 fPPPoEView(NULL)
62 fHeight = 20 // interface name control
63 + 20 // service control
64 + 5 + 2; // space between controls and bottom
68 PPPoEAddon::~PPPoEAddon()
70 delete fPPPoEView;
71 // this may have been set to NULL from the view's destructor!
75 const char*
76 PPPoEAddon::FriendlyName() const
78 return kFriendlyName;
82 const char*
83 PPPoEAddon::TechnicalName() const
85 return kTechnicalName;
89 const char*
90 PPPoEAddon::KernelModuleName() const
92 return kKernelModuleName;
96 bool
97 PPPoEAddon::LoadSettings(BMessage *settings, BMessage *profile, bool isNew)
99 fIsNew = isNew;
100 fInterfaceName = fServiceName = "";
101 fSettings = settings;
102 fProfile = profile;
104 if(fPPPoEView)
105 fPPPoEView->Reload();
107 if(!settings || !profile || isNew)
108 return true;
110 BMessage device;
111 int32 deviceIndex = 0;
112 if(!FindMessageParameter(PPP_DEVICE_KEY, *fSettings, &device, &deviceIndex))
113 return false;
114 // error: no device
116 BString name;
117 if(device.FindString(MDSU_VALUES, &name) != B_OK || name != kKernelModuleName)
118 return false;
119 // error: no device
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);
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);
141 device.AddBool(MDSU_VALID, true);
142 fSettings->ReplaceMessage(MDSU_PARAMETERS, deviceIndex, &device);
144 if(fPPPoEView)
145 fPPPoEView->Reload();
147 return true;
151 void
152 PPPoEAddon::IsModified(bool *settings, bool *profile) const
154 *profile = false;
156 if(!fSettings) {
157 *settings = false;
158 return;
161 *settings = (fInterfaceName != fPPPoEView->InterfaceName()
162 || fServiceName != fPPPoEView->ServiceName());
166 bool
167 PPPoEAddon::SaveSettings(BMessage *settings, BMessage *profile, bool saveTemporary)
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)
174 BMessage device, interface;
175 device.AddString(MDSU_NAME, PPP_DEVICE_KEY);
176 device.AddString(MDSU_VALUES, kKernelModuleName);
178 interface.AddString(MDSU_NAME, PPPoE_INTERFACE_KEY);
179 interface.AddString(MDSU_VALUES, fPPPoEView->InterfaceName());
180 device.AddMessage(MDSU_PARAMETERS, &interface);
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);
190 settings->AddMessage(MDSU_PARAMETERS, &device);
192 return true;
196 bool
197 PPPoEAddon::GetPreferredSize(float *width, float *height) const
199 float viewWidth;
200 if(Addons()->FindFloat(DUN_DEVICE_VIEW_WIDTH, &viewWidth) != B_OK)
201 viewWidth = 270;
202 // default value
204 if(width)
205 *width = viewWidth;
206 if(height)
207 *height = fHeight;
209 return true;
213 BView*
214 PPPoEAddon::CreateView()
216 if(!fPPPoEView) {
217 float width;
218 if(!Addons()->FindFloat(DUN_DEVICE_VIEW_WIDTH, &width))
219 width = 270;
220 // default value
222 BRect rect(0, 0, width, fHeight);
223 fPPPoEView = new PPPoEView(this, rect);
224 fPPPoEView->Reload();
227 return fPPPoEView;
231 PPPoEView::PPPoEView(PPPoEAddon *addon, BRect frame)
232 : BView(frame, "PPPoEView", B_FOLLOW_NONE, 0),
233 fAddon(addon)
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));
255 AddChild(fInterface);
256 AddChild(fServiceName);
260 PPPoEView::~PPPoEView()
262 Addon()->UnregisterView();
266 void
267 PPPoEView::Reload()
269 ReloadInterfaces();
270 fServiceName->SetText(Addon()->ServiceName());
274 void
275 PPPoEView::AttachedToWindow()
277 SetViewColor(Parent()->ViewColor());
278 fInterface->Menu()->SetTargetForItems(this);
279 fServiceName->SetTarget(this);
283 void
284 PPPoEView::MessageReceived(BMessage *message)
286 switch(message->what) {
287 case kMsgSelectInterface: {
288 BMenuItem *item = fInterface->Menu()->FindMarked();
289 if(item)
290 fInterfaceName = item->Label();
291 } break;
293 case kMsgSelectOther:
294 (new TextRequestDialog("InterfaceName", NULL, kRequestInterfaceName,
295 fInterfaceName.String()))->Go(new BInvoker(
296 new BMessage(kMsgFinishSelectOther), this));
297 break;
299 case kMsgFinishSelectOther: {
300 int32 which;
301 message->FindInt32("which", &which);
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);
313 return;
316 fInterfaceName = name;
318 item = menu->FindItem(fInterfaceName.String());
319 if(item && menu->IndexOf(item) <= menu->CountItems() - 2) {
320 item->SetMarked(true);
321 return;
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;
331 default:
332 BView::MessageReceived(message);
337 void
338 PPPoEView::ReloadInterfaces()
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);
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);
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;
361 item->SetTarget(this);
362 menu->AddItem(item, insertAt);
363 name += strlen(name) + 1;
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 = "";
374 delete interfaces;
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);