Death of the Desktop

I’m a geek. If you didn’t know this, it’s because you’ve never met me or talked to me for more than five minutes.

I keep reading that the desktop PC is dying: , even as tablet and smartphone sales are rising. One popular theory, then, is that people are doing on their tablets and phones what they used to do on their desktop PCs.

I hope this isn’t the case, because frankly, tablets and phones are crap when it comes to doing real work.

Don’t get me wrong: I’ve been using PDAs, and now a smartphone, for well over a decade. I also have an iPad that I use regularly. I also have a Swiss army knife, but while it’s a wonderful tool in a pinch, I’d rather have a real set of tools if they’re available.

The same goes for laptops, tablets, and phones: they’re portable, and that certainly counts for a lot. But size matters, too, and size is intrinsically non-portable.

I’m not terribly picky about keyboards: as long as it’s full-sized (i.e., the keys are roughly the size of my fingers), has arrow keys, function keys, a keypad, and reasonable action (in the piano sense of the word), I’m happy. I know people who swear by the industrial-style IBM keyboards, and while I don’t share their enthusiasm, I get it: not only are they nigh-indestructible, they also have decent springs and make a satisfying “click” noise when you type. When you’ve typed a key, you know it. It’s a small thing, but it makes a difference.

At home, I have a 20-inch monitor, and wouldn’t consider anything smaller. In fact, I wouldn’t mind adding a second one, the way I have at work, to be able to have more windows in front of me.

I see people who resize their browser or spreadsheet or whatever to the full size of the display, and I don’t get it. Half the screen seems ample, and would allow them to see what else is open at the same time. Even worse are people who have a full-screen browser with multiple tabs open. How can they see what’s going on in those other tabs, with the current one blocking their view?

I’m not terribly picky when it comes to mice, though I do prefer a mouse to a trackball or laptop-style trackpad (though I find myself tempted by Apple’s super-sized trackpad). It’s more a matter of dexterity and fine control than anything else. I’m not as good zeroing in on a small button with a trackpad that lies between my thumbs as I am with a mouse that has its own area to the side.

All of these things are relatively minor: they don’t stop me from doing work, they just make it a little easier, a little more pleasant. But then, what makes a workspace pleasant isn’t so much the things it does, as the things it doesn’t do: the annoyances that aren’t there so they don’t get in the way. Not having to look down at my fingers to make sure they’re on the home row. Not clicking on the wrong button by mistake.

But the other thing, the thing that keeps getting me awed reactions about how fast I work, is keybindings. I’ve taken the time to either learn or customize my environment—both the windowing environment and common applications—to be able to do common operations from the keyboard, without having to move my hand all the way to the mouse. Again, I see people who raise their hand, move it over to the mouse, click on the window they want to switch to, then put their hand back on the keyboard. It’s like watching someone with a 1970s-era TV set get up off the couch, turn the station knob on the set, and come back to the couch. You’d want to say “Why don’t you just use the remote?” just as I want to yell “Why don’t you just alt-tab through to the window you want?”

(Also, in both Firefox and Chrome, did you know that you can set up a URL with a keyword, that’ll fill in whatever you type after the keyword? If I want to look up Star Wars at IMDb, I don’t type in eye em dee bee dot com into the browser’s URL bar, then click on the search box and type in the name. I just type “imdb Star Wars” into the URL bar, and the browser replaces that with “http://www.imdb.com/find?s=all&q=Star%20Wars”. Try it with images.google.com, Wikipedia, or Bible Gateway and see how convenient it is.)

Yes, these things only take a few seconds each. But a few seconds here, a few seconds there, and it all eventually adds up to significant time.

So when I hear it suggested that people are abandoning desktop machines for portable ones, what I hear is that people are switching from dedicated workspaces where you can get stuff done comfortably, to something fundamentally inferior.

In principle, there’s no reason why a portable device running, say, Android, couldn’t be as flexible and configurable as a Linux/FreeBSD/Solaris box running X11/KDE/GNOME/what have you. But in practice, they’re not. Whether it’s a matter of limiting the configurability to simplify development, or the fact that Android apps are sandboxed and can’t talk to each other, or something else, I don’t know. But the fact is that right now, I couldn’t bind “shake the phone up and down” to mean “create a new appointment in the calendar” if I wanted to.

And then comes along something like Ubuntu’s Unity, which aims to be a common UI for both desktop and portable devices. Which is to say, it aims to strip down the desktop to allow only those things that are convenient on tablets.

That’s taking away configurability; it’s simplification that makes it harder to get work done, and that annoys me.

UNIX was not designed to stop you from doing stupid things, because that would also stop you from doing clever things.
—Doug Gwyn

In Defense of Gussie Fink-Nottle

For those who may have forgotten, Gussie Fink-Nottle is a character in the Jeeves stories by P.G. Wodehouse. He is the series’s stereotypical nerd: socially inept, a teetotaler, and physically unimpressive. His most memorable trait, however, is his fascination with newts.

Clearly Wodehouse tried to find the least interesting subject he could think of, to allow his character to easily bore all the other characters to tears by going on at length about his pathetic pet subject.

I don’t remember his early life ever being discussed in any detail, but I imagine that, as a weakling, he was never any good at sports and thus never developed an interest in them. Unable to hold his liquor, he never got into the habit of meeting with the chaps over drinks and experiencing the sorts of things that only seem to happen during alcohol-fueled debaucheries. His social ineptitude meant that he never became a lothario. Eventually, he was forced to become interested in that most uninteresting of subjects, newts.

But I would look at it from another angle: there is an infinite number of subjects in the world. What is it about newts that’s so interesting that Gussie would choose to devote his life to them?

Stephen Jay Gould, as I recall, did his graduate research on snails. Carl Sagan was interested in points of light in the sky. Bertrand Russell worked on breaking down existing mathematical proofs into longer chains of simpler steps. In each case, they found something interesting in what might appear to be an unintersting subject.

Likewise, I sometimes wonder what makes people want to go into professions like accounting or proctology. It can’t just be the money, can it? Presumably there’s something there that I don’t see, some hidden bit of beauty that I haven’t seen or had explained to me.

I don’t want to think, “Wow, what a loser, for being interested in something as boring as newts.” Rather, I want to ask, “What is it about newts that’s so interesting?”

XKCD: Beauty

Both Parties Lie, Right?

So I made some comment about the Republican convention being based on a lie or something, and my interlocutor made a comment about how, well, both parties lie. Well, sure. But the Republicans are worse than the Democrats. And she said no, they both lie about the same.

And thus, me being the type of person I am (and that type is “anal retentive”. Or “obsessive-compulsive”. Or something along those lines. Supply your own wild-ass psychoanalysis in the comments), I went looking for data.

FactCheck.org is good, but they have an annoying tendency to provide nuance and context, rather than just boiling a statement down to a single icon.

WaPo’s Fact Checker is better, with its Pinocchio-based truth scale, but when I checked, there wan’t a lot of easily-accessible data.

Which brings us to PolitiFact. They have both a cutesy-icon-based measurement, but also a lot of data. Although they allegedly have an API, I wasn’t able to find details on how to use it, so I just scraped a bunch of their web pages and grepped out the information I wanted.

And since you’ve been patiently waiting for, like, four or five paragraphs for a chart or something, here it is:

Comparison of Politifact rulings for major US parties. Each bar represents the percentage of statements by that party that fall into a given category.

The data I used is here. There are separate sheets for Democrats and Republicans, with a count of how many statements each person or organization has made in each truth bucket (BTW, in case the phrase “truth bucket” becomes useful during this or any other campaign season, remember that you read it here first).

The first thing that jumps out is that, well, Republicans have fewer “True” and “Mostly True” statements than Democrats, and more “Mostly False”, “False”, and “Pants on Fire”. Which is kind of what I figured anyway, but it’s nice to see my opinion confirmed in chart form.

Anyway, often a person’s or organization’s page has a field that gives their political affiliation, e.g., Barack Obama is listed as “Democrat from Illinois”, while Concerned Taxpayers of America is listed as “Republican from Oregon”. I took the people and organizations listed as “Democrat from” or “Republican from” wherever, and discarded the rest.

Then it was just a matter of spreadsheetizing the data, and totting up the total number of statements by each party, counting up how many statements fall into each category, and, of course, endless fiddling about with fonts and column layouts.

The result is as objective as I could make it. You could argue that PolitiFact is biased for or against the party of your choice, but if there’s bias in the above, I don’t want to come from me.

“Motion Capture” for Text-to-Speech?

I had a random thought over the weekend, and while I suspect it’s not original, I couldn’t find anyone working on it.

One big reason why text-to-speech (TTS) synthesis sucks so badly is that the result sounds flat. Yes, the synthesizer can try to infer cadence and tone from things like commas, paragraph breaks, exclamation points, and question marks, but the result still falls far short of what a human reader sounds like. In the end, the problem seems to be Turing-hard, since you need to understand the meaning of a piece of text in order to read it properly.

So would it be possible to record a human reading a piece of text, and extract just the intonation, cadence, and pacing of the text? Hollywood already uses motion capture, in which cameras record the movements of a human being, and makes a CGI creature move the same way (e.g., Gollum in The Lord of the Rings or Shrek). In fact, you can combine multiple people’s movements into one synthesized creature, say by using one person’s stride, another’s hand movements, and a third person’s facial expressions.

So why not apply the same principle to synthesized speech? For instance, you could have someone read a paragraph of text. We already have voice-recognition software, so it should be possible to analyze that recording and match it to individual words and phonemes in the text. That gives you timing, for things like the length of a comma or reading speed. The recording can then be analyzed for things like whether a given word was spoken more loudly, or at a higher pitch, than other surrounding words, and by how much. This can be converted to speech markup.

This means that you could synthesize Stephen Fry reading a book in Patrick Stewart’s voice.

Perhaps more to the point, if you poke around Project Gutenberg, you’ll see that there are two types of audio books: ones generated via TTS, and ones read by people. The recordings of humans are, of course, better, but they require that an actual person sit down and read the whole book from start to finish, which is time-consuming.

If it were possible to apply a human’s reading style to the synthesis of a known piece of text, then it would be possible for multiple people to share the job of recording an audio book. Allow volunteers to read one or two pages at a time, and synthesize a recording of those pages using the volunteer’s intonation and cadence, but using a standard voice.

I imagine that there would still be lots of problems with this — for instance, it might feel somewhat jarring when the book switches from one person’s reading style to another’s — but it should still be an improvement over what we have now. And there are probably lots of other problems that I can’t imagine.

But hey, it would still be an improvements. Is anyone out there working on this?

Disk Hack

One of the things I enjoy about Unix system administration is the McGyver aspect of it: when something goes pear-shaped, and your preferred tools aren’t available because they’re on the disk that just died, or on the other side of the pile of smoking ashes that used to be a router, you have to figure out how to recover with what you’ve got left. It’s a bit like that scene in Apollo 13 when they realize that the space capsule has a round hole for the air filter, but only square filters, and the engineer dumps all the equipment the astronauts have available onto the table, and says “We’ve got to find a way to make this fit into the hole for this, using nothing but that“.

So anyway, my mom’s Mac recently died. And, naturally, there are no available backups. But I said I’d do what I could, and took the machine home.

I’m glad we wrote off the old machine as a total loss, since it was (the tense should give you an idea of what’s coming) an iMac, one of those compact everyting-in-the-monitor models that tries oh-so-hard to fit everything into as small a space as possible. Of course, this compactness means that there’s no room to do anything: the disk is behind the LCD display, and wedged in a tight slot between the graphics card and the DVD drive. And the whole thing is wrapped in — I kid you not — foil, most likely to help control airflow. So basically I wound up ripping things out with little or no grace or elegance. If it wasn’t totaled then, it certainly is now.

At any rate, that left me with a disk that, thankfully, turned out to be unharmed. The next question was how to hook it up. I was pretty sure it had an HFS or HFS+ filesystem, which meant that the obvious thing to do would be to put it in a Mac to read. But I don’t have a Mac that I could put a second internal drive in. I toyed briefly with the idea of finding an enclosure and whatever conversion hardware would be necessary to turn an internal SATA drive into an external USB drive, but figured that was too hard for a one-shot. Then I found that my Linux box has hfs and hfsplus filesystem kernel modules, so hey.

(Of course, I don’t know how stable the Linux HFS driver is, so I figured it’d be best to write-protect the disk. At which point I discovered that this model only has one hardware jumper slot, and it doesn’t write-protect the disk. Fuck you very much, Maxtor/Apple.)

The Linux HFS driver turned out to be good enough for reading, and I could mount the disk and read files, so yay. The next question was how to get the files from there to a laptop that I could bring over to my parents’. Ths is complicated by the fact that on HFS, a file isn’t just a stream of bytes, the way it is in Unix; it has two “forks”: the data fork contains the actual data of the file (e.g., a JPEG image), and the resource fork contains metadata about the file, such as its icon, the application that should open the file by default, and so on. I didn’t want to lose that if I could help it.

The way the Linux HFS driver deals with resource forks is to create virtual or transient or whatever you want to call them files: if you open myfile, you’ll get the data fork, which looks just like any file. But if it has a resource fork, you can also open myfile/rsrc and read the contents of that. This meant that in the worst case, I 1) copy over the data forks to a directory on the Mac, then 2) find which files have resource forks (something like

find /mnt -type f |
sh -c 'while read filename; do
    if [ -s "$filename/rsrc" ]; then
        echo "$filename";
    fi;
done'

and 3) somehow re-graft the resource forks onto the files on the Mac end. But that seemed like a lot of work.

Apple software is often distributed on .dmg (disk image) files, which are mounted as virtual disks. I figured that’d be the obvious way to package up the contents of the disk. So I dded the raw disk device (/dev/sdb rather than /dev/sdb2 which was the mounted partition, in order to get the entire disk, including partition map and such), but when I tried to mount that, it didn’t work, so presumably there’s more to a .dmg file than just the raw disk data. I tried a couple of variations on that theme, but without success.

(In passing, I also noticed that rsync supports “extended attributes” on both my Mac and my Linux box, so I tried using that to copy files (with resource forks) over, only to find that the two implementations use different options to say “turn on extended attributes”, so the client couldn’t start the remote server correctly.)

Eventually, I realized that dd could be used not just to read a disk image, but to write one. Yes, I said above that reading from the disk and writing to a file didn’t produce a usable disk image. But I also said that .dmg files are mounted like disks, and that implies that there has to be a device to mount.

So on the Mac, I created a disk image file with hdiutil create, then opened it with the Disk Utility. Forcing “Verify disk” made the Disk Utility mount the image on /dev/disk2s9, just before telling me that there was no usable filesystem on the disk image. That was fine; all I wanted was for it to create a /dev/disk* device that I could write to. Then I was able to

ssh linuxbox 'dd if=/dev/sdb bs=2M' | dd bs=2048k of=/dev/disk2

to transfer the raw contents of the disk to the “disk data” portion of the disk image.

To my slight surprise, this actually worked. Yes, I had to repair the disk image, but from the log messages, that appears to be because some of the superblock copies were missing (the disk is 120Gb, but I only created a 32Gb image).

The final problem should be that of getting the disk image from my locked-down(-ish) laptop to my mom’s new vanilla Mac, but I don’t think I’ll bother. It’ll be a lot easier, and better in the long run, to put the old disk image onto an external drive that can then double as a backup disk, so I don’t have to do this again.

Because while it can be fun to solve a puzzle and figure out how to fix something with suboptimal tools, there’s also wisdom in avoiding getting into such situations in the first place.

“Avowed”

The New York Times ran a piece about the David Mabus affair (tl;dr version: he’s a mentally-ill troll who’d been sending death threats to people for years, and was finally arrested after enough people complained to the police).

It begins:

Over the years, someone writing as David Mabus made himself known to scientists and avowed atheists across North America in thousands of threatening e-mails and violently profane messages on Twitter.

The phrase “avowed atheists” annoyed me, because I see it a lot. I even twatted about it:

The phrase “avowed atheist” still annoys me, though. When’s the last time someone was an “avowed Baptist”?

Then I realized that with an entire browserful of Internet at my disposal, I could answer that question.
Read More

Meta-Social Code

I had an idea the other day, and I’m not sure why no one’s implemented. I suspect that either a) someone has and I don’t know about it, or b) there’s some fundamentally-unsolvable problem. If so, please point this out in the comments.

At any rate, the idea is this: as a site owner, I want to make it easy for people to link to my site. I want a wall of social-site buttons on every page, with every site from AOL to Zynga.

But as a reader, I only have a few sites that I use to link to places. I don’t want to wade through row after row of useless icons just to find the one that I want to use to share the URL.

So it seems the obvious thing to do would be for some entrepreneur (not me) to offer “social site button bar as a service”. The site owner adds some markup to the page to say “this is something that can be recommended/liked/shared”, and include a JavaScript script that takes care of the magic behind the scenes. Something like:

<html>
<head>
http://social.com/siteid12345/api.js
</head>
<body>
<h1>This is my page</h1>
<p>Hello world</p>
<social:button-bar/>
</body>
</html>

The script can take care of adding additional <script>s to load additional APIs from whichever social sites are being loaded, and add a DOMContentLoaded listener that’ll replace <social:button-bar> with a series of other elements, like <g:plusone> and <fb:like>.

The end-user, meanwhile, can visit a configuration page and decide which social sites will appear in the button bar. This can be saved in a cookie.

I’ve consed up a quick and dirty prototype, and was surprised that it worked. I haven’t tested it extensively, though.

The obvious objection (aside from “but how does one make money off of this thing?” But they said that about Kozmo.com too. So there) is that this seems like an engraved invitation to cross-site scripting (CSS) holes. And privacy leaking, and who knows what all else.

A related question, which I haven’t answered, is who can see the cookie? If the JavaScript code comes from social.com, then social.com needs to be able to see the user configuration cookie to know which buttons’ code to serve up. But if the reader is looking at content.com, there’s no good way to get a social.com cookie and pass it along. It might be possible to set a content.com cookie, but of course that won’t help when the user surfs over to othersite.org, where we want the end-user to see the same button bar.

I confess that I’m not entirely clear on the policies that govern which sites/scripts can see what data. So it’s quite possible that I’m missing something glaringly obvious.

Fun With Barcodes

If you have an Android phone, odds are that you have the Barcode Scanner app. And if you’ve looked in the settings, you may have noticed one called “Custom Search URL”.

This is, as the name says, a URL you can fill in. Once you do, you’ll get a “Custom search” button at the bottom of the screen when you scan a barcode. A “%s” in the URL will be replaced by the numeric UPC value, and “%f” with its format (which is displayed next to the code when you scan one).

It seems to me that this can be used as a poor man’s plugin API. You can use http://www.mydomain.org/barcode?f=%f&s=%s, and make barcode be a CGI/PHP/whatever script that looks at the format and code and decides what to do.

For instance, $EMPLOYER has barcoded asset tags on all inventory items. So today I was able to scan a machine’s code and be redirected to the inventory web page for that machine.

Likewise, if it’s an EAN-13 code that begins with 978 or 979, then presumably it’s an ISBN or ISMN, and you can look it up at Amazon, your library, or wherever.

As far as I know, you can’t recognize that a UPC corresponds to a CD or DVD, without having a table of every CD/DVD publisher, but there’s nothing that says your script has to only do redirection; you can present a list of links to the user. So anyway, for CDs, you can construct MusicBrainz or Discogs lookup URLs. Or perhaps you can parse the code, get the manufacturer, and based on the user’s choice, remember what sort of item that manufacturer corresponds to. Over time you can build up a “good enough” database of the things you scan most often.

I wouldn’t mind having a properly organized library of books, CDs, etc. Which is kind of the point of looking this data up on the net in the first place. But while a phone may make a serviceable barcode scanner, it’s no good for lengthy data input. So really, what I’d like would be for the script to remember what I’ve scanned, along with a quick and dirty readable reference (e.g., “ISBN such-and-such: The Wee Free Men by Terry Pratchett) and stash that someplace so that I can later go back and import the data into Koha or whatever I’m using.

Of course, since it’s a web page, I’m guessing you have access to the full range of goodies that people put in browsers these days. I’m thinking of geographical location, in particular. So the script could in principle behave differently based on where you’re located at the moment (e.g., at home or at work).

There are lots of possibilities. Must. Explore.

A Couple of Shell Quickies

Since I got asked several sh-related questions, I might as well get a post out of them.

One person asks:

I’m writing a portable shell script to download a file from the web, and then compare it to a locally-stored version of the same file, using diff.

My first version of the script used mktemp to download the web-file to temporary file, run the diff command, and then delete the temporary file afterwards. e.g.

TEMPFILE=$(mktemp)
wget -q $ONLINEFILEURL -O $TEMPFILE
diff $TEMPFILE $LOCALFILE
rm $TEMPFILE

However I later discovered that the BSD version of mktemp has an incompatible syntax to the GNU version of mktemp. So then I got rid of the usage of temporary files completely, by using input-redirection, e.g.

diff <(wget -q $ONLINEFILEURL -O -) $LOCALFILE

However while this works fine under bash and ksh, it fails under ash and sh with

Syntax error: "(" unexpected

to which I replied:

The first obvious problem here is that “(wget -q $ONLINEFILEURL -O -)” isn’t a filename, it’s a subprocess. So the shell sees “<” and expects a filename, but finds “(” instead.

It looks as though the way to get diff to read from stdin is the standard way: specify “-” as the filename, and give it input on stdin. Since you’re feeding it the output from a process, you want to use a pipe:

wget -q $ONLINEFILEURL -O - | diff - $LOCALFILE

I also suggested that he could try to figure out which version of mkfile he was using:

# Wrapper function for GNU mktemp
gnu_mktemp() {
	mktemp /tmp/tmpfile.XXXXXX "$@"
}

# Wrapper function for BSD mktemp
bsd_mktemp() {
	mktemp -t /tmp/tmpfile.XXXXXX "$@"
}

# Try to figure out which wrapper to use
if mktemp -V | grep version >/dev/null 2>&1; then
	MKTEMP=gnu_mktemp
else
	MKTEMP=bsd_mktemp
fi

mytmpfile=`$MKTEMP`

And, of course, if race conditions and security aren’t a big concern, there’s always

mytmpfile=/tmp/myprogramname.$$

Another person wanted to write a bash script that would do one thing when run by him or root, and another thing if run by anyone else (basically, die with an error message about insufficient privileges and/or grooviness).

He asked whether the following two expressions were equivalent:

  • if [[ ( `whoami` != "root" ) || ( `whoami` != "coolguy" ) ]]
  • if [[ ! ( `whoami` = "root" ) || ( `whoami` = "coolguy" ) ]]

They’re not, but maybe not for obvious reasons, because propositional logic is a harsh mistress.

In the first expression,

if [[ ( `whoami` != "root" ) || ( `whoami` != "coolguy" ) ]]

let’s say that the user is joeblow. In this case, “`whoami` != "root"” is true, and so the shell can short-circuit the rest of the “||“, because the entire expression is true.

If the user is root, then the first part, “( `whoami` != "root" )” is false. However, the second part, “( `whoami` != "coolguy" )” is true (because rootcoolguy), and so the entire expression is “false || true”, which is true.

The second expression,

if [[ ! ( `whoami` = "root" ) || ( `whoami` = "coolguy" ) ]]

is closer to what he wanted, but doesn’t work because of operator precedence: “!” binds more tightly than “||“, so the expression is equivalen tto “(whoami ≠ root) || (whoami = coolguy)”.

In this case, if the user is joeblow, the first clause, “whoami ≠ root“, is true, and so the entire expression is true.

Worse yet, if the user is root, then neither the first nor second clause is true, so the entire clause is false.

What he really wanted was something like:

if [[ ( `whoami` = "root" ) || ( `whoami` = "coolguy" ) ]]; then
	# Do nothing
	:
else
	# Do something
	echo "Go away"
	exit 1
fi

Except, of course, that since the if-clause is empty, it can be cut out entirely. Then all we need to do is to negate the condition and only keep the code in the else-clause:

if [[ ! ((`whoami` = "root" ) || ( `whoami` = "coolguy" )) ]]

Note the extra pair of parentheses, to make sure that the “!” applies to the whole thing.

(Update, May 18: Fixed HTML entities.)

GDMF Exchange!

Yet more reason to hate MS Exchange. Here are the relevant headers and MIME lines from a meeting notification I got recently:

Header:

Subject: XXX Staff Meeting
Content-Type: multipart/alternative;
	boundary="_000_A32122FBAE23C145ABBEFDEA852187CE01E77A1505B7BLADEBLA03V_"
MIME-Version: 1.0

Body:

--_000_A32122FBAE23C145ABBEFDEA852187CE01E77A1505B7BLADEBLA03V_
Content-Type: text/plain; charset="utf-8"
Content-Transfer-Encoding: base64

…
--_000_A32122FBAE23C145ABBEFDEA852187CE01E77A1505B7BLADEBLA03V_
Content-Type: text/html; charset="utf-8"
Content-Transfer-Encoding: base64

…
--_000_A32122FBAE23C145ABBEFDEA852187CE01E77A1505B7BLADEBLA03V_
Content-Type: text/calendar; charset="utf-8"; method=REQUEST
Content-Transfer-Encoding: base64

…

--_000_A32122FBAE23C145ABBEFDEA852187CE01E77A1505B7BLADEBLA03V_--

At first glance, all might look normal: there’s a calendar entry with a note attached.

So first we have the plain text version of the note, followed by the HTML version of the note, followed by the vCalendar file describing the meeting itself.

But a closer look at the header shows that the message as a whole has Content-Type: multipart/alternative.

RFC 1521 says:

The multipart/alternative type is syntactically identical to multipart/mixed, but the semantics are different. In particular, each of the parts is an “alternative” version of the same information.

Systems should recognize that the content of the various parts are interchangeable. Systems should choose the “best” type based on the local environment and preferences, in some cases even through user interaction.

In other words, any standards-compliant mail reader should see those three MIME chunks as three different versions of the same information. So if it decides to (or you tell it to) display the HTML version of the note, it shouldn’t display the calendar file. And if it displays the calendar entry, it shouldn’t show the attached note.

Clearly somebody at Microsoft needs to be slapped. Hard.

(And in case you’re wondering, the proper way to do what they’re trying to do would be for the message as a whole to be multipart/mixed with a multipart/alternative chunk for the note, and a text/calendar chunk for the calendar entry. The note chunk would be further subdivided into a text/plain chunk and a text/html chunk.)

I think that when people are first told that Exchange is both a mail server and a calendar server, they think it’s kind of like a goose — something that can competently walk, swim, and fly, even though it may not excel at any of those — but in reality, it’s more like a crocoduck: massive fail at every level, no matter how you look at it.