Monthly Archives: September 2008

Force remove a message stuck in an Outlook outbox

I’m writing these instructions up for posterity, since this is now the second time this incident has happened and I wanted to preserve the instructions for the MDBVU32 tool. The first time, it was a bad read receipt causing an annoying popup for every sent message; an outstanding client can’t send or receive any messages. (Original instructions are at howto-outlook.com.)

This situation can occur on most versions of Outlook and requires a repair utility from Microsoft to fix. To avoid completely trashing the mailstore, grab a copy of MDBVU32 (the Microsoft Exchange Server Information Store Viewer) from Microsoft or from here.

Start the utility, then click OK to the first dialog. Then,

  • Click MDB > OpenMessageStore, select the item with the “D” next to it for the default PST file.
  • The message will be in either MDB > Open Root Folder or MDB > Open IPM Outbox.
  • Select the stuck message in the middle column and select lpMDB->AbortSubmit(), then Call Function.
  • Select OK, then log out by MDB > Store Logoff > OK > OK
  • Close the application by Session > Session Logoff, then close any remaining windows.

ADODB for PHP and MySQL – a few ‘fun’ facts

I nearly burned up my entire afternoon today troubleshooting a few annoying inconveniences with the ADODB database layer, plus the design decisions of MySQL. Here’s what I’ve found out in a few ‘fun’ facts. This post is reasonably heavy on the technical content, so be warned.


You may be tempted to use the MySQL “REPLACE INTO” function for your own code. A sort of hybrid between INSERT or UPDATE operations, MySQL will seek the primary key in your query and check if it matches a database row. A match results in an UPDATE operation, while no match results in an INSERT query being run. Unfortunately, reading the documentation reveals an enraging drawback:

…except that if an old row in the table has the same value as a new row for a PRIMARY KEY or a UNIQUE index, the old row is deleted before the new row is inserted.

This is a poor showing from an optimization perspective, but consider a typical business application: we’re not going for any kind of ridiculous efficiency, and the overhead of a DELETE operation is minimal. The real gain achieved by going through a REPLACE statement is on the development side, where no longer are two code paths or separate queries required for add and edit operations.

Except this isn’t the case.

My specific condition was the standard implementation of a users table: a PRIMARY KEY with an auto-incrementing user identifier, username, a few other fields, and a password storage column. Unlike the chumps at MySpace, I don’t store passwords in reversible encryption/plaintext or make a habit of sending the field contents for account reset emails.

By default, an UPDATE operation only changes the requested fields in a table – so if I left out the password column, the contents would stay the same for that user. Yet somehow, even when I didn’t specify a password change for a user, their password field became blank.

Lo and behold: because of the ridiculous DELETE behaviour present behind the scenes in a REPLACE query, you lose all other contents of that row if you don’t store and specify their values again.

Strike one for REPLACE. The fact that silent data loss can occur is what I’d consider a severity one problem, and if you’re planning on using REPLACE in one of your own programs, ensure that you’ve retrieved all columns from that table first. Not only is it weak from a performance standpoint, but its ability to nuke perfectly legitimate hashed data makes it dangerous.


The second such entertaining point was what happened when I tried to use ADODB’s “AutoExecute” function. This method provides a database-agnostic call to run an insert or update statement based simply on a key/value array:

AutoExecute($table, $arrFields, $mode, $where=false, $forceUpdate=true,$magicq=false)

AutoExecute() inserts or updates $table given an array of $arrFields, where the keys are the field names and the array values are the field values to store. Note that there is some overhead because the table is first queried to extract key information before the SQL is generated. We generate an INSERT or UPDATE based on $mode (see below).

This seems like an incredibly lazy and awesome feature when you think about it: the advantages of the REPLACE INTO statement, with only one minor if/then code block based on insertion or update. However, in the infinite wisdom of ADODB, all strings end up being quoted automatically. This means that you can’t use CURRENT_TIMESTAMP to update columns, nor can you easily use DBTimeStamp since the result of that function has already been escaped. For some reason, ”2008-09-24 20:36” won’t parse inside SQL.

As a result, I’ve dropped back to writing my own parameterized queries for this application. This provides the sanitization features of escaping potentially malicious user input, while preserving the ability to run timestamp updates for rows.

Thoughts? How would you go about ensuring an optimal database interaction?

Rogers’ DNS shenanigans: screwing with VPNs (and alternate servers)

While it may seem like all I write about these days is Rogers, it’s really the only thing I’ve been dealing with on the service provider front. All my other corporate relations have been going well: I pay people money and they provide a service without bothering me unduly. (I must congratulate the wireless business for their 6GB data plan extension and forthcoming reasonably priced data packages, although one could make the case that Telus and Bell really forced them into it.) This time, it’s about the Internet side of the equation.

Beginning July 18th, Rogers began implementing a provider-wide SiteFinder-style service, where users are redirected to a “search” page with sponsored results for mistyped and nonexistent domains. On a technical level, I fundamentally disagree with this change: it breaks the concept of NXDOMAIN (a useful “domain does not exist” response) and makes things much more difficult to troubleshoot with respect to network architecture. The only reason I haven’t bitched and whined about this much earlier is that I’ve been using OpenDNS for completely unrelated reasons. It was only when my roommate Alex complained about VPN connectivity that I actually looked into the issue.

It turns out that Rogers’ marketing effort completely bricks internal domain resolution for a lot of common VPN clients, including the default Windows XP offering. So if your company, like many others, has internal domains such as corpweb.example.com, Rogers’ search will open up with the terms “corpweb example” at the minimum. This practice has data exposure implications: not only does Rogers now know about an internal domain you’re trying to access, but a third party provider like Yahoo now knows.

If you were an employee of a competing search engine and trying to VPN from home, Yahoo would now know something about your internal network structure; this is bad news all around. Hitting a favourite or quick launch link to corpweb.example.com/livelink/llsapi.exe?doc=Network_Security_Breach_Sept0408.doc would reveal the choice of LiveLink as a corporate CMS, a dependence on Microsoft Word and a document detailing a potentially classified incident.

OpenDNS isn’t any better by default, either. They redirect search results and mistyped domains, and in the process intercept VPN traffic. To get around this, you have to create an account and blacklist corporate VPN connections from “helpful results” on a per-domain basis. The solution also involves downloading and maintaining a dynamic IP address update client, or setting a Tomato-enabled router to perform the same task.

What I’ve done for now is listened to the accurate advice on trevoro.ca and changed my primary Rogers DNS server to an unadvertised IP address: altdns.rnc.net.cable.rogers.com, or 64.71.255.202. This server seems reasonably quick for name resolution and returns proper responses when a domain is not found, allowing VPN software to resolve internal addresses.