Traveling within Washington

I just found a neat site: the Washington State DOT continues to amaze me. :-) This site gives a summary for long-distance driving within the state. For example, on the I-90 corridor, it shows temperature, elevation, and traffic cameras coming out of Seattle and going over Snoqualmie Pass.

Of course, you know I’ll forget about this before the next time I drive out that way…

Posted by Garrett on November 28th, 2004 in Travel, Web | No Comments

Gmail and phishing

Ooh, that was neat. I just got a phishing message allegedly from Washington Mutual at GMail. When I clicked on “More Options”, to get the info to report it, I saw a link I had never seen before: “Report phishing”. I was very pleased to see that GMail was being proactive enough to special-case this.

Posted by Garrett on November 27th, 2004 in Uncategorized | 1 Comment

In my next life…

This hard-hitting article from the New York Times today tells it like it is.

Thanks to Tom for the link.

Posted by Garrett on November 25th, 2004 in Uncategorized | No Comments

How to write Firefox extensions

How to write Firefox extensions

Posted by Garrett on November 19th, 2004 in Uncategorized | No Comments

Vote Fraud?

It’s hard to judge from hearing just one side, but this story sure stinks.

Thanks to Zane for the pointer.

Posted by Garrett on November 19th, 2004 in Uncategorized | No Comments

Aw, they spoiled the movie!

Now I know what’s on the back of the Declaration, so going to see the movie won’t be the same. *sniff sniff*

Thanks to Laura for the link.

Posted by Garrett on November 19th, 2004 in Uncategorized | No Comments

Being a good netizen

Today, irked at a particular site that hits my blog every 15 minutes, instead of the generally-accepted hour or more, I was reminded of the HTTP/1.1 If-Modified-Since header, which causes only the header to be returned if there has been no change to the requested file. Since I couldn’t tell if this worked on my site (I don’t have direct log file access on donnael.com), I decided to write some code to check the behavior myself.

While I created all of this code from the MSDN documentation, I have to give a nod to Rick Strahl’s wwIPStuff, which does this much better than I did (error checking? What’s that?), and which gave me a couple of pointers on how to properly make these calls.

*!* USERAGENT is more typically IE or Mozilla.
*!* BLOGSITE is just the name of the site, with no protocol
*!* RSSFEED works equally well without the leading slash,
*!*         in this particular case.
#DEFINE USERAGENT "donnael ChangeCheck"
#DEFINE BLOGSITE "blog.donnael.com"
#DEFINE RSSFEED "/blog.xml"
*!* Defines further down in the code are taken from
*!* Program Files\Microsoft Visual Studio .NET 2003\Vc7\PlatformSDK\Include\WinInet.h

*!* Open a connection to the internet, but don't go
*!* anywhere.
DECLARE integer InternetOpen IN wininet.dll ;
  string lpszAgent, ;
  integer dwAccessType, ;
  string lpszProxyName, ;
  string lpszProxyBypass, ;
  integer dwFlags 

lnHNet = InternetOpen(USERAGENT, 0, "", "", 0)

*!* Now make a connection to the chosen site.
DECLARE integer InternetConnect IN wininet.dll ;
  integer hInternet, ;
  string lpszServerName, ;
  integer nServerPort, ;
  string lpszUsername, ;
  string lpszPassword, ;
  integer dwService, ;
  integer dwFlags, ;
  integer dwContext
#DEFINE INTERNET_SERVICE_HTTP   3

lnHConn = InternetConnect(lnHNet, BLOGSITE, 0, ;
 "", "", ;
 INTERNET_SERVICE_HTTP, 0, 0)

*!* Once we're connected, we can decide which file we're
*!* interested in asking for.
DECLARE integer HttpOpenRequest IN wininet.dll ;
  integer hConnect, ;
  string lpszVerb, ;
  string lpszObjectName, ;
  string lpszVersion, ;
  string lpszReferer, ;
  string @ lpszAcceptTypes, ;
  integer dwFlags, ;
  integer dwContext

lcType = ""

lnHRequest = HttpOpenRequest(lnHConn, ;
 "GET", RSSFEED, "HTTP/1.1", ;
 "", @lcType, 0, 0)

*!* Once everything's set up, actually send the request
*!* to the site, along with any additional headers we
*!* need.
DECLARE integer HttpSendRequest IN wininet.dll ;
  integer hRequest, ;
  string lpszHeaders, ;
  integer dwHeadersLength, ;
  integer lpOptional, ;
  integer dwOptionalLength

lcModified = "If-Modified-Since:" + HTTPDate(DATE() - 1)

llSentRequest = HttpSendRequest(lnHRequest, ;
 lcModified, LEN(lcModified), ;
 0, 0)

*!* Once the query's been sent, there's certain info we can
*!* check on, without actually bringing the file back.
DECLARE integer HttpQueryInfo IN wininet.dll ;
  integer hRequest, ;
  integer dwInfoLevel, ;
  string @ lpvBuffer, ;
  integer @ lpdwBufferLength, ;
  integer lpdwIndex

#DEFINE HTTP_QUERY_STATUS_CODE       19
#DEFINE HTTP_QUERY_CONTENT_LENGTH     5

*!* First, we can check the status code, to see what the
*!* server did with our request.
lcBuffer = SPACE(3)
lnBufferSize = 3
llQuery = HttpQueryInfo(lnHRequest, HTTP_QUERY_STATUS_CODE, ;
 @lcBuffer, @lnBufferSize, 0)

*!* If there was no change, only the status code is returned,
*!* with no file.
IF lcBuffer = "304"
 MESSAGEBOX("Not updated!")
ELSE
 *!* Otherwise, we need to find out how large the return will be.
 lcBuffer = SPACE(32)
 lnBufferSize = 32
 llQuery = HttpQueryInfo(lnHRequest, HTTP_QUERY_CONTENT_LENGTH, ;
  @lcBuffer, @lnBufferSize, 0)

 *!* Given that information, we know how big a buffer to prepare
 *!* for the data when we ask for it. Buffer Overruns Are Evil.
 DECLARE integer InternetReadFile IN wininet.dll ;
   integer hFile, ;
   string @ lpBuffer, ;
   integer dwNumberOfBytesToRead, ;
   integer @ lpdwNumberOfBytesRead

 lnRSSSize = VAL(lcBuffer)
 lcRSS = SPACE(lnRSSSize)
 lnActualSize = -1
 llRead = InternetReadFile(lnHRequest, ;
  @lcRSS, lnRSSSize, @lnActualSize)

 *!* Now we can show what we brought back. This is the
 *!* quick-and-dirty way. :-)
 STRTOFILE(lcRSS, "MyBlog.RSS")
 MODIFY FILE MyBlog.RSS
 ERASE MyBlog.RSS
ENDIF

*!* Now we clean up.
DECLARE integer InternetCloseHandle IN wininet.dll ;
  integer hInternet 

InternetCloseHandle(lnHRequest)
InternetCloseHandle(lnHConn)
InternetCloseHandle(lnHNet)

*!* This function parses the date into the format expected
*!* in an HTTP header, as specified in RFC2616. Conversion
*!* between GMT and your own time zone is left as an exercise
*!* for the reader.
FUNCTION HTTPDate
LPARAMETERS ttWhen

lcDow = LEFT(CDOW(ttWhen), 3)

lcDate = TRANSFORM(DAY(ttWhen))
lcMonth = LEFT(CMONTH(ttWhen), 3)
lcYear = TRANSFORM(YEAR(ttWhen))

lcHour = PADL(HOUR(ttWhen), 2, "0")
lcMinute = PADL(MINUTE(ttWhen), 2, "0")
lcSecond = PADL(SEC(ttWhen), 2, "0")

lcRetVal = lcDow + ", " + ;
 lcDate + " " + ;
 lcMonth + " " + ;
 lcYear + " " + ;
 lcHour + ":" + ;
 lcMinute + ":" + ;
 lcSecond + " GMT"

RETURN lcRetVal

Update: There’s a problem with the call involving lpszAcceptTypes: see my bugfix post for details.

Posted by Garrett on November 17th, 2004 in Uncategorized | 1 Comment

Still here, still relevant

David Anderson wrote a great opinion piece for DevX about Visual FoxPro. He covers its ancestry, positioning, and the reasons it still fits in today, despite not being “strategic” to Microsoft.

Posted by Garrett on November 17th, 2004 in Uncategorized | No Comments

Nyx Net Status

Recently, my main mail machine, Nyx Net, went down, and its DNS servers went down with it. Many of us were stuck with no way to find out the status: we didn’t know what had happened, or when it would be back.

Therefore, the secretary of the Nyx board, Darlene Cypser, has created an off-site Nyx status page. Thanks, Darlene!

Update: oops, wrong title. Fixed.

Posted by Garrett on November 17th, 2004 in Uncategorized | No Comments

Culture clash

TV: Stop Making Sense, Talking Heads

Daughters: “What a Friend We Have in Jesus”

Posted by Garrett on November 16th, 2004 in Uncategorized | No Comments

« Previous Entries