Detect internet connection?

I’d like to write a script to be launched at each login, which will detect whether or not my computer is conneted to the internet. If so, it’ll tell all of my internet-related apps (Safari, Mail, iChat, NetNewsWire, etc.) to launch. The point of this is to keep from having all of these apps launch even if no connection exists.

I’m just not sure which app I should be scripting in order to get the status of my internet connection. Any ideas?

I use this:

set intnt to do shell script "ping -c 1 63.208.196.110"
tell application "Finder"
	set p to number of paragraphs in intnt
	if p < 5 then
		display dialog "Internet connection is down."
	else
		display dialog "Internet connection is up."
	end if
end tell

Obviously, you can change what happens from a dialog to any other script. To make it launch at login you save it as an application (without a startup screen) and then include it among the Login Items in that pane of your System Preferences > Accounts settings.

This is exactly what I was looking for, thanks!

I saw the Cyclosaurus’ reply in discussions.apple.com. I replied there that

If you wanted to add a further test you could do this:

set int_1 to do shell script "ping -c 1 63.208.196.110"
set int_2 to do shell script "ping -c 1 63.208.196.111"
tell application "Finder"
	set p to number of paragraphs in int_1
	if p < 5 then
		set p to number of paragraphs in int_2
		if p < 5 then display dialog "Internet connection is Down."
	else
		display dialog "Internet connection is Up."
	end if
end tell

Adam,

Why are you counting lines instead of catching the output message of ping? There also isn’t really a reason to bring the Finder into the mix.

Please see my post to the Discussions thread on the matter.

http://discussions.apple.com/thread.jspa?messageID=1234303&#1234303

Because I didn’t think of your approach and mine worked - happens to me a lot and is one of the confusing aspects of learning any new language - there are a lot of ways to do most things.

Adam

No worries at all. The single most useful thing I’ve found in AppleScript it its ability to interact with the shell, from catching output to calling complex shell scripts to perform tasks that would otherwise be slow or a massive pain in the neck with plainjane AppleScript. (File manipulation, complex control statements, text manipulation, etc.)

AppleScript Studio is essentially the awesome-est GUI front-end system for shell scripting ever made. :slight_smile:

I use this:

check_net()
on check_net()
	try
		set the_URL to "http://www.apple.com" as URL
		set dotted_ to dotted decimal form of host of the_URL --> this will return the IP address if there is a live connection 
		return true
	on error
		return false
	end try
end check_net

I’ve never seen: “dotted decimal form of host of the_URL”. That is really slick and I can think of lots of other uses as well. Because it’s so crisp and to the point, it’s worth sticking in Code Exchange. I’ll add mine as a reply, and Mikey-san can add his as well. Three ways to answer the question: “Internet Up?”

FWIW, here’s a twist on Vincent’s suggestion that avoids a try block:

(count (get (("http://www.apple.com" as URL)'s host & {dotted decimal form:""})'s dotted decimal form)) > 0

Neat, as always - a one-liner to put in a simple if statement. Not sure I get the nested dotted decimal form, but will figure it out.

And for those that like redundancy:

set testIP to chkUP("http://www.apple.com") or chkUP("http://www.google.com")
if testIP then
	display dialog "Internet Connection is UP"
else
	display dialog "Internet Connection is DOWN"
end if

to chkUP(theURL)
	return (count (get ((theURL as URL)'s host & {dotted decimal form:""})'s dotted decimal form)) > 0
end chkUP

I have no doubt of that, Adam - though perhaps a brief explanation might still help things along a bit. :slight_smile:

The method simply takes advantage of AppleScript’s rules for concatenating records:

For instance (and I hope you’ll forgive the example):

[code]set x to {firstName:“Adam”, lastName:“Bell”}
set y to {telNum:“123456”, firstName:“Tinker”}

x & y
→ {firstName:“Adam”, lastName:“Bell”, telNum:“123456”}

y & x
→ {telNum:“123456”, firstName:“Tinker”, lastName:“Bell”}

firstName of (x & y)
→ “Adam”

firstName of (y & x)
→ “Tinker”[/code]
In our real-world example, the host of a URL is a record. Whether or not this record contains a property called dotted decimal form depends on a successful connection with the URL. So, if there’s a connection, we get a record that looks like this:

If no connection is established, we get a record that has no dotted decimal form property:

Of course, if we try to extract the value of a property called dotted decimal form from the latter record as it stands, the result will be an error - because no such property exists.

One way around this is to use a try block. However, the alternative I suggested concatenates the original record with a dummy one, containing a property called dotted decimal form whose value is an empty string. This ensures that the record resulting from the concatenation contains a dotted decimal form property - either from the original URL’s host, or from the dummy record. And since the required property should now always exist, an error is avoided.

Here’s a breakdown of what the complete statement does if there’s a connection:

("http://www.apple.com" as URL)'s host
--> {class:Internet address, DNS form:"www.apple.com", port:80, dotted decimal form:"17.254.0.91"}

result & {dotted decimal form:""}
--> {class:Internet address, DNS form:"www.apple.com", port:80, dotted decimal form:"17.254.0.91"}

result's dotted decimal form
--> "17.254.0.91"

count result
--> 11

result > 0
--> true

And this is what happens when no connection exists:

("http://www.apple.com" as URL)'s host
--> {class:Internet address, DNS form:"www.apple.com", port:80}

result & {dotted decimal form:""}
--> {class:Internet address, DNS form:"www.apple.com", port:80, dotted decimal form:""}

result's dotted decimal form
--> ""

count result
--> 0

result > 0
--> false

Beautiful. Not only was I previously unaware of “dotted decimal form”, but had of course tried it on for size after seeing your one-liner and wondering what "host[ was about:

set theURL to "http://www.google.com"
get (theURL as URL)'s host

-- Result:{class:Internet address, DNS form:"www.google.com", port:80, dotted decimal form:"72.14.203.99"}

which is a hell of lot faster than using the Network Utility and thus of great general use, but I was unaware that records could be concatinated in the way you’ve demonstrated.

Thanks for the lovely explanation.

One thing I don’t understand, however: why doesn’t this line work:

set theURL to text returned of (display dialog "Enter a URL in the text box below" default answer "http://www.apple.com/" default button 2) as URL

What I really wanted (but clearly have a coercion problem with) is

display dialog dotted decimal form of ((text returned of (display dialog "Enter a URL in the text box below" default answer "http://www.apple.com/" default button 2) as URL)'s host) default button 2

Both of these error with: Can’t make “http://www.apple.com/” into type URL.

This looks very much like a Unicode-related bug to me, Adam. As we’ve already seen, plain text works just fine. However, it seems the text returned from display dialog (which is now Unicode text) is causing the text-to-URL coercion to fail.

This should help to demonstrate the point:

set theURL to "http://www.apple.com/"
set r to {}
repeat with u in {theURL, theURL as Unicode text}
	try
		set r's end to u as URL
	on error e
		set r's end to e
	end try
end repeat
r

--> {{class:URL, scheme:http URL, path:"http://www.apple.com/", host:{class:Internet address, DNS form:"www.apple.com", port:80, dotted decimal form:"17.254.0.91"}}, "Can't make \"http://www.apple.com/\" into type URL."}

Unfortunately, a regular Unicode text-to-string coercion doesn’t fix matters. In spite of the reported class reverting from “Unicode text” to “string” the result of such a coercion is actually international/styled text. This means that the text still contains some encoding, mainly related to style data - which is just as likely to break the text-to-URL coercion. At the moment, one of the few techniques left to convert text back to genuinely plain text is a bit of a hack. (Most of the original methods were, too - but Apple seems to have been “fixing” them…) :wink:

I think this issue is worthy of a bug report to Apple - which I’ll gladly take care of. In the meantime, something like this should do the trick - even if it means that you may have to live with a two-liner:

text returned of (display dialog "Enter a URL in the text box below:" default answer ¬
	"http://www.apple.com/" default button 2) as string returning {text:theURL}
display dialog dotted decimal form of (theURL as URL)'s host

Exellent, Kai;

I assume the “as string returning {text:theURL}” forces the necessary coercion and therefore necessitates the second line and the introduction of a variable (I did try a variety of alternatives, all of which failed). By all means file the bug - I don’t know how.

P.S. - I got interested in the “variableless” approach after reading this script of Nigel Garvey’s (to be found in his "DateTips 1.1 in ScriptBuilders:

tell {current date}
	copy beginning to end
	set end's month to January
	tell ((beginning's year) * 10000 + (beginning - (end - 3944592)) div 2629728 * 100 + (beginning's day)) as string
		text 7 thru 8 & "/" & text 5 thru 6 & "/" & text 1 thru 4
	end tell
end tell
display dialog result

I understand that this can be accomplished with a one-liner shell script, but I’ll bet this is faster.

Just a quick update, Adam - since I really should be elsewhere at the moment.

One of the coercions that I thought was broken, evidently isn’t (quite) - so now you should be able to have your one-liner:

display dialog dotted decimal form of (host of ((text returned of (display dialog "Please enter a URL:" default answer "http://www.apple.com/") as string as record)'s «class ktxt» as URL) & {dotted decimal form:"No connection."})

:slight_smile:

Thank you again. It’s fun to play with that - make up some URL you can’t imagine being claimed and discover that it actually exists! (I was trying to test the “No Connection”).

Of course, the more practical form for general fiddling around is:

text returned of (display dialog "Enter a URL in the text box below:" default answer ¬
	"[url=http://www.apple.com]www.apple.com[/url]" buttons {"OK"} default button 1) as string returning {text:theURL}
-- the following line presumes that a reasonable URL has been entered in the form given by the default - it will not correct anything else.
if theURL does not contain "http://" then set theURL to "http://" & theURL
try
	set theHost to (dotted decimal form of ((theURL as URL))'s host)
	display dialog (theURL & "'s IP Address is: " & theHost) buttons {"OK"} default button 1
on error
	display dialog "No such URL" buttons {"Oops"} default button 1
end try

Just a few miscellaneous snippets on some of the above…

extracting plain text from encoded text
The conversion method I suggested initially used a hack devised by the ingenious Arthur Knapp (a.k.a. AdmiralNovia). Put simply, it extracts the plain text from any encoding through an implicit coercion to record.

In terms of explicit coercion, I suppose a near equivalent might be something like:

"http://www.apple.com/" as Unicode text
text of (result as text as record) as text as URL
--> {class:URL, scheme:http URL, path:"http://www.apple.com/", host:{class:Internet address, DNS form:"www.apple.com", port:80, dotted decimal form:"17.254.0.91"}}

However, if the source happens to be plain text, an explicit coercion will result in an error:

"http://www.apple.com/"
text of (result as text as record) as text as URL
--> error number -1700: "Can't make \"http://www.apple.com/\" into type record."

One of the cunning aspects of Arthur’s approach is that it exploits an ambiguity in the meaning of text - so it doesn’t error when fed plain text. :cool:

set-to vs. returning
The returning command is simply another way to assign a value to a variable - and is therefore synonymous with set-to. So instead of saying set x to y, we could say y returning x. The choice of syntax is largely down to preference (as it is when, say, starting a subroutine with on doSomething() or to doSomething()). To demonstrate, here’s a mixture:

set theStart to "http://www."
"apple.com" returning theMiddle
set theEnd to "/"
theStart & theMiddle & theEnd returning theURL
theURL
--> "http://www.apple.com/"

So, coming back to the question of the two-liner, the second line was needed because AppleScript normally expects the assigning of a variable to come at the end of a statement.

bug stomp

Consider it done: Bug ID# [u]4360112[/u]

To file a bug, you’ll need to be an Apple Developer Connection (ADC) member. (Membership is free.) Then, go to Bug Reporter, login and give details of the issue. Advice on sequence, format, etc. is available there, making the process of reporting a bit easier. Folks shouldn’t be too concerned about filing duplicate reports, since the more bugs Apple receives about an issue, the more likely it is to move up their priority list. It’s a great way to make sure we enjoy better products in the future! :smiley:

reducing variable assignment

Where execution speed is critical, it’s possible to shave off a few milliseconds here and there by reducing the assignment of values to variables. Using a tell statement, for example, is one way to achieve this - although care should be taken to avoid confusion such as: tell 3 to beep. (An over-simplified example, perhaps - but you’ll get the idea if you try running it.) It’s also possible at times to get a bit carried away:stuck_out_tongue:

a better error message

I once tried a similar exercise for a different reason - and was also amazed to find sites with the unlikeliest names! But your point’s a good one, Adam. Perhaps the error message should read something like: “Invalid connection or URL.”

vanilla vs. shell

Pure native applescript with no external call to an application, a scripting addition or the shell (all of which carry an initial overhead). For this kind of job (where no heavy lifting is involved), good ol’ vanilla can be pretty hard to beat (IMO). :slight_smile:

coercion confusion

It might be worth clarifying what I meant by that. It used to be possible to coerce Unicode text to a record directly:

"test" as Unicode text
result as record
--> {«class ktxt»:"test", «class ksty»:«data styl0001000000000010000E00030000000C000000000000»}

But that’s evidently no longer the case:

"test" as Unicode text
result as record
--> error: "Can't make \"test\" into type record."

However, by using an intermediate coercion to string (actually styled text), a record can still be produced:

"test" as Unicode text
result as string as record
--> {«class ktxt»:"test", «class ksty»:«data styl0001000000000010000E00030000000C000000000000»}

Um… my apologies for ‘going on’ a bit… :rolleyes:

No apology required - great read. We should probably close this thread though (moderators disgression, not mine) - we’ll scare off all the folks just learning AppleScript. Last spring this would have boggled my mind - now I find it entertaining. AppleScript is a lot of fun when you get over the hump that what looks like plain English really isn’t and get your head around the fact that your notions of grammer still work. AppleScript has verbs, nouns, adjectives, etc. Thanks for this.

If I can resurrect this thread…

This has put me on a great start for a project i’m working on.

My university is requiring logons for wireless and wired connections. However, wireless and wired have different IP ranges, so i figured that I could use that to differentiate between the connections.

Is there any way to use dialog decimal form with “contains” to specify a port range in an if statement?

I hope you guys can help… .I’m pulling my hair out because of this :-/