brettpoole / growl

Automatically exported from code.google.com/p/growl
BSD 3-Clause "New" or "Revised" License
0 stars 0 forks source link

HardwareGrowler is confused about network interfaces on Macbook Air #459

Closed GoogleCodeExporter closed 8 years ago

GoogleCodeExporter commented 8 years ago
See conversation in email list. Patch is below. I have attached a tar file of 
the binary Localizable.strings strings, to untar in the HardwareGrowler 
directory.

YA

diff -r 193986cc6493 Extras/HardwareGrowler/NetworkNotifier.m
--- a/Extras/HardwareGrowler/NetworkNotifier.m  Mon Nov 07 10:48:13 2011 -0600
+++ b/Extras/HardwareGrowler/NetworkNotifier.m  Wed Feb 29 15:20:50 2012 -0800
@@ -3,6 +3,7 @@
 //  HardwareGrowler
 //
 //  Created by Ingmar Stein on 18.02.05.
+//  Modified by Yves Arrouye on 22.02.11 to support MacBook Airs.
 //  Copyright 2005 The Growl Project. All rights reserved.
 //  Copyright (C) 2004 Scott Lamb <slamb@slamb.org>
 //
@@ -32,6 +33,16 @@
 /** A reference to the SystemConfiguration dynamic store. */
 static SCDynamicStoreRef dynStore;

+/** Keys to watch. Entries 1 and 2 will be filled in with the appropriate keys 
for the interfaces we are watching. Ideally, this module would be changed to 
support an arbitraty number of interfaces of each type, but this will fix the 
issues about reporting Airport as Ethernet on MacBook Air machines and that is 
all we care about right now. */
+CFStringRef keys[3] = {
+    CFSTR("State:/Network/Global/IPv4")
+};
+static int keysFirstInterfaceEntry = 1;
+int keysNumEntries = 1;
+
+int airportKey = -1;
+int ethernetKey = -1;
+
 /** Our run loop source for notification. */
 static CFRunLoopSourceRef rlSrc;

@@ -44,11 +55,11 @@
    // This is all made by looking through Darwin's src/network_cmds/ifconfig.tproj.
    // There's no pretty way to get media stuff; I've stripped it down to the essentials
    // for what I'm doing.
-
+    
    size_t length = strlen(interface);
    if (length >= IFNAMSIZ)
        NSLog(@"Interface name too long");
-
+    
    int s = socket(AF_INET, SOCK_DGRAM, 0);
    if (s < 0) {
        NSLog(@"Can't open datagram socket");
@@ -57,21 +68,21 @@
    struct ifmediareq ifmr;
    memset(&ifmr, 0, sizeof(ifmr));
    strncpy(ifmr.ifm_name, interface, sizeof(ifmr.ifm_name));
-
+    
    if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0) {
        // Media not supported.
        close(s);
        return NULL;
    }
-
+    
    close(s);
-
+    
    // Now ifmr.ifm_current holds the selected type (probably auto-select)
    // ifmr.ifm_active holds details (100baseT <full-duplex> or similar)
    // We only want the ifm_active bit.
-
+    
    const char *type = "Unknown";
-
+    
    // We'll only look in the Ethernet list. I don't care about anything else.
    struct ifmedia_description *desc;
    for (desc = ifm_subtype_ethernet_descriptions; desc->ifmt_string; ++desc) {
@@ -80,9 +91,9 @@
            break;
        }
    }
-
+    
    NSMutableString *options = nil;
-
+    
    // And fill in the duplex settings.
    for (desc = ifm_shared_option_descriptions; desc->ifmt_string; desc++) {
        if (ifmr.ifm_active & desc->ifmt_word) {
@@ -93,33 +104,37 @@
            }
        }
    }
-
+    
    NSString *media;
    if (options) {
        media = [NSString stringWithFormat:@"%s <%@>",
-                                        type,
-                                        options];
+                 type,
+                 options];
    } else {
        media = [NSString stringWithUTF8String:type];
    }
-
+    
    return media;
 }

 - (void)linkStatusChange:(NSDictionary *)newValue {
    int newActive = [[newValue objectForKey:@"Active"] intValue];
    int oldActive = [[(NSDictionary*)ethernetStatus objectForKey:@"Active"] intValue];
-   
+
+    NSString *ifName = [NSString stringWithFormat:@"en%d", ethernetKey - 
keysFirstInterfaceEntry];
+
    if (newActive && !oldActive) {
-       NSString *media = [self getMediaForInterface:"en0"];
-       NSString *desc = [NSString stringWithFormat:
-                         NSLocalizedString(@"Interface:\ten0\nMedia:\t%@", "The %@ will be 
replaced by a description of the Ethernet media such as '100BT/full-duplex'"),
+       NSString *media = [self getMediaForInterface:[ifName UTF8String]];
+        NSString *desc = [NSString stringWithFormat:
+                          NSLocalizedString(@"Interface:\t%@\nMedia:\t%@", 
"The first %@ will bereplaced by the interface name, e.g. en0; the second %@ 
will be replaced by a description of the Ethernet media such as 
'100BT/full-duplex'"),
                          media];
        AppController_linkUp((CFStringRef)desc);
    } else if (!newActive && oldActive) {
-       AppController_linkDown((CFStringRef)NSLocalizedString(@"Interface:\ten0", 
nil));
+        NSString *desc = [NSString stringWithFormat:
+                          NSLocalizedString(@"Interface:\t%@", "The %@ will be 
replaced by the interface name, e.g. en0"), ifName];
+       AppController_linkDown((CFStringRef)desc);
    }
-
+    
    if (ethernetStatus)
        CFRelease(ethernetStatus);
    ethernetStatus = newValue ? CFRetain(newValue) : NULL;
@@ -164,8 +179,8 @@
        for (unsigned i=0U; i<9; ++i) {
            if ((a & types[i].netmask) == types[i].network) {
                return [[NSBundle bundleForClass:[self class]] localizedStringForKey:types[i].type
-                                                                             value:types[i].type
-                                                                             table:nil];
+                                                                               
value:types[i].type
+                                                                               
table:nil];
            }
        }
    }
@@ -192,16 +207,16 @@
 }

 - (void)airportStatusChange:(NSDictionary *)newValue {
-// NSLog(CFSTR("AirPort event"));
-
+    // NSLog(CFSTR("AirPort event"));
+    
    CFDataRef newBSSID = NULL;
    if (newValue)
        newBSSID = (CFDataRef)[newValue objectForKey:@"BSSID"];
-
+    
    CFDataRef oldBSSID = NULL;
    if (airportStatus)
        oldBSSID = CFDictionaryGetValue(airportStatus, CFSTR("BSSID"));
-
+    
    if (newValue && oldBSSID != newBSSID && !(newBSSID && oldBSSID && CFEqual(oldBSSID, newBSSID))) {
        NSNumber *linkStatus = [newValue objectForKey:@"Link Status"];
        NSNumber *powerStatus = [newValue objectForKey:@"Power Status"];
@@ -227,10 +242,10 @@
            }
        }
    }
-
+    
    if (airportStatus)
        CFRelease(airportStatus);
-
+    
    if (newValue)
        airportStatus = CFRetain(newValue);
    else
@@ -239,13 +254,11 @@

 static void scCallback(SCDynamicStoreRef store, CFArrayRef changedKeys, void *info) {
    NetworkNotifier *self = info;
-
+    
    CFIndex count = CFArrayGetCount(changedKeys);
    for (CFIndex i=0; i<count; ++i) {
        CFStringRef key = CFArrayGetValueAtIndex(changedKeys, i);
-       if (CFStringCompare(key,
-                           CFSTR("State:/Network/Interface/en0/Link"),
-                           0) == kCFCompareEqualTo) {
+       if (ethernetKey >= 0 && CFStringCompare(key, keys[ethernetKey], 0) == 
kCFCompareEqualTo) {
            CFDictionaryRef newValue = SCDynamicStoreCopyValue(store, key);
            [self linkStatusChange:(NSDictionary *)newValue];
            if (newValue)
@@ -257,9 +270,7 @@
            [self ipAddressChange:(NSDictionary *)newValue];
            if (newValue)
                CFRelease(newValue);
-       } else if (CFStringCompare(key,
-                                  CFSTR("State:/Network/Interface/en1/AirPort"),
-                                  0) == kCFCompareEqualTo) {
+       } else if (airportKey >= 0 && CFStringCompare(key, keys[airportKey], 0) == 
kCFCompareEqualTo) {
            CFDictionaryRef newValue = SCDynamicStoreCopyValue(store, key);
            [self airportStatusChange:(NSDictionary *)newValue];
            if (newValue)
@@ -272,7 +283,7 @@
    if (!(self = [super init])) return nil;

    SCDynamicStoreContext context = {0, self, NULL, NULL, NULL};
-
+    
    dynStore = SCDynamicStoreCreate(kCFAllocatorDefault,
                                    CFBundleGetIdentifier(CFBundleGetMainBundle()),
                                    scCallback,
@@ -282,16 +293,93 @@
        [self release];
        return nil;
    }
+       
+   rlSrc = SCDynamicStoreCreateRunLoopSource(kCFAllocatorDefault, dynStore, 0);
+   CFRunLoopAddSource(CFRunLoopGetCurrent(), rlSrc, kCFRunLoopDefaultMode);
+   CFRelease(rlSrc);

-   const CFStringRef keys[3] = {
-       CFSTR("State:/Network/Interface/en0/Link"),
-       CFSTR("State:/Network/Global/IPv4"),
-       CFSTR("State:/Network/Interface/en1/AirPort")
-   };
-   CFArrayRef watchedKeys = CFArrayCreate(kCFAllocatorDefault,
-                                          (const void **)keys,
-                                          3,
-                                          &kCFTypeArrayCallBacks);
+    // Are we going to notify about existing interfaces?
+    
+    Boolean notifyAboutExistingHardware = false;
+    
+    Boolean keyExistsAndHasValidFormat;
+    if (CFPreferencesGetAppBooleanValue(CFSTR("ShowExisting"), 
CFSTR("com.growl.hardwaregrowler"), &keyExistsAndHasValidFormat)) {
+        notifyAboutExistingHardware = true;
+    }
+    
+    // Look at network interfaces. Determine for each whether they are 
Ethernet or Airport.
+    // The proper way to do this is probably to look at system preferences. We 
will however
+    // cheat here and just enumerate the en* interfaces.
+    
+    airportStatus = ethernetStatus = NULL;
+    
+    NSDictionary *interfaceDict = (__bridge_transfer NSDictionary *) 
SCDynamicStoreCopyValue(dynStore, CFSTR("State:/Network/Interface"));
+    if (interfaceDict) {
+        NSArray *interfaceNames = [interfaceDict objectForKey:@"Interfaces"];
+        if (interfaceNames) {
+            for (NSString *ifName in interfaceNames) {
+                
+                // Let's not look at any interface that is not Ethernet or 
Airpot.
+                
+                if (![ifName hasPrefix:@"en"] || [ifName length] < 3 || 
!isdigit([ifName characterAtIndex:2])) {
+                    continue;
+                }
+                
+                // Alright, we can proceed. We will look for Airport first, as 
both Airport
+                // and Ethernet interfaces can have a link (indicating their 
status).
+                
+                CFStringRef key = 
CFStringCreateWithFormat(kCFAllocatorDefault, NULL, 
CFSTR("State:/Network/Interface/%@/AirPort"), ifName);
+                CFDictionaryRef status = SCDynamicStoreCopyValue(dynStore, 
key);
+                
+                if (status) {
+                    if (!airportStatus) {
+                        if (notifyAboutExistingHardware) {
+                            [self airportStatusChange:(__bridge NSDictionary 
*)status];
+                            [self ipAddressChange:(__bridge NSDictionary 
*)status];
+                            CFRelease(status);
+                        } else {
+                            airportStatus = status;
+                        }
+                        
+                        keys[airportKey = keysNumEntries++] = CFRetain(key);
+                    }
+                    
+                    CFRelease(key);
+                    continue;
+                }
+                CFRelease(key);
+                
+                
+                key = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, 
CFSTR("State:/Network/Interface/%@/Link"), ifName);
+                status = SCDynamicStoreCopyValue(dynStore, key);
+                
+                if (status) {
+                    if (!ethernetStatus) {
+                        if (notifyAboutExistingHardware) {
+                            [self linkStatusChange:(__bridge NSDictionary 
*)status];
+                            [self ipAddressChange:(__bridge NSDictionary 
*)status];
+                            CFRelease(status);
+                        } else {
+                            ethernetStatus = status;
+                        }
+                        
+                        keys[ethernetKey = keysNumEntries++] = CFRetain(key);
+                    }
+                    
+                    CFRelease(key);
+                    continue;
+                }  
+                CFRelease(key);
+            }
+        }
+    }
+    
+    // Register the keys to watch.
+    
+    CFArrayRef watchedKeys = CFArrayCreate(kCFAllocatorDefault,
+                                           (const void **)keys,
+                                           keysNumEntries,
+                                           &kCFTypeArrayCallBacks);
    if (!SCDynamicStoreSetNotificationKeys(dynStore,
                                           watchedKeys,
                                           NULL)) {
@@ -304,13 +392,7 @@
        return nil;
    }
    CFRelease(watchedKeys);
-   
-   rlSrc = SCDynamicStoreCreateRunLoopSource(kCFAllocatorDefault, dynStore, 0);
-   CFRunLoopAddSource(CFRunLoopGetCurrent(), rlSrc, kCFRunLoopDefaultMode);
-   CFRelease(rlSrc);
-   
-   airportStatus  = SCDynamicStoreCopyValue(dynStore, 
CFSTR("State:/Network/Interface/en1/AirPort"));
-   ethernetStatus = SCDynamicStoreCopyValue(dynStore, 
CFSTR("State:/Network/Interface/en0/Link"));
+    
    return self;
 }

@@ -324,6 +406,11 @@
    if (ethernetStatus)
        CFRelease(ethernetStatus);

+    if (keys[1])
+        CFRelease(keys[1]);
+    if (keys[2])
+        CFRelease(keys[2]);
+
    [super dealloc];
 }

diff -r 193986cc6493 Extras/HardwareGrowler/ar.lproj/Localizable.strings
Binary file Extras/HardwareGrowler/ar.lproj/Localizable.strings has changed
diff -r 193986cc6493 Extras/HardwareGrowler/cs.lproj/Localizable.strings
Binary file Extras/HardwareGrowler/cs.lproj/Localizable.strings has changed
diff -r 193986cc6493 Extras/HardwareGrowler/de.lproj/Localizable.strings
Binary file Extras/HardwareGrowler/de.lproj/Localizable.strings has changed
diff -r 193986cc6493 Extras/HardwareGrowler/el.lproj/Localizable.strings
Binary file Extras/HardwareGrowler/el.lproj/Localizable.strings has changed
diff -r 193986cc6493 Extras/HardwareGrowler/en.lproj/Localizable.strings
Binary file Extras/HardwareGrowler/en.lproj/Localizable.strings has changed
diff -r 193986cc6493 Extras/HardwareGrowler/it.lproj/Localizable.strings
Binary file Extras/HardwareGrowler/it.lproj/Localizable.strings has changed
diff -r 193986cc6493 Extras/HardwareGrowler/ja.lproj/Localizable.strings
Binary file Extras/HardwareGrowler/ja.lproj/Localizable.strings has changed
diff -r 193986cc6493 Extras/HardwareGrowler/ko.lproj/Localizable.strings
Binary file Extras/HardwareGrowler/ko.lproj/Localizable.strings has changed
diff -r 193986cc6493 Extras/HardwareGrowler/lv.lproj/Localizable.strings
Binary file Extras/HardwareGrowler/lv.lproj/Localizable.strings has changed
diff -r 193986cc6493 Extras/HardwareGrowler/nl.lproj/Localizable.strings
Binary file Extras/HardwareGrowler/nl.lproj/Localizable.strings has changed
diff -r 193986cc6493 Extras/HardwareGrowler/ro.lproj/Localizable.strings
--- a/Extras/HardwareGrowler/ro.lproj/Localizable.strings   Mon Nov 07 10:48:13 
2011 -0600
+++ b/Extras/HardwareGrowler/ro.lproj/Localizable.strings   Wed Feb 29 15:20:50 
2012 -0800
@@ -17,13 +17,13 @@
 "FireWire Device Disconnected" = "Dispozitiv cu cablu deconectat ";
 "FireWire Disconnection" = "Deconectare cablu";
 "Group Network Notifications" = "Grup rețea de notificări";
-"Interface:\ten0" = "Interfață:\ten0";
-"Interface:\ten0\nMedia:\t%@" = "Interfață:\ten0\nMedia:\t%@";
+"Interface:\t%@" = "Interfață:%@";
+"Interface:\t%@\nMedia:\t%@" = "Interfață:%@\nMedia:\t%@";
 "IP Acquired" = "IP primit";
 "IP address acquired" = "Adresă IP primită";
 "IP address released" = "Adresă IP expediată";
 "IP Released" = "IP expediat";
-"Joined network.\nSSID:\t\t%@\nBSSID:\t%@" = "Rețea 
conectată.\nSSID:\t\t%1$@\nBSSID:\t%2$@";
+"Joined network.\nSSID:\t%@\nBSSID:\t%@" = "Rețea 
conectată.\nSSID:\t%1$@\nBSSID:\t%2$@";
 "Left network %@." = "Rețea părăsită %@.";
 "Link-local" = "Legătură-locală";
 "Loopback" = "Revenire la forma inițială";
diff -r 193986cc6493 Extras/HardwareGrowler/sk.lproj/Localizable.strings
Binary file Extras/HardwareGrowler/sk.lproj/Localizable.strings has changed
diff -r 193986cc6493 Extras/HardwareGrowler/sv.lproj/Localizable.strings
Binary file Extras/HardwareGrowler/sv.lproj/Localizable.strings has changed
diff -r 193986cc6493 Extras/HardwareGrowler/zh-Hans.lproj/Localizable.strings
Binary file Extras/HardwareGrowler/zh-Hans.lproj/Localizable.strings has changed
diff -r 193986cc6493 Extras/HardwareGrowler/zh-Hant.lproj/Localizable.strings
Binary file Extras/HardwareGrowler/zh-Hant.lproj/Localizable.strings has changed

Original issue reported on code.google.com by yves.arr...@gmail.com on 1 Mar 2012 at 12:27

GoogleCodeExporter commented 8 years ago
Attached file with ALL the strings.

Original comment by yves.arr...@gmail.com on 1 Mar 2012 at 12:29

Attachments:

GoogleCodeExporter commented 8 years ago

Original comment by rarich...@gmail.com on 9 Mar 2012 at 3:33

GoogleCodeExporter commented 8 years ago
HWGrowler 2.0 is getting a complete rewrite, including the network module so 
that it handles ipv6 and other things, including this.  I will look through 
these changes, since I was wondering a bit how to handle determining link type. 
 And I will look at making it handle an arbitrary number of interfaces and 
types (I believe MacPro's also face issues with how HWGrowler currently works 
after all).  

Original comment by dan...@growl.info on 4 May 2012 at 10:38

GoogleCodeExporter commented 8 years ago
Flagging as FixedInSource as of [369c41d15682] in the dev repo, will be in 
HWGrowler 2.0, its dynamic and should support any number of interfaces in any 
order.  Thanks for your help with the patch even if I didn't use it verbatim, 
it helped me get this done a lot quicker without having to figure out how to 
test for an AirPort vs Ethernet link.

Original comment by dan...@growl.info on 8 May 2012 at 9:46

GoogleCodeExporter commented 8 years ago
You are welcome! 

Original comment by yves.arr...@gmail.com on 8 May 2012 at 10:07

GoogleCodeExporter commented 8 years ago
Growl 2 is released, marking these as fixed.

Original comment by ch...@growl.info on 20 Sep 2012 at 3:16

GoogleCodeExporter commented 8 years ago
unfortunately there is some unknown condition on a wide range of OS and 
machines that causes registering for SC notifications on 
State:/Network/Interface to fail.

Original comment by rarich...@gmail.com on 24 Nov 2012 at 1:49

GoogleCodeExporter commented 8 years ago

Original comment by ch...@growl.info on 11 Jan 2013 at 6:56