Xfce

Subdomains
 

Git Weirdness

  • March 17, 2009
  • Brian Tarricone

So I have a git repo on my machine at home, that’s cloned from a repo on git.xfce.org. I was doing some work in it the other day — in a private branch, not published to git.xfce.org — and I wanted to continue working on the private branch from another machine. But… it won’t work. Let’s say ‘machine1′ has the repo with the private branch, and ‘machine2′ is where I want to work today.

So, on machine2, I cloned from the master repo on git.xfce.org:

[brian@machine2 src $] git clone git@git.xfce.org:kelnos/airconfig
[... stuff happens...]
[brian@machine2 src $] cd airconfig
[brian@machine2 airconfig $] git branch -a
* master
  origin/master
  origin/pre-hal

Ok, cool, that’s what I expect. So I ssh over to machine1 (the one I eventually want to pull from), and I check out my list of branches there:

[brian@machine1 airconfig $] git branch -a
  advanced-ip-settings
  master
* nm-frontend
  notification-rework
  reconnect
  origin/master
  origin/pre-hal

Ok, cool. the ‘nm-frontend’ branch is the one I want to pull to machine2. So on machine2, I do this:

[brian@machine2 airconfig $] git remote add machine1 machine1:src/airconfig
[brian@machine2 airconfig $] git pull machine1 nm-frontend
fatal: Couldn't find remote ref nm-frontend
fatal: The remote end hung up unexpectedly

Uh… what? Do I have the wrong syntax? Ok, let me just try to pull everything from the remote:

[brian@machine2 airconfig $] git pull machine1
remote: Counting objects: 1085, done.
remote: Compressing objects: 100% (301/301), done.
remote: Total 1085 (delta 774), reused 1085 (delta 774)
Receiving objects: 100% (1085/1085), 323.43 KiB | 14 KiB/s, done.
Resolving deltas: 100% (774/774), done.
From machine1:src/airconfig
 * [new branch]      advanced-ip-settings -> machine1/advanced-ip-settings
 * [new branch]      master     -> machine1/master
 * [new branch]      pre-hal    -> machine1/pre-hal

And then at the bottom it prints out a message about not knowing which local branches to merge stuff into. That’s fine, no big deal. But… how come it pulled 3 of my local branches on machine1, but left off 2 of them (‘notification-rework’ and ‘nm-frontend’). No combination of src:dest refspecs seem to do the trick. Pulling one of the 3 branches it seems to like using the syntax I used above seems to work fine, but it can’t see the one I want. What am I doing wrong…?

Git Weirdness

  • March 17, 2009
  • Brian Tarricone

So I have a git repo on my machine at home, that’s cloned from a repo on git.xfce.org. I was doing some work in it the other day – in a private branch, not published to git.xfce.org – and I wanted to continue working on the private branch from another machine. But… it won’t work. Let’s say ‘machine1’ has the repo with the private branch, and ‘machine2’ is where I want to work today.

So, on machine2, I cloned from the master repo on git.xfce.org:

[brian@machine2 src $] git clone git@git.xfce.org:kelnos/airconfig
[... stuff happens...]
[brian@machine2 src $] cd airconfig
[brian@machine2 airconfig $] git branch -a
* master
  origin/master
  origin/pre-hal

Ok, cool, that’s what I expect. So I ssh over to machine1 (the one I eventually want to pull from), and I check out my list of branches there:

[brian@machine1 airconfig $] git branch -a
  advanced-ip-settings
  master
* nm-frontend
  notification-rework
  reconnect
  origin/master
  origin/pre-hal

Ok, cool. the ‘nm-frontend’ branch is the one I want to pull to machine2. So on machine2, I do this:

[brian@machine2 airconfig $] git remote add machine1 machine1:src/airconfig
[brian@machine2 airconfig $] git pull machine1 nm-frontend
fatal: Couldn't find remote ref nm-frontend
fatal: The remote end hung up unexpectedly

Uh… what? Do I have the wrong syntax? Ok, let me just try to pull everything from the remote:

[brian@machine2 airconfig $] git pull machine1
remote: Counting objects: 1085, done.
remote: Compressing objects: 100% (301/301), done.
remote: Total 1085 (delta 774), reused 1085 (delta 774)
Receiving objects: 100% (1085/1085), 323.43 KiB | 14 KiB/s, done.
Resolving deltas: 100% (774/774), done.
From machine1:src/airconfig
 * [new branch]      advanced-ip-settings -> machine1/advanced-ip-settings
 * [new branch]      master     -> machine1/master
 * [new branch]      pre-hal    -> machine1/pre-hal

And then at the bottom it prints out a message about not knowing which local branches to merge stuff into. That’s fine, no big deal. But… how come it pulled 3 of my local branches on machine1, but left off 2 of them (‘notification-rework’ and ‘nm-frontend’). No combination of src:dest refspecs seem to do the trick. Pulling one of the 3 branches it seems to like using the syntax I used above seems to work fine, but it can’t see the one I want. What am I doing wrong…?

Ruby for Web Development

  • February 12, 2009
  • Brian Tarricone

I recently started a new web dev project, and decided to use it to better learn Ruby. However, I don’t want to use Rails. I’d like to keep it simple. I also prefer to know a lot about the inner workings of a particular technology before I go and use a large framework that hides a bunch of details from me.

However, I want to use ActiveRecord. ORM seems to be all the rage these days, promising to abstract the annoying details of database access behind OO natural for your chosen language. It also helps avoid common errors and pitfalls with regard to constructing SQL queries and the like.

So, ActiveRecord. I install it on my laptop with “emerge ruby-activerecord”, and there I go. One “require ‘activerecord’” in my script later, and, awesome, it starts working.

Then I start working on my web host (DreamHost, if you’re wondering). It can’t find ActiveRecord. But it’s obviously installed, because I know DH supports Rails out of the box, and I don’t think you can have an install of Rails without ActiveRecord. So I poke, and then realise it might be installed as a Ruby “gem.” Ok, so I put a “require ‘rubygems’” above my activerecord require. Nice, now it works. Then I think, well, what if I put this somewhere that doesn’t require rubygems? Not hard to work around automatically:

begin
  require 'activerecord'
rescue LoadError
  require 'rubygems'
  require 'activerecord'
end

Nice, ok, that works. It’s probably a foolish micro-optimisation, but whatever.

Then I notice… ugh, this is super slow. Even on the web host, it can take a good two seconds for the “require ‘activerecord’” statement to execute. Yeah, I know, ruby is kinda slow. But 2 extra seconds each time someone hits basically any page of the website? Ugh.

So…. FastCGI. I know DH supports it, so I head over to the control panel and enable it for the domain I’m working on, and start googling around to figure out how to use FastCGI in a ruby script.

Unfortunately, there aren’t too many resources on this. Fortunately I found a couple sample dispatch scripts, one of which I ended up basing mine off of.

But then there was a problem. Inside my app, I use ruby’s CGI class to access CGI form variables and other stuff. Since the FastCGI stuff overrides and partially replaces ruby’s internal CGI class, there’s a problem. Doing “cgi = CGI.new” inside a ruby script that’s being served through FastCGI throws a weird exception. But I wanted to try to retain compatibility for non-FastCGI mode. And I couldn’t figure out how to get the ‘cgi’ variable from the ruby dispatch script into my app’s script, since I was using ‘eval’ to run my script. The dispatch script I saw used some weird Binding voodoo. Up at the top level we have:

def getBinding(cgi, env)
  return binding
end

I had no idea what that was doing, so I looked it up. Apparently the built-in “binding” function returns a Binding object that describes the current execution context, including local variables and function/method arguments. Ok, that seems really powerful and cool. So I look down to the sample dispatch script’s eval statement, and I see:

eval File.open(script).read, getBinding(cgi, cgi.env_table)

Ok, so it appears it tries to eval the script while providing an execution context that contains just ‘cgi’ and one of its member vars. I only sorta understand this. So I ditched the “cgi = CGI.new” line in my app’s script. But I got a NameError when just trying to use ‘cgi’. Huh? What’s going on? So I get rid of the getBinding() call entirely, and just let it use the current execution context, and suddenly everything works right. Weird.

Well, sorta. Now, remember, I want to preserve compatibility with running as a normal CGI. So the normal CGI needs to create its own ‘cgi’ object, but the FastCGI one should just use the one from the dispatch script. So I came up with this:

begin
  if !cgi.nil?
    mycgi = cgi
  end
rescue NameError
  require 'cgi'
  mycgi = CGI.new
end

Ok, that seemed to work ok. After that block, ‘mycgi’ should be usable as a CGI/FCGI::CGI object regardless of which mode it’s running under.

So I play around a bit more, and suddenly notice that my POST requests have stopped working. I dig into it a bit, and realise that my POST requests are actually just fine. What’s happening is that, somehow, the FCGI::CGI object completely ignores $QUERY_STRING on a POST request, while ruby’s normal CGI object will take care of it and merge it with the POST data variables. You see, to make my URLs pretty, I have normal URLs rewritten such that the script sees “page=whatever” in the query string. So when I did a POST, the page= would get lost, and so the POST would end up fetching the root web page rather than the one that should be receiving the form variables. I’m not sure if this is “normal” behavior, or if the version of the fcgi ruby module on DreamHost has a bug. Regardless, we need a workaround. So I go back to my last code snippet, and hack something together:

begin
  if !cgi.nil?
    if cgi.env_table['REQUEST_METHOD'] == 'POST'
      CGI.parse(cgi.env_table['QUERY_STRING']).each do |k,v|
        cgi.params[k] = v
      end
    end
    mycgi = cgi
  end
rescue NameError
  require 'cgi'
  mycgi = CGI.new
end

Ick. But at least it works.

So far, I’m liking ruby quite a lot. It’s a beautiful language, and seems well-suited for this kind of work, especially since I want to get something that works up and running relatively quickly.

We’ll see, however, how many more gotchas I run into.

Ruby for Web Development

  • February 12, 2009
  • Brian Tarricone

I recently started a new web dev project, and decided to use it to better learn Ruby. However, I don’t want to use Rails. I’d like to keep it simple. I also prefer to know a lot about the inner workings of a particular technology before I go and use a large framework that hides a bunch of details from me.

However, I want to use ActiveRecord. ORM seems to be all the rage these days, promising to abstract the annoying details of database access behind OO natural for your chosen language. It also helps avoid common errors and pitfalls with regard to constructing SQL queries and the like.

So, ActiveRecord. I install it on my laptop with “emerge ruby-activerecord”, and there I go. One “require ‘activerecord’” in my script later, and, awesome, it starts working.

Then I start working on my web host (DreamHost, if you’re wondering). It can’t find ActiveRecord. But it’s obviously installed, because I know DH supports Rails out of the box, and I don’t think you can have an install of Rails without ActiveRecord. So I poke, and then realise it might be installed as a Ruby “gem.” Ok, so I put a “require ‘rubygems’” above my activerecord require. Nice, now it works. Then I think, well, what if I put this somewhere that doesn’t require rubygems? Not hard to work around automatically:

``begin
  require 'activerecord'
rescue LoadError
  require 'rubygems'
  require 'activerecord'
end``

Nice, ok, that works. It’s probably a foolish micro-optimisation, but whatever.

Then I notice… ugh, this is super slow. Even on the web host, it can take a good two seconds for the “require ‘activerecord’” statement to execute. Yeah, I know, ruby is kinda slow. But 2 extra seconds each time someone hits basically any page of the website? Ugh.

So…. FastCGI. I know DH supports it, so I head over to the control panel and enable it for the domain I’m working on, and start googling around to figure out how to use FastCGI in a ruby script.

Unfortunately, there aren’t too many resources on this. Fortunately I found a couple sample dispatch scripts, one of which I ended up basing mine off of.

But then there was a problem. Inside my app, I use ruby’s CGI class to access CGI form variables and other stuff. Since the FastCGI stuff overrides and partially replaces ruby’s internal CGI class, there’s a problem. Doing “cgi = CGI.new” inside a ruby script that’s being served through FastCGI throws a weird exception. But I wanted to try to retain compatibility for non-FastCGI mode. And I couldn’t figure out how to get the ‘cgi’ variable from the ruby dispatch script into my app’s script, since I was using ‘eval’ to run my script. The dispatch script I saw used some weird Binding voodoo. Up at the top level we have:

``def getBinding(cgi, env)
  return binding
end``

I had no idea what that was doing, so I looked it up. Apparently the built-in “binding” function returns a Binding object that describes the current execution context, including local variables and function/method arguments. Ok, that seems really powerful and cool. So I look down to the sample dispatch script’s eval statement, and I see:

``eval File.open(script).read, getBinding(cgi, cgi.env_table)``

Ok, so it appears it tries to eval the script while providing an execution context that contains just ‘cgi’ and one of its member vars. I only sorta understand this. So I ditched the “cgi = CGI.new” line in my app’s script. But I got a NameError when just trying to use ‘cgi’. Huh? What’s going on? So I get rid of the getBinding() call entirely, and just let it use the current execution context, and suddenly everything works right. Weird.

Well, sorta. Now, remember, I want to preserve compatibility with running as a normal CGI. So the normal CGI needs to create its own ‘cgi’ object, but the FastCGI one should just use the one from the dispatch script. So I came up with this:

``begin
  if !cgi.nil?
    mycgi = cgi
  end
rescue NameError
  require 'cgi'
  mycgi = CGI.new
end``

Ok, that seemed to work ok. After that block, ‘mycgi’ should be usable as a CGI/FCGI::CGI object regardless of which mode it’s running under.

So I play around a bit more, and suddenly notice that my POST requests have stopped working. I dig into it a bit, and realise that my POST requests are actually just fine. What’s happening is that, somehow, the FCGI::CGI object completely ignores $QUERY_STRING on a POST request, while ruby’s normal CGI object will take care of it and merge it with the POST data variables. You see, to make my URLs pretty, I have normal URLs rewritten such that the script sees “page=whatever” in the query string. So when I did a POST, the page= would get lost, and so the POST would end up fetching the root web page rather than the one that should be receiving the form variables. I’m not sure if this is “normal” behavior, or if the version of the fcgi ruby module on DreamHost has a bug. Regardless, we need a workaround. So I go back to my last code snippet, and hack something together:

``begin
  if !cgi.nil?
    if cgi.env_table['REQUEST_METHOD'] == 'POST'
      CGI.parse(cgi.env_table['QUERY_STRING']).each do |k,v|
        cgi.params[k] = v
      end
    end
    mycgi = cgi
  end
rescue NameError
  require 'cgi'
  mycgi = CGI.new
end``

Ick. But at least it works.

So far, I’m liking ruby quite a lot. It’s a beautiful language, and seems well-suited for this kind of work, especially since I want to get something that works up and running relatively quickly.

We’ll see, however, how many more gotchas I run into.

Xfce Commit Messages on IRC

  • October 30, 2008
  • Brian Tarricone

This is a little dumb, but kinda fun. A week or 2 ago I set up a CIA bot in #xfce-commits on Freenode. If you have nothing better to do with your life than watch Xfce commit messages scroll by, feel free to join and idle with the rest of us losers.

Xfconf – A New Configuration Storage System

  • October 6, 2008
  • Brian Tarricone

I suppose others have written in broad terms about Xfconf, Xfce 4.6’s new configuration storage/retrieval system, but I guess an in-depth explanation is overdue and is probably up to me.

First, some background.

Xfce has used a configuration system called MCS (Multi-Channel Settings) for some time now, since 4.0 was released near the end of 2003. It’s inflexible and very monolithic. Only a single application (xfce-mcs-manager) is allowed to actually modify settings; all other applications can only query values. That means that the GUI settings dialogs have to run in the xfce-mcs-manager process. The GUI dialogs are implemented in shared libraries that are linked into the xfce-mcs-manager process at runtime. To add more confusion as to its purpose, xfce-mcs-manager also acts as an XSETTINGS manager, automatically proxying the settings stored in a “special” channel.

I had a few loosely-defined goals when designing Xfconf.

  • Keep the familiar “channels” concept from MCS, but make the namespaces for settings storage inside channels hierarchical.

  • The configuration storage daemon should be able to run without a GUI environment, and the client library shouldn’t have GUI dependencies.

  • Get the XSETTINGS manager out of the configuration daemon.

  • Integrate “kiosk mode” functionality directly into the configuration storage mechanism.

  • Native support for arrays/structs in the configuration store.

  • Provide a client library that’s easy to use and exposes commonly-used functionality.

  • No client application is special: any app can read or write any setting.

There were probably others, but those seem to be the ones that stick out in my mind after the fact.

MCS used a protocol involving a special X window, X selections, and X window properties to pass settings around at runtime. Obviously this kind of thing isn’t suitable for a configuration system that can run without a GUI, or even on a non-X11 system. So, that was right out. Given momentum over the past couple years, D-Bus seemed to make the most sense as an IPC method. So, the D-Bus API for Xfconf was born. (Please note that I don’t consider this frozen until we release 4.6.0 final. I’ll do my best not to remove or change existing interfaces, though.)

The rest of the story might sound rather gconf-like, and I guess it probably is. There’s a settings daemon (xfconfd) and a client library (libxfconf). Apps use the client library to fetch settings from and store settings to xfconfd. The daemon stores the settings on disk in a format of its choosing and manages the D-Bus interface. D-Bus gives us a few nice things for free; for example, xfconfd starts via D-Bus activation, so there’s no need to include it in any startup scripts or have client applications specifically start it. D-Bus also ensures that two instances of xfconfd aren’t running, fighting over the config store (well, unless you start a separate session bus daemon).

As for settings themselves, you have a channel that holds an arbitrary number of hierarchical properties. Channel names are simple ASCII text strings, like “xfwm4” or “xfce4-desktop”. Property names look a bit like path names and are, as I said, hierarchical. You can use this to logically organise properties inside your application. Xfdesktop is a good example of this, prefixing menu-related preferences with “/desktop-menu/” and backdrop-related prefs with “/backdrop/”. Xfwm4 is a terrible example of this, with all preferences prefixed with “/general/” for no apparent reason.

Anyhow, we support a variety of different data types: basically all of those supported and marshalable by dbus-glib, plus special 16-bit signed and unsigned types (though those two are pretty hacky at the moment and I’d like to be able to do those in a better way). The client library, libxfconf, lets you set commonly-used data types directly, and also has a generic interface for setting the others.

One thing I really like about libxfconf is its incredibly flexible support for array properties. Any property can be set to an array of values rather than a single value. The values in the array need not even be of the same type. Libxfconf has native support for setting array types, and also can directly map C structs to and from array types, automatically.

A final bit of usefulness is in libxfconf’s bindings mechanism. Libxfconf can “bind” an Xfconf property to a GObject property in your application. If the GObject property changes, then libxfconf will automatically update the value in the Xfconf store. If the value in the Xfconf store changes, libxfconf will automatically update the GObject property. This can greatly simplify the Xfconf code in your application. In your settings dialog, you simply have a single line of code to – for example – connect a GtkCheckButton’s “toggled” property to a boolean Xfconf property. If the user toggles the checkbox, Xfconf gets updated automatically. If the setting gets changed outside the application somehow while the settings dialog is open, the dialog gets updated automatically too. You can also use this functionality on the other “end” of the equation, too: if you use GObjects in your application, and your settings map to GObject properties on those objects, you can bind the properties there, too, and not have to manually take action when the user sets a setting in the settings dialog. Unfortunately, libxfconf only supports setting scalar properties now (not arrays), except for the special case of the GdkColor struct. Hopefully this will change in a future release.

We also include an “xfconf-query” application in the xfconf package, written mostly by Stephan Arts, which is a simple command-line Xfconf client. As you might guess, you can use it to query the values of Xfconf properties from the command-line, or from scripts. However, despite the “query” part of its name, it can modify Xfconf properties as well.

In Xfce 4.4 and below, we had the “XfceKiosk” system, which would allow you to lock down a desktop install so certain settings can and can’t be changed by particular users. It worked decently well, but was sometimes confusing to configure, and the application had to do special things to support it. Xfconf integrates a “locking” system whereby the system administrator can install a normally-formatted Xfconf configuration file with directives that instruct xfconfd to consider some properties unmodifiable by the user (and allows the sysadmin to set defaults too). This takes the burden away from applications to support a particular locking framework, as it’s natively built into the configuration system. (Unfortunately, as of this writing, the locking system isn’t working properly. It’ll definitely be finished by 4.6.0 final.)

So, I guess that’s it. If you’d like to get started with Xfconf, a good place to look would be the API documentation (please note that the API will not be frozen until 4.6.0 final). Otherwise, feel free to ask questions on the xfce4-dev mailing list.

Xfce Mailwach Plugin 1.1.0 Released

  • September 15, 2008
  • Brian Tarricone

After a good two and a half years of being lazy, I’ve finally found some time to work on the Mailwatch plugin, and I have a new release ready too!

There’s lots of chewy goodness in this release. Here are some useful links:

As always, please report bugs over at the Xfce bug tracker.

Enjoy!

Signals

  • September 2, 2008
  • Brian Tarricone

I meant to write about this a while ago, but I forgot, and it just popped into my head for some reason.

If you’re ever using POSIX signals as a means of primitive IPC, and SIGUSR1 and SIGUSR2 aren’t enough for you, never, ever, EVER make use of SIGRTMIN and/or SIGRTMIN plus some offset. Always use SIGRTMAX and SIGRTMAX minus some offset.

Why?

(Disclaimer: this might only be a problem on Linux, but if you want your app to be portable, blah blah blah…) Depending on what C library you’re using, and what pthreads implementation you’re using, the actual numerical value of SIGRTMIN may not be the same in different applications, depending on – get this – whether or not the app links with libpthread. In my case, the pthread impl makes use of the first 3 SIGRT slots, and so when you use the SIGRTMIN macro, you actually call __libc_current_sigrtmin(), and you get a number that’s 3 higher than what you get when you use SIGRTMIN in an app that doesn’t link against libpthread.

Fortunately, SIGRTMAX (which actually expands to a call to __libc_current_sigrtmax()) seems to be a bit more stable. That is, even if SIGRTMIN gets shifted up 3 slots, SIGRTMAX is still the same.

So, the moral of the story is: I never want to see the SIGRTMIN macro ever appear in your code, unless you really know what you’re doing. Instead, use things like SIGRTMAX, SIGRTMAX-4, etc. It may just save you 4 hours of debugging.

Git Snapshot Versioning?

  • August 23, 2008
  • Brian Tarricone

With our SVN repository, we version SVN snapshots using the SVN revision number – we tack “svn-r$REVISION” on the end of the normal version number. This works well, and it’s easy to tell if a given snapshot is newer or older than another one.

Git doesn’t have revision numbers. Commits are identified by SHA1 checksums. Since these are “random,” there’s no way to tell chronological order. How are other people doing git snapshot versioning? The best I’ve come up with is to parse git-log output to get the date and time of the last commit, and then do something like X.Y.Zgit-YYYYMMDD.HHMMSS… which is rather long and ugly. I guess it would be ok to use a 2-digit year here, though. And maybe drop the seconds bit, but I think it’s decently possible to have more than one commit in the same minute. But still… long and ugly.

Any other ideas? My requirements are simple: easy to tell based on just the version string if a snapshot is older or newer than another, must be able to automatically generate this tag, and must be able to identify the exact HEAD that the snapshot was made from.

More Firefox 3 SSL Junk

  • August 6, 2008
  • Brian Tarricone

Lately I’ve noticed a flood of Firefox 3-related posts regarding the new SSL error handling on Planet GNOME. It’s a little funny, as I was writing about this myself a little under two months ago.

Chris Blizzard posts in favor of the new arrangement, and points to an interesting post by Johnathan Nightingale explaining Mozilla’s position. Yes, agreed, Jonathan’s post is a good read, but the salient point is that the new UI is just awful from an average non-technical user’s perspective.

The extra clicks and somewhat abnormal flow (e.g. the need to click a button in the dialog to fetch the certificate) make it harder for the user to understand how to successfully add the exception. You might say that some false positives (i.e., users who fail to access a site that they really actually do want to access) is better than a user succumbing to a MITM attack, but I’m not sure I’d agree.

Equally importantly, the error messages make no distinction between the potential severity of the various SSL errors. For example, I’d say a self-signed cert on a site that you’ve never visited before is fairly low-risk. But a self-signed cert on a site that used to have a trusted cert would be a huge red flag. Domain mismatches and expired certs would fall somewhere in between. It’s hard for the average user to make an informed decision on risk/severity if they were to encounter both of these situations because the error messages and dialogs look exactly the same.

Addressing Johnathan’s main point about self-signed certs and level of security: as a highly technical/advanced user, I personally can say that, in the vast majority of instances where I encounter a self-signed cert, I really do just care about the encryption, and I don’t particularly care about the identity verification of the site that a trusted cert could offer. Now, Firefox probably shouldn’t use me as an example as a target user that needs protection, but that’s a data point nonetheless. I don’t care for things like: Bugzilla installations, my blog, accounts at sites like identi.ca, Twitter, Slashdot (they don’t offer SSL at present, but if they did…), etc.

Pretty much the only time I do care are for financial institutions. And guess what? They’ve already decided that SSL as used for identity verification is useless! Most of them (I can only think of one that I use that hasn’t) have already implemented a “security image” system wherein I pick a random image that gets shown to me every time I log in. If a site claiming to be the site I want shows me an image I don’t recognise, I’ll know that the site is a fraud. Is it perfect? Probably not. But it’s orders of magnitude better then what SSL error dialogs offer.

And I guess that’s really it: as much as I hate the phrase, I really think that the SSL error dialogs are “a solution in search of a problem.” In the cases where I care about site spoofing, the sites themselves have already implemented a better solution. In the cases where I don’t care, well… I don’t care.