├── world_icon.icns ├── world_icon.png ├── iconping ├── en.lproj │ ├── InfoPlist.strings │ ├── Credits.rtf │ └── MainMenu.xib ├── iconko.png ├── iconok.png ├── iconslow.png ├── iconping-Prefix.pch ├── main.m ├── iconpingAppDelegate.h ├── iconping-Info.plist └── iconpingAppDelegate.m ├── .gitignore ├── README ├── COPYING └── iconping.xcodeproj └── project.pbxproj /world_icon.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antirez/iconping/HEAD/world_icon.icns -------------------------------------------------------------------------------- /world_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antirez/iconping/HEAD/world_icon.png -------------------------------------------------------------------------------- /iconping/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /iconping/iconko.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antirez/iconping/HEAD/iconping/iconko.png -------------------------------------------------------------------------------- /iconping/iconok.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antirez/iconping/HEAD/iconping/iconok.png -------------------------------------------------------------------------------- /iconping/iconslow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antirez/iconping/HEAD/iconping/iconslow.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | iconping.xcodeproj/project.xcworkspace/ 3 | iconping.xcodeproj/xcuserdata/ 4 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | This is the source code of Icon Ping, for more information please check: 2 | 3 | http://antirez.com/iconping 4 | -------------------------------------------------------------------------------- /iconping/iconping-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header for all source files of the 'iconping' target in the 'iconping' project 3 | // 4 | 5 | #ifdef __OBJC__ 6 | #import 7 | #endif 8 | -------------------------------------------------------------------------------- /iconping/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // iconping 4 | // 5 | // Created by Salvatore Sanfilippo on 25/07/11. 6 | // Copyright 2011 Salvatore Sanfilippo. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | int main(int argc, char *argv[]) 12 | { 13 | return NSApplicationMain(argc, (const char **)argv); 14 | } 15 | -------------------------------------------------------------------------------- /iconping/en.lproj/Credits.rtf: -------------------------------------------------------------------------------- 1 | {\rtf0\ansi{\fonttbl\f0\fswiss Helvetica;} 2 | {\colortbl;\red255\green255\blue255;} 3 | \paperw9840\paperh8400 4 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural 5 | 6 | \f0\b\fs24 \cf0 Engineering: 7 | \b0 \ 8 | Some people\ 9 | \ 10 | 11 | \b Human Interface Design: 12 | \b0 \ 13 | Some other people\ 14 | \ 15 | 16 | \b Testing: 17 | \b0 \ 18 | Hopefully not nobody\ 19 | \ 20 | 21 | \b Documentation: 22 | \b0 \ 23 | Whoever\ 24 | \ 25 | 26 | \b With special thanks to: 27 | \b0 \ 28 | Mom\ 29 | } 30 | -------------------------------------------------------------------------------- /iconping/iconpingAppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // iconpingAppDelegate.h 3 | // iconping 4 | // 5 | // Created by Salvatore Sanfilippo on 25/07/11. 6 | // Copyright 2011 Salvatore Sanfilippo. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface iconpingAppDelegate : NSObject { 12 | NSWindow *window; 13 | NSStatusItem *myStatusItem; 14 | NSImage *myStatusImageOK, *myStatusImageSLOW, *myStatusImageKO; 15 | NSMenu *myMenu; 16 | NSMenuItem *statusMenuItem, *openAtStartupMenuItem; 17 | uint16_t icmp_id; 18 | uint16_t icmp_seq; 19 | int64_t last_received_time; 20 | int last_rtt; 21 | int icmp_socket; 22 | int connection_state; 23 | } 24 | 25 | - (void) changeConnectionState: (int) state; 26 | - (BOOL)loginItemExists; 27 | - (BOOL)toggleLoginItem; 28 | 29 | @property (assign) IBOutlet NSWindow *window; 30 | @end 31 | 32 | int setSocketNonBlocking(int fd); 33 | int64_t ustime(void); 34 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | Copyright (c) 2011, Salvatore Sanfilippo 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 5 | 6 | * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 7 | * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 8 | * Neither the name of Redis nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 9 | 10 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 11 | -------------------------------------------------------------------------------- /iconping/iconping-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDocumentTypes 8 | 9 | CFBundleExecutable 10 | ${EXECUTABLE_NAME} 11 | CFBundleIconFile 12 | world_icon.icns 13 | CFBundleIdentifier 14 | com.antirez.${PRODUCT_NAME:rfc1034identifier} 15 | CFBundleInfoDictionaryVersion 16 | 6.0 17 | CFBundleName 18 | ${PRODUCT_NAME} 19 | CFBundlePackageType 20 | APPL 21 | CFBundleShortVersionString 22 | 1.02 23 | CFBundleSignature 24 | ???? 25 | CFBundleURLTypes 26 | 27 | CFBundleVersion 28 | 1 29 | LSApplicationCategoryType 30 | public.app-category.utilities 31 | LSMinimumSystemVersion 32 | ${MACOSX_DEPLOYMENT_TARGET} 33 | NSHumanReadableCopyright 34 | Copyright © 2014 Salvatore Sanfilippo. All rights reserved. 35 | NSMainNibFile 36 | MainMenu 37 | NSPrincipalClass 38 | NSApplication 39 | NSServices 40 | 41 | NSUIElement 42 | 1 43 | UTExportedTypeDeclarations 44 | 45 | UTImportedTypeDeclarations 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /iconping/en.lproj/MainMenu.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 1070 5 | 11A511 6 | 1617 7 | 1138 8 | 566.00 9 | 10 | com.apple.InterfaceBuilder.CocoaPlugin 11 | 1617 12 | 13 | 14 | YES 15 | NSCustomObject 16 | 17 | 18 | YES 19 | com.apple.InterfaceBuilder.CocoaPlugin 20 | 21 | 22 | YES 23 | 24 | YES 25 | 26 | 27 | 28 | 29 | YES 30 | 31 | NSApplication 32 | 33 | 34 | FirstResponder 35 | 36 | 37 | NSApplication 38 | 39 | 40 | iconpingAppDelegate 41 | 42 | 43 | NSFontManager 44 | 45 | 46 | 47 | 48 | YES 49 | 50 | 51 | delegate 52 | 53 | 54 | 55 | 495 56 | 57 | 58 | 59 | 60 | YES 61 | 62 | 0 63 | 64 | 65 | 66 | 67 | 68 | -2 69 | 70 | 71 | File's Owner 72 | 73 | 74 | -1 75 | 76 | 77 | First Responder 78 | 79 | 80 | -3 81 | 82 | 83 | Application 84 | 85 | 86 | 420 87 | 88 | 89 | 90 | 91 | 494 92 | 93 | 94 | 95 | 96 | 97 | 98 | YES 99 | 100 | YES 101 | -1.IBPluginDependency 102 | -2.IBPluginDependency 103 | -3.IBPluginDependency 104 | 420.IBPluginDependency 105 | 494.IBPluginDependency 106 | 107 | 108 | YES 109 | com.apple.InterfaceBuilder.CocoaPlugin 110 | com.apple.InterfaceBuilder.CocoaPlugin 111 | com.apple.InterfaceBuilder.CocoaPlugin 112 | com.apple.InterfaceBuilder.CocoaPlugin 113 | com.apple.InterfaceBuilder.CocoaPlugin 114 | 115 | 116 | 117 | YES 118 | 119 | 120 | 121 | 122 | 123 | YES 124 | 125 | 126 | 127 | 128 | 535 129 | 130 | 131 | 132 | YES 133 | 134 | iconpingAppDelegate 135 | NSObject 136 | 137 | window 138 | NSWindow 139 | 140 | 141 | window 142 | 143 | window 144 | NSWindow 145 | 146 | 147 | 148 | IBProjectSource 149 | ./Classes/iconpingAppDelegate.h 150 | 151 | 152 | 153 | 154 | 0 155 | IBCocoaFramework 156 | 157 | com.apple.InterfaceBuilder.CocoaPlugin.InterfaceBuilder3 158 | 159 | 160 | YES 161 | 3 162 | 163 | 164 | -------------------------------------------------------------------------------- /iconping/iconpingAppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // iconpingAppDelegate.m 3 | // iconping 4 | // 5 | // Created by Salvatore Sanfilippo on 25/07/11. 6 | // Copyright Salvatore Sanfilippo. All rights reserved. 7 | // 8 | 9 | #import "iconpingAppDelegate.h" 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | @implementation iconpingAppDelegate 20 | 21 | @synthesize window; 22 | 23 | struct ICMPHeader { 24 | uint8_t type; 25 | uint8_t code; 26 | uint16_t checksum; 27 | uint16_t identifier; 28 | uint16_t sequenceNumber; 29 | // data... 30 | int64_t sentTime; 31 | }; 32 | 33 | #define ICMP_TYPE_ECHO_REPLY 0 34 | #define ICMP_TYPE_ECHO_REQUEST 8 35 | 36 | #define CONN_STATE_KO 0 37 | #define CONN_STATE_SLOW 1 38 | #define CONN_STATE_OK 2 39 | 40 | /* This is the standard BSD checksum code, modified to use modern types. */ 41 | static uint16_t in_cksum(const void *buffer, size_t bufferLen) 42 | { 43 | size_t bytesLeft; 44 | int32_t sum; 45 | const uint16_t * cursor; 46 | union { 47 | uint16_t us; 48 | uint8_t uc[2]; 49 | } last; 50 | uint16_t answer; 51 | 52 | bytesLeft = bufferLen; 53 | sum = 0; 54 | cursor = buffer; 55 | 56 | /* 57 | * Our algorithm is simple, using a 32 bit accumulator (sum), we add 58 | * sequential 16 bit words to it, and at the end, fold back all the 59 | * carry bits from the top 16 bits into the lower 16 bits. 60 | */ 61 | while (bytesLeft > 1) { 62 | sum += *cursor; 63 | cursor += 1; 64 | bytesLeft -= 2; 65 | } 66 | /* mop up an odd byte, if necessary */ 67 | if (bytesLeft == 1) { 68 | last.uc[0] = * (const uint8_t *) cursor; 69 | last.uc[1] = 0; 70 | sum += last.us; 71 | } 72 | 73 | /* add back carry outs from top 16 bits to low 16 bits */ 74 | sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */ 75 | sum += (sum >> 16); /* add carry */ 76 | answer = ~sum; /* truncate to 16 bits */ 77 | 78 | return answer; 79 | } 80 | 81 | int setSocketNonBlocking(int fd) { 82 | int flags; 83 | 84 | /* Set the socket nonblocking. 85 | * Note that fcntl(2) for F_GETFL and F_SETFL can't be 86 | * interrupted by a signal. */ 87 | if ((flags = fcntl(fd, F_GETFL)) == -1) return -1; 88 | if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) return -1; 89 | return 0; 90 | } 91 | 92 | /* Return the UNIX time in microseconds */ 93 | int64_t ustime(void) { 94 | struct timeval tv; 95 | long long ust; 96 | 97 | gettimeofday(&tv, NULL); 98 | ust = ((int64_t)tv.tv_sec)*1000000; 99 | ust += tv.tv_usec; 100 | return ust; 101 | } 102 | 103 | - (void) sendPingwithId: (int) identifier andSeq: (int) seq { 104 | if (icmp_socket != -1) close(icmp_socket); 105 | 106 | int s = icmp_socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_ICMP); 107 | struct sockaddr_in sa; 108 | struct ICMPHeader icmp; 109 | 110 | if (s == -1) return; 111 | inet_aton("8.8.8.8", &sa.sin_addr); 112 | setSocketNonBlocking(s); 113 | 114 | /* Note that we create always a new socket, with a different identifier 115 | * and sequence number. This is to avoid to read old replies to our ICMP 116 | * request, and to be sure that even in the case the user changes 117 | * connection, routing, interfaces, everything will continue to work. */ 118 | icmp.type = ICMP_TYPE_ECHO_REQUEST; 119 | icmp.code = 0; 120 | icmp.checksum = 0; 121 | icmp.identifier = identifier; 122 | icmp.sequenceNumber = seq; 123 | icmp.sentTime = ustime(); 124 | icmp.checksum = in_cksum(&icmp,sizeof(icmp)); 125 | 126 | sendto(s,&icmp,sizeof(icmp),0,(struct sockaddr*)&sa,sizeof(sa)); 127 | } 128 | 129 | - (void) receivePing { 130 | unsigned char packet[1024*16]; 131 | struct ICMPHeader *reply; 132 | int s = icmp_socket; 133 | ssize_t nread = read(s,packet,sizeof(packet)); 134 | int icmpoff; 135 | 136 | if (nread <= 0) return; 137 | NSLog(@"Received ICMP %d bytes\n", (int)nread); 138 | 139 | icmpoff = (packet[0]&0x0f)*4; 140 | NSLog(@"ICMP offset: %d\n", icmpoff); 141 | 142 | /* Don't process malformed packets. */ 143 | if (nread < (icmpoff + (signed)sizeof(struct ICMPHeader))) return; 144 | reply = (struct ICMPHeader*) (packet+icmpoff); 145 | 146 | /* Make sure that identifier and sequence match */ 147 | if (reply->identifier != icmp_id || 148 | reply->sequenceNumber != icmp_seq) 149 | { 150 | return; 151 | } 152 | 153 | NSLog(@"OK received an ICMP packet that matches!\n"); 154 | if (reply->sentTime > last_received_time) { 155 | last_rtt = (int)(ustime()-reply->sentTime)/1000; 156 | last_received_time = reply->sentTime; 157 | [myStatusItem setToolTip:[NSString stringWithFormat:@"rtt < %.1f seconds", (float)last_rtt/1000]]; 158 | } 159 | } 160 | 161 | - (void)applicationDidFinishLaunching:(NSNotification *)aNotification 162 | { 163 | NSBundle *bundle = [NSBundle mainBundle]; 164 | /* 165 | [NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(timerHandler:) userInfo:nil repeats:YES]; 166 | */ 167 | NSInvocation *invocation = [NSInvocation invocationWithMethodSignature: 168 | [self methodSignatureForSelector:@selector(timerHandler:)]]; 169 | [invocation setTarget:self]; 170 | [invocation setSelector:@selector(timerHandler:)]; 171 | [[NSRunLoop mainRunLoop] addTimer:[NSTimer timerWithTimeInterval:0.1 invocation:invocation repeats:YES] forMode:NSRunLoopCommonModes]; 172 | 173 | myMenu = [[NSMenu alloc] initWithTitle:@"Menu Title"]; 174 | NSMenuItem *menuItem = [[NSMenuItem alloc] initWithTitle:@"Quit Icon Ping" action:@selector(exitAction) keyEquivalent:@"q"]; 175 | [menuItem setEnabled:YES]; 176 | 177 | statusMenuItem = [[NSMenuItem alloc] initWithTitle:@"..." action:nil keyEquivalent:@""]; 178 | [statusMenuItem setEnabled:NO]; 179 | 180 | openAtStartupMenuItem = [[NSMenuItem alloc] initWithTitle:@"Open at startup" action:@selector(toggleStartupAction) keyEquivalent:@""]; 181 | [openAtStartupMenuItem setEnabled:YES]; 182 | if ([self loginItemExists]) [openAtStartupMenuItem setState:NSOnState]; 183 | 184 | [myMenu addItem: statusMenuItem]; 185 | [myMenu addItem: openAtStartupMenuItem]; 186 | [myMenu addItem: menuItem]; 187 | 188 | myStatusItem = [[[NSStatusBar systemStatusBar] statusItemWithLength:NSVariableStatusItemLength] retain]; 189 | 190 | myStatusImageOK = [[NSImage alloc] initWithContentsOfFile: [bundle pathForResource:@"iconok" ofType:@"png"]]; 191 | myStatusImageSLOW = [[NSImage alloc] initWithContentsOfFile: [bundle pathForResource:@"iconslow" ofType:@"png"]]; 192 | myStatusImageKO = [[NSImage alloc] initWithContentsOfFile: [bundle pathForResource:@"iconko" ofType:@"png"]]; 193 | [myStatusItem setImage:myStatusImageKO]; 194 | [myStatusItem setMenu: myMenu]; 195 | [self changeConnectionState: CONN_STATE_KO]; 196 | 197 | icmp_socket = -1; 198 | last_received_time = 0; 199 | last_rtt = 0; 200 | icmp_id = random()&0xffff; 201 | icmp_seq = random()&0xffff; 202 | } 203 | 204 | - (void) timerHandler: (NSTimer *) t 205 | { 206 | static long clicks = -1; 207 | int state; 208 | int64_t elapsed; 209 | 210 | clicks++; 211 | if ((clicks % 10) == 0) { 212 | NSLog(@"Sending ping\n"); 213 | 214 | [self sendPingwithId:icmp_id andSeq: icmp_seq]; 215 | } 216 | [self receivePing]; 217 | 218 | /* Update the current state accordingly */ 219 | elapsed = (ustime() - last_received_time)/1000; /* in milliseconds */ 220 | if (elapsed > 3000) { 221 | state = CONN_STATE_KO; 222 | } else if (last_rtt < 300) { 223 | state = CONN_STATE_OK; 224 | } else { 225 | state = CONN_STATE_SLOW; 226 | } 227 | if (state != connection_state) { 228 | [self changeConnectionState: state]; 229 | } 230 | } 231 | 232 | - (void) changeConnectionState: (int) state 233 | { 234 | if (state == CONN_STATE_KO) { 235 | [myStatusItem setImage:myStatusImageKO]; 236 | [statusMenuItem setTitle:@"No Connection!"]; 237 | } else if (state == CONN_STATE_OK) { 238 | [myStatusItem setImage:myStatusImageOK]; 239 | [statusMenuItem setTitle:@"Connection OK"]; 240 | } else if (state == CONN_STATE_SLOW) { 241 | [myStatusItem setImage:myStatusImageSLOW]; 242 | [statusMenuItem setTitle:@"Connection is slow"]; 243 | } 244 | connection_state = state; 245 | } 246 | 247 | - (void) exitAction { 248 | exit(0); 249 | } 250 | 251 | - (void) toggleStartupAction { 252 | if ([self toggleLoginItem]) { 253 | [openAtStartupMenuItem setState:NSOnState]; 254 | } else { 255 | [openAtStartupMenuItem setState:NSOffState]; 256 | } 257 | } 258 | 259 | /* 260 | 261 | The MIT License 262 | 263 | Copyright (c) 2010 Justin Williams, Second Gear 264 | Copyright (c) 2010 Salvatore Sanfilippo, antirez@gmail.com 265 | 266 | The following code was adapted by Salvatore Sanfilippo for iconping needs. 267 | 268 | Permission is hereby granted, free of charge, to any person obtaining a copy 269 | of this software and associated documentation files (the "Software"), to deal 270 | in the Software without restriction, including without limitation the rights 271 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 272 | copies of the Software, and to permit persons to whom the Software is 273 | furnished to do so, subject to the following conditions: 274 | 275 | The above copyright notice and this permission notice shall be included in 276 | all copies or substantial portions of the Software. 277 | 278 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 279 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 280 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 281 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 282 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 283 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 284 | THE SOFTWARE. 285 | 286 | */ 287 | 288 | 289 | - (void)enableLoginItemWithLoginItemsReference:(LSSharedFileListRef )theLoginItemsRefs ForPath:(NSString *)appPath { 290 | // We call LSSharedFileListInsertItemURL to insert the item at the bottom of Login Items list. 291 | CFURLRef url = (CFURLRef)[NSURL fileURLWithPath:appPath]; 292 | LSSharedFileListItemRef item = LSSharedFileListInsertItemURL(theLoginItemsRefs, kLSSharedFileListItemLast, NULL, NULL, url, NULL, NULL); 293 | if (item) 294 | CFRelease(item); 295 | } 296 | 297 | - (void)disableLoginItemWithLoginItemsReference:(LSSharedFileListRef )theLoginItemsRefs ForPath:(NSString *)appPath { 298 | UInt32 seedValue; 299 | CFURLRef thePath; 300 | // We're going to grab the contents of the shared file list (LSSharedFileListItemRef objects) 301 | // and pop it in an array so we can iterate through it to find our item. 302 | CFArrayRef loginItemsArray = LSSharedFileListCopySnapshot(theLoginItemsRefs, &seedValue); 303 | for (id item in (NSArray *)loginItemsArray) { 304 | LSSharedFileListItemRef itemRef = (LSSharedFileListItemRef)item; 305 | if (LSSharedFileListItemResolve(itemRef, 0, (CFURLRef*) &thePath, NULL) == noErr) { 306 | if ([[(NSURL *)thePath path] hasPrefix:appPath]) { 307 | LSSharedFileListItemRemove(theLoginItemsRefs, itemRef); // Deleting the item 308 | } 309 | CFRelease(thePath); 310 | } 311 | } 312 | CFRelease(loginItemsArray); 313 | } 314 | 315 | - (BOOL)loginItemExistsWithLoginItemReference:(LSSharedFileListRef)theLoginItemsRefs ForPath:(NSString *)appPath { 316 | BOOL found = NO; 317 | UInt32 seedValue; 318 | CFURLRef thePath; 319 | 320 | // We're going to grab the contents of the shared file list (LSSharedFileListItemRef objects) 321 | // and pop it in an array so we can iterate through it to find our item. 322 | CFArrayRef loginItemsArray = LSSharedFileListCopySnapshot(theLoginItemsRefs, &seedValue); 323 | for (id item in (NSArray *)loginItemsArray) { 324 | LSSharedFileListItemRef itemRef = (LSSharedFileListItemRef)item; 325 | if (LSSharedFileListItemResolve(itemRef, 0, (CFURLRef*) &thePath, NULL) == noErr) { 326 | if ([[(NSURL *)thePath path] hasPrefix:appPath]) { 327 | found = YES; 328 | CFRelease(thePath); 329 | break; 330 | } else { 331 | CFRelease(thePath); 332 | } 333 | } 334 | } 335 | CFRelease(loginItemsArray); 336 | 337 | return found; 338 | } 339 | 340 | - (BOOL)loginItemExists { 341 | // This will retrieve the path for the application 342 | // For example, /Applications/test.app 343 | NSString * appPath = [[NSBundle mainBundle] bundlePath]; 344 | BOOL retval = NO; 345 | 346 | LSSharedFileListRef loginItems = LSSharedFileListCreate(NULL, kLSSharedFileListSessionLoginItems, NULL); 347 | if ([self loginItemExistsWithLoginItemReference:loginItems ForPath:appPath]) { 348 | retval = YES; 349 | } 350 | CFRelease(loginItems); 351 | return retval; 352 | } 353 | 354 | - (BOOL)toggleLoginItem { 355 | NSString * appPath = [[NSBundle mainBundle] bundlePath]; 356 | BOOL retval; 357 | 358 | // Create a reference to the shared file list. 359 | LSSharedFileListRef loginItems = LSSharedFileListCreate(NULL, kLSSharedFileListSessionLoginItems, NULL); 360 | if (loginItems) { 361 | if (![self loginItemExistsWithLoginItemReference:loginItems ForPath:appPath]) { 362 | [self enableLoginItemWithLoginItemsReference:loginItems ForPath:appPath]; 363 | retval = YES; 364 | } else { 365 | [self disableLoginItemWithLoginItemsReference:loginItems ForPath:appPath]; 366 | retval = NO; 367 | } 368 | } 369 | CFRelease(loginItems); 370 | return retval; 371 | } 372 | 373 | @end 374 | -------------------------------------------------------------------------------- /iconping.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | B6869BA013DD8DDE00F2D69B /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B6869B9F13DD8DDE00F2D69B /* Cocoa.framework */; }; 11 | B6869BAA13DD8DDE00F2D69B /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = B6869BA813DD8DDE00F2D69B /* InfoPlist.strings */; }; 12 | B6869BAC13DD8DDE00F2D69B /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = B6869BAB13DD8DDE00F2D69B /* main.m */; }; 13 | B6869BB013DD8DDE00F2D69B /* Credits.rtf in Resources */ = {isa = PBXBuildFile; fileRef = B6869BAE13DD8DDE00F2D69B /* Credits.rtf */; }; 14 | B6869BB313DD8DDE00F2D69B /* iconpingAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = B6869BB213DD8DDE00F2D69B /* iconpingAppDelegate.m */; }; 15 | B6869BB613DD8DDE00F2D69B /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = B6869BB413DD8DDE00F2D69B /* MainMenu.xib */; }; 16 | B6869BBD13DDA3D900F2D69B /* iconok.png in Resources */ = {isa = PBXBuildFile; fileRef = B6869BBC13DDA3D900F2D69B /* iconok.png */; }; 17 | B6869BBF13DDAEA600F2D69B /* iconko.png in Resources */ = {isa = PBXBuildFile; fileRef = B6869BBE13DDAEA600F2D69B /* iconko.png */; }; 18 | B6869BC113DDAEB500F2D69B /* iconslow.png in Resources */ = {isa = PBXBuildFile; fileRef = B6869BC013DDAEB500F2D69B /* iconslow.png */; }; 19 | B688E44813ED7C7A00D58F00 /* world_icon.png in Resources */ = {isa = PBXBuildFile; fileRef = B688E44713ED7C7A00D58F00 /* world_icon.png */; }; 20 | B688E44B13ED874400D58F00 /* world_icon.icns in Resources */ = {isa = PBXBuildFile; fileRef = B688E44A13ED874400D58F00 /* world_icon.icns */; }; 21 | /* End PBXBuildFile section */ 22 | 23 | /* Begin PBXFileReference section */ 24 | B6869B9B13DD8DDE00F2D69B /* iconping.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = iconping.app; sourceTree = BUILT_PRODUCTS_DIR; }; 25 | B6869B9F13DD8DDE00F2D69B /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; }; 26 | B6869BA213DD8DDE00F2D69B /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = System/Library/Frameworks/AppKit.framework; sourceTree = SDKROOT; }; 27 | B6869BA313DD8DDE00F2D69B /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = System/Library/Frameworks/CoreData.framework; sourceTree = SDKROOT; }; 28 | B6869BA413DD8DDE00F2D69B /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 29 | B6869BA713DD8DDE00F2D69B /* iconping-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "iconping-Info.plist"; sourceTree = ""; }; 30 | B6869BA913DD8DDE00F2D69B /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 31 | B6869BAB13DD8DDE00F2D69B /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 32 | B6869BAD13DD8DDE00F2D69B /* iconping-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "iconping-Prefix.pch"; sourceTree = ""; }; 33 | B6869BAF13DD8DDE00F2D69B /* en */ = {isa = PBXFileReference; lastKnownFileType = text.rtf; name = en; path = en.lproj/Credits.rtf; sourceTree = ""; }; 34 | B6869BB113DD8DDE00F2D69B /* iconpingAppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = iconpingAppDelegate.h; sourceTree = ""; }; 35 | B6869BB213DD8DDE00F2D69B /* iconpingAppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = iconpingAppDelegate.m; sourceTree = ""; }; 36 | B6869BB513DD8DDE00F2D69B /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/MainMenu.xib; sourceTree = ""; }; 37 | B6869BBC13DDA3D900F2D69B /* iconok.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = iconok.png; sourceTree = ""; }; 38 | B6869BBE13DDAEA600F2D69B /* iconko.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = iconko.png; sourceTree = ""; }; 39 | B6869BC013DDAEB500F2D69B /* iconslow.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = iconslow.png; sourceTree = ""; }; 40 | B688E44713ED7C7A00D58F00 /* world_icon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = world_icon.png; sourceTree = ""; }; 41 | B688E44A13ED874400D58F00 /* world_icon.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; path = world_icon.icns; sourceTree = ""; }; 42 | /* End PBXFileReference section */ 43 | 44 | /* Begin PBXFrameworksBuildPhase section */ 45 | B6869B9813DD8DDE00F2D69B /* Frameworks */ = { 46 | isa = PBXFrameworksBuildPhase; 47 | buildActionMask = 2147483647; 48 | files = ( 49 | B6869BA013DD8DDE00F2D69B /* Cocoa.framework in Frameworks */, 50 | ); 51 | runOnlyForDeploymentPostprocessing = 0; 52 | }; 53 | /* End PBXFrameworksBuildPhase section */ 54 | 55 | /* Begin PBXGroup section */ 56 | B6869B9013DD8DDD00F2D69B = { 57 | isa = PBXGroup; 58 | children = ( 59 | B688E44A13ED874400D58F00 /* world_icon.icns */, 60 | B688E44713ED7C7A00D58F00 /* world_icon.png */, 61 | B6869BA513DD8DDE00F2D69B /* iconping */, 62 | B6869B9E13DD8DDE00F2D69B /* Frameworks */, 63 | B6869B9C13DD8DDE00F2D69B /* Products */, 64 | ); 65 | sourceTree = ""; 66 | }; 67 | B6869B9C13DD8DDE00F2D69B /* Products */ = { 68 | isa = PBXGroup; 69 | children = ( 70 | B6869B9B13DD8DDE00F2D69B /* iconping.app */, 71 | ); 72 | name = Products; 73 | sourceTree = ""; 74 | }; 75 | B6869B9E13DD8DDE00F2D69B /* Frameworks */ = { 76 | isa = PBXGroup; 77 | children = ( 78 | B6869B9F13DD8DDE00F2D69B /* Cocoa.framework */, 79 | B6869BA113DD8DDE00F2D69B /* Other Frameworks */, 80 | ); 81 | name = Frameworks; 82 | sourceTree = ""; 83 | }; 84 | B6869BA113DD8DDE00F2D69B /* Other Frameworks */ = { 85 | isa = PBXGroup; 86 | children = ( 87 | B6869BA213DD8DDE00F2D69B /* AppKit.framework */, 88 | B6869BA313DD8DDE00F2D69B /* CoreData.framework */, 89 | B6869BA413DD8DDE00F2D69B /* Foundation.framework */, 90 | ); 91 | name = "Other Frameworks"; 92 | sourceTree = ""; 93 | }; 94 | B6869BA513DD8DDE00F2D69B /* iconping */ = { 95 | isa = PBXGroup; 96 | children = ( 97 | B6869BB113DD8DDE00F2D69B /* iconpingAppDelegate.h */, 98 | B6869BB213DD8DDE00F2D69B /* iconpingAppDelegate.m */, 99 | B6869BB413DD8DDE00F2D69B /* MainMenu.xib */, 100 | B6869BA613DD8DDE00F2D69B /* Supporting Files */, 101 | ); 102 | path = iconping; 103 | sourceTree = ""; 104 | }; 105 | B6869BA613DD8DDE00F2D69B /* Supporting Files */ = { 106 | isa = PBXGroup; 107 | children = ( 108 | B6869BC013DDAEB500F2D69B /* iconslow.png */, 109 | B6869BBE13DDAEA600F2D69B /* iconko.png */, 110 | B6869BBC13DDA3D900F2D69B /* iconok.png */, 111 | B6869BA713DD8DDE00F2D69B /* iconping-Info.plist */, 112 | B6869BA813DD8DDE00F2D69B /* InfoPlist.strings */, 113 | B6869BAB13DD8DDE00F2D69B /* main.m */, 114 | B6869BAD13DD8DDE00F2D69B /* iconping-Prefix.pch */, 115 | B6869BAE13DD8DDE00F2D69B /* Credits.rtf */, 116 | ); 117 | name = "Supporting Files"; 118 | sourceTree = ""; 119 | }; 120 | /* End PBXGroup section */ 121 | 122 | /* Begin PBXNativeTarget section */ 123 | B6869B9A13DD8DDE00F2D69B /* iconping */ = { 124 | isa = PBXNativeTarget; 125 | buildConfigurationList = B6869BB913DD8DDE00F2D69B /* Build configuration list for PBXNativeTarget "iconping" */; 126 | buildPhases = ( 127 | B6869B9713DD8DDE00F2D69B /* Sources */, 128 | B6869B9813DD8DDE00F2D69B /* Frameworks */, 129 | B6869B9913DD8DDE00F2D69B /* Resources */, 130 | ); 131 | buildRules = ( 132 | ); 133 | dependencies = ( 134 | ); 135 | name = iconping; 136 | productName = iconping; 137 | productReference = B6869B9B13DD8DDE00F2D69B /* iconping.app */; 138 | productType = "com.apple.product-type.application"; 139 | }; 140 | /* End PBXNativeTarget section */ 141 | 142 | /* Begin PBXProject section */ 143 | B6869B9213DD8DDD00F2D69B /* Project object */ = { 144 | isa = PBXProject; 145 | attributes = { 146 | LastUpgradeCheck = 0410; 147 | ORGANIZATIONNAME = "Kiurma s.r.l. / Merzia s.r.l."; 148 | }; 149 | buildConfigurationList = B6869B9513DD8DDD00F2D69B /* Build configuration list for PBXProject "iconping" */; 150 | compatibilityVersion = "Xcode 3.2"; 151 | developmentRegion = English; 152 | hasScannedForEncodings = 0; 153 | knownRegions = ( 154 | English, 155 | en, 156 | ); 157 | mainGroup = B6869B9013DD8DDD00F2D69B; 158 | productRefGroup = B6869B9C13DD8DDE00F2D69B /* Products */; 159 | projectDirPath = ""; 160 | projectRoot = ""; 161 | targets = ( 162 | B6869B9A13DD8DDE00F2D69B /* iconping */, 163 | ); 164 | }; 165 | /* End PBXProject section */ 166 | 167 | /* Begin PBXResourcesBuildPhase section */ 168 | B6869B9913DD8DDE00F2D69B /* Resources */ = { 169 | isa = PBXResourcesBuildPhase; 170 | buildActionMask = 2147483647; 171 | files = ( 172 | B6869BAA13DD8DDE00F2D69B /* InfoPlist.strings in Resources */, 173 | B6869BB013DD8DDE00F2D69B /* Credits.rtf in Resources */, 174 | B6869BB613DD8DDE00F2D69B /* MainMenu.xib in Resources */, 175 | B6869BBD13DDA3D900F2D69B /* iconok.png in Resources */, 176 | B6869BBF13DDAEA600F2D69B /* iconko.png in Resources */, 177 | B6869BC113DDAEB500F2D69B /* iconslow.png in Resources */, 178 | B688E44813ED7C7A00D58F00 /* world_icon.png in Resources */, 179 | B688E44B13ED874400D58F00 /* world_icon.icns in Resources */, 180 | ); 181 | runOnlyForDeploymentPostprocessing = 0; 182 | }; 183 | /* End PBXResourcesBuildPhase section */ 184 | 185 | /* Begin PBXSourcesBuildPhase section */ 186 | B6869B9713DD8DDE00F2D69B /* Sources */ = { 187 | isa = PBXSourcesBuildPhase; 188 | buildActionMask = 2147483647; 189 | files = ( 190 | B6869BAC13DD8DDE00F2D69B /* main.m in Sources */, 191 | B6869BB313DD8DDE00F2D69B /* iconpingAppDelegate.m in Sources */, 192 | ); 193 | runOnlyForDeploymentPostprocessing = 0; 194 | }; 195 | /* End PBXSourcesBuildPhase section */ 196 | 197 | /* Begin PBXVariantGroup section */ 198 | B6869BA813DD8DDE00F2D69B /* InfoPlist.strings */ = { 199 | isa = PBXVariantGroup; 200 | children = ( 201 | B6869BA913DD8DDE00F2D69B /* en */, 202 | ); 203 | name = InfoPlist.strings; 204 | sourceTree = ""; 205 | }; 206 | B6869BAE13DD8DDE00F2D69B /* Credits.rtf */ = { 207 | isa = PBXVariantGroup; 208 | children = ( 209 | B6869BAF13DD8DDE00F2D69B /* en */, 210 | ); 211 | name = Credits.rtf; 212 | sourceTree = ""; 213 | }; 214 | B6869BB413DD8DDE00F2D69B /* MainMenu.xib */ = { 215 | isa = PBXVariantGroup; 216 | children = ( 217 | B6869BB513DD8DDE00F2D69B /* en */, 218 | ); 219 | name = MainMenu.xib; 220 | sourceTree = ""; 221 | }; 222 | /* End PBXVariantGroup section */ 223 | 224 | /* Begin XCBuildConfiguration section */ 225 | B6869BB713DD8DDE00F2D69B /* Debug */ = { 226 | isa = XCBuildConfiguration; 227 | buildSettings = { 228 | ALWAYS_SEARCH_USER_PATHS = NO; 229 | ARCHS = "$(ARCHS_STANDARD)"; 230 | COPY_PHASE_STRIP = NO; 231 | GCC_C_LANGUAGE_STANDARD = gnu99; 232 | GCC_DYNAMIC_NO_PIC = NO; 233 | GCC_ENABLE_OBJC_EXCEPTIONS = YES; 234 | GCC_OPTIMIZATION_LEVEL = 0; 235 | GCC_PREPROCESSOR_DEFINITIONS = ( 236 | "DEBUG=1", 237 | "$(inherited)", 238 | ); 239 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 240 | GCC_VERSION = com.apple.compilers.llvm.clang.1_0; 241 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 242 | GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; 243 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 244 | GCC_WARN_UNUSED_VARIABLE = YES; 245 | MACOSX_DEPLOYMENT_TARGET = 10.6; 246 | ONLY_ACTIVE_ARCH = YES; 247 | SDKROOT = macosx; 248 | }; 249 | name = Debug; 250 | }; 251 | B6869BB813DD8DDE00F2D69B /* Release */ = { 252 | isa = XCBuildConfiguration; 253 | buildSettings = { 254 | ALWAYS_SEARCH_USER_PATHS = NO; 255 | ARCHS = "$(ARCHS_STANDARD)"; 256 | COPY_PHASE_STRIP = YES; 257 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 258 | GCC_C_LANGUAGE_STANDARD = gnu99; 259 | GCC_ENABLE_OBJC_EXCEPTIONS = YES; 260 | GCC_VERSION = com.apple.compilers.llvm.clang.1_0; 261 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 262 | GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; 263 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 264 | GCC_WARN_UNUSED_VARIABLE = YES; 265 | MACOSX_DEPLOYMENT_TARGET = 10.6; 266 | SDKROOT = macosx; 267 | }; 268 | name = Release; 269 | }; 270 | B6869BBA13DD8DDE00F2D69B /* Debug */ = { 271 | isa = XCBuildConfiguration; 272 | buildSettings = { 273 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 274 | GCC_PREFIX_HEADER = "iconping/iconping-Prefix.pch"; 275 | INFOPLIST_FILE = "iconping/iconping-Info.plist"; 276 | MACOSX_DEPLOYMENT_TARGET = 10.6; 277 | PRODUCT_NAME = "$(TARGET_NAME)"; 278 | SDKROOT = macosx; 279 | WRAPPER_EXTENSION = app; 280 | }; 281 | name = Debug; 282 | }; 283 | B6869BBB13DD8DDE00F2D69B /* Release */ = { 284 | isa = XCBuildConfiguration; 285 | buildSettings = { 286 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 287 | GCC_PREFIX_HEADER = "iconping/iconping-Prefix.pch"; 288 | INFOPLIST_FILE = "iconping/iconping-Info.plist"; 289 | MACOSX_DEPLOYMENT_TARGET = 10.6; 290 | PRODUCT_NAME = "$(TARGET_NAME)"; 291 | SDKROOT = macosx; 292 | WRAPPER_EXTENSION = app; 293 | }; 294 | name = Release; 295 | }; 296 | /* End XCBuildConfiguration section */ 297 | 298 | /* Begin XCConfigurationList section */ 299 | B6869B9513DD8DDD00F2D69B /* Build configuration list for PBXProject "iconping" */ = { 300 | isa = XCConfigurationList; 301 | buildConfigurations = ( 302 | B6869BB713DD8DDE00F2D69B /* Debug */, 303 | B6869BB813DD8DDE00F2D69B /* Release */, 304 | ); 305 | defaultConfigurationIsVisible = 0; 306 | defaultConfigurationName = Release; 307 | }; 308 | B6869BB913DD8DDE00F2D69B /* Build configuration list for PBXNativeTarget "iconping" */ = { 309 | isa = XCConfigurationList; 310 | buildConfigurations = ( 311 | B6869BBA13DD8DDE00F2D69B /* Debug */, 312 | B6869BBB13DD8DDE00F2D69B /* Release */, 313 | ); 314 | defaultConfigurationIsVisible = 0; 315 | defaultConfigurationName = Release; 316 | }; 317 | /* End XCConfigurationList section */ 318 | }; 319 | rootObject = B6869B9213DD8DDD00F2D69B /* Project object */; 320 | } 321 | --------------------------------------------------------------------------------