iUI and the iPhone

My employer recently purchased a set of iPhones from AT&T for those in the workforce that have a need for such a thing. One of our first priorities was getting our rolodex accessible (read only) from the road. The main problem is that the data is in a restrictive, old school database. Until we can find time to move it into a more open platform I did the following:

  • Set up a routine for dumping the rolodex into a flat xml file monthly
  • Coded the searching of the the data using PHP and SimpleXML
  • Coded the cookie management (sessions) and most important, a “remember me” feature (because Safari doesn’t remember passwords on the iPhone)
  • Found this lovely library for creating iPhone compatible user intarfaces via the web (read, looks like a native app): iUI (User Interface Library for Safari development on iPhone)

Checkout the screenshots:

Login  Search  Results  Info

It’s pretty cool, because if the contact in the rolodex has a telephone number, address, email address, or webpage associated with them, the data will be displayed and linked to iPhone friendly functions… For example, the telephone number, when clicked on will provide a call button. An address clicked on will link to the built in maps app. Email links open up directly in the built in mail app. Finally, of course, webpages openup in Safari.

So here’s for getting the world more connected… one app at at time.

Goldfish and forged spam

Recently I had the goldfish autoresponder (vacation responses / email auto reply) setup for a user for about one week. Checking their inbox about half way through this time period revealed it having over 47,000 unread messages. What was happening is that spammers were sending email with forged headers. Have you ever received a spam message that apparently has been sent from yourself?

I suppose it can be accomplished via a variety of ways, however I was able to reproduce this particular issue via generating one of these tasty spam mails via the following (all internally of course… I am not a spammer):

telnet smtp.example.com 25

and then issuing these commands:

ehlo workstation.example.com
mail from:
rcpt to:
data
From: 
To: 
Subject: testing a loop
Message text
.
quit

Notice the mail is being sent to the user… and from the user…

  1. The server would receive the email addressed to emailuser@example.com
  2. goldfish would parse the message and notice it needed to respond to… emailuser@example.com
  3. The mail was delivered
  4. Rinse, wash, repeat

The source of the message looked something like this:

root@server:/var/local/vmail/example.com/emailuser# cat new/1220557062.P6882Q0M652544.server,S=1082
Return-Path: 
Delivered-To: emailuser@example.com
Received: from localhost (localhost [127.0.0.1]) by server.example.com (Postfix) with ESMTP id 923E9185F7 for ; Thu, 4 Sep 2008 15:37:42 -0400 (EDT)
X-Virus-Scanned: Debian amavisd-new at server.example.com
Received: from server.example.com ([127.0.0.1]) by localhost (server.example.com [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id q3tScOaitRoS for ; Thu, 4 Sep 2008 15:37:42 -0400 (EDT)
Received: from workstation.example.com (workstation.example.com [xx.xxx.xxx.xx]) by server.example.com (Postfix) with ESMTP id B89E1185EB for ; Thu, 4 Sep 2008 15:37:25 -0400 (EDT)
From: 
To: 
Subject: testing a loop
Message-Id: 
Date: Thu, 4 Sep 2008 15:37:25 -0400 (EDT)
Message text

and to prevent goldfish from causing havoc on the particular inbox (or mitigating what was already done… and preventing future issues), I added the following PHP:

//strip the line break from $address for checks
$addressCheck = substr($address,0,strlen($address)-1);
if ($addressCheck==$email)
{
	$log->addLine("Email address from autoresponder table  
	is the same as the intended recipient! Not sending the 
	mail!");
	break;
}

just before letting the mail being sent…

mail($address, $subject, $message, $headers);

I love goldfish. It’s like a do it yourself autoresponder! Keep in mind, this code works on Version 002, patch level 1, but could very well not work on any future releases (there have been indications that a newer version is in the works). Maybe I will post a few more tweaks in upcoming posts if the latest stable stays around for much longer.

Autoresponders – a loop

This past week I encountered an interesting situation between two web applications I work with regularly. The first is the goldfish autoresponder for postfix. The second is RT: Request Tracker.

The situation went something like this:

  • I had a ticket in RT that I wanted to resolve.
  • I set the form to cc the comment to a group of users who were interested in the details of the resolution.
  • I applied the ticket in RT.
  • RT cc’ed the users about the resolution.
  • One of the users had an autoresponder setup using goldfish, so it emailed back to RT about the user’s absence.
  • RT opened a ticket with the content of the email from the autoresponder, faithfully attaching the subject explaining the user’s absence.
  • RT then responded to the user’s email account about the new ticket’s creation.
  • Again goldfish autoresponds to a message from RT, creating a loop.

Every five minutes a new ticket was being created in RT because of goldfish’s configuration and cron job being set to run that often. I caught the cycle happening when the incoming queue of tickets had three or four created with their subjects typical of those created by an autoresponder.

reCAPTCHA plugin error messages

By default, on two of my installs of reCAPTCHA Plugin for WordPress – v2.7, I receive no error message if the captcha is entered incorrectly… the user of the weblog is to assume that they made a mistake I guess…

That is until I wrote this script to check for error messages being passed around on the URL by the plugin:

if (window.location.search != "") {
	var searchArray = window.location.search.split("&");
	for (var i=0; i < searchArray.length; i++) {
		var searchSubArray = searchArray[i].split("=");
		if (searchSubArray[0] == "rerror" && 
		searchSubArray[1] == "incorrect-captcha-sol") {
			document.write(&quot;<p>The two words in the picture were 
			typed incorrectly.</p>");
		}				
	}
}

Just drop that snippet into your “comments.php” template. When the captcha is filled in incorrectly, the plugin adds “rerror=incorrect-captcha-sol” to the url. This checks for that string, and if found, writes an error message in red.

reCAPTCHA plugin styling

Installing a CAPTCHA implementation on WordPress is quite easy when using the reCAPTCHA plugin, however the styling is hard coded into the main php file included.

Goto the installation directory, for example, “wp-content/plugins/recaptcha-wordpress-2.7″ and edit recaptcha.php. Look for the line that embeds the theme type and change it.

    var RecaptchaOptions = { theme : "red", tabindex : 5 };

I used the “clean” theme. There are other options and ideas for editing the code with css changes.

Motion Capture Sorting

When using Motion for a security camera setup, it can generate a lot of files… One installation I have setup has “Encode movies in real-time” enabled, so not only are there many .jpgs in the capture directory, but also .avis.

This can become quite tedious… copying and pasting them from a GUI every day. Consequently, I would let the files simply pile up for a few days before moving them around. Then it became a big job.

Scripting to the rescue. The following below is a PHP-CLI script, that when run from the motion capture directory will sort the various files into a nice little structure that allows for dropping the .avis into a play list for viewing, and keeps the .jpgs around for backup.

#!/usr/bin/php
<?php
 
$fileExtOne = ".jpg";
$fileExtTwo = ".avi";
$fileNameArray = array();
 
//dump filenames (ending in .jpg or .avi)
//in current directory into array
if ($handle = opendir(".")) {
    while (false !== ($file = readdir($handle))) {
        if (substr($file, -4) == $fileExtOne ||
            substr($file, -4) == $fileExtTwo) {
            array_push($fileNameArray, $file);
        }
    }
    closedir($handle);
}
 
//make multi-dimensional array with substrs of filename
for ($i=0; $i<count($fileNameArray); $i++) {
    $fileNameSplit = split("-",$fileNameArray[$i]);
    $dirArray[$i]["group"] = $fileNameSplit[0];
    $dirArray[$i]["year"] = substr($fileNameSplit[1], 0, 4);
    $dirArray[$i]["month"] = substr($fileNameSplit[1], 4, 2);
    $dirArray[$i]["day"] = substr($fileNameSplit[1], 6, 2);
    $dirArray[$i]["name"] = $fileNameArray[$i];
}
 
//create unique array with new directory names and mkdir them
for ($i=0; $i<count($dirArray); $i++) {
    $dirNameArray[$i] = $dirArray[$i]["year"]
            ."-". $dirArray[$i]["month"]
            ."-". $dirArray[$i]["day"]
            ."/". $dirArray[$i]["group"];
}
$uniqueNewDirNames = array_unique($dirNameArray);
foreach ($uniqueNewDirNames as $value) {
    $splitUniqueDirNames = split("/", $value);
    mkdir($splitUniqueDirNames[0], 0755);
    mkdir($splitUniqueDirNames[0]
        ."/". $splitUniqueDirNames[1], 0755);
}
 
//move files into the appropriate directories
for ($i=0; $i<count($dirArray); $i++) {
    if (substr($dirArray[$i]["name"], -4) == $fileExtOne) {
        rename($dirArray[$i]["name"], $dirArray[$i]["year"]
            ."-". $dirArray[$i]["month"]
            ."-". $dirArray[$i]["day"]
            ."/". $dirArray[$i]["group"]
            ."/". $dirArray[$i]["name"]);
    }
    if (substr($dirArray[$i]["name"], -4) == $fileExtTwo) {
        rename($dirArray[$i]["name"], $dirArray[$i]["year"]
            ."-". $dirArray[$i]["month"]
            ."-". $dirArray[$i]["day"]
            ."/". $dirArray[$i]["name"]);
    }
}
 
?>

Here’s what find returns after running the script on the capture directory full of sample .avis and .jpgs.

username@workstation:~/captures> find .
.
./2008-01-06
./2008-01-06/01
./2008-01-06/01/01-20080106145755-02.jpg
./2008-01-06/01/01-20080106145755-04.jpg
./2008-01-06/01/01-20080106145756-00.jpg
./2008-01-06/01/01-20080106145757-00.jpg
./2008-01-06/01/01-20080106145757-01.jpg
./2008-01-06/01/01-20080106145758-00.jpg
./2008-01-06/01/01-20080106145758-01.jpg
./2008-01-06/01/01-20080106145758-02.jpg
./2008-01-06/01/01-20080106145758-04.jpg
./2008-01-06/01/01-20080106145758-05.jpg
./2008-01-06/01/01-20080106145758-06.jpg
./2008-01-06/01/01-20080106145759-00.jpg
./2008-01-06/01/01-20080106145808-01.jpg
./2008-01-06/01-20080106145755.avi

Currency Conversion

A long time ago, I wrote a PHP script to compare current gas prices from Michigan and Ontario in current US and Canadian dollar rates from the following three sites:

http://ontariogasprices.com/
http://michigangasprices.com
http://finance.yahoo.com

as soon as all of the data was retreived (gas prices used a php web scraping library, currency data from Yahoo! Finance retrieved similarly to how Exch does), do the math, and it would let me know who was paying what for gas prices… well using a little Google search, most of the logic of this script became a lot easier (well it has been for some time, but I thought I would share on this little known secret :-)… for example Google these searches below:

3.16 USD per gallon in CAD per liter
3.16 (U.S. dollars per US gallon) = 0.945976868 Canadian dollars per liter

1.10 CAD per litre in USD per gallon
1.10 (Canadian dollars per litre) = 3.67450845 U.S. dollars per US gallon

1.10 CAD per litre in EUR per gallon
1.10 (Canadian dollars per litre) = 2.90268461 Euros per US gallon

1.10 CAD per litre in EUR per litre
1.10 (Canadian dollars per litre) = 0.766808149 Euros per litre

Google even acknowledges the alternative spellings of “liter/litre” … nice huh?