Skip to content

Instantly share code, notes, and snippets.

Created February 19, 2014 21:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save anonymous/9101907 to your computer and use it in GitHub Desktop.
Save anonymous/9101907 to your computer and use it in GitHub Desktop.
geohashd.nt
module geohashd;
import std.smtp, std.process, std.string, std.getopt, std.file, std.hash.md5;
import c.time;
string dateformat(int i) {
if (i < 10) return "0$i";
else return "$i";
}
string htmlEscape(string s) {
return s.replace(" ", "%20").replace("\"", "%22").replace(",", "%2C");
}
void main(string[] args) {
set-handler(UnrecoverableError uerr) {
writeln "$uerr".replace(":", "\n");
invoke-exit "ret";
}
define-exit "ret" return;
string home, area, email, smtpdata;
float maxdist;
bool walk;
void printHelpData() {
writeln "Usage: geohashd [--home, -h] [--maxdist, -d]";
writeln " [--area, -a] [--email, -m] [--walk, -w]";
writeln " [--smtpdata, -s] [--help, -h]";
writeln "";
writeln "Note: geohashd is not authorized to use Google Maps.";
writeln "It scrapes the webview. As a result, it can suddenly break on updates.";
writeln "";
writeln "--home: Home address that you start out at.";
writeln "--maxdist: maximum distance that you want to drive, in km.";
writeln "--area: \"latitude,+-longitude\". Target quadrant to search in.";
writeln "--email: Address to mail when a location is found.";
writeln "--walk: Whether to use Google Maps in walking mode. For people without cars.";
writeln "--smtpdata: username:password@smtpserver . SMTP server that's used to send email";
writeln "--help: this page";
writeln "";
}
bool tHome, tArea, tEmail, tSmtpData, tMaxdist;
using new Options {
addLong("home", "h", λ(string s) { home = s; tHome = true; });
addLong("maxdist", "d", λ(string s) { maxdist = s.atof(); tMaxdist = true; });
addLong("area", "a", λ(string s) { area = s; tArea = true; });
addLong("email", "m", λ(string s) { email = s; tEmail = true; });
addLong("walk", "w", λ{ walk = true; });
addLong("smtpdata", "s", λ(string s) { smtpdata = s; tSmtpData = true; });
addLong("help", "h", λ{ printHelpData; });
args = process args;
}
if (!tHome) fail "Please set --home to your home address";
if (!tArea) fail "Please set --area to your lat/long area (xx, ±yy)";
if (!tEmail) fail "Please set --email to your email address";
if (!tSmtpData) fail "Please set --smtpdata to your email info: username:password@host";
if (!tMaxdist) fail "Please set --maxdist to your maximum interest distance";
auto currentTime = localtime &auto t1 = time(null);
auto day = currentTime.tm_mday, month = currentTime.tm_mon + 1, year = currentTime.tm_year + 1900;
auto correctedTime = currentTime;
auto lon = area.split(",")[1].atoi();
if (lon > -30) {
// this may validly go negative! study man 3 localtime
correctedTime.tm_mday --; // 30W change
correctedTime = localtime &auto t2 = mktime correctedTime; // reconstruct
}
auto cday = correctedTime.tm_mday, cmonth = correctedTime.tm_mon + 1, cyear = correctedTime.tm_year + 1900;
// auto url = "http://irc.peeron.com/xkcd/map/data/%Y/%m/%d".insertTimes(cday, cmonth, cyear);
auto url = "http://geo.crox.net/djia/$cyear/$cmonth/$cday";
auto opening = readback("wget", ["-q", "-O-", url]).join("");
auto date = "$(dateformat(year))-$(dateformat(month))-$(dateformat(day))";
write "Date";
if (lon > -30) write ", including W30";
writeln ": $date - $url";
auto infostring = "$date-$opening";
MD5Hash hash;
hash.sum ubyte[]: infostring;
alias digest = hash.hash;
double toReal(ubyte[] field) {
double res = 0;
double factor = 1;
for auto value <- field {
factor /= 0x100;
res += value * factor;
}
return res;
}
auto digest1 = toReal(digest[0..8]), digest2 = toReal(digest[8..16]);
writeln "'$infostring': $digest => $digest1, $digest2";
// remove leading 0
auto sp = area.split(","), dest = sp[0] ~ "$digest1"[1 .. $] ~ "," ~ sp[1] ~ "$digest2"[1 .. $];
if (home.length && (home[0] != "\"" || home[$-1] != "\"")) home = "\"$home\"";
auto groute = "http://maps.google.com/maps?saddr=$home&daddr=$dest&pw=2"~walk?.("&dirflg=w");
writeln "groute $groute";
auto grata = readback("wget", ["-q", "-O-", groute]).join(""); // google route data
auto dist = grata.between("div\\x3e\\x3cb\\x3e", "\\x26").atof();
writeln "$groute -> $dist km";
if (dist > maxdist) { writeln "Out of range!"; return; }
if (dist == 0f) { writeln "Too close. Probably a bug. "; return; }
writeln "Within range!";
auto host = smtpdata; string username, pass;
if (auto at = host.find("@")) {
username = host[0 .. at];
host = host[at+1 .. $];
auto sep = username.find(":");
if (sep != -1) {
pass = username[sep+1 .. $];
username = username[0 .. sep];
}
}
sendmail(=>smtps, email, email,
"[geohashd] location within range: $(dist)km for $date",
host => host, logindata => "$username:$pass", =>dbg,
"A geohashing location has been discovered in your area that is close enough to reach: $dist km!
The link to the Google Maps data is $(groute.htmlEscape()) . Have fun!"
);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment