Fun with Garmin Forensics

As you’ll recall from my Christmas post the company I work for is replacing their fleet management equipment, and in part that means upgrading some of our older Garmin GPS screens. As a result a steady stream of old equipment has been trickling into my office.

old_garmins

Even though these units no longer fit our needs, there is still plenty of life left to them. In my next couple of posts I’ll be covering some of the more interesting things to do with these devices.

Science!

Wikipedia states that “forensic science is the scientific method of gathering and examining information about the past“, our methods might not be too scientific, but these devices are chock-full of information about the past.

In preparation for finding them new homes, I thought it might be wise to see what kind of private data these things have stored. I came across a nice overview presentation on GPS forensics that covers a variety of models and brands. That presentation listed some files of interest:

Current.gpx
Archive.gpx
Position.gpx
GarminDevice.xml

After connecting the Garmin to a computer and waiting for the Garmin’s operating system to start I was able to see the Garmin as a storage device.

garmin_usb

Navigating to the \Garmin\GPX directory I was able to locate Current.gpx.
garmin_nuvi_5000_mass_storage

garmin_nuvi_5000_root_folder

garmin_nuvi_5000_garmin_folder

garmin_nuvi_5000_gpx_folder

GPX Format

The GPX in the GPX file format stands for GPS eXchange Format. It’s a fairly simple XML format with plenty of human readable items of interest. Here are some (slightly sanitized) snippets from the GPX file I recovered to give you an idea of the format. The file I was working with was devoid of line breaks, but I’ve added some here for clarity.

After a quick header we get into some more interesting stuff.

<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<gpx xmlns="http://www.topografix.com/GPX/1/1" xmlns:gpxx="http://www.garmin.com/xmlschemas/GpxExtensions/v3" xmlns:gpxtpx="http://www.garmin.com/xmlschemas/TrackPointExtension/v1" creator="nĂ¼vi 5000" version="1.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd http://www.garmin.com/xmlschemas/GpxExtensions/v3 http://www.garmin.com/xmlschemas/GpxExtensionsv3.xsd http://www.garmin.com/xmlschemas/TrackPointExtension/v1 http://www.garmin.com/xmlschemas/TrackPointExtensionv1.xsd">

The “metadata” section seems pretty boring. I think the time listed here is the last time the unit was used.

<metadata>
 <link href="http://www.garmin.com">
  <text>Garmin International</text>
  </link>
  <time>2014-01-16T21:44:20Z</time>
</metadata>

Now on to some good stuff, Waypoints.

<wpt lat="23.137160" lon="-81.687469">
  <ele>241.17</ele>
  <name>001</name>
  <sym>Waypoint</sym>
</wpt>

Some Waypoint entries contain “extensions”, these might include Address Book entries

<extensions>
 <gpxx:WaypointExtension>
  <gpxx:Categories>
    <gpxx:Category>Address Book</gpxx:Category>
  </gpxx:Categories>

Or just addresses

<extensions>
 <gpxx:WaypointExtension>
  <gpxx:Address>
    <gpxx:StreetAddress>101 W. Flagler St</gpxx:StreetAddress>
    <gpxx:City>Miami</gpxx:City>
    <gpxx:State>FL</gpxx:State>
    <gpxx:Country>USA</gpxx:Country>
    <gpxx:PostalCode>33130</gpxx:PostalCode>
  </gpxx:Address>
 </gpxx:WaypointExtension>
</extensions>

Far more interesting than the Waypoints however is the Tracks log. This data is a series of positions at a given time which leaves a trail of breadcrumbs which we can use to reconstruct the journey.

Here is part of one particular journey

<trk>
  <name>ACTIVE LOG: 08 JAN 2014 12:06</name>
   <trkseg>

After the “trkseg” element begins a series of coordinates, elevations, and times follow

<trkpt lat="23.884920" lon="-81.686757">
  <ele>196.25</ele>
  <time>2014-01-08T17:06:41Z</time>
</trkpt>
<trkpt lat="23.884317" lon="-81.686580">
  <ele>196.73</ele>
  <time>2014-01-08T17:06:43Z</time>
</trkpt>
<trkpt lat="23.884317" lon="-81.686580">
  <ele>196.73</ele>
  <time>2014-01-08T17:06:44Z</time>
</trkpt>
<trkpt lat="23.884317" lon="-81.686580">
  <ele>196.73</ele>
  <time>2014-01-08T17:06:45Z</time>
</trkpt>

…And so on

Google Earth

As you can see this information is easy to work with to suit your needs. If your needs are just to watch what happened and when, Google Earth is great tool for this. It turns out Google Earth already understands the GPX format, so we don’t need to extract any data manually.

Just click on Tools then GPS
google_earth_import_1

Select the Import from file option followed by the Import button
google_earth_import_2

Navigate to your Current.gpx file (in my case \Garmin\GPX), select it and click Open
google_earth_import_3

Google Earth will tell you what data it was able to find. Click OK
google_earth_import_4

On the left panel you can move between waypoints to see them on the map.
google_earth_view_imported_2

Fun

For even more fun, select one of the “Tracks” logs, and click the play button with breadcrumb icon (I assume that’s what that is anyhow).
google_earth_view_imported_3

Here is some sample video I captured from the playback of some track log data. The data isn’t real-time of course (that would be boring), but there is still some relevant timing preserved. Notice how you can even tell which stop lights were red by the time elapsed between movements. Very interesting and potentially revealing stuff.



Posted in General Nonsense, Software | Leave a comment

Garland & Garmin Greetings

My office at work wasn’t feeling very Christmas-like, so I flaked out a little and hatched a plan to address the stark lack of festiveness.

I have a bunch of these old Garmin Nuvi 5000 model GPS displays in my office right now.

garmin_5000

We are replacing our fleet management software and with it our vehicle tracking system.

Both the old and the new system have the ability to connect to Garmin GPS displays via FMI cable in order to push waypoints and information to the driver. Unfortunately the Garmin Nuvi 5000 displays are kind of old at this point, the FMI interface isn’t compatible with our new system (hence a pile of GPS screens on my desk). This cable previously wired in to the vehicle accessory power.

garmin_fmi_serial

I compiled a pile of useful ingredients.
christmas_tools

I twisted the power wires of the FMI cables together, soldered it up to some spare wire, and covered it with some shrink tube.
fmi_twisted

fmi_twisted_soldered

Using the multimeter I measured the current of one of the Garmin displays, it fluctuated a bit as the system booted up and looked for satellites, but it seemed to stay pretty well under 150mA. I ended up using 6 Garmins, so figure maybe 900mA, add some buffer room, and I decided that this 12 volt DC 2 Amp power supply would be a good donor.

garmin_xmas_power

The whole time I had Garmin’s commerical jingles stuck in my head.

Peace & Joy

Posted in General Nonsense | Leave a comment

Bash Snippet: Decimal to Binary Conversion

Convert a decimal value into the binary representation and vice versa in Bash using only built-ins. If you know a better way, please let me know. To ensure a properly formatted expression for the arithmetic expansion in bin2dec, the dec2bin function prefixes zeros as needed to pad to a character count evenly divisible by 8.

dec2bin () {
    num="$1"
    bin=""
    padding=""
    base2=(0 1)
    while [ "$num" -gt 0 ];
    do
            bin=${base2[$(($num % 2))]}$bin
            num=$(($num / 2))
    done
    if [ $((8 - (${#bin} % 8))) -ne 8 ]; then
            printf -v padding '%*s' $((8 - (${#bin} % 8))) ''
            padding=${padding// /0}
    fi
    echo $padding$bin
}


bin2dec () {
        echo $((2#$1))
}

Examples:

user@host:~$ dec2bin 1
00000001
user@host:~$ bin2dec 00000001
1
user@host:~$ dec2bin 255
11111111
user@host:~$ bin2dec 11111111
255
user@host:~$ bin2dec 1010101010101010
43690
user@host:~$ dec2bin 43690
1010101010101010

Perhaps not the most efficient way, but at least for small numbers it appears to be quicker than opening a subshell.

user@host:~$ time dec2bin 43690
1010101010101010

real    0m0.001s
user    0m0.000s
sys 0m0.000s
user@host:~$ time echo "obase=2;43690" | bc
1010101010101010

real    0m0.002s
user    0m0.000s
sys 0m0.000s
Posted in General Nonsense | Leave a comment

Firefox javascript:alert(); Not Working in Location Bar

Did you notice that the “javascript:” URI scheme has been removed from Firefox 6.0 and later? Sometimes I think Firefox is purposely trying to get me to switch browsers, but the intent of this change was evidently to fix a security issue. The downside is no more ad hoc debugging with javascript:alert(var); from the location bar. This is an article about the new way to do that kind of thing (in anecdotal form).

Some SSL and site validation services provide seals for their customers, little badges of warm “security” feelings. Say you want to demonstrate to a friend how meaningless those security seal images are. Just right-click and copy the image right?

firefox_javascriptimage-to-grab

Well usually, but Thawte (our example) was a bit more clever than many of the other snake-oil salesmen, and they added a little javascript to obfuscate the process. My right-click is hijacked, and I get a popup window instead.

firefox_javascript-right-click-hijack

No problem, we’ll just turn off javascript temporarily and try again.

firefox_javascript-disable-javascript

Hmm.. OK, so I guess they use javascript to load the image. Clever girl.

firefox_javascript-disabled-no-image

Alright, we’ll re-enable javascript and look at the page source. Ah, here, this looks promising.

firefox_javascript-viewsource-1

This seems to be what I want, but what’s in this seal_url variable, and these other things, this is starting to seem like too much work. Oh, hey, lets look at the “u2″ variable, that seems like it might be helpful.

firefox_javascript-viewsource-2

So, we try to do the ‘ol javascript:alert(u2); and…nothing.

firefox-javascript-alert-uri-deprecated

No suprise, we already said that feature was deprecated, so how then do we get around it? One way is with a bookmarklet. Yeah, turns out “bookmarklet” is a word now, all it means is putting javascript in a bookmark location though (did we need a new word for that?).

firefox-javascript-bookmarklet

Clicking on the new bookmark returns the results we were hoping for, but it’s kind of a chore. Another method is to use the Web Developer Scratchpad. You can navigate to it as shown below, but that’s not much quicker than constantly editing a bookmark *ahem* bookmark-let. Hitting Shift+F4 however also brings up the Scratchpad, and is far more acceptable.

firefox-javascript-webdev-scratchpad-1

In the scratchpad we add in our alert(u2); call.

firefox-javascript-webdev-scratchpad-2

Run the script.

firefox-javascript-webdev-scratchpad-run

And, victory is mine.

firefox-javascript-success

The story of Firefox and the javascript ends here, but the story of the Thawte seal misappropriation has one more, unexpected detail. Thawte apparently was clever enough to look at the referrer passed by the browser during the image request. If the referer domain doesn’t match the validated domain, the end user is presented with an emblem indicating there is a problem with the “trust” that seal would normally instill. We could easy download the image file ourselves from the website, but it’s visibly date stamped, so that would lose some panache. Instead we could just make the request for the image in the user’s behalf without bothering to send a referrer.

<?php
header('Content-type: image/gif');
echo file_get_contents ('https://seal.thawte.com/getthawteseal?at=0&sealid=0&dn=WWW.THAWTE.COM&lang=en&gmtoff=300');
?>
Posted in General Nonsense | Leave a comment

SanDisk 25th Anniversary Contest

sandisk_contest

A pile of SanDisk micro SD cards showed up on my desk today, part of an order for some new “smart” phones. I noticed that there was some print about a 25th anniversary contest on the package. The odds on something like that surely sucks, but I figured, “hey, I have a pile of these, why not?“.

Inside the packaging of eligible SanDisk brand products there is a stamped bit of plastic with your special code. I was quickly disheartened to learn that all of my special codes were the same code.

sandisk_code

“I must be looking at the wrong number” I thought, but a visit to the SanDisk contest site confirmed my suspicion. If you want to play this game legitimately without a purchase you can mail in a 3×5″ card, but that seems pretty pointless since evidently these special codes are just to fool the rubes and are in no way unique. According to the official rules (and enforced by the website) each person/email address can try up to 10 codes. Each code puts in an entry for the $25,000 prize and gives 5 instant spins of the prize wheel. I have at least 17 left over codes to use, but I guess someone else will have to use mine. As you can see from the picture, all of my codes were marked 54-53-10242. I had hoped for some Real Genius-style Frito-Lay contest fun, but these rules were not compatible.

sandisk-slot-machine

The official rules do not list the odds in winning, probably because you can’t really determine odds without knowing how many people will play (sorry Lazlo). Suffice it to say the odds appear to be worse than 1 in 50, as none of my instant win attempts succeeded. If you feel like wasting your time on a game you too can almost certainly not win, I’d recommend the SanDisk 25th Anniversary Contest. It’s a fun 15 minute diversion from your otherwise productive day.

sandisk-lost

I played around with Firebug until I felt better, but it wasn’t much consolation.

sandisk-won-nothing

Posted in General Nonsense | Leave a comment

Remove Hidden Hardware in Device Manager

This article applies to Windows 2003 and Windows XP, it may apply to other versions of Windows as well, but I have not tested.

After converting a Windows 2003 server to a virtual machine I had some problems. The OS would not boot properly, although I could still boot into “Safe Mode with Command Prompt”. Many times this problem is caused by the OS trying to load device drivers for components no longer in the system. Here is a quick tip on how to “remove” devices that are no longer present on your system.

If the “devmgr_show_nonpresent_devices” environment variable is set to “1” when Device Manager is opened it will show devices on the system that are no longer present as well as devices that are currently detected. This feature is documented in Microsoft knowledge base article 315539 http://support.microsoft.com/kb/315539

After booting into the command prompt I ran the following commands:

Microsoft Windows [Version 5.2.3790]
(C) Copyright 1985-2003 Microsoft Corp.

C:\Documents and Settings\Administrator>set devmgr_show_nonpresent_devices=1

C:\Documents and Settings\Administrator>start devmgmt.msc

Enable “Show hidden devices“. Although “Show hidden devices” is always available from the “View” menu, it does not show non-present hardware if “devmgr_show_nonpresent_devices” is not set to “1”.

Several items show up now with faded/ghostly versions of the normal item icon. The “HP” SCSI drives listed below are no longer present in the system and can be removed. On my system several network card drivers, some SCSI drivers, a display driver, and other system components that were no longer required were found.

Posted in General Nonsense | Leave a comment

Canon, [Third-]World Class Support

Here is rant of no redeeming quality other than maybe a little amusement. I was searching for a way to use both legal sized and 8.5×11″ paper in a Canon MF8350Cdn without needing to constantly switch out the paper and adjust the paper tray. I found a “cassette feeding unit” under “Supplies & Accessories” for my device at Canon’s site, but there was no additional info. The “250-sheet” description lead me to believe that maybe paper was involved, so I was feeling a little optimistic.

There was no link to click for additional details, nothing of any use for getting a little more insight about the accessory. I tried to use Canon’s search feature for “Cassette Feeding Unit-V1″, which turned up nothing. I managed to find a possible part number from a third-party website, but that too failed to lead me to any product literature on Canon’s site.

I checked some vendor websites for details, or at least a clue as to what this thing is, I figure maybe if I see a picture I’ll know if this is worth perusing.

CDW had no picture.

TigerDirect had no picture.

Results from a Google image search produced conflicting pictures. One of the pictures looks like it’s an additional tray (desired) and the other looks like it’s some kind of funky attachment that maybe holds more paper in the multi-purpose tray (not desired). Well, at least this accessory appears to be related to paper of some kind.

This device costs like $200, and I’m not even sure that it does what I want. I’d like to know it’s at least in the ball park of what I’m looking for before ordering. I broke down and emailed Canon customer service. The website, as I mostly anticipated, did not provide me with an email address, but rather directed me to some obnoxious html form (which FYI, in turn generates a form email to “carecenter@cits.canon.com”).

Oh look! Awesome, my printer isn’t even in the list. Sarcasm, growing.

So finally I send the following message:

I have a color imageCLASS MF8350Cdn. I am inquiring about the optional accessory “Canon Cassette Feeding Unit-V1″ (0732A024AA), there is essentially no information available about this item on the Canon USA website. Using the accessory can I configure the primary tray for legal sized paper, and use the “Canon Cassette Feeding Unit-V1″ for 8.5×11″ paper? Does the additional tray provided by the “Canon Cassette Feeding Unit-V1″ work independently of the primary tray?

A day later I get this irrelevant response.

It’s not like this is the first time I’ve gotten brushed off by a company. I mean I get it, I understand; you have thousands of people asking you questions and there just isn’t a cheap enough way to answer them all. This is a dead end, I give up. What’s this? The fun doesn’t stop here? Canon turns over my info to some other company: “MarketTools CustomerSat” (http://www.customersat.com/) who nags me 3 days after my inquiry for a customer satisfaction survey.. yeah right, trust me fella, you don’t want to know. Another 3 days go by, another nagging message from CustomerSat.. RAGE!

I opt-out of the communications, but I’m pretty irritated at this point so I complete the survey despite suspecting no one will ever read it. If they don’t have the money to hire people with enough patience to read my initial question, why would they pay someone to read my response to their response? It seemed likely to me that the whole thing was probably a contraption invented to allow inevitably frustrated people to vent without tying up more costly telephone time.

Incidentally, I ended up ordering the part and it was what I was hoping for, but I didn’t know for sure until I opened the box it shipped in.

EDIT: I’m continuing to receive unsolicited emails from Canon despite explicitly removing myself from all the lists they’ll let me remove myself from.

Posted in Rants | Leave a comment

Detect Wi-Fi Clients on your DD-WRT Router

Here is a script I wrote that scrapes the web interface of a router running DD-WRT. The script looks for the MAC addresses of wireless users. When it sees a MAC address that it hasn’t logged before it issues an alert. To help identify the new equipment, a portion of the MAC address is sent to an IEEE OUI database search (Internet connection required) to determine the manufacturer name. This script is intended to be ran periodically from crond on a system other than the router. When the script detects a new MAC address it writes to STDOUT, in most cron configurations this will result in an email being generated to the local system user running the process, or to another address specified in the MAILTO variable.

Sample /etc/crontab entry

MAILTO="5558675309@sms.mobile.example.org"
* * * * *       root    /usr/local/sbin/wifi-macs.sh

Sample output generated when a new iPhone connects to the ‘MySSID’ network.

Alert new client found on MySSID MAC: 040CCECAFE00 (Apple, Inc.)

Download wifi-macs.sh

#!/bin/bash

#Set the username used for web access to the router
ROUTER_USER="root"
#Set the password used for web access to the router
ROUTER_PWD="admin"
#Set the IP address where the router can be reached, optional port
#number can be specified like 192.168.1.1:80
ROUTER_IP="192.168.1.1"

#If you have your router setup to support https, change to https
PROTO="http"

LOGS="/var/log/wifi"

read_macs () {
        while read line
        do
                if [ "${line//active_wireless/}" != "$line" ]; then
                        OFS="$IFS"
                        IFS="\'"
                        for word in ${line[@]}
                        do
                                if [ "${#word}" -eq "17" ]; then
                                mac="${word//:/}"
                                        if [ "${#mac}" -eq "12" ]; then
                                                echo "$mac"
                                        fi
                                fi
                        done
                        OFS="$IFS"
                        mac=""
                        word=""
                fi
        done
}

read_ssid () {
        while read line
        do
                if [ "${line//wl_ssid/}" != "$line" ]; then
                        line="${line##*"wl_ssid::"}"
                        line="${line%%"}"*}"
                        echo "
$line"
                fi
        done
}

read_company () {
        while read line
        do
                if [ "
${line//"(base 16)"/}" != "$line" ]; then
                        line="
${line##*'(base 16)'}"
                        line="
${line:2}"
                        echo "
$line"
                fi
        done
}


if ! [ -d "
$LOGS" ]; then
        echo "
Logs directory $LOGS does not exist" >&2
        exit 1
fi

wldata="
`curl -s --user $ROUTER_USER:$ROUTER_PWD $PROTO://$ROUTER_IP/Status_Wireless.live.asp`"
ssid="
`echo $wldata |read_ssid`"
macs=(`echo $wldata |read_macs`)

for mac in ${macs[@]}
do
        if ! [ -f "
$LOGS/$mac" ]; then
                company="
`curl -s "http://standards.ieee.org/cgi-bin/ouisearch?${mac:0:6}" |read_company`"
                echo "
Alert new client found on $ssid MAC: $mac ($company)"
                echo "
New MAC Address detected: `date`" >>$LOGS/$mac
                echo -e "
${mac:0:6}\t\t$company" >>$LOGS/$mac
                echo -e "
Additional Data:\n$wldata" >>$LOGS/$mac
        fi
done
Posted in Bash, System Administration | Leave a comment

Import Nextel iDEN Contacts to Google

Sprint is decommissioning it’s Nextel iDEN network in 2013. The Nextel network has been very popular with businesses for it’s push-to-talk (PTT) “walkie-talkie“-like service. Several rugged (and bulky) mobile phones like the Motorola i355 and i365 are well adapted to the sometimes harsh environments of field work and clumsy service technicians. Unfortunately it seems that many of these phones will outlive the network that supports them, leaving just SouthernLINC and a handful of small regional providers to offer any iDEN network service in the U.S. market.

It seems that everyone is switching to smartphones these days, and my office is no exception. One of the nicest features from an information technology standpoint about this new generation of phone is cloud integration. Frequently setting up one Exchange server or Google Apps account on the phone will synchronize calendars, contacts, and email. It soon became apparent while migrating the staff off their beastly “dumb”-phones that people were going to be spending a lot of time manually transferring their contacts from one phone to the other. To speed up the process I created a VBScript that works with the Motorola iDEN Phonebook Manager to export the phone book Jet database into a CSV file compatible with Google Contacts.

EDIT: Updated to add a kludgy work-around for 64-bit Windows

Download iden2googlecontacts.zip

CSVname = "export.csv"
DBname = "import.mdb"

'Optional Usage: iden2googlecontacts.vbs SourceDB TargetCSV

If WScript.Arguments.Count => 1 Then
    DBname = WScript.Arguments(0)
End If
If WScript.Arguments.Count => 2 Then
    CSVname = WScript.Arguments(1)
End If


'So I guess this doesn't work with the default WSH interpreter on 64-bit versions of Windows
If WScript.Arguments.Count < 3 Then
    Set objShell = CreateObject("WScript.Shell")
    If objShell.RegRead("HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Environment\PROCESSOR_ARCHITECTURE") = "AMD64" Then
        WINDIR=objShell.ExpandEnvironmentStrings("%WINDIR%")

        Set fs = CreateObject("Scripting.FileSystemObject")
        If Not fs.FileExists(WINDIR & "\SysWOW64\wscript.exe") Then
            WScript.Echo WINDIR & "\SysWOW64\wscript.exe"
            WScript.Echo "Warning: Can't find 64-bit Wscript.exe, this probably won't work."
            Set colSystemEnvVars = Nothing
            Set objShell = Nothing
            Set fs = Nothing
        Else
            'The script won't fork if there are 3 or more arguments on the command line
            Command = WINDIR & "\SysWOW64\wscript.exe "
            Command = Command & Chr(34) & WScript.ScriptFullName & Chr(34)
            Command = Command & " "
            Command = Command & Chr(34) & DBname & Chr(34)
            Command = Command & " "
            Command = COmmand & Chr(34) & CSVname & Chr(34)
            Command = Command & " "
            Command = Command & "NO_FORK"
            objShell.Run Command
            WScript.Quit
        End If
    End If
End If
'OK Things should be back to normal at this point

If InStr(CSVname, "\") = 0 Then
    Set objShell = CreateObject("WScript.shell")
    CSVname = objShell.CurrentDirectory & "\" & CSVname
    Set objShell = Nothing
End If

If InStr(DBname, "\") = 0 Then
    Set objShell = CreateObject("WScript.shell")
    DBname = objShell.CurrentDirectory & "\" & DBname
    Set objShell = Nothing
End If

Set fs = CreateObject("Scripting.FileSystemObject")
If Not fs.FileExists(DBname) Then
    WScript.Echo "Error: Database " & DBname & " was not found!"
    WScript.Quit
End If
Set fs = Nothing

WScript.Echo "Exporting " & DBname & " to CSV file " & CSVname

Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objTextFile = objFSO.CreateTextFile(CSVname, True)

i=0

objTextFile.Write("Name,Given Name,Additional Name,Family Name,Yomi Name,Given Name Yomi,Additional Name Yomi,Family Name Yomi,Name Prefix,Name Suffix,Initials,Nickname,Short Name,Maiden Name,Birthday,Gender,Location,Billing Information,Directory Server,Mileage,Occupation,Hobby,Sensitivity,Priority,Subject,Notes,Group Membership,E-mail 1 - Type,E-mail 1 - Value,E-mail 2 - Type,E-mail 2 - Value,Phone 1 - Type,Phone 1 - Value,Organization 1 - Type,Organization 1 - Name,Organization 1 - Yomi Name,Organization 1 - Title,Organization 1 - Department,Organization 1 - Symbol,Organization 1 - Location,Organization 1 - Job Description" & vbCRLF)

SQL = "SELECT ContactName, Number, NumberType FROM tblContactList WHERE NumberType<>1 AND NumberType <= 6;"

set oConn=CreateObject("ADODB.Connection")
oConn.Open "Driver={Microsoft Access Driver (*.mdb)}; DBQ=" & DBname & ";"
Set oRS=oConn.Execute(SQL)

Do While Not oRS.EOF
        'Name
    objTextFile.Write(oRS.Fields("ContactName"))
    objTextFile.Write(",")
    'Given Name
    objTextFile.Write(",")
    'Additional Name
    objTextFile.Write(",")
    'Family Name
    objTextFile.Write(",")
    'Yomi Name
    objTextFile.Write(",")
    'Given Name Yomi
    objTextFile.Write(",")
    'Additional Name Yomi
    objTextFile.Write(",")
    'Family Name Yomi
    objTextFile.Write(",")
    'Name Prefix
    objTextFile.Write(",")
    'Name Suffix
    objTextFile.Write(",")
    'Initials
    objTextFile.Write(",")
    'Nickname
    objTextFile.Write(",")
    'Short Name
    objTextFile.Write(",")
    'Maiden Name
    objTextFile.Write(",")
    'Birthday
    objTextFile.Write(",")
    'Gender
    objTextFile.Write(",")
    'Location
    objTextFile.Write(",")
    'Billing Information
    objTextFile.Write(",")
    'Directory Server
    objTextFile.Write(",")
    'Mileage
    objTextFile.Write(",")
    'Occupation
    objTextFile.Write(",")
    'Hobby
    objTextFile.Write(",")
    'Sensitivity
    objTextFile.Write(",")
    'Priority
    objTextFile.Write(",")
    'Subject
    objTextFile.Write(",")
    'Notes
    objTextFile.Write(",")
    'Group Membership
    objTextFile.Write(",")
    'E-mail 1 - Type
    objTextFile.Write(",")
    'E-mail 1 - Value
    objTextFile.Write(",")
    'E-mail 2 - Type
    objTextFile.Write(",")
    'E-mail 2 - Value
    objTextFile.Write(",")
    'Phone 1 - Type
    Select Case oRS.Fields("NumberType")
        Case "0"
            objTextFile.Write("Mobile")
        Case "2"
            objTextFile.Write("Home")
        Case "3"
            objTextFile.Write("Work")
        Case "4"
            objTextFile.Write("Mobile")
        Case "5"
            objTextFile.Write("Work Fax")
        Case "6"
            objTextFile.Write("Pager")
        Case else
            objTextFile.Write("Mobile")
    End Select
    objTextFile.Write(",")
    'Phone 1 - Value
    objTextFile.Write(oRS.Fields("Number"))
    'Organization 1 - Type
    objTextFile.Write(",")
    'Organization 1 - Name
    objTextFile.Write(",")
    'Organization 1 - Yomi Name
    objTextFile.Write(",")
    'Organization 1 - Title
    objTextFile.Write(",")
    'Organization 1 - Department
    objTextFile.Write(",")
    'Organization 1 - Symbol
    objTextFile.Write(",")
    'Organization 1 - Location
    objTextFile.Write(",")
    'Organization 1 - Job Description
    objTextFile.Write("," & vbCRLF)
    i = i + 1
    oRS.MoveNext
Loop

objTextFile.Close
Set objFSO = Nothing

If i > 1 Then
    WScript.Echo "Exported " & i & " record"
Else
    WScript.Echo "Exported " & i & " records"
End If

If oRS.State = 1 or oRS.State = True Then
    oRS.Close
        oConn.Close
        set oRS = Nothing
        set oConn = Nothing
End If

The Motorola iDEN Phonebook Manager is a free download, but you’ll need a cheap cable (available on eBay for under $5 for many phones) to dump the contacts off the iDEN SIM card.

Dock the phone to the USB cable and connect it to the computer you’ll be working with. You may be prompted to install additional drivers for your phone, but most of what you need will probably be included with the Motorola iDEN software download.

Open up Motorola iDEN Phonebook Manager and select “New/Edit Phonebook“.

Next select “Load From Phone“.

The software will prompt you to make sure the cable is connected between the phone and computer. Press “OK“.

An activity screen will open showing communication in progress between the computer and the phone.

The phone’s display may also show some indication of something unusual happening (as seen on an i355) or may just go blank (i365).

Once all the contacts are imported click the “Continue” button on the bottom of the window.

Select “Save To File“.

Pick a name for your file. I chose “import.mdb“, if you choose something else, you’ll have to edit the VBScript accordingly. Remember where you save the file.

Download iden2googlecontacts.zip and extract the iden2googlecontacts.vbs script into the same directory as your phone book export (“import.mdb” in this example).

Edit the script to change the input or output file names if required. When you are ready to run the script, double-click on iden2googlecontacts.vbs. The script will output the file names for verification, or warn you if it is unable to find the database to import contacts from.

When the script is complete it will tell you how many contacts it exported into the new CSV file (named export.csv by default).

Armed with the new CSV file export you just created, open up Google Contacts. under the “More” button choose “Import…“.

Click the “Choose File” button.

Navigate to the location where your export file was created and select the file (export.csv in this example). Click “Open” to proceed.

Click the “Import” button.

If everything worked OK, you should now see the new contacts. Click “Find & merge duplicates” to reconcile the import with any contacts the user may have already had in Google Contacts.

To be useful on the smartphone you may have to move these contacts to the “My Contacts” group label. Click the square selection box as shown below and then choose “All” to select all contacts.

Click the group button (the thing with three heads on it) and remove the check mark from the auto-generated label (shown here as “Import 9/28/12″). Place a check mark next to “My Contacts” and click “Apply

The contacts should all be removed from the auto-generated group label. You may optionally remove this group label now. Click the “More” icon again and choose “Delete group“.

Google will prompt you to confirm the deletion.

That’s it. Depending on the model of your mobile phone additional steps may be required to resynchronise your contacts with the server, but many phones handle this automatically.

If you are processing many phone books, consider the following command for batch processing

for %f in (*.mdb) do cscript iden2googlecontacts.vbs %~nf.mdb %~nf.csv

If you use this script and find it helpful (or run into problems), please let me know in the comments.

Posted in Helpful Tools, VBScript | 4 Comments

Dell Vostro 1000 Backlight Inverter Replacement

An aging Dell Vostro 1000 ended up on my desk the other day. The owner said it had died, when he turned it on some LEDs lit up, but there was no display. It turned out that the backlight which illuminates the LCD panel was not working. This is a common problem with older laptops. A bright flashlight aimed at the screen revealed the ghostly faint image of a Windows desktop struggling to be seen. The backlight is actually an edge light that illuminates a panel behind the LCD screen. On older laptops and LCD monitors this is a compact florescent light (CFL). Many newer displays use LEDs as the light source. A CFL is kind of a miniature version of florescent office light tubes. Just like florescent office lights needs a high voltage ballast to excite the gasses in the tube, a CFL needs an “inverter”. The backlight inverter is by far the more common failure point in an inverter & CFL system. Replacement kits with both the CFL and inverter for most laptops are available on eBay, but I’d recommend just trying the inverter board to start with. The cost is usually less than $5 shipped.

Since I was stuck repairing this dinosaur, I figured I’d document the process for the benefit of anyone else finding themselves in a similar situation.

You’ll want to gather some tools, a small Phillips-head screw driver, a small flat-head screw driver or spudger, some double-sided tape and a pry tool.

Pry tools are nice for opening plastic enclosures of electronics as the soft plastic of the pry tool often gives way before the work material which helps to prevent marring the device. Pry tools can be picked up for cheap on eBay. Guitar picks are also useful for this purpose.

First, remove the battery from the laptop to prevent accidental powering on the device while working with it.

Carefully pry off the rubber bumpers covering the screws on the LCD bezel. I used a small flat-head screw driver. I attempted to insert the screw driver head under the edge of the rubber bumpers to prevent tearing them. If you’re lucky you’ll take the adhesive material with you. If not you’ll need to replace the adhesive with a small bit of your double-sided tape later. Do not glue these back in place, it will be a mess and whoever opens the screen next will curse your name.

Locate and remove the rubber bumpers and screws and the indicated locations.

Locate the gap in the upper right area above the keyboard, this will make a good pry point to begin loosening the bezel with the power button on it.

Using a firm, but not forceful prying or subtle twisting action of the pry tool, you should feel the bezel loosen as you move along the perimeter. Continue to work around the bezel as shown

The bezel is now off exposing some screws, however we don’t need to do anything with those screw. This piece was removed to make it easier to access the monitor bezel.

Work the pry tool into a separation in the LCD bezel. I worked around the frame twisting the pry tool slightly, and the front came off without a problem.

The LCD bezel should be off now.

We can see the back of the inverter (in the red square). Remove the single screw holding the inverter in place (shown in the red circle).

Look on the left and right edges of the LCD panel. There are screws attaching the panel to the rest of the screen assembly that will need to be removed. The right side is shown with the screws of interest circled in red.

With the screws removed from each side, find the two metal tabs near the top of the LCD panel. They make a useful point to carefully grip the LCD panel and flip it downward gently onto the keyboard as shown.

Remove the new LCD from it’s packaging, and verify that the part correctly matches the old inverter

The control connector for the inverter board is shown below (circled in red). Carefully pull upward on the blue tab to free the connector from the board.

On the other side of the board, unplug the high voltage power feed.

The inverter will take some work to free, as there is some strong double-sided tape found underneath.

Replace the double-sided tape if necessary, then insert the new inverter. Carefully flip the LCD panel back up into position and secure with the screws you removed earlier. Don’t forget to reinsert the small screw that holds the inverter in place. Reattach the LCD bezel, it should snap back together with light pressure.

When reattaching the bezel with the power button, insert the left-hand side first. There are two tabs that must be inserted under the slots (shown circled in red).

Replace the screws on the LCD bezel front. Add a small amount of double-sided tape if necessary to the rubber bumpers to secure them back in place.

Reinsert the battery and power on the laptop. If everything worked out, you should have a working backlight again. If the problem persists you may have purchased a bum backlight inverter or the CFL might have actually died, in which case maybe it’s time to break down and buy a CFL & backlight kit. or just get a new laptop.

Posted in Trash to Treasure | 1 Comment