1/*
2 * Copyright 2004-2011 Haiku Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 *	Authors:
6 *		Alexander von Gluck, <kallisti5@unixzen.com>
7 */
8
9
10#include "NetworkSetupWindow.h"
11
12#include <Application.h>
13#include <Catalog.h>
14#include <GroupLayout.h>
15#include <GroupLayoutBuilder.h>
16#include <InterfaceKit.h>
17#include <Locale.h>
18#include <Roster.h>
19#include <StorageKit.h>
20#include <SupportKit.h>
21#include <TabView.h>
22
23#include <stdio.h>
24#include <string.h>
25#include <stdlib.h>
26
27
28#undef B_TRANSLATION_CONTEXT
29#define B_TRANSLATION_CONTEXT	"NetworkSetupWindow"
30
31
32// --------------------------------------------------------------
33NetworkSetupWindow::NetworkSetupWindow(const char *title)
34	:
35	BWindow(BRect(100, 100, 300, 300), title, B_TITLED_WINDOW,
36		B_ASYNCHRONOUS_CONTROLS | B_NOT_ZOOMABLE | B_AUTO_UPDATE_SIZE_LIMITS),
37	fAddonCount(0)
38{
39	// ---- Profiles section
40	BMenu *profilesPopup = new BPopUpMenu("<none>");
41	_BuildProfilesMenu(profilesPopup, kMsgProfileSelected);
42
43	BMenuField *profilesMenuField = new BMenuField("profiles_menu",
44		B_TRANSLATE("Profile:"), profilesPopup);
45
46	profilesMenuField->SetFont(be_bold_font);
47	profilesMenuField->SetEnabled(false);
48
49	// ---- Settings section
50
51	fPanel = new BTabView("showview_box");
52
53	// ---- Bottom globals buttons section
54	BBox *bottomDivider = new BBox(B_EMPTY_STRING);
55	bottomDivider->SetBorder(B_PLAIN_BORDER);
56
57	fApplyButton = new BButton("apply", B_TRANSLATE("Apply"),
58		new BMessage(kMsgApply));
59
60	fRevertButton = new BButton("revert", B_TRANSLATE("Revert"),
61		new BMessage(kMsgRevert));
62	// fRevertButton->SetEnabled(false);
63
64	// Enable boxes resizing modes
65	fPanel->SetResizingMode(B_FOLLOW_ALL);
66
67	// Build the layout
68	SetLayout(new BGroupLayout(B_VERTICAL));
69
70	AddChild(BGroupLayoutBuilder(B_VERTICAL, 10)
71		.AddGroup(B_HORIZONTAL, 5)
72			.Add(profilesMenuField)
73			.AddGlue()
74		.End()
75		.Add(fPanel)
76		.Add(bottomDivider)
77		.AddGroup(B_HORIZONTAL, 5)
78			.AddGlue()
79			.Add(fRevertButton)
80			.Add(fApplyButton)
81		.End()
82		.SetInsets(10, 10, 10, 10)
83	);
84
85	_BuildShowTabView(kMsgAddonShow);
86
87	bottomDivider->SetExplicitMaxSize(BSize(B_SIZE_UNSET, 1));
88	fPanel->SetExplicitMinSize(BSize(fMinAddonViewRect.Width(),
89		fMinAddonViewRect.Height()));
90
91	fAddonView = NULL;
92
93}
94
95
96NetworkSetupWindow::~NetworkSetupWindow()
97{
98}
99
100
101bool
102NetworkSetupWindow::QuitRequested()
103{
104	be_app->PostMessage(B_QUIT_REQUESTED);
105	return true;
106}
107
108
109void
110NetworkSetupWindow::MessageReceived(BMessage*	msg)
111{
112	switch (msg->what) {
113		case kMsgProfileNew:
114			break;
115
116		case kMsgProfileSelected: {
117			BPath name;
118			const char *path;
119			bool is_default;
120			bool is_current;
121
122			if (msg->FindString("path", &path) != B_OK)
123				break;
124
125			name.SetTo(path);
126
127			is_default = (strcmp(name.Leaf(), "default") == 0);
128			is_current = (strcmp(name.Leaf(), "current") == 0);
129
130			fApplyButton->SetEnabled(!is_current);
131			break;
132		}
133
134		case kMsgRevert: {
135			for (int addonIndex = 0; addonIndex < fAddonCount; addonIndex++) {
136				NetworkSetupAddOn* addon
137					= fNetworkAddOnMap[addonIndex];
138				addon->Revert();
139			}
140			break;
141		}
142
143
144		case kMsgApply: {
145			for (int addonIndex = 0; addonIndex < fAddonCount; addonIndex++) {
146				NetworkSetupAddOn* addon
147					= fNetworkAddOnMap[addonIndex];
148				addon->Save();
149			}
150			break;
151		}
152
153		case kMsgAddonShow: {
154			if (fAddonView)
155				fAddonView->RemoveSelf();
156
157			fAddonView = NULL;
158			if (msg->FindPointer("addon_view", (void **) &fAddonView) != B_OK)
159				break;
160
161			fPanel->AddChild(fAddonView);
162			fAddonView->ResizeTo(fPanel->Bounds().Width(),
163				fPanel->Bounds().Height());
164			break;
165		}
166
167		default:
168			inherited::MessageReceived(msg);
169	}
170}
171
172
173void
174NetworkSetupWindow::_BuildProfilesMenu(BMenu* menu, int32 msg_what)
175{
176	BMenuItem*	item;
177	char current_profile[256] = { 0 };
178
179	menu->SetRadioMode(true);
180
181	BDirectory dir("/boot/common/settings/network/profiles");
182
183	if (dir.InitCheck() == B_OK) {
184		BEntry entry;
185		BMessage* msg;
186
187		dir.Rewind();
188		while (dir.GetNextEntry(&entry) >= 0) {
189			BPath name;
190			entry.GetPath(&name);
191
192			if (entry.IsSymLink() &&
193				strcmp("current", name.Leaf()) == 0) {
194				BSymLink symlink(&entry);
195
196				if (symlink.IsAbsolute())
197					// oh oh, sorry, wrong symlink...
198					continue;
199
200				symlink.ReadLink(current_profile, sizeof(current_profile));
201				continue;
202			};
203
204			if (!entry.IsDirectory())
205				continue;
206
207			msg = new BMessage(msg_what);
208			msg->AddString("path", name.Path());
209
210			item = new BMenuItem(name.Leaf(), msg);
211			menu->AddItem(item);
212		}
213	}
214
215	menu->AddSeparatorItem();
216	menu->AddItem(new BMenuItem(B_TRANSLATE("New" B_UTF8_ELLIPSIS),
217		new BMessage(kMsgProfileNew)));
218	menu->AddItem(new BMenuItem(B_TRANSLATE("Manage" B_UTF8_ELLIPSIS),
219		new BMessage(kMsgProfileManage)));
220
221	if (strlen(current_profile)) {
222		item = menu->FindItem(current_profile);
223		if (item) {
224			BString label;
225			label << item->Label();
226			label << " (current)";
227			item->SetLabel(label.String());
228			item->SetMarked(true);
229		}
230	}
231}
232
233
234void
235NetworkSetupWindow::_BuildShowTabView(int32 msg_what)
236{
237	BPath path;
238	BPath addon_path;
239	BDirectory dir;
240	BEntry entry;
241
242	char* search_paths = getenv("ADDON_PATH");
243	if (!search_paths)
244		return;
245
246	fMinAddonViewRect.Set(0, 0, 375, 225);	// Minimum size
247
248	search_paths = strdup(search_paths);
249	char* next_path_token;
250	char* search_path = strtok_r(search_paths, ":", &next_path_token);
251
252	while (search_path) {
253		if (strncmp(search_path, "%A/", 3) == 0) {
254			app_info ai;
255			be_app->GetAppInfo(&ai);
256			entry.SetTo(&ai.ref);
257			entry.GetPath(&path);
258			path.GetParent(&path);
259			path.Append(search_path + 3);
260		} else {
261			path.SetTo(search_path);
262			path.Append("Network Setup");
263		}
264
265		search_path = strtok_r(NULL, ":", &next_path_token);
266
267		dir.SetTo(path.Path());
268		if (dir.InitCheck() != B_OK)
269			continue;
270
271		dir.Rewind();
272		while (dir.GetNextEntry(&entry) >= 0) {
273			if (entry.IsDirectory())
274				continue;
275
276			entry.GetPath(&addon_path);
277			image_id addon_id = load_add_on(addon_path.Path());
278			if (addon_id < 0) {
279				printf("Failed to load %s addon: %s.\n", addon_path.Path(),
280					strerror(addon_id));
281				continue;
282			}
283
284			network_setup_addon_instantiate get_nth_addon;
285			status_t status = get_image_symbol(addon_id, "get_nth_addon",
286				B_SYMBOL_TYPE_TEXT, (void **) &get_nth_addon);
287
288			int tabCount = 0;
289
290			if (status == B_OK) {
291				while ((fNetworkAddOnMap[fAddonCount]
292					= get_nth_addon(addon_id, tabCount)) != NULL) {
293					printf("Adding Tab: %d\n", fAddonCount);
294					BMessage* msg = new BMessage(msg_what);
295
296					BRect r(0, 0, 0, 0);
297					BView* addon_view
298						= fNetworkAddOnMap[fAddonCount]->CreateView(&r);
299					fMinAddonViewRect = fMinAddonViewRect | r;
300
301					msg->AddInt32("image_id", addon_id);
302					msg->AddString("addon_path", addon_path.Path());
303					msg->AddPointer("addon", fNetworkAddOnMap[fAddonCount]);
304					msg->AddPointer("addon_view", addon_view);
305
306					BTab *tab = new BTab;
307					fPanel->AddTab(addon_view, tab);
308					tab->SetLabel(fNetworkAddOnMap[fAddonCount]->Name());
309					fAddonCount++;
310						// Number of tab addons total
311					tabCount++;
312						// Tabs for *this* addon
313				}
314				continue;
315			}
316
317			//  No "addon instantiate function" symbol found in this addon
318			printf("No symbol \"get_nth_addon\" found in %s addon: not a "
319				"network setup addon!\n", addon_path.Path());
320			unload_add_on(addon_id);
321		}
322	}
323
324	free(search_paths);
325}
326