1f01106c3SAxel Dörfler /* 26c7caf44SAxel Dörfler * Copyright 2006-2013, Haiku, Inc. All rights reserved. 3f01106c3SAxel Dörfler * Distributed under the terms of the MIT License. 4f01106c3SAxel Dörfler * 5f01106c3SAxel Dörfler * Authors: 63b41ad86SStephan Aßmus * Dario Casalinuovo 7937ca113SRene Gollent * Axel Dörfler, axeld@pinc-software.de 85c46b171SRene Gollent * Rene Gollent, rene@gollent.com 9937ca113SRene Gollent * Hugo Santos, hugosantos@gmail.com 10f01106c3SAxel Dörfler */ 11f01106c3SAxel Dörfler 12f01106c3SAxel Dörfler 13f01106c3SAxel Dörfler #include "NetworkStatusView.h" 14f01106c3SAxel Dörfler 15aba4cb20SMichael Lotz #include <algorithm> 16440d0e61SAxel Dörfler #include <set> 17aba4cb20SMichael Lotz #include <vector> 18440d0e61SAxel Dörfler 19195981bbSAxel Dörfler #include <arpa/inet.h> 20195981bbSAxel Dörfler #include <net/if.h> 21195981bbSAxel Dörfler #include <stdio.h> 22195981bbSAxel Dörfler #include <stdlib.h> 233aeed660SJérôme Duval #include <strings.h> 24195981bbSAxel Dörfler #include <sys/socket.h> 25195981bbSAxel Dörfler #include <sys/sockio.h> 26195981bbSAxel Dörfler #include <unistd.h> 27f01106c3SAxel Dörfler 28730a45eeSJohn Scipione #include <AboutWindow.h> 29f01106c3SAxel Dörfler #include <Alert.h> 30f01106c3SAxel Dörfler #include <Application.h> 31757e7059SAdrien Destugues #include <Catalog.h> 32f01106c3SAxel Dörfler #include <Bitmap.h> 33f01106c3SAxel Dörfler #include <Deskbar.h> 34f01106c3SAxel Dörfler #include <Dragger.h> 35f01106c3SAxel Dörfler #include <Drivers.h> 36f01106c3SAxel Dörfler #include <IconUtils.h> 37757e7059SAdrien Destugues #include <Locale.h> 38f01106c3SAxel Dörfler #include <MenuItem.h> 39f01106c3SAxel Dörfler #include <MessageRunner.h> 405fe97f21SAxel Dörfler #include <NetworkInterface.h> 415fe97f21SAxel Dörfler #include <NetworkRoster.h> 42f01106c3SAxel Dörfler #include <PopUpMenu.h> 43f01106c3SAxel Dörfler #include <Resources.h> 44d5ba07a3SAxel Dörfler #include <Roster.h> 45f01106c3SAxel Dörfler #include <String.h> 46f01106c3SAxel Dörfler #include <TextView.h> 47f01106c3SAxel Dörfler 48195981bbSAxel Dörfler #include "NetworkStatus.h" 49195981bbSAxel Dörfler #include "NetworkStatusIcons.h" 505fe97f21SAxel Dörfler #include "RadioView.h" 513ca00ffdSAxel Dörfler #include "WirelessNetworkMenuItem.h" 52195981bbSAxel Dörfler 53f01106c3SAxel Dörfler 54546208a5SOliver Tappe #undef B_TRANSLATION_CONTEXT 55546208a5SOliver Tappe #define B_TRANSLATION_CONTEXT "NetworkStatusView" 56757e7059SAdrien Destugues 57757e7059SAdrien Destugues 58f01106c3SAxel Dörfler static const char *kStatusDescriptions[] = { 592ee8f3f6SSiarzhuk Zharski B_TRANSLATE("Unknown"), 602ee8f3f6SSiarzhuk Zharski B_TRANSLATE("No link"), 612ee8f3f6SSiarzhuk Zharski B_TRANSLATE("No stateful configuration"), 622ee8f3f6SSiarzhuk Zharski B_TRANSLATE("Configuring"), 632ee8f3f6SSiarzhuk Zharski B_TRANSLATE("Ready") 64f01106c3SAxel Dörfler }; 65f01106c3SAxel Dörfler 66efafab64SAxel Dörfler extern "C" _EXPORT BView *instantiate_deskbar_item(float maxWidth, float maxHeight); 67f01106c3SAxel Dörfler 68f01106c3SAxel Dörfler 69f01106c3SAxel Dörfler const uint32 kMsgShowConfiguration = 'shcf'; 70c1502c9aSStephan Aßmus const uint32 kMsgOpenNetworkPreferences = 'onwp'; 712e1a6286SAxel Dörfler const uint32 kMsgJoinNetwork = 'join'; 72f01106c3SAxel Dörfler 73f01106c3SAxel Dörfler const uint32 kMinIconWidth = 16; 74f01106c3SAxel Dörfler const uint32 kMinIconHeight = 16; 75f01106c3SAxel Dörfler 76195981bbSAxel Dörfler 7702ad9218SJohn Scipione // #pragma mark - NetworkStatusView 78aba4cb20SMichael Lotz 79aba4cb20SMichael Lotz 80f01106c3SAxel Dörfler NetworkStatusView::NetworkStatusView(BRect frame, int32 resizingMode, 81f01106c3SAxel Dörfler bool inDeskbar) 82f01106c3SAxel Dörfler : BView(frame, kDeskbarItemName, resizingMode, 8347102c07SX512 B_WILL_DRAW | B_TRANSPARENT_BACKGROUND | B_FRAME_EVENTS), 845c46b171SRene Gollent fInDeskbar(inDeskbar) 85f01106c3SAxel Dörfler { 86f01106c3SAxel Dörfler _Init(); 87f01106c3SAxel Dörfler 88f01106c3SAxel Dörfler if (!inDeskbar) { 89f01106c3SAxel Dörfler // we were obviously added to a standard window - let's add a dragger 90f01106c3SAxel Dörfler frame.OffsetTo(B_ORIGIN); 91f01106c3SAxel Dörfler frame.top = frame.bottom - 7; 92f01106c3SAxel Dörfler frame.left = frame.right - 7; 93f01106c3SAxel Dörfler BDragger* dragger = new BDragger(frame, this, 94f01106c3SAxel Dörfler B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM); 95f01106c3SAxel Dörfler AddChild(dragger); 96f01106c3SAxel Dörfler } else 97f01106c3SAxel Dörfler _Update(); 98f01106c3SAxel Dörfler } 99f01106c3SAxel Dörfler 100f01106c3SAxel Dörfler 101f01106c3SAxel Dörfler NetworkStatusView::NetworkStatusView(BMessage* archive) 102d5ba07a3SAxel Dörfler : BView(archive), 103d5ba07a3SAxel Dörfler fInDeskbar(false) 104f01106c3SAxel Dörfler { 105d5ba07a3SAxel Dörfler app_info info; 106d5ba07a3SAxel Dörfler if (be_app->GetAppInfo(&info) == B_OK 107d5ba07a3SAxel Dörfler && !strcasecmp(info.signature, "application/x-vnd.Be-TSKB")) 108d5ba07a3SAxel Dörfler fInDeskbar = true; 109d5ba07a3SAxel Dörfler 110f01106c3SAxel Dörfler _Init(); 111f01106c3SAxel Dörfler } 112f01106c3SAxel Dörfler 113f01106c3SAxel Dörfler 114f01106c3SAxel Dörfler NetworkStatusView::~NetworkStatusView() 115f01106c3SAxel Dörfler { 116f01106c3SAxel Dörfler } 117f01106c3SAxel Dörfler 118f01106c3SAxel Dörfler 119f01106c3SAxel Dörfler void 120f01106c3SAxel Dörfler NetworkStatusView::_Init() 121f01106c3SAxel Dörfler { 122f01106c3SAxel Dörfler for (int i = 0; i < kStatusCount; i++) { 123e58807edSAlexander von Gluck IV fTrayIcons[i] = NULL; 124e58807edSAlexander von Gluck IV fNotifyIcons[i] = NULL; 125f01106c3SAxel Dörfler } 126f01106c3SAxel Dörfler 127f01106c3SAxel Dörfler _UpdateBitmaps(); 128f01106c3SAxel Dörfler } 129f01106c3SAxel Dörfler 130f01106c3SAxel Dörfler 131f01106c3SAxel Dörfler void 132f01106c3SAxel Dörfler NetworkStatusView::_UpdateBitmaps() 133f01106c3SAxel Dörfler { 134f01106c3SAxel Dörfler for (int i = 0; i < kStatusCount; i++) { 135e58807edSAlexander von Gluck IV delete fTrayIcons[i]; 136e58807edSAlexander von Gluck IV delete fNotifyIcons[i]; 137e58807edSAlexander von Gluck IV fTrayIcons[i] = NULL; 138e58807edSAlexander von Gluck IV fNotifyIcons[i] = NULL; 139f01106c3SAxel Dörfler } 140f01106c3SAxel Dörfler 141f01106c3SAxel Dörfler image_info info; 142f01106c3SAxel Dörfler if (our_image(info) != B_OK) 143f01106c3SAxel Dörfler return; 144f01106c3SAxel Dörfler 145f01106c3SAxel Dörfler BFile file(info.name, B_READ_ONLY); 146f01106c3SAxel Dörfler if (file.InitCheck() < B_OK) 147f01106c3SAxel Dörfler return; 148f01106c3SAxel Dörfler 149f01106c3SAxel Dörfler BResources resources(&file); 150f01106c3SAxel Dörfler #ifdef HAIKU_TARGET_PLATFORM_HAIKU 151f01106c3SAxel Dörfler if (resources.InitCheck() < B_OK) 152f01106c3SAxel Dörfler return; 153f01106c3SAxel Dörfler #endif 154f01106c3SAxel Dörfler 155f01106c3SAxel Dörfler for (int i = 0; i < kStatusCount; i++) { 156f01106c3SAxel Dörfler const void* data = NULL; 157f01106c3SAxel Dörfler size_t size; 158f01106c3SAxel Dörfler data = resources.LoadResource(B_VECTOR_ICON_TYPE, 159f01106c3SAxel Dörfler kNetworkStatusNoDevice + i, &size); 160f01106c3SAxel Dörfler if (data != NULL) { 161e58807edSAlexander von Gluck IV // Scale main tray icon 162e58807edSAlexander von Gluck IV BBitmap* trayIcon = new BBitmap(Bounds(), B_RGBA32); 163e58807edSAlexander von Gluck IV if (trayIcon->InitCheck() == B_OK 164f01106c3SAxel Dörfler && BIconUtils::GetVectorIcon((const uint8 *)data, 165e58807edSAlexander von Gluck IV size, trayIcon) == B_OK) { 166e58807edSAlexander von Gluck IV fTrayIcons[i] = trayIcon; 167f01106c3SAxel Dörfler } else 168e58807edSAlexander von Gluck IV delete trayIcon; 169e58807edSAlexander von Gluck IV 170e58807edSAlexander von Gluck IV // Scale notification icon 171e58807edSAlexander von Gluck IV BBitmap* notifyIcon = new BBitmap(BRect(0, 0, 31, 31), B_RGBA32); 172e58807edSAlexander von Gluck IV if (notifyIcon->InitCheck() == B_OK 173e58807edSAlexander von Gluck IV && BIconUtils::GetVectorIcon((const uint8 *)data, 174e58807edSAlexander von Gluck IV size, notifyIcon) == B_OK) { 175e58807edSAlexander von Gluck IV fNotifyIcons[i] = notifyIcon; 176e58807edSAlexander von Gluck IV } else 177e58807edSAlexander von Gluck IV delete notifyIcon; 178f01106c3SAxel Dörfler } 179f01106c3SAxel Dörfler } 180f01106c3SAxel Dörfler } 181f01106c3SAxel Dörfler 182f01106c3SAxel Dörfler 183f01106c3SAxel Dörfler void 184f01106c3SAxel Dörfler NetworkStatusView::_Quit() 185f01106c3SAxel Dörfler { 186f01106c3SAxel Dörfler if (fInDeskbar) { 187f01106c3SAxel Dörfler BDeskbar deskbar; 188f01106c3SAxel Dörfler deskbar.RemoveItem(kDeskbarItemName); 189f01106c3SAxel Dörfler } else 190f01106c3SAxel Dörfler be_app->PostMessage(B_QUIT_REQUESTED); 191f01106c3SAxel Dörfler } 192f01106c3SAxel Dörfler 193f01106c3SAxel Dörfler 194f01106c3SAxel Dörfler NetworkStatusView* 195f01106c3SAxel Dörfler NetworkStatusView::Instantiate(BMessage* archive) 196f01106c3SAxel Dörfler { 197f01106c3SAxel Dörfler if (!validate_instantiation(archive, "NetworkStatusView")) 198f01106c3SAxel Dörfler return NULL; 199f01106c3SAxel Dörfler 200f01106c3SAxel Dörfler return new NetworkStatusView(archive); 201f01106c3SAxel Dörfler } 202f01106c3SAxel Dörfler 203f01106c3SAxel Dörfler 204f01106c3SAxel Dörfler status_t 205f01106c3SAxel Dörfler NetworkStatusView::Archive(BMessage* archive, bool deep) const 206f01106c3SAxel Dörfler { 207f01106c3SAxel Dörfler status_t status = BView::Archive(archive, deep); 208f01106c3SAxel Dörfler if (status == B_OK) 209f01106c3SAxel Dörfler status = archive->AddString("add_on", kSignature); 210f01106c3SAxel Dörfler if (status == B_OK) 211f01106c3SAxel Dörfler status = archive->AddString("class", "NetworkStatusView"); 212f01106c3SAxel Dörfler 213f01106c3SAxel Dörfler return status; 214f01106c3SAxel Dörfler } 215f01106c3SAxel Dörfler 216f01106c3SAxel Dörfler 217f01106c3SAxel Dörfler void 218f01106c3SAxel Dörfler NetworkStatusView::AttachedToWindow() 219f01106c3SAxel Dörfler { 220f01106c3SAxel Dörfler BView::AttachedToWindow(); 221f01106c3SAxel Dörfler 222485a9ea0SX512 SetViewColor(B_TRANSPARENT_COLOR); 223f01106c3SAxel Dörfler 224195981bbSAxel Dörfler start_watching_network( 225195981bbSAxel Dörfler B_WATCH_NETWORK_INTERFACE_CHANGES | B_WATCH_NETWORK_LINK_CHANGES, this); 226f01106c3SAxel Dörfler 227f01106c3SAxel Dörfler _Update(); 228f01106c3SAxel Dörfler } 229f01106c3SAxel Dörfler 230f01106c3SAxel Dörfler 231f01106c3SAxel Dörfler void 232f01106c3SAxel Dörfler NetworkStatusView::DetachedFromWindow() 233f01106c3SAxel Dörfler { 234195981bbSAxel Dörfler stop_watching_network(this); 235f01106c3SAxel Dörfler } 236f01106c3SAxel Dörfler 237f01106c3SAxel Dörfler 238f01106c3SAxel Dörfler void 239f01106c3SAxel Dörfler NetworkStatusView::MessageReceived(BMessage* message) 240f01106c3SAxel Dörfler { 241f01106c3SAxel Dörfler switch (message->what) { 242195981bbSAxel Dörfler case B_NETWORK_MONITOR: 243f01106c3SAxel Dörfler _Update(); 244f01106c3SAxel Dörfler break; 245f01106c3SAxel Dörfler 246f01106c3SAxel Dörfler case kMsgShowConfiguration: 247f01106c3SAxel Dörfler _ShowConfiguration(message); 248f01106c3SAxel Dörfler break; 249f01106c3SAxel Dörfler 250c1502c9aSStephan Aßmus case kMsgOpenNetworkPreferences: 2513b41ad86SStephan Aßmus _OpenNetworksPreferences(); 2523b41ad86SStephan Aßmus break; 2533b41ad86SStephan Aßmus 2542e1a6286SAxel Dörfler case kMsgJoinNetwork: 2552e1a6286SAxel Dörfler { 2562e1a6286SAxel Dörfler const char* deviceName; 2572e1a6286SAxel Dörfler const char* name; 2586c7caf44SAxel Dörfler BNetworkAddress address; 2592e1a6286SAxel Dörfler if (message->FindString("device", &deviceName) == B_OK 2606c7caf44SAxel Dörfler && message->FindString("name", &name) == B_OK 2616c7caf44SAxel Dörfler && message->FindFlat("address", &address) == B_OK) { 2622e1a6286SAxel Dörfler BNetworkDevice device(deviceName); 2636c7caf44SAxel Dörfler status_t status = device.JoinNetwork(address); 2642e1a6286SAxel Dörfler if (status != B_OK) { 2652e1a6286SAxel Dörfler BString text 2662e1a6286SAxel Dörfler = B_TRANSLATE("Could not join wireless network:\n"); 2672e1a6286SAxel Dörfler text << strerror(status); 2682e1a6286SAxel Dörfler BAlert* alert = new BAlert(name, text.String(), 2692e1a6286SAxel Dörfler B_TRANSLATE("OK"), NULL, NULL, B_WIDTH_AS_USUAL, 2702e1a6286SAxel Dörfler B_STOP_ALERT); 271aed35104SHumdinger alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE); 2722e1a6286SAxel Dörfler alert->Go(NULL); 2732e1a6286SAxel Dörfler } 2742e1a6286SAxel Dörfler } 2752e1a6286SAxel Dörfler break; 2762e1a6286SAxel Dörfler } 2772e1a6286SAxel Dörfler 278f01106c3SAxel Dörfler case B_ABOUT_REQUESTED: 279f01106c3SAxel Dörfler _AboutRequested(); 280f01106c3SAxel Dörfler break; 281f01106c3SAxel Dörfler 282f01106c3SAxel Dörfler case B_QUIT_REQUESTED: 283f01106c3SAxel Dörfler _Quit(); 284f01106c3SAxel Dörfler break; 285f01106c3SAxel Dörfler 286f01106c3SAxel Dörfler default: 287f01106c3SAxel Dörfler BView::MessageReceived(message); 288ab05d368Ssushilhub break; 289f01106c3SAxel Dörfler } 290f01106c3SAxel Dörfler } 291f01106c3SAxel Dörfler 292f01106c3SAxel Dörfler 293f01106c3SAxel Dörfler void 294f01106c3SAxel Dörfler NetworkStatusView::FrameResized(float width, float height) 295f01106c3SAxel Dörfler { 296f01106c3SAxel Dörfler _UpdateBitmaps(); 297d5ba07a3SAxel Dörfler Invalidate(); 298f01106c3SAxel Dörfler } 299f01106c3SAxel Dörfler 300f01106c3SAxel Dörfler 301f01106c3SAxel Dörfler void 302f01106c3SAxel Dörfler NetworkStatusView::Draw(BRect updateRect) 303f01106c3SAxel Dörfler { 3045c46b171SRene Gollent int32 status = kStatusUnknown; 3055c46b171SRene Gollent for (std::map<BString, int32>::const_iterator it 3065c46b171SRene Gollent = fInterfaceStatuses.begin(); it != fInterfaceStatuses.end(); ++it) { 3075c46b171SRene Gollent if (it->second > status) 3085c46b171SRene Gollent status = it->second; 3095c46b171SRene Gollent } 3105c46b171SRene Gollent 3115c46b171SRene Gollent if (fTrayIcons[status] == NULL) 312f01106c3SAxel Dörfler return; 313f01106c3SAxel Dörfler 314f01106c3SAxel Dörfler SetDrawingMode(B_OP_ALPHA); 3155c46b171SRene Gollent DrawBitmap(fTrayIcons[status]); 316f01106c3SAxel Dörfler SetDrawingMode(B_OP_COPY); 317f01106c3SAxel Dörfler } 318f01106c3SAxel Dörfler 319f01106c3SAxel Dörfler 320f01106c3SAxel Dörfler void 321f01106c3SAxel Dörfler NetworkStatusView::_ShowConfiguration(BMessage* message) 322f01106c3SAxel Dörfler { 323f01106c3SAxel Dörfler const char* name; 324f01106c3SAxel Dörfler if (message->FindString("interface", &name) != B_OK) 325f01106c3SAxel Dörfler return; 326f01106c3SAxel Dörfler 3278897f278SStefano Ceccherini BNetworkInterface networkInterface(name); 3288897f278SStefano Ceccherini if (!networkInterface.Exists()) 329f01106c3SAxel Dörfler return; 330f01106c3SAxel Dörfler 3312ee8f3f6SSiarzhuk Zharski BString text(B_TRANSLATE("%ifaceName information:\n")); 3322ee8f3f6SSiarzhuk Zharski text.ReplaceFirst("%ifaceName", name); 333757e7059SAdrien Destugues 334f01106c3SAxel Dörfler size_t boldLength = text.Length(); 335f01106c3SAxel Dörfler 336b81d67edSJeremy Visser int32 numAddrs = networkInterface.CountAddresses(); 337b81d67edSJeremy Visser for (int32 i = 0; i < numAddrs; i++) { 338b81d67edSJeremy Visser BNetworkInterfaceAddress address; 339b81d67edSJeremy Visser networkInterface.GetAddressAt(i, address); 340b81d67edSJeremy Visser switch (address.Address().Family()) { 341b81d67edSJeremy Visser case AF_INET: 3428ff235aaSHumdinger text << "\n" << B_TRANSLATE("IPv4 address:") << " " 343b81d67edSJeremy Visser << address.Address().ToString() 3448ff235aaSHumdinger << "\n" << B_TRANSLATE("Broadcast:") << " " 345b81d67edSJeremy Visser << address.Broadcast().ToString() 3468ff235aaSHumdinger << "\n" << B_TRANSLATE("Netmask:") << " " 347b81d67edSJeremy Visser << address.Mask().ToString() 348b81d67edSJeremy Visser << "\n"; 349b81d67edSJeremy Visser break; 350b81d67edSJeremy Visser case AF_INET6: 3518ff235aaSHumdinger text << "\n" << B_TRANSLATE("IPv6 address:") << " " 35296fbe0f7SAdrien Destugues << address.Address().ToString() 35396fbe0f7SAdrien Destugues << "/" << address.Mask().PrefixLength() 354b81d67edSJeremy Visser << "\n"; 355b81d67edSJeremy Visser break; 356b81d67edSJeremy Visser default: 357b81d67edSJeremy Visser break; 358b81d67edSJeremy Visser } 359b81d67edSJeremy Visser } 360f01106c3SAxel Dörfler 361757e7059SAdrien Destugues BAlert* alert = new BAlert(name, text.String(), B_TRANSLATE("OK")); 362aed35104SHumdinger alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE); 363f01106c3SAxel Dörfler BTextView* view = alert->TextView(); 364f01106c3SAxel Dörfler BFont font; 365f01106c3SAxel Dörfler 366f01106c3SAxel Dörfler view->SetStylable(true); 367f01106c3SAxel Dörfler view->GetFont(&font); 368f01106c3SAxel Dörfler font.SetFace(B_BOLD_FACE); 369f01106c3SAxel Dörfler view->SetFontAndColor(0, boldLength, &font); 370f01106c3SAxel Dörfler 371f01106c3SAxel Dörfler alert->Go(NULL); 372f01106c3SAxel Dörfler } 373f01106c3SAxel Dörfler 374f01106c3SAxel Dörfler 375f01106c3SAxel Dörfler void 376f01106c3SAxel Dörfler NetworkStatusView::MouseDown(BPoint point) 377f01106c3SAxel Dörfler { 378f01106c3SAxel Dörfler BPopUpMenu* menu = new BPopUpMenu(B_EMPTY_STRING, false, false); 379a31688d2SAxel Dörfler menu->SetAsyncAutoDestruct(true); 380f01106c3SAxel Dörfler menu->SetFont(be_plain_font); 3815c46b171SRene Gollent BString wifiInterface; 38202ad9218SJohn Scipione BNetworkDevice device; 383f01106c3SAxel Dörfler 38402ad9218SJohn Scipione if (!fInterfaceStatuses.empty()) { 3855c46b171SRene Gollent for (std::map<BString, int32>::const_iterator it 38602ad9218SJohn Scipione = fInterfaceStatuses.begin(); it != fInterfaceStatuses.end(); 38702ad9218SJohn Scipione ++it) { 3885c46b171SRene Gollent const BString& name = it->first; 389f01106c3SAxel Dörfler 39002ad9218SJohn Scipione // we only show network of the first wireless device we find 3915c46b171SRene Gollent if (wifiInterface.IsEmpty()) { 39202ad9218SJohn Scipione device.SetTo(name); 39302ad9218SJohn Scipione if (device.IsWireless()) 3945c46b171SRene Gollent wifiInterface = name; 3955c46b171SRene Gollent } 396f01106c3SAxel Dörfler } 39702ad9218SJohn Scipione } 398f01106c3SAxel Dörfler 39902ad9218SJohn Scipione // Add wireless networks, if any, first so that we can sort the menu 4005fe97f21SAxel Dörfler 4015c46b171SRene Gollent if (!wifiInterface.IsEmpty()) { 402440d0e61SAxel Dörfler std::set<BNetworkAddress> associated; 403440d0e61SAxel Dörfler BNetworkAddress address; 40402ad9218SJohn Scipione wireless_network network; 405440d0e61SAxel Dörfler uint32 cookie = 0; 40602ad9218SJohn Scipione while (device.GetNextAssociatedNetwork(cookie, address) == B_OK) 407440d0e61SAxel Dörfler associated.insert(address); 408440d0e61SAxel Dörfler 40902ad9218SJohn Scipione int32 wifiCount = 0; 410440d0e61SAxel Dörfler cookie = 0; 41102ad9218SJohn Scipione while (device.GetNextNetwork(cookie, network) == B_OK) { 4122e1a6286SAxel Dörfler BMessage* message = new BMessage(kMsgJoinNetwork); 4135c46b171SRene Gollent message->AddString("device", wifiInterface); 4142e1a6286SAxel Dörfler message->AddString("name", network.name); 4156c7caf44SAxel Dörfler message->AddFlat("address", &network.address); 4162e1a6286SAxel Dörfler 41702ad9218SJohn Scipione BMenuItem* item = new WirelessNetworkMenuItem(network, message); 418440d0e61SAxel Dörfler menu->AddItem(item); 41902ad9218SJohn Scipione wifiCount++; 420440d0e61SAxel Dörfler if (associated.find(network.address) != associated.end()) 421440d0e61SAxel Dörfler item->SetMarked(true); 4225fe97f21SAxel Dörfler } 42302ad9218SJohn Scipione 42402ad9218SJohn Scipione if (wifiCount == 0) { 4255fe97f21SAxel Dörfler BMenuItem* item = new BMenuItem( 4265fe97f21SAxel Dörfler B_TRANSLATE("<no wireless networks found>"), NULL); 4275fe97f21SAxel Dörfler item->SetEnabled(false); 4285fe97f21SAxel Dörfler menu->AddItem(item); 42902ad9218SJohn Scipione } else 43002ad9218SJohn Scipione menu->SortItems(WirelessNetworkMenuItem::CompareSignalStrength); 43102ad9218SJohn Scipione 4325fe97f21SAxel Dörfler menu->AddSeparatorItem(); 4335fe97f21SAxel Dörfler } 4345fe97f21SAxel Dörfler 43502ad9218SJohn Scipione // add action menu items 43602ad9218SJohn Scipione 437757e7059SAdrien Destugues menu->AddItem(new BMenuItem(B_TRANSLATE( 438757e7059SAdrien Destugues "Open network preferences" B_UTF8_ELLIPSIS), 439c1502c9aSStephan Aßmus new BMessage(kMsgOpenNetworkPreferences))); 4403b41ad86SStephan Aßmus 4415fe97f21SAxel Dörfler if (fInDeskbar) { 442757e7059SAdrien Destugues menu->AddItem(new BMenuItem(B_TRANSLATE("Quit"), 443757e7059SAdrien Destugues new BMessage(B_QUIT_REQUESTED))); 4445fe97f21SAxel Dörfler } 44502ad9218SJohn Scipione 44602ad9218SJohn Scipione // Add wired interfaces to top of menu 44702ad9218SJohn Scipione if (!fInterfaceStatuses.empty()) { 44802ad9218SJohn Scipione int32 wiredCount = 0; 44902ad9218SJohn Scipione for (std::map<BString, int32>::const_iterator it 45002ad9218SJohn Scipione = fInterfaceStatuses.begin(); it != fInterfaceStatuses.end(); 45102ad9218SJohn Scipione ++it) { 45202ad9218SJohn Scipione const BString& name = it->first; 45302ad9218SJohn Scipione 45402ad9218SJohn Scipione BString label = name; 45502ad9218SJohn Scipione label += ": "; 45602ad9218SJohn Scipione label += kStatusDescriptions[ 45702ad9218SJohn Scipione _DetermineInterfaceStatus(name.String())]; 45802ad9218SJohn Scipione 45902ad9218SJohn Scipione BMessage* info = new BMessage(kMsgShowConfiguration); 46002ad9218SJohn Scipione info->AddString("interface", name.String()); 46102ad9218SJohn Scipione menu->AddItem(new BMenuItem(label.String(), info), wiredCount); 46202ad9218SJohn Scipione wiredCount++; 46302ad9218SJohn Scipione } 46402ad9218SJohn Scipione 46502ad9218SJohn Scipione // add separator item between wired and wireless networks 46602ad9218SJohn Scipione // (or between wired networks and actions if no wireless found) 46702ad9218SJohn Scipione if (wiredCount > 0) 46802ad9218SJohn Scipione menu->AddItem(new BSeparatorItem(), wiredCount); 46902ad9218SJohn Scipione } 47002ad9218SJohn Scipione 471f01106c3SAxel Dörfler menu->SetTargetForItems(this); 472f01106c3SAxel Dörfler 473f01106c3SAxel Dörfler ConvertToScreen(&point); 474a31688d2SAxel Dörfler menu->Go(point, true, true, true); 475f01106c3SAxel Dörfler } 476f01106c3SAxel Dörfler 477f01106c3SAxel Dörfler 478f01106c3SAxel Dörfler void 479f01106c3SAxel Dörfler NetworkStatusView::_AboutRequested() 480f01106c3SAxel Dörfler { 48131535ac6SAdrien Destugues BAboutWindow* window = new BAboutWindow( 48231535ac6SAdrien Destugues B_TRANSLATE_SYSTEM_NAME("NetworkStatus"), kSignature); 483fd19c736SAdrien Destugues 484730a45eeSJohn Scipione const char* authors[] = { 485730a45eeSJohn Scipione "Axel Dörfler", 486730a45eeSJohn Scipione "Hugo Santos", 487730a45eeSJohn Scipione NULL 488730a45eeSJohn Scipione }; 489f01106c3SAxel Dörfler 490fd19c736SAdrien Destugues window->AddCopyright(2007, "Haiku, Inc."); 491fd19c736SAdrien Destugues window->AddAuthors(authors); 492fd19c736SAdrien Destugues 493fd19c736SAdrien Destugues window->Show(); 494f01106c3SAxel Dörfler } 495f01106c3SAxel Dörfler 496f01106c3SAxel Dörfler 497f01106c3SAxel Dörfler int32 4985c46b171SRene Gollent NetworkStatusView::_DetermineInterfaceStatus( 4995c46b171SRene Gollent const BNetworkInterface& interface) 500f01106c3SAxel Dörfler { 5015fe97f21SAxel Dörfler uint32 flags = interface.Flags(); 502f01106c3SAxel Dörfler 503cb7833c7SPhilippe Houdoin if ((flags & IFF_LINK) == 0) 504cb7833c7SPhilippe Houdoin return kStatusNoLink; 505cb7833c7SPhilippe Houdoin if ((flags & (IFF_UP | IFF_LINK | IFF_CONFIGURING)) == IFF_LINK) 506cb7833c7SPhilippe Houdoin return kStatusLinkNoConfig; 5074a531db1SPhilippe Houdoin if ((flags & IFF_CONFIGURING) == IFF_CONFIGURING) 508cb7833c7SPhilippe Houdoin return kStatusConnecting; 509cb7833c7SPhilippe Houdoin if ((flags & (IFF_UP | IFF_LINK)) == (IFF_UP | IFF_LINK)) 510cb7833c7SPhilippe Houdoin return kStatusReady; 511f01106c3SAxel Dörfler 512cb7833c7SPhilippe Houdoin return kStatusUnknown; 513f01106c3SAxel Dörfler } 514f01106c3SAxel Dörfler 515f01106c3SAxel Dörfler 516f01106c3SAxel Dörfler void 517f01106c3SAxel Dörfler NetworkStatusView::_Update(bool force) 518f01106c3SAxel Dörfler { 5195fe97f21SAxel Dörfler BNetworkRoster& roster = BNetworkRoster::Default(); 5205fe97f21SAxel Dörfler BNetworkInterface interface; 5215fe97f21SAxel Dörfler uint32 cookie = 0; 522*702ff421SJavier Steinaker std::set<BString> currentInterfaces; 5235fe97f21SAxel Dörfler 5245fe97f21SAxel Dörfler while (roster.GetNextInterface(&cookie, interface) == B_OK) { 5255fe97f21SAxel Dörfler if ((interface.Flags() & IFF_LOOPBACK) == 0) { 526*702ff421SJavier Steinaker currentInterfaces.insert((BString)interface.Name()); 5275c46b171SRene Gollent int32 oldStatus = kStatusUnknown; 5285c46b171SRene Gollent if (fInterfaceStatuses.find(interface.Name()) 5295c46b171SRene Gollent != fInterfaceStatuses.end()) { 5305c46b171SRene Gollent oldStatus = fInterfaceStatuses[interface.Name()]; 531f01106c3SAxel Dörfler } 5325c46b171SRene Gollent int32 status = _DetermineInterfaceStatus(interface); 5335c46b171SRene Gollent if (oldStatus != status) { 534b44d24c0SAlexander von Gluck IV BNotification notification(B_INFORMATION_NOTIFICATION); 535b44d24c0SAlexander von Gluck IV notification.SetGroup(B_TRANSLATE("Network Status")); 536b44d24c0SAlexander von Gluck IV notification.SetTitle(interface.Name()); 537b44d24c0SAlexander von Gluck IV notification.SetMessageID(interface.Name()); 5385c46b171SRene Gollent notification.SetIcon(fNotifyIcons[status]); 5395c46b171SRene Gollent if (status == kStatusConnecting 5405c46b171SRene Gollent || (status == kStatusReady 5415c46b171SRene Gollent && oldStatus == kStatusConnecting) 5425c46b171SRene Gollent || (status == kStatusNoLink 5435c46b171SRene Gollent && oldStatus == kStatusReady) 5445c46b171SRene Gollent || (status == kStatusNoLink 5455c46b171SRene Gollent && oldStatus == kStatusConnecting)) { 54643c68287SAlexander von Gluck IV // A significant state change, raise notification. 5475c46b171SRene Gollent notification.SetContent(kStatusDescriptions[status]); 548b44d24c0SAlexander von Gluck IV notification.Send(); 549b44d24c0SAlexander von Gluck IV } 550f01106c3SAxel Dörfler Invalidate(); 551f01106c3SAxel Dörfler } 5525c46b171SRene Gollent fInterfaceStatuses[interface.Name()] = status; 5535c46b171SRene Gollent } 5545c46b171SRene Gollent } 555*702ff421SJavier Steinaker 556*702ff421SJavier Steinaker // Check every element in fInterfaceStatuses against our current interface 557*702ff421SJavier Steinaker // list. If it's not there, then the interface is not present anymore and 558*702ff421SJavier Steinaker // should be removed from fInterfaceStatuses. 559*702ff421SJavier Steinaker std::map<BString, int32>::iterator it = fInterfaceStatuses.begin(); 560*702ff421SJavier Steinaker while (it != fInterfaceStatuses.end()) { 561*702ff421SJavier Steinaker std::map<BString, int32>::iterator backupIt = it; 562*702ff421SJavier Steinaker if (currentInterfaces.find(it->first) == currentInterfaces.end()) 563*702ff421SJavier Steinaker fInterfaceStatuses.erase(it); 564*702ff421SJavier Steinaker it = ++backupIt; 565*702ff421SJavier Steinaker } 566b44d24c0SAlexander von Gluck IV } 567f01106c3SAxel Dörfler 568f01106c3SAxel Dörfler 5693b41ad86SStephan Aßmus void 5703b41ad86SStephan Aßmus NetworkStatusView::_OpenNetworksPreferences() 5713b41ad86SStephan Aßmus { 572195981bbSAxel Dörfler status_t status = be_roster->Launch("application/x-vnd.Haiku-Network"); 57346cac7f7SAlexandre Deckner if (status != B_OK && status != B_ALREADY_RUNNING) { 574757e7059SAdrien Destugues BString errorMessage(B_TRANSLATE("Launching the network preflet " 575757e7059SAdrien Destugues "failed.\n\nError: ")); 576195981bbSAxel Dörfler errorMessage << strerror(status); 5773b41ad86SStephan Aßmus BAlert* alert = new BAlert("launch error", errorMessage.String(), 578757e7059SAdrien Destugues B_TRANSLATE("OK")); 579aed35104SHumdinger alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE); 580195981bbSAxel Dörfler 581195981bbSAxel Dörfler // asynchronous alert in order to not block replicant host application 5823b41ad86SStephan Aßmus alert->Go(NULL); 5833b41ad86SStephan Aßmus } 5843b41ad86SStephan Aßmus } 5853b41ad86SStephan Aßmus 5863b41ad86SStephan Aßmus 587f01106c3SAxel Dörfler // #pragma mark - 588f01106c3SAxel Dörfler 589f01106c3SAxel Dörfler 590f01106c3SAxel Dörfler extern "C" _EXPORT BView * 591efafab64SAxel Dörfler instantiate_deskbar_item(float maxWidth, float maxHeight) 592f01106c3SAxel Dörfler { 593efafab64SAxel Dörfler return new NetworkStatusView(BRect(0, 0, maxHeight - 1, maxHeight - 1), 59466eba86fSAxel Dörfler B_FOLLOW_LEFT | B_FOLLOW_TOP, true); 595f01106c3SAxel Dörfler } 596