<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>Tumbleweed Rants</title>
  <subtitle>Stefano's World</subtitle>
  <link rel="alternate" type="text/html" href="http://tumbleweed.org.za"/>
  <link rel="self" type="application/atom+xml" href="http://tumbleweed.org.za/atom/feed"/>
  <id>http://tumbleweed.org.za/atom/feed</id>
  <updated>2008-01-21T11:34:06+00:00</updated>
  <entry>
    <title>Fixing a Digital Camera</title>
    <link rel="alternate" type="text/html" href="http://tumbleweed.org.za/2008/07/13/fixing-digital-camera" />
    <id>http://tumbleweed.org.za/2008/07/13/fixing-digital-camera</id>
    <published>2008-07-13T01:57:11+01:00</published>
    <updated>2008-07-13T20:56:25+01:00</updated>
    <author>
      <name>tumbleweed</name>
    </author>
    <category term="canon" />
    <category term="digital camera" />
    <category term="error 18" />
    <category term="fix" />
    <category term="howto" />
    <category term="ixus" />
    <category term="technical" />
    <summary type="html"><![CDATA[<p>My brother was talking about buying my Canon Digital IXUS 750 Camera off me. (or PowerShot SD550 for Americans)
He had an identical camera and waterproof housing for it (this costs significantly more than the camera). But said waterproof housing had not been properly closed once&#8230;</p>

<p>My camera wasn&#8217;t having any of that, and the next time I turned it on, it half-opened the lens, groaned, and said &#8220;E18&#8221;. Bugger. Googling E18 turned up a few sites showing other people with the same problem, <em>lots</em> of other people: <a href="http://www.e18error.com/">e18error.com</a>, <a href="http://en.wikipedia.org/wiki/E18_Error">E18 Error on Wikipedia</a>. It appears to be a generic error for lens problems in Canon cameras, and occurs so often that class action suits have been filed against Canon.</p>

<p>I read the tales of woe, and tried the suggested remedies of shaking, banging, prodding, and otherwise mauling my poor camera. Nothing helped. I put it in a <a href="http://en.wikipedia.org/wiki/Pelican_case">pelican case</a> and forgot about it  for a few weeks.</p>

<p>Reading on, I discovered a few tales of brave owners disassembling and repairing their cameras, mostly successfully. As a geek, I knew I was going to <em>have to</em> give this a shot. I&#8217;ve taken things apart since I learned how to use a screwdriver, so I can normally put them back together again (these days), <em>and</em> they normally still work.</p>

<p>Eventually, I got around to this, last week. Nobody has posted disassembly instructions for any camera near my model, so I had to work it out for myself. Now, let&#8217;s remedy that:</p>

<h1>My Symptoms</h1>

<p>My camera&#8217;s lens was open, and wouldn&#8217;t move at all. Turning it on gave an E18 error.</p>

<h1>Preparation</h1>

<p><img src="/files/equipment.jpg" alt="My equipment" title="" /></p>

<p>I&#8217;d recommend the following:</p>

<ul>
<li>An afternoon &amp; evening to yourself</li>
<li>A large, empty desk (preferably with a lip, to catch dropped screws)</li>
<li>A lino floor (carpets can lose dropped screws)</li>
<li>A good desk light</li>
<li>Lens tissue (or better yet, the wet-wipe version)</li>
<li>Meths and ear-buds (or other solvent of choice)</li>
<li>Superglue (in case you break something or something is broken)</li>
<li>Tweezers, pliers, leatherman, etc. (you are dealing with lots of little things)</li>
<li>Screwdrivers: small philips-head drivers for screws, and a few tiny flat ones for prying.</li>
<li>A torch (to help you find dropped screws)</li>
<li>A third-hand (or at least its magnifying glass)</li>
<li>A blower/brush (to get rid of dirt)</li>
<li>A working camera (to document the procedure, so you can put it back together)</li>
<li>Patience - dropped screws can be hard to find</li>
</ul>

<p>Warnings: You need to have a willingness to part with your patient&#8217;s life. You also need to be aware that camera flash assemblies contain high-voltage capacitors, that usually hold a small residual charge. Stay well clear of them and their circuitry. If possible, discharge it as soon as you see it, with a heavy-duty resistor.</p>

<p>Tips: Lay out the removed parts in the order you disassembled them, together with their screws. That way you won&#8217;t have the &#8220;left-over screw&#8221; problem or put things together in the wrong order.</p>

<h1>Disassembly</h1>

<p>Remove the battery and SD card.</p>

<p><img src="/files/case.jpg" alt="Unscrewing the case" title="" /></p>

<p>To remove the case, you need to undo all the exterior screws: 3 on the base, 2 on the left, and 2 on the right (one is under flap C). The side plate A is loose, and B is a plastic sheet that can be pulled out, revealing an additional screw. Flap C is attached to the body, not B. When reassembling, take care to insert lip D under the back panel.</p>

<p>There are no clips on the bottom or sides, but there are 3 along the top, between the front and back halves. One to the right of the shutter, two to the left. Pry up on the front half.</p>

<p><img src="/files/opened.jpg" alt="Opened" title="" /></p>

<p>There should be a black O-ring on the outer part of the lens. Lift it off and store.</p>

<p><img src="/files/parts-connectors.jpg" alt="Parts and Connectors" title="" /></p>

<p>The three main modules are now visible. Motherboard and battery (A), Flash unit (B), and Optics (C). While we won&#8217;t undo these connectors quite yet, as the LCD is currently attached to both sides, but this is a good opportunity to explain the connectors that you&#8217;ll be encountering.</p>

<p>The ribbon cable E plugs into the white connector with a black lid. The black lid needs to be folded back for the ribbon to be removed. It simply pulls out along it&#8217;s axis. To re-insert: open, push in ribbon as far as it&#8217;ll go, and close. These connectors are quite delicate, be careful.</p>

<p>There is another type of ribbon connector which simply relies on friction. The LCD back-light cable is an example. You just pull it out with tweezers, and push it back with tweezers (without bending it, if possible).</p>

<p>The flash power lead D must be pulled up, away from the camera. Insert a tiny screwdriver underneath the wires at the point indicated, and pry up.</p>

<p><img src="/files/lcd.jpg" alt="LCD and back" title="" /></p>

<p>The buttons are a loose piece of rubber. Lift off.</p>

<p>The LCD needs to be removed first. Pull out the backlight power ribbon (A). Unscrew the screw above the LCD, releasing a bar. The left side has a small clip that needs to be released, and then the LCD-backlight assembly should lift upwards. The right hand side has a lip under the keypad module, so lift the left side first. You won&#8217;t be able to disconnect the LCD ribbon until you remove the keypad plate.</p>

<p>Unscrew the 2 screws at the top of the keypad plate. There are a few clips holding the bottom in place (arrowed). But you should be able to pull the plate away, revealing the ribbon connectors for both units. Unplug them both.</p>

<p><img src="/files/flash-unit.jpg" alt="Flash Unit and Optical Assembly" title="" /></p>

<p>The Flash unit can now be removed. Unplug the cables shown earlier, as well as the screw on the bottom right-corner. The ribbon plugs into the flash unit, unplug (C).</p>

<p>The left two screws on the back (red) will release the flash unit.</p>

<p>Before unscrewing the optical assembly, open the CCD ribbon connector (A). When re-attaching the module, the cable should again be inserted first, and locked last.</p>

<p>The three (green) screws on the metal frame will release the optical module. Beware a tiny spring hiding under B. Lift it out, and store it.</p>

<p><img src="/files/optical-assembly.jpg" alt="Optical Assembly" title="" /></p>

<p>Before we can take the Optical assembly apart, the focussing LED has to be removed. Unstick ribbon A, and pry up the LED (B). Continue lifting the ribbon, unsticking the status LED section (C), too.</p>

<p>While we are here, the focussing servo&#8217;s cogs are under D, if you are cog-cleaning. Don&#8217;t open if you don&#8217;t need to.</p>

<p>Unplug (pull) the shutter-ribbon from E, and unstick E&#8217;s ribbon from the lens-body.</p>

<p>The lens and viewfinder assembly can now be removed from the base-plate with the CCD and motors. Unscrew the 4 screws and one on the base. The long screw comes from near F. Lift up the lens carefully. A small black cog will be loose near F. Remove and store.</p>

<p>The green screw gives access to the zoom servo&#8217;s cogs. Don&#8217;t open unless you need to.</p>

<p><img src="/files/ccd.jpg" alt="CCD" title="" /></p>

<p>On the CCD base, the sharp bit (A) activates the lens-cap mechanism in the lens, when it&#8217;s closed. The lens element (B) is for focussing, and in my case it&#8217;s sitting at an odd angle, because the short pin (circled) had broken, and had to be glued back in place. This pin passes through an IR light-switch when the lens is at a certain hight, allowing the camera to calibrate its focus.</p>

<p>Check that the focussing element moves up and down smoothly when you rotate the thread below A.</p>

<p>While you are here, blow any dust off the lens and CCD below it.</p>

<p><img src="/files/lens.jpg" alt="Lens" title="" /></p>

<p>To disassemble the lens: Un-thread the ribbon. Roll the big cog on the side until it&#8217;s fully closed, and clicks, revealing the pins of the inner rings, and push the outermost interior ring of the lens backwards from the front. It should pop out.</p>

<p><img src="/files/lens-rings.jpg" alt="Lens Rings" title="" /></p>

<p>The rings either simply pop out backwards, or have a track leading to the surface. Clean all the tracks and pins.</p>

<p>If you are having shutter-trouble, you can open the innermost module, but beware it&#8217;s delicate. If the lens-cap is jamming, operate it a bit with a screwdriver (wiggle), blow air at it, etc until it works cleanly.</p>

<h1>Reassembly</h1>

<p>Finally, if you found your problem, reassemble.</p>

<p>Remember to rethread the lens ribbon before you attach the outermost ring. The lens should operate smoothly when zoomed with the big cog. It&#8217;s easiest if you attach it to the CCD plate in the opened state.</p>

<p>The camera behaves well, and can be tested disassembled. If you are having E18 trouble, you can just connect the lens to the motherboard, insert the battery, and turn it on. If it&#8217;s working, the lens should open, and close when turned off (and the power button LED should go out promptly, if it doesn&#8217;t you haven&#8217;t found the trouble yet).</p>

<p>Enjoy your newly fixed camera. I am, mine.</p>
    ]]></summary>
    <content type="html"><![CDATA[<p>My brother was talking about buying my Canon Digital IXUS 750 Camera off me. (or PowerShot SD550 for Americans)
He had an identical camera and waterproof housing for it (this costs significantly more than the camera). But said waterproof housing had not been properly closed once&#8230;</p>

<p>My camera wasn&#8217;t having any of that, and the next time I turned it on, it half-opened the lens, groaned, and said &#8220;E18&#8221;. Bugger. Googling E18 turned up a few sites showing other people with the same problem, <em>lots</em> of other people: <a href="http://www.e18error.com/">e18error.com</a>, <a href="http://en.wikipedia.org/wiki/E18_Error">E18 Error on Wikipedia</a>. It appears to be a generic error for lens problems in Canon cameras, and occurs so often that class action suits have been filed against Canon.</p>

<p>I read the tales of woe, and tried the suggested remedies of shaking, banging, prodding, and otherwise mauling my poor camera. Nothing helped. I put it in a <a href="http://en.wikipedia.org/wiki/Pelican_case">pelican case</a> and forgot about it  for a few weeks.</p>

<p>Reading on, I discovered a few tales of brave owners disassembling and repairing their cameras, mostly successfully. As a geek, I knew I was going to <em>have to</em> give this a shot. I&#8217;ve taken things apart since I learned how to use a screwdriver, so I can normally put them back together again (these days), <em>and</em> they normally still work.</p>

<p>Eventually, I got around to this, last week. Nobody has posted disassembly instructions for any camera near my model, so I had to work it out for myself. Now, let&#8217;s remedy that:</p>

<h1>My Symptoms</h1>

<p>My camera&#8217;s lens was open, and wouldn&#8217;t move at all. Turning it on gave an E18 error.</p>

<h1>Preparation</h1>

<p><img src="/files/equipment.jpg" alt="My equipment" title="" /></p>

<p>I&#8217;d recommend the following:</p>

<ul>
<li>An afternoon &amp; evening to yourself</li>
<li>A large, empty desk (preferably with a lip, to catch dropped screws)</li>
<li>A lino floor (carpets can lose dropped screws)</li>
<li>A good desk light</li>
<li>Lens tissue (or better yet, the wet-wipe version)</li>
<li>Meths and ear-buds (or other solvent of choice)</li>
<li>Superglue (in case you break something or something is broken)</li>
<li>Tweezers, pliers, leatherman, etc. (you are dealing with lots of little things)</li>
<li>Screwdrivers: small philips-head drivers for screws, and a few tiny flat ones for prying.</li>
<li>A torch (to help you find dropped screws)</li>
<li>A third-hand (or at least its magnifying glass)</li>
<li>A blower/brush (to get rid of dirt)</li>
<li>A working camera (to document the procedure, so you can put it back together)</li>
<li>Patience - dropped screws can be hard to find</li>
</ul>

<p>Warnings: You need to have a willingness to part with your patient&#8217;s life. You also need to be aware that camera flash assemblies contain high-voltage capacitors, that usually hold a small residual charge. Stay well clear of them and their circuitry. If possible, discharge it as soon as you see it, with a heavy-duty resistor.</p>

<p>Tips: Lay out the removed parts in the order you disassembled them, together with their screws. That way you won&#8217;t have the &#8220;left-over screw&#8221; problem or put things together in the wrong order.</p>

<h1>Disassembly</h1>

<p>Remove the battery and SD card.</p>

<p><img src="/files/case.jpg" alt="Unscrewing the case" title="" /></p>

<p>To remove the case, you need to undo all the exterior screws: 3 on the base, 2 on the left, and 2 on the right (one is under flap C). The side plate A is loose, and B is a plastic sheet that can be pulled out, revealing an additional screw. Flap C is attached to the body, not B. When reassembling, take care to insert lip D under the back panel.</p>

<p>There are no clips on the bottom or sides, but there are 3 along the top, between the front and back halves. One to the right of the shutter, two to the left. Pry up on the front half.</p>

<p><img src="/files/opened.jpg" alt="Opened" title="" /></p>

<p>There should be a black O-ring on the outer part of the lens. Lift it off and store.</p>

<p><img src="/files/parts-connectors.jpg" alt="Parts and Connectors" title="" /></p>

<p>The three main modules are now visible. Motherboard and battery (A), Flash unit (B), and Optics (C). While we won&#8217;t undo these connectors quite yet, as the LCD is currently attached to both sides, but this is a good opportunity to explain the connectors that you&#8217;ll be encountering.</p>

<p>The ribbon cable E plugs into the white connector with a black lid. The black lid needs to be folded back for the ribbon to be removed. It simply pulls out along it&#8217;s axis. To re-insert: open, push in ribbon as far as it&#8217;ll go, and close. These connectors are quite delicate, be careful.</p>

<p>There is another type of ribbon connector which simply relies on friction. The LCD back-light cable is an example. You just pull it out with tweezers, and push it back with tweezers (without bending it, if possible).</p>

<p>The flash power lead D must be pulled up, away from the camera. Insert a tiny screwdriver underneath the wires at the point indicated, and pry up.</p>

<p><img src="/files/lcd.jpg" alt="LCD and back" title="" /></p>

<p>The buttons are a loose piece of rubber. Lift off.</p>

<p>The LCD needs to be removed first. Pull out the backlight power ribbon (A). Unscrew the screw above the LCD, releasing a bar. The left side has a small clip that needs to be released, and then the LCD-backlight assembly should lift upwards. The right hand side has a lip under the keypad module, so lift the left side first. You won&#8217;t be able to disconnect the LCD ribbon until you remove the keypad plate.</p>

<p>Unscrew the 2 screws at the top of the keypad plate. There are a few clips holding the bottom in place (arrowed). But you should be able to pull the plate away, revealing the ribbon connectors for both units. Unplug them both.</p>

<p><img src="/files/flash-unit.jpg" alt="Flash Unit and Optical Assembly" title="" /></p>

<p>The Flash unit can now be removed. Unplug the cables shown earlier, as well as the screw on the bottom right-corner. The ribbon plugs into the flash unit, unplug (C).</p>

<p>The left two screws on the back (red) will release the flash unit.</p>

<p>Before unscrewing the optical assembly, open the CCD ribbon connector (A). When re-attaching the module, the cable should again be inserted first, and locked last.</p>

<p>The three (green) screws on the metal frame will release the optical module. Beware a tiny spring hiding under B. Lift it out, and store it.</p>

<p><img src="/files/optical-assembly.jpg" alt="Optical Assembly" title="" /></p>

<p>Before we can take the Optical assembly apart, the focussing LED has to be removed. Unstick ribbon A, and pry up the LED (B). Continue lifting the ribbon, unsticking the status LED section (C), too.</p>

<p>While we are here, the focussing servo&#8217;s cogs are under D, if you are cog-cleaning. Don&#8217;t open if you don&#8217;t need to.</p>

<p>Unplug (pull) the shutter-ribbon from E, and unstick E&#8217;s ribbon from the lens-body.</p>

<p>The lens and viewfinder assembly can now be removed from the base-plate with the CCD and motors. Unscrew the 4 screws and one on the base. The long screw comes from near F. Lift up the lens carefully. A small black cog will be loose near F. Remove and store.</p>

<p>The green screw gives access to the zoom servo&#8217;s cogs. Don&#8217;t open unless you need to.</p>

<p><img src="/files/ccd.jpg" alt="CCD" title="" /></p>

<p>On the CCD base, the sharp bit (A) activates the lens-cap mechanism in the lens, when it&#8217;s closed. The lens element (B) is for focussing, and in my case it&#8217;s sitting at an odd angle, because the short pin (circled) had broken, and had to be glued back in place. This pin passes through an IR light-switch when the lens is at a certain hight, allowing the camera to calibrate its focus.</p>

<p>Check that the focussing element moves up and down smoothly when you rotate the thread below A.</p>

<p>While you are here, blow any dust off the lens and CCD below it.</p>

<p><img src="/files/lens.jpg" alt="Lens" title="" /></p>

<p>To disassemble the lens: Un-thread the ribbon. Roll the big cog on the side until it&#8217;s fully closed, and clicks, revealing the pins of the inner rings, and push the outermost interior ring of the lens backwards from the front. It should pop out.</p>

<p><img src="/files/lens-rings.jpg" alt="Lens Rings" title="" /></p>

<p>The rings either simply pop out backwards, or have a track leading to the surface. Clean all the tracks and pins.</p>

<p>If you are having shutter-trouble, you can open the innermost module, but beware it&#8217;s delicate. If the lens-cap is jamming, operate it a bit with a screwdriver (wiggle), blow air at it, etc until it works cleanly.</p>

<h1>Reassembly</h1>

<p>Finally, if you found your problem, reassemble.</p>

<p>Remember to rethread the lens ribbon before you attach the outermost ring. The lens should operate smoothly when zoomed with the big cog. It&#8217;s easiest if you attach it to the CCD plate in the opened state.</p>

<p>The camera behaves well, and can be tested disassembled. If you are having E18 trouble, you can just connect the lens to the motherboard, insert the battery, and turn it on. If it&#8217;s working, the lens should open, and close when turned off (and the power button LED should go out promptly, if it doesn&#8217;t you haven&#8217;t found the trouble yet).</p>

<p>Enjoy your newly fixed camera. I am, mine.</p>
    ]]></content>
  </entry>
  <entry>
    <title>An open letter to NatWest bank</title>
    <link rel="alternate" type="text/html" href="http://tumbleweed.org.za/2008/05/28/natwest-letter" />
    <id>http://tumbleweed.org.za/2008/05/28/natwest-letter</id>
    <published>2008-05-28T17:27:30+01:00</published>
    <updated>2008-06-03T17:15:15+01:00</updated>
    <author>
      <name>tumbleweed</name>
    </author>
    <category term="banking" />
    <category term="natwest" />
    <category term="rant" />
    <summary type="html"><![CDATA[<blockquote>
  <p>Subject: Strict Browser restrictions</p>

  <p>Hi, I&#8217;m a customer of yours, and a GNU/Linux user who gets frequently
  frustrated by your browser detection.</p>

  <p>Basically, the problem is that very few web browsers have been
  certified with your website. Now, I have no real issue with that,
  nobody has enough time to try <em>every</em> web browser in the world, and
  adjust their websites to fit around every browser&#8217;s bugs. <em>But</em> that
  doesn&#8217;t mean it&#8217;s acceptable to reject your users with a message like
  &#8220;The Internet browser you are using is not supported by online banking.
  Use the link below to see the complete list of browsers we support.&#8221;</p>

  <p>Firstly, the browsers I use <em>are</em> listed as being supported on your
  list <a href="http://www.natwest.com/personal/day-to-day/online-banking/g1/faqs.ashx">[1]</a>:</p>

  <ul>
  <li>On this laptop, I use a Firefox 3.0 beta. Firefox 3.0 is listed is
  being supported, and it works (if I tweak it to identify it as
  Firefox 2.0, then I can use the site just fine).</li>
  <li>On my desktops, I use Iceweasel 2.x. Iceweasel is Firefox with a
  different name, to get around trademark issues. Ask your
  Linux-techies, they should know about it. Again, it works as
  expected.</li>
  </ul>

  <p>Secondly, <a href="http://www.natwest.com/personal/day-to-day/online-banking/g1/faqs.ashx">[1]</a> states: &#8220;Netscape, Mozilla and Firefox users with other
  operating systems such as Linux may also be able to access the
  service.&#8221; How are we supposed to access the service if you deny us
  access?</p>

  <p>More generally, locking out unknown browsers goes completely against
  your policy of Accessibility <a href="http://www.natwest.com/popup/global/access.ashx">[2]</a>. While the WAI <a href="http://www.w3.org/TR/WAI-WEBCONTENT">[3]</a> doesn&#8217;t
  specifically recommend against turning away unknown browsers, I think
  you&#8217;ll find that&#8217;s because the authors didn&#8217;t even <em>dream</em> of
  <em>considering</em> such a thing. The <em>entire point</em> of WAI, is to make your
  site as portable as possible, and to work for everyone with a far
  wider variety of user agents than you could ever test with.</p>

  <p>I don&#8217;t know how you can call yourself WAI-compliant and reject
  un-&#8220;certified&#8221; browsers. Your webmasters should hang their heads in
  shame.</p>

  <p>Now, I don&#8217;t intend to rant any more than that, because that&#8217;s the
  only problem I have with your site (and your service). Beyond this
  little niggle (which stops me being able to bank, without configuring
  my browser to lie) I&#8217;m very impressed with your services.</p>

  <p>Please sort this out, it&#8217;ll turn me back into a happy customer.</p>

  <p>SR</p>

  <p>PS: I&#8217;d have sent this by e-mail, where I&#8217;d, but you don&#8217;t provide any
     e-mail contact details on your site.
  PPS: Only providing a small feedback form doesn&#8217;t help users give you
      real feedback, it just intimidates and irritates them.</p>

  <p>[1]: <a href="http://www.natwest.com/personal/day-to-day/online-banking/g1/faqs.ashx">http://www.natwest.com/personal/day-to-day/online-banking/g1/faqs.ashx</a><br />
  [2]: <a href="http://www.natwest.com/popup/global/access.ashx">http://www.natwest.com/popup/global/access.ashx</a><br />
  [3]: <a href="http://www.w3.org/TR/WAI-WEBCONTENT">http://www.w3.org/TR/WAI-WEBCONTENT/</a></p>

  <p>&#8212;<br />
  Stefano Rivera<br />
   http://rivera.za.net/<br />
   H: +27 21 794 7937   C: +27 72 419 8559</p>
</blockquote>

<p>Now, that was rather harsh to them, but this has been irritating me for ages. Then, when I did decide to <em>do something</em> about it, I was rather worked up, and ranted.</p>

<p>I got a call back from NatWest this morning, and was basically told that they aren&#8217;t going to change anything. I can understand their position, but I don&#8217;t that they were seeing mine. (Oh, and I think they are wrong.)</p>

<p>The reasons I was given for this non-approved lockout are:</p>

<ol>
<li>Support. But of course, if your web site is decent, then you shouldn&#8217;t have any support issues. (OK, that&#8217;s rather utopic, but the kind of people who use alternative browsers will be OK in such situations).</li>
<li>Security. Apparently Opera caches previously visited pages as they were. Clicking back doesn&#8217;t revalidate with the server, and so someone who&#8217;s logged out of their Internet banking and gone on to google still has their private data visible in the history. Anyone coming up to their computer can go back to it.</li>
</ol>

<p>Now, I don&#8217;t think point 2 is NatWest&#8217;s problem. If Opera doesn&#8217;t support revalidation, then Opera must fix it. If Opera do, and NatWest doesn&#8217;t send the correct Pragma headers, then it&#8217;s NatWest&#8217;s problem.</p>

<p>But still, that doesn&#8217;t mean you lock-out untested browers, dammit. <em>Especially</em> if you call yourself WAI-compliant.</p>

<p>I&#8217;d love to see some feedback from a WAI board member on this type of issue. I don&#8217;t think the WAI specs address it.</p>

<p>Oh, and everyone, please stand up for your right to browse the web however you see fit. If more people did so, these kind of issues would crop up less often.</p>
    ]]></summary>
    <content type="html"><![CDATA[<blockquote>
  <p>Subject: Strict Browser restrictions</p>
  
  <p>Hi, I&#8217;m a customer of yours, and a GNU/Linux user who gets frequently
  frustrated by your browser detection.</p>
  
  <p>Basically, the problem is that very few web browsers have been
  certified with your website. Now, I have no real issue with that,
  nobody has enough time to try <em>every</em> web browser in the world, and
  adjust their websites to fit around every browser&#8217;s bugs. <em>But</em> that
  doesn&#8217;t mean it&#8217;s acceptable to reject your users with a message like
  &#8220;The Internet browser you are using is not supported by online banking.
  Use the link below to see the complete list of browsers we support.&#8221;</p>
  
  <p>Firstly, the browsers I use <em>are</em> listed as being supported on your
  list <a href="http://www.natwest.com/personal/day-to-day/online-banking/g1/faqs.ashx">[1]</a>:</p>
  
  <ul>
  <li>On this laptop, I use a Firefox 3.0 beta. Firefox 3.0 is listed is
  being supported, and it works (if I tweak it to identify it as
  Firefox 2.0, then I can use the site just fine).</li>
  <li>On my desktops, I use Iceweasel 2.x. Iceweasel is Firefox with a
  different name, to get around trademark issues. Ask your
  Linux-techies, they should know about it. Again, it works as
  expected.</li>
  </ul>
  
  <p>Secondly, <a href="http://www.natwest.com/personal/day-to-day/online-banking/g1/faqs.ashx">[1]</a> states: &#8220;Netscape, Mozilla and Firefox users with other
  operating systems such as Linux may also be able to access the
  service.&#8221; How are we supposed to access the service if you deny us
  access?</p>
  
  <p>More generally, locking out unknown browsers goes completely against
  your policy of Accessibility <a href="http://www.natwest.com/popup/global/access.ashx">[2]</a>. While the WAI <a href="http://www.w3.org/TR/WAI-WEBCONTENT">[3]</a> doesn&#8217;t
  specifically recommend against turning away unknown browsers, I think
  you&#8217;ll find that&#8217;s because the authors didn&#8217;t even <em>dream</em> of
  <em>considering</em> such a thing. The <em>entire point</em> of WAI, is to make your
  site as portable as possible, and to work for everyone with a far
  wider variety of user agents than you could ever test with.</p>
  
  <p>I don&#8217;t know how you can call yourself WAI-compliant and reject
  un-&#8220;certified&#8221; browsers. Your webmasters should hang their heads in
  shame.</p>
  
  <p>Now, I don&#8217;t intend to rant any more than that, because that&#8217;s the
  only problem I have with your site (and your service). Beyond this
  little niggle (which stops me being able to bank, without configuring
  my browser to lie) I&#8217;m very impressed with your services.</p>
  
  <p>Please sort this out, it&#8217;ll turn me back into a happy customer.</p>
  
  <p>SR</p>
  
  <p>PS: I&#8217;d have sent this by e-mail, where I&#8217;d, but you don&#8217;t provide any
     e-mail contact details on your site.
  PPS: Only providing a small feedback form doesn&#8217;t help users give you
      real feedback, it just intimidates and irritates them.</p>
  
  <p>[1]: <a href="http://www.natwest.com/personal/day-to-day/online-banking/g1/faqs.ashx">http://www.natwest.com/personal/day-to-day/online-banking/g1/faqs.ashx</a><br />
  [2]: <a href="http://www.natwest.com/popup/global/access.ashx">http://www.natwest.com/popup/global/access.ashx</a><br />
  [3]: <a href="http://www.w3.org/TR/WAI-WEBCONTENT">http://www.w3.org/TR/WAI-WEBCONTENT/</a></p>
  
  <p>&#8212;<br />
  Stefano Rivera<br />
   http://rivera.za.net/<br />
   H: +27 21 794 7937   C: +27 72 419 8559</p>
</blockquote>

<p>Now, that was rather harsh to them, but this has been irritating me for ages. Then, when I did decide to <em>do something</em> about it, I was rather worked up, and ranted.</p>

<p>I got a call back from NatWest this morning, and was basically told that they aren&#8217;t going to change anything. I can understand their position, but I don&#8217;t that they were seeing mine. (Oh, and I think they are wrong.)</p>

<p>The reasons I was given for this non-approved lockout are:</p>

<ol>
<li>Support. But of course, if your web site is decent, then you shouldn&#8217;t have any support issues. (OK, that&#8217;s rather utopic, but the kind of people who use alternative browsers will be OK in such situations).</li>
<li>Security. Apparently Opera caches previously visited pages as they were. Clicking back doesn&#8217;t revalidate with the server, and so someone who&#8217;s logged out of their Internet banking and gone on to google still has their private data visible in the history. Anyone coming up to their computer can go back to it.</li>
</ol>

<p>Now, I don&#8217;t think point 2 is NatWest&#8217;s problem. If Opera doesn&#8217;t support revalidation, then Opera must fix it. If Opera do, and NatWest doesn&#8217;t send the correct Pragma headers, then it&#8217;s NatWest&#8217;s problem.</p>

<p>But still, that doesn&#8217;t mean you lock-out untested browers, dammit. <em>Especially</em> if you call yourself WAI-compliant.</p>

<p>I&#8217;d love to see some feedback from a WAI board member on this type of issue. I don&#8217;t think the WAI specs address it.</p>

<p>Oh, and everyone, please stand up for your right to browse the web however you see fit. If more people did so, these kind of issues would crop up less often.</p>
    ]]></content>
  </entry>
  <entry>
    <title>Gammu with Samsung</title>
    <link rel="alternate" type="text/html" href="http://tumbleweed.org.za/2008/04/29/gammu-samsung" />
    <id>http://tumbleweed.org.za/2008/04/29/gammu-samsung</id>
    <published>2008-04-29T21:33:29+01:00</published>
    <updated>2008-04-29T21:40:14+01:00</updated>
    <author>
      <name>tumbleweed</name>
    </author>
    <category term="cell-phone" />
    <category term="gammu" />
    <category term="python" />
    <category term="samsung" />
    <category term="technical" />
    <summary type="html"><![CDATA[<p>A housemate of mine got a new Samsung phone on the weekend. Being a resident geek, I offered to transfer her contacts across rather than get her sister to manually retype 500-odd contacts.</p>

<p>Naturally, I thought this would be a simple problem, right? I mean, everyone updates their phones every 2 years, this must be a pretty common use case. All my Sony Ericsson phones have had a &#8220;send all contacts by Bluetooth&#8221; option since the inception of Bluetooth. Naturally, it didn&#8217;t have such a feature, it only supports sending one contact at a time. (Although, to Samsung&#8217;s credit, the <em>new</em> phone will be able to do for the next upgrade)</p>

<p>Next option: I&#8217;ll sync old phone to laptop to new phone.</p>

<p>The Samsung website has a helpful Windows utility that you can download to do this, however you need the cable to link the phone to the computer. The phones needed different cables, and I had neither. My laptop with a Windows partition has had broken Bluetooth ever since <a href="/2006/12/29/acer-laptop-woes-part-7">its motherboard got replaced</a>. So that wasn&#8217;t an option. The phones don&#8217;t have IRDA, so there was no way to connect them with the Windows laptop.</p>

<p>Time to do it properly.</p>

<p>I tried <a href="http://wammu.eu/">wammu</a>, a python-based <a href="http://www.gammu.org/">gammu</a> GUI. It supported the phones via the &#8220;blueat&#8221; driver, and could browse their SIM cards fine, but not their internal Phonebooks. It couldn&#8217;t back them up either. A bit of poking around with gammu on the command line showed that the internal phone books are not 0-indexed (normal computer counting, 0 to n-1) or 1-indexed (normal human counting, 1 to n), but 2-indexed. Dijkstra would turn in his grave!</p>

<p>At this point, I could see that I was going to have to write my own, backup utility. The output of gammu was awkable, but seeing as there are good gammu-python bindings, I decided to do it in pure Python.</p>

<p>Reading the address book went something like this:</p>

<pre><code>import gammu, pickle
sm = gammu.StateMachine()
sm.ReadConfig(3, 0)
sm.Init()
old = []
for i in range(2, 587):
    old.append(sm.GetMemory("ME", i)

pickle.dump(old, file("phonebook.dump", "w"))
</code></pre>

<p>The 3 signifies gammu configuration number 3, read into position 0. 587 is the number of address book entries. &#8220;ME&#8221; means internal memory. I then pickled &#8220;old&#8221; in preparation for the next stage. Here is an example of an item in old:</p>

<pre><code>{'Entries': [{'AddError': 7517792,
              'Type': 'Text_FirstName',
              'Value': u'Foo'},
             {'AddError': 796160623,
              'Type': 'Text_LastName',
              'Value': u'Bar'},
             {'AddError': 796160623,
              'SMSList': [],
              'Type': 'Number_Other',
              'Value': u'0211234567',
              'VoiceTag': 0},
             {'Type': 'Category', 'Value': 0}],
 'Location': 2,
 'MemoryType': 'ME'}
</code></pre>

<p>Pretty icky, but at least all the information is there. At this point, one should be able to feed it into the new phone:</p>

<pre><code>sm.Terminate()
sm = gammu.StateMachine()
sm.ReadConfig(4, 0)
sm.Init()
for i in old:
    sm.AddMemory(i)
</code></pre>

<p>However nothing I tried worked, I always got an &#8220;Invalid Location&#8221; error. I think the 2-indexing is trumping gammu again.</p>

<p>Next idea, lets munge the data into vCard format and use wammu / gammu&#8217;s &#8220;import from vCard&#8221; function. (Code coming up soon) Turns out this doesn&#8217;t work either. The phone only received the First name, first phone number, and various other things that I didn&#8217;t send it (i.e. custom ring tones that it made up). Hmph!</p>

<p>Aha, but cellphones can normally Bluetooth vCards to each other. So I pushed it the vCard collection via obexftp. Starts transmitting, but then the phone reboots. I played around a bit, and found that if you send it more than one vCard in a vCard file, it reboots. Lovely.</p>

<p>So my final solution was: Extract address book with python-gammu. Transform into vCards. Send each one individually. At least the phone had a &#8220;trust this device&#8221; option so that it wouldn&#8217;t prompt the user for every vCard I sent, but just automatically import them - the first sensible feature I&#8217;ve found on it.</p>

<p>Here goes:</p>

<pre><code>#!/usr/bin/env python
import os, pickle, time

def normalise_num(n):
    "Neaten up the phone number, internationalise, etc."
    if n.startswith("+"):
        return n
    if n.startswith("00"):
        return "+" + n[2:]
    if len(n) == 10 and n[0] == "0":
        return "+27" + n[1:]
    return n

d = pickle.load(file("phonebook.dump", "r"))

# Normalise into a sensible format:
o = []
for i in d:
    t = {}
    for j in i["Entries"]:
        if j["Type"] == "Text_FirstName":
            t["First"] = j["Value"]
        if j["Type"] == "Text_LastName":
            t["Last"] = j["Value"]
        if j["Type"] == "Number_Other":
            n = normalise_num(j["Value"])
            type = "Home"
            if n[3] in ("7", "8"):
                type = "Cell"
            if type not in t:
                t[type] = []
            t[type].append(n)
    o.append(t)

# Write &amp; Send vCards:
for i in o:
    f = file("temp.vcf", "w")
    f.write("BEGIN:VCARD\n")
    f.write("VERSION:2.1\n")
    f.write("N:%s;%s;;;\n" % (i.get("Last", ""), i.get("First", "")))
    pref = ";PREF"
    for j in i["Cell"]:
        f.write("TEL;CELL%s:%s\n" % (pref, j))
        pref=""
    for j in i["Home"]:
        f.write("TEL;HOME%s:%s\n" % (pref, j))
        pref=""
    f.write("END:VCARD\n")
    f.close()
    os.system("obexftp -b 00:DE:AD:00:BE:EF -p temp.vcf")
    # Give the thing a chance to recover:
    time.sleep(0.1)
</code></pre>

<p>Yes, the normalisation could be done with list comprehensions, but it would be horrible to read. And there might by Python Obex bindings, but I couldn&#8217;t be bothered.</p>

<p>I got to spend an afternoon messing with dodgy Cellphones, rather than having a teenager do the job for free. I think I chose the wrong option, but at least it was fun.</p>

<p>Footnote: Samsung, your phones User Interface is <em>awful</em>. Why on earth is Bluetooth under &#8220;Applications&#8221; rather than &#8220;Settings&#8221;? I searched everywhere but there, and finally googled before I found it&#8230;</p>
    ]]></summary>
    <content type="html"><![CDATA[<p>A housemate of mine got a new Samsung phone on the weekend. Being a resident geek, I offered to transfer her contacts across rather than get her sister to manually retype 500-odd contacts.</p>

<p>Naturally, I thought this would be a simple problem, right? I mean, everyone updates their phones every 2 years, this must be a pretty common use case. All my Sony Ericsson phones have had a &#8220;send all contacts by Bluetooth&#8221; option since the inception of Bluetooth. Naturally, it didn&#8217;t have such a feature, it only supports sending one contact at a time. (Although, to Samsung&#8217;s credit, the <em>new</em> phone will be able to do for the next upgrade)</p>

<p>Next option: I&#8217;ll sync old phone to laptop to new phone.</p>

<p>The Samsung website has a helpful Windows utility that you can download to do this, however you need the cable to link the phone to the computer. The phones needed different cables, and I had neither. My laptop with a Windows partition has had broken Bluetooth ever since <a href="/2006/12/29/acer-laptop-woes-part-7">its motherboard got replaced</a>. So that wasn&#8217;t an option. The phones don&#8217;t have IRDA, so there was no way to connect them with the Windows laptop.</p>

<p>Time to do it properly.</p>

<p>I tried <a href="http://wammu.eu/">wammu</a>, a python-based <a href="http://www.gammu.org/">gammu</a> GUI. It supported the phones via the &#8220;blueat&#8221; driver, and could browse their SIM cards fine, but not their internal Phonebooks. It couldn&#8217;t back them up either. A bit of poking around with gammu on the command line showed that the internal phone books are not 0-indexed (normal computer counting, 0 to n-1) or 1-indexed (normal human counting, 1 to n), but 2-indexed. Dijkstra would turn in his grave!</p>

<p>At this point, I could see that I was going to have to write my own, backup utility. The output of gammu was awkable, but seeing as there are good gammu-python bindings, I decided to do it in pure Python.</p>

<p>Reading the address book went something like this:</p>

<pre><code>import gammu, pickle
sm = gammu.StateMachine()
sm.ReadConfig(3, 0)
sm.Init()
old = []
for i in range(2, 587):
    old.append(sm.GetMemory("ME", i)

pickle.dump(old, file("phonebook.dump", "w"))
</code></pre>

<p>The 3 signifies gammu configuration number 3, read into position 0. 587 is the number of address book entries. &#8220;ME&#8221; means internal memory. I then pickled &#8220;old&#8221; in preparation for the next stage. Here is an example of an item in old:</p>

<pre><code>{'Entries': [{'AddError': 7517792,
              'Type': 'Text_FirstName',
              'Value': u'Foo'},
             {'AddError': 796160623,
              'Type': 'Text_LastName',
              'Value': u'Bar'},
             {'AddError': 796160623,
              'SMSList': [],
              'Type': 'Number_Other',
              'Value': u'0211234567',
              'VoiceTag': 0},
             {'Type': 'Category', 'Value': 0}],
 'Location': 2,
 'MemoryType': 'ME'}
</code></pre>

<p>Pretty icky, but at least all the information is there. At this point, one should be able to feed it into the new phone:</p>

<pre><code>sm.Terminate()
sm = gammu.StateMachine()
sm.ReadConfig(4, 0)
sm.Init()
for i in old:
    sm.AddMemory(i)
</code></pre>

<p>However nothing I tried worked, I always got an &#8220;Invalid Location&#8221; error. I think the 2-indexing is trumping gammu again.</p>

<p>Next idea, lets munge the data into vCard format and use wammu / gammu&#8217;s &#8220;import from vCard&#8221; function. (Code coming up soon) Turns out this doesn&#8217;t work either. The phone only received the First name, first phone number, and various other things that I didn&#8217;t send it (i.e. custom ring tones that it made up). Hmph!</p>

<p>Aha, but cellphones can normally Bluetooth vCards to each other. So I pushed it the vCard collection via obexftp. Starts transmitting, but then the phone reboots. I played around a bit, and found that if you send it more than one vCard in a vCard file, it reboots. Lovely.</p>

<p>So my final solution was: Extract address book with python-gammu. Transform into vCards. Send each one individually. At least the phone had a &#8220;trust this device&#8221; option so that it wouldn&#8217;t prompt the user for every vCard I sent, but just automatically import them - the first sensible feature I&#8217;ve found on it.</p>

<p>Here goes:</p>

<pre><code>#!/usr/bin/env python
import os, pickle, time

def normalise_num(n):
    "Neaten up the phone number, internationalise, etc."
    if n.startswith("+"):
        return n
    if n.startswith("00"):
        return "+" + n[2:]
    if len(n) == 10 and n[0] == "0":
        return "+27" + n[1:]
    return n

d = pickle.load(file("phonebook.dump", "r"))

# Normalise into a sensible format:
o = []
for i in d:
    t = {}
    for j in i["Entries"]:
        if j["Type"] == "Text_FirstName":
            t["First"] = j["Value"]
        if j["Type"] == "Text_LastName":
            t["Last"] = j["Value"]
        if j["Type"] == "Number_Other":
            n = normalise_num(j["Value"])
            type = "Home"
            if n[3] in ("7", "8"):
                type = "Cell"
            if type not in t:
                t[type] = []
            t[type].append(n)
    o.append(t)

# Write &amp; Send vCards:
for i in o:
    f = file("temp.vcf", "w")
    f.write("BEGIN:VCARD\n")
    f.write("VERSION:2.1\n")
    f.write("N:%s;%s;;;\n" % (i.get("Last", ""), i.get("First", "")))
    pref = ";PREF"
    for j in i["Cell"]:
        f.write("TEL;CELL%s:%s\n" % (pref, j))
        pref=""
    for j in i["Home"]:
        f.write("TEL;HOME%s:%s\n" % (pref, j))
        pref=""
    f.write("END:VCARD\n")
    f.close()
    os.system("obexftp -b 00:DE:AD:00:BE:EF -p temp.vcf")
    # Give the thing a chance to recover:
    time.sleep(0.1)
</code></pre>

<p>Yes, the normalisation could be done with list comprehensions, but it would be horrible to read. And there might by Python Obex bindings, but I couldn&#8217;t be bothered.</p>

<p>I got to spend an afternoon messing with dodgy Cellphones, rather than having a teenager do the job for free. I think I chose the wrong option, but at least it was fun.</p>

<p>Footnote: Samsung, your phones User Interface is <em>awful</em>. Why on earth is Bluetooth under &#8220;Applications&#8221; rather than &#8220;Settings&#8221;? I searched everywhere but there, and finally googled before I found it&#8230;</p>
    ]]></content>
  </entry>
  <entry>
    <title>Spam Spam Spam Spam, Spam Spam Spam Spam, Lovely Spam, Wonderful Spam</title>
    <link rel="alternate" type="text/html" href="http://tumbleweed.org.za/2008/04/12/spam-spam-spam-spam-spam-spam-spam-spam-lovely-spam-wonderful-spam" />
    <id>http://tumbleweed.org.za/2008/04/12/spam-spam-spam-spam-spam-spam-spam-spam-lovely-spam-wonderful-spam</id>
    <published>2008-04-12T14:35:57+01:00</published>
    <updated>2008-04-12T18:23:04+01:00</updated>
    <author>
      <name>tumbleweed</name>
    </author>
    <category term="rants" />
    <category term="sms" />
    <category term="south-africa" />
    <category term="spam" />
    <summary type="html"><![CDATA[<p>This morning I got an unsolicited SMS spam &#8220;Home owners ? do u need money? R100,000 @ R752 pm! Reply YES and we?ll phone you&#8221;. I know that everybody gets things like this and they just shrug them off, but I have a rabid hatred of spammers.</p>

<p>With e-mail spam, there&#8217;s normally nothing you can do. The spammers are on the other side of the world, and they&#8217;ve used a botnet. But when I get something from South Africans, I act. We have the ECT act protecting us against spam. It&#8217;s not the most effective anti-spam legislation, but it&#8217;s better than nothing. I&#8217;ll send the <a href="http://www.internet.org.za/spam_message.txt">IOZ Spam Message</a> to the spammers, their ISP, the domain registrants etc etc. Usually I get a response. Usually they remove me from their lists. (If they don&#8217;t, their VP of marketing is going to have me harassing him over the phone in short order.) But of course they rarely mend their ways. Sometimes we end up in long e-mail arguments backwards and forwards, them saying &#8220;but I&#8217;m justified in spamming, because of foo&#8221;, me saying &#8220;no bloody way, because of bar&#8221; etc. It&#8217;s ineffectual and depressing, but at least I&#8217;m doing <em>something</em> to deter spammers and keep South Africa relatively clean.</p>

<p>But enough about e-mail. It&#8217;s time for some tips on dealing with SMS-spam. The SMS Spamming industry (euphemisms: direct marketing, wireless application service provider) is attempting to regulate itself rather than be regulated by government. They&#8217;ve formed <a href="http://www.waspa.org.za/">WASPA</a> and signed the <a href="http://www.smscode.co.za/">sms code of practice</a>. WASPA lets you file complaints against its members and fines them (although the fines are rather paltry).</p>

<p>I heard about them via <a href="http://jerith.livejournal.com/42256.html">Jeremy Thurgood&#8217;s recent spam-scapades</a>. His spammers were charging R1 to opt-out. While the WASPA code of conduct allows a &lt;=R1 fee, I agree with him that this is intolerable extortion.</p>

<p>In my case, my spammers had broken a few WASPA <a href="http://www.waspa.org.za/code/index.shtml">code of conduct</a> rules:</p>

<ul>
<li>5.1.1.: They didn&#8217;t identify themselves in the SMS</li>
<li>5.1.2.: There is no opt-out facility that I know of.</li>
<li>5.1.4.: There is no advertised opt-out procedure.</li>
<li>5.2.1.: I&#8217;m very careful about not allowing people to spam me, so I&#8217;m pretty sure they failed all the options. I&#8217;d like them to prove otherwise.</li>
</ul>

<p>I looked up the originating number on the SMS Code website. It belongs to <a href="http://www.bulksms.com/">Celerity Systems</a>. They are currently under <a href="http://www.waspa.org.za/code/detail.php?id=3317">a suspended sentence</a> at WASPA, so my WASPA complaint should force them to fork out a fine. Lets hope for the best.</p>

<p>I&#8217;m against capital punishment, but I wouldn&#8217;t mind seeing a few spammers being hanged, drawn and quartered :-)</p>
    ]]></summary>
    <content type="html"><![CDATA[<p>This morning I got an unsolicited SMS spam &#8220;Home owners ? do u need money? R100,000 @ R752 pm! Reply YES and we?ll phone you&#8221;. I know that everybody gets things like this and they just shrug them off, but I have a rabid hatred of spammers.</p>

<p>With e-mail spam, there&#8217;s normally nothing you can do. The spammers are on the other side of the world, and they&#8217;ve used a botnet. But when I get something from South Africans, I act. We have the ECT act protecting us against spam. It&#8217;s not the most effective anti-spam legislation, but it&#8217;s better than nothing. I&#8217;ll send the <a href="http://www.internet.org.za/spam_message.txt">IOZ Spam Message</a> to the spammers, their ISP, the domain registrants etc etc. Usually I get a response. Usually they remove me from their lists. (If they don&#8217;t, their VP of marketing is going to have me harassing him over the phone in short order.) But of course they rarely mend their ways. Sometimes we end up in long e-mail arguments backwards and forwards, them saying &#8220;but I&#8217;m justified in spamming, because of foo&#8221;, me saying &#8220;no bloody way, because of bar&#8221; etc. It&#8217;s ineffectual and depressing, but at least I&#8217;m doing <em>something</em> to deter spammers and keep South Africa relatively clean.</p>

<p>But enough about e-mail. It&#8217;s time for some tips on dealing with SMS-spam. The SMS Spamming industry (euphemisms: direct marketing, wireless application service provider) is attempting to regulate itself rather than be regulated by government. They&#8217;ve formed <a href="http://www.waspa.org.za/">WASPA</a> and signed the <a href="http://www.smscode.co.za/">sms code of practice</a>. WASPA lets you file complaints against its members and fines them (although the fines are rather paltry).</p>

<p>I heard about them via <a href="http://jerith.livejournal.com/42256.html">Jeremy Thurgood&#8217;s recent spam-scapades</a>. His spammers were charging R1 to opt-out. While the WASPA code of conduct allows a &lt;=R1 fee, I agree with him that this is intolerable extortion.</p>

<p>In my case, my spammers had broken a few WASPA <a href="http://www.waspa.org.za/code/index.shtml">code of conduct</a> rules:</p>

<ul>
<li>5.1.1.: They didn&#8217;t identify themselves in the SMS</li>
<li>5.1.2.: There is no opt-out facility that I know of.</li>
<li>5.1.4.: There is no advertised opt-out procedure.</li>
<li>5.2.1.: I&#8217;m very careful about not allowing people to spam me, so I&#8217;m pretty sure they failed all the options. I&#8217;d like them to prove otherwise.</li>
</ul>

<p>I looked up the originating number on the SMS Code website. It belongs to <a href="http://www.bulksms.com/">Celerity Systems</a>. They are currently under <a href="http://www.waspa.org.za/code/detail.php?id=3317">a suspended sentence</a> at WASPA, so my WASPA complaint should force them to fork out a fine. Lets hope for the best.</p>

<p>I&#8217;m against capital punishment, but I wouldn&#8217;t mind seeing a few spammers being hanged, drawn and quartered :-)</p>
    ]]></content>
  </entry>
  <entry>
    <title>Bandwidth accounting with ulogd</title>
    <link rel="alternate" type="text/html" href="http://tumbleweed.org.za/2008/04/02/bandwidth-accounting-ulogd" />
    <id>http://tumbleweed.org.za/2008/04/02/bandwidth-accounting-ulogd</id>
    <published>2008-04-02T23:31:36+01:00</published>
    <updated>2008-04-05T14:32:01+01:00</updated>
    <author>
      <name>tumbleweed</name>
    </author>
    <category term="accounting" />
    <category term="debian" />
    <category term="iptables" />
    <category term="mysql" />
    <category term="technical" />
    <category term="traffic" />
    <category term="ulogd" />
    <summary type="html"><![CDATA[<p>My <a href="/2008/04/02/my-first-real-debian-repo">post about repositories</a> wasn&#8217;t just a <em>little</em> attempt to stave off work, it was part of a larger scheme.</p>

<p>I share the ADSL line in my digs with 3 other people. We do <a href="/local-only-dsl">split-routing</a> to save money, but we still have to divide the phone bill at the end of the month. Rather than buy a fixed cap, and have a fight over who&#8217;s fault it was when we get capped, we are running a pay-per-use system (with local use free, subsidised by me). It means you don&#8217;t have to restrain yourself for the common cap, but it also means I need to calculate who owes what.</p>

<p>For the first month, I used my old standby, <a href="http://bandwidthd.sourceforge.net/">bandwidthd</a>. It uses pcap to count traffic, and gives you totals and graphs. For simplicity of logging, I gave each person a /28 for their machines and configured static DHCP leases. Then bandwidthd totalled up the internet use for each /28.</p>

<p>This was sub-optimal. bandwidthd either sees the local network, in which case it can&#8217;t see which packets went out over which link. Or it can watch the international link, but then not know which user is responsible.</p>

<p>I could have installed some netflow utilities at this point, but I wanted to roll my own with the correct Linux approach (ulog) rather than any pcapping. <a href="http://www.netfilter.org/projects/ulogd/index.html">ulogd</a> is the easy ulog solution.</p>

<p>Ulogd can pick up packets that you &#8220;-j ULOG&#8221; from iptables. It receives them over a netlink interface. You can tell iptables how many bytes of each packet to send, and how many to queue up before sending them. E.g.</p>

<pre><code># iptables -I INPUT 1 -j ULOG --ulog-nlgroup 1 --ulog-qthreshold 50 --ulog-cprange 48 --ulog-prefix input
</code></pre>

<p>will log the first 48 bytes of any incoming packet to netlink-group 1. It will tag the packet as being &#8220;input&#8221;, and send them in batches of 50. 48 bytes is usually enough to catch any data you could want from the headers. If you were only need size, 4 bytes will do, and for source and destination as well, 20.</p>

<p>Now, we tell ulogd to listen for this stuff and log it. Ulogd has a pluggable architecture. IPv4 decoding is a plugin, and there are various logging plugins for &#8220;-j LOG&#8221; emulation, Text files, pcap-files, MySQL, PostgreSQL, and SQLite. For my purposes, I used MySQL as the router in question already had MySQL on it (for <a href="http://cacti.sourceforge.net/">Cacti</a>). Otherwise, I would have opted for SQLite. Be warned that the etch version of ulogd doesn&#8217;t automatically reconnect to the MySQL server should the connection break for any reason. I <a href="http://mirrors.tumbleweed.org.za/sr-backports/pool/main/u/ulogd/">backported the lenny version</a> to etch to get around that. (You also need to provide the <code>reconnect</code> and <code>connect_timeout</code> options.)</p>

<p>Besides the reconnection issue, the SQL implementations are quite nice. They have a set schema, and you just need to create a table with the columns in it that you are interested in. No other configuration (beyond connection details) is necessary.</p>

<p>My MySQL table:</p>

<pre><code>CREATE TABLE `ulog` (
  `id` int(10) unsigned NOT NULL auto_increment,
  `oob_time_sec` int(10) unsigned NOT NULL,
  `oob_prefix` char(4) NOT NULL,
  `ip_totlen` smallint(5) unsigned NOT NULL,
  PRIMARY KEY  (`id`),
  UNIQUE KEY `id` (`id`),
  KEY `oob_prefix` (`oob_prefix`),
  KEY `oob_time_sec` (`oob_time_sec`)
);
</code></pre>

<p>My ulogd.conf:</p>

<pre><code>[global]
# netlink multicast group (the same as the iptables --ulog-nlgroup param)
nlgroup=1    
# logfile for status messages
logfile="/var/log/ulog/ulogd.log"    
# loglevel: debug(1), info(3), notice(5), error(7) or fatal(8)
loglevel=5    
# socket receive buffer size (should be at least the size of the
# in-kernel buffer (ipt_ULOG.o 'nlbufsiz' parameter)
rmem=131071    
# libipulog/ulogd receive buffer size, should be &gt; rmem
bufsize=150000
# ulogd_BASE.so - interpreter plugin for basic IPv4 header fields
#             you will always need this
plugin="/usr/lib/ulogd/ulogd_BASE.so"
plugin="/usr/lib/ulogd/ulogd_MYSQL.so"

[MYSQL]
table="ulog"
pass="foo"
user="ulog"
db="ulog"
host="localhost"
reconnect=5
connect_timeout=10
</code></pre>

<p>The relevant parts of my firewall rules:</p>

<pre><code># Count proxy usage (transparent and explicit)
iptables -A count-from-inside -p ! tcp -j RETURN
iptables -A count-from-inside -p tcp -m multiport --destination-ports ! 3128,8080 -j RETURN
iptables -A count-from-inside -s 10.0.0.16/28 -j ULOG --ulog-nlgroup 1 --ulog-qthreshold 50 --ulog-cprange 4 --ulog-prefix sr-p
iptables -A count-from-inside -s 10.0.0.32/28 -j ULOG --ulog-nlgroup 1 --ulog-qthreshold 50 --ulog-cprange 4 --ulog-prefix fb-p
iptables -A count-from-inside -s 10.0.0.128/25 -j ULOG --ulog-nlgroup 1 --ulog-qthreshold 50 --ulog-cprange 4 --ulog-prefix gu-p

iptables -A count-to-inside -p ! tcp -j RETURN
iptables -A count-to-inside -p tcp -m multiport --source-ports ! 3128,8080 -j RETURN
iptables -A count-to-inside -d 10.0.0.16/28 -j ULOG --ulog-nlgroup 1 --ulog-qthreshold 50 --ulog-cprange 4 --ulog-prefix sr-p
iptables -A count-to-inside -d 10.0.0.32/28 -j ULOG --ulog-nlgroup 1 --ulog-qthreshold 50 --ulog-cprange 4 --ulog-prefix fb-p
iptables -A count-to-inside -d 10.0.0.128/25 -j ULOG --ulog-nlgroup 1 --ulog-qthreshold 50 --ulog-cprange 4 --ulog-prefix gu-p

# Count forwarded traffic (excluding local internet connection - ppp2)
iptables -A count-forward-in -i ppp2 -j RETURN
iptables -A count-forward-in -d 10.0.0.16/28 -j ULOG --ulog-nlgroup 1 --ulog-qthreshold 50 --ulog-cprange 4 --ulog-prefix sr-f
iptables -A count-forward-in -d 10.0.0.32/28 -j ULOG --ulog-nlgroup 1 --ulog-qthreshold 50 --ulog-cprange 4 --ulog-prefix fb-f
iptables -A count-forward-in -d 10.0.0.128/25 -j ULOG --ulog-nlgroup 1 --ulog-qthreshold 50 --ulog-cprange 4 --ulog-prefix gu-f

iptables -A count-forward-out -o ppp2 -j RETURN
iptables -A count-forward-out -s 10.0.0.16/28 -j ULOG --ulog-nlgroup 1 --ulog-qthreshold 50 --ulog-cprange 4 --ulog-prefix sr-f
iptables -A count-forward-out -s 10.0.0.32/28 -j ULOG --ulog-nlgroup 1 --ulog-qthreshold 50 --ulog-cprange 4 --ulog-prefix fb-f
iptables -A count-forward-out -s 10.0.0.128/25 -j ULOG --ulog-nlgroup 1 --ulog-qthreshold 50 --ulog-cprange 4 --ulog-prefix gu-f

# Glue
iptables -A INPUT -i eth0 -j count-from-inside
iptables -A OUTPUT  -o eth0 -j count-to-inside
iptables -A FORWARD -i ppp+ -j count-forward-in
iptables -A FORWARD -o ppp+ -j count-forward-out
</code></pre>

<p>So, traffic for my /28 (sr) will be counted as <code>sr-f</code> or <code>sr-p</code> so I can tally up proxy &amp; forwarded traffic separately. (Yes, I can count traffic with squid too, but doing it all in one place is simpler.) <code>fb</code> is random housemate Foo Bar, and <code>gu</code> guest (unreserved IP addresses).</p>

<p>You can query the usage this month with for example:</p>

<pre><code>SELECT oob_prefix, SUM(ip_totlen) FROM ulog WHERE oob_time_sec &gt; UNIX_TIMESTAMP('2008-04-01 00:00:00') GROUP BY oob_prefix;
</code></pre>

<p>Your table will fill up fast. We are averaging around 200 000 rows per day. So obviously some caching is in order:</p>

<pre><code>CREATE TABLE daily (
  id INT UNSIGNED NOT NULL AUTO_INCREMENT,
  time TIMESTAMP,
  oob_prefix CHAR(4) NOT NULL,
  data INT UNSIGNED NOT NULL,
  PRIMARY KEY (id),
  KEY (oob_prefix(4)),
  KEY (time)
);
</code></pre>

<p>And every night, run something like:</p>

<pre><code>INSERT INTO daily (time, oob_prefix, data)
SELECT FROM_UNIXTIME(MAX(oob_time_sec)), oob_prefix, SUM(ip_totlen)
FROM ulog
WHERE oob_time_sec &gt;= UNIX_TIMESTAMP('2008-04-01 00:00:00')
  AND oob_time_sec &lt; UNIX_TIMESTAMP('2008-04-02 00:00:00')
GROUP BY oob_prefix;
DELETE FROM ulog WHERE oob_time_sec  &gt;= UNIX_TIMESTAMP('2008-04-01 00:00:00')
  AND oob_time_sec &lt; UNIX_TIMESTAMP('2008-04-02 00:00:00');
</code></pre>

<p>Finally, I have a simple little PHP script that provides reporting and calculates dues. Done.</p>
    ]]></summary>
    <content type="html"><![CDATA[<p>My <a href="/2008/04/02/my-first-real-debian-repo">post about repositories</a> wasn&#8217;t just a <em>little</em> attempt to stave off work, it was part of a larger scheme.</p>

<p>I share the ADSL line in my digs with 3 other people. We do <a href="/local-only-dsl">split-routing</a> to save money, but we still have to divide the phone bill at the end of the month. Rather than buy a fixed cap, and have a fight over who&#8217;s fault it was when we get capped, we are running a pay-per-use system (with local use free, subsidised by me). It means you don&#8217;t have to restrain yourself for the common cap, but it also means I need to calculate who owes what.</p>

<p>For the first month, I used my old standby, <a href="http://bandwidthd.sourceforge.net/">bandwidthd</a>. It uses pcap to count traffic, and gives you totals and graphs. For simplicity of logging, I gave each person a /28 for their machines and configured static DHCP leases. Then bandwidthd totalled up the internet use for each /28.</p>

<p>This was sub-optimal. bandwidthd either sees the local network, in which case it can&#8217;t see which packets went out over which link. Or it can watch the international link, but then not know which user is responsible.</p>

<p>I could have installed some netflow utilities at this point, but I wanted to roll my own with the correct Linux approach (ulog) rather than any pcapping. <a href="http://www.netfilter.org/projects/ulogd/index.html">ulogd</a> is the easy ulog solution.</p>

<p>Ulogd can pick up packets that you &#8220;-j ULOG&#8221; from iptables. It receives them over a netlink interface. You can tell iptables how many bytes of each packet to send, and how many to queue up before sending them. E.g.</p>

<pre><code># iptables -I INPUT 1 -j ULOG --ulog-nlgroup 1 --ulog-qthreshold 50 --ulog-cprange 48 --ulog-prefix input
</code></pre>

<p>will log the first 48 bytes of any incoming packet to netlink-group 1. It will tag the packet as being &#8220;input&#8221;, and send them in batches of 50. 48 bytes is usually enough to catch any data you could want from the headers. If you were only need size, 4 bytes will do, and for source and destination as well, 20.</p>

<p>Now, we tell ulogd to listen for this stuff and log it. Ulogd has a pluggable architecture. IPv4 decoding is a plugin, and there are various logging plugins for &#8220;-j LOG&#8221; emulation, Text files, pcap-files, MySQL, PostgreSQL, and SQLite. For my purposes, I used MySQL as the router in question already had MySQL on it (for <a href="http://cacti.sourceforge.net/">Cacti</a>). Otherwise, I would have opted for SQLite. Be warned that the etch version of ulogd doesn&#8217;t automatically reconnect to the MySQL server should the connection break for any reason. I <a href="http://mirrors.tumbleweed.org.za/sr-backports/pool/main/u/ulogd/">backported the lenny version</a> to etch to get around that. (You also need to provide the <code>reconnect</code> and <code>connect_timeout</code> options.)</p>

<p>Besides the reconnection issue, the SQL implementations are quite nice. They have a set schema, and you just need to create a table with the columns in it that you are interested in. No other configuration (beyond connection details) is necessary.</p>

<p>My MySQL table:</p>

<pre><code>CREATE TABLE `ulog` (
  `id` int(10) unsigned NOT NULL auto_increment,
  `oob_time_sec` int(10) unsigned NOT NULL,
  `oob_prefix` char(4) NOT NULL,
  `ip_totlen` smallint(5) unsigned NOT NULL,
  PRIMARY KEY  (`id`),
  UNIQUE KEY `id` (`id`),
  KEY `oob_prefix` (`oob_prefix`),
  KEY `oob_time_sec` (`oob_time_sec`)
);
</code></pre>

<p>My ulogd.conf:</p>

<pre><code>[global]
# netlink multicast group (the same as the iptables --ulog-nlgroup param)
nlgroup=1    
# logfile for status messages
logfile="/var/log/ulog/ulogd.log"    
# loglevel: debug(1), info(3), notice(5), error(7) or fatal(8)
loglevel=5    
# socket receive buffer size (should be at least the size of the
# in-kernel buffer (ipt_ULOG.o 'nlbufsiz' parameter)
rmem=131071    
# libipulog/ulogd receive buffer size, should be &gt; rmem
bufsize=150000
# ulogd_BASE.so - interpreter plugin for basic IPv4 header fields
#             you will always need this
plugin="/usr/lib/ulogd/ulogd_BASE.so"
plugin="/usr/lib/ulogd/ulogd_MYSQL.so"

[MYSQL]
table="ulog"
pass="foo"
user="ulog"
db="ulog"
host="localhost"
reconnect=5
connect_timeout=10
</code></pre>

<p>The relevant parts of my firewall rules:</p>

<pre><code># Count proxy usage (transparent and explicit)
iptables -A count-from-inside -p ! tcp -j RETURN
iptables -A count-from-inside -p tcp -m multiport --destination-ports ! 3128,8080 -j RETURN
iptables -A count-from-inside -s 10.0.0.16/28 -j ULOG --ulog-nlgroup 1 --ulog-qthreshold 50 --ulog-cprange 4 --ulog-prefix sr-p
iptables -A count-from-inside -s 10.0.0.32/28 -j ULOG --ulog-nlgroup 1 --ulog-qthreshold 50 --ulog-cprange 4 --ulog-prefix fb-p
iptables -A count-from-inside -s 10.0.0.128/25 -j ULOG --ulog-nlgroup 1 --ulog-qthreshold 50 --ulog-cprange 4 --ulog-prefix gu-p

iptables -A count-to-inside -p ! tcp -j RETURN
iptables -A count-to-inside -p tcp -m multiport --source-ports ! 3128,8080 -j RETURN
iptables -A count-to-inside -d 10.0.0.16/28 -j ULOG --ulog-nlgroup 1 --ulog-qthreshold 50 --ulog-cprange 4 --ulog-prefix sr-p
iptables -A count-to-inside -d 10.0.0.32/28 -j ULOG --ulog-nlgroup 1 --ulog-qthreshold 50 --ulog-cprange 4 --ulog-prefix fb-p
iptables -A count-to-inside -d 10.0.0.128/25 -j ULOG --ulog-nlgroup 1 --ulog-qthreshold 50 --ulog-cprange 4 --ulog-prefix gu-p

# Count forwarded traffic (excluding local internet connection - ppp2)
iptables -A count-forward-in -i ppp2 -j RETURN
iptables -A count-forward-in -d 10.0.0.16/28 -j ULOG --ulog-nlgroup 1 --ulog-qthreshold 50 --ulog-cprange 4 --ulog-prefix sr-f
iptables -A count-forward-in -d 10.0.0.32/28 -j ULOG --ulog-nlgroup 1 --ulog-qthreshold 50 --ulog-cprange 4 --ulog-prefix fb-f
iptables -A count-forward-in -d 10.0.0.128/25 -j ULOG --ulog-nlgroup 1 --ulog-qthreshold 50 --ulog-cprange 4 --ulog-prefix gu-f

iptables -A count-forward-out -o ppp2 -j RETURN
iptables -A count-forward-out -s 10.0.0.16/28 -j ULOG --ulog-nlgroup 1 --ulog-qthreshold 50 --ulog-cprange 4 --ulog-prefix sr-f
iptables -A count-forward-out -s 10.0.0.32/28 -j ULOG --ulog-nlgroup 1 --ulog-qthreshold 50 --ulog-cprange 4 --ulog-prefix fb-f
iptables -A count-forward-out -s 10.0.0.128/25 -j ULOG --ulog-nlgroup 1 --ulog-qthreshold 50 --ulog-cprange 4 --ulog-prefix gu-f

# Glue
iptables -A INPUT -i eth0 -j count-from-inside
iptables -A OUTPUT  -o eth0 -j count-to-inside
iptables -A FORWARD -i ppp+ -j count-forward-in
iptables -A FORWARD -o ppp+ -j count-forward-out
</code></pre>

<p>So, traffic for my /28 (sr) will be counted as <code>sr-f</code> or <code>sr-p</code> so I can tally up proxy &amp; forwarded traffic separately. (Yes, I can count traffic with squid too, but doing it all in one place is simpler.) <code>fb</code> is random housemate Foo Bar, and <code>gu</code> guest (unreserved IP addresses).</p>

<p>You can query the usage this month with for example:</p>

<pre><code>SELECT oob_prefix, SUM(ip_totlen) FROM ulog WHERE oob_time_sec &gt; UNIX_TIMESTAMP('2008-04-01 00:00:00') GROUP BY oob_prefix;
</code></pre>

<p>Your table will fill up fast. We are averaging around 200 000 rows per day. So obviously some caching is in order:</p>

<pre><code>CREATE TABLE daily (
  id INT UNSIGNED NOT NULL AUTO_INCREMENT,
  time TIMESTAMP,
  oob_prefix CHAR(4) NOT NULL,
  data INT UNSIGNED NOT NULL,
  PRIMARY KEY (id),
  KEY (oob_prefix(4)),
  KEY (time)
);
</code></pre>

<p>And every night, run something like:</p>

<pre><code>INSERT INTO daily (time, oob_prefix, data)
SELECT FROM_UNIXTIME(MAX(oob_time_sec)), oob_prefix, SUM(ip_totlen)
FROM ulog
WHERE oob_time_sec &gt;= UNIX_TIMESTAMP('2008-04-01 00:00:00')
  AND oob_time_sec &lt; UNIX_TIMESTAMP('2008-04-02 00:00:00')
GROUP BY oob_prefix;
DELETE FROM ulog WHERE oob_time_sec  &gt;= UNIX_TIMESTAMP('2008-04-01 00:00:00')
  AND oob_time_sec &lt; UNIX_TIMESTAMP('2008-04-02 00:00:00');
</code></pre>

<p>Finally, I have a simple little PHP script that provides reporting and calculates dues. Done.</p>
    ]]></content>
  </entry>
  <entry>
    <title>My first (real) debian repo</title>
    <link rel="alternate" type="text/html" href="http://tumbleweed.org.za/2008/04/02/my-first-real-debian-repo" />
    <id>http://tumbleweed.org.za/2008/04/02/my-first-real-debian-repo</id>
    <published>2008-04-02T23:01:02+01:00</published>
    <updated>2008-04-02T23:05:44+01:00</updated>
    <author>
      <name>tumbleweed</name>
    </author>
    <category term="backport" />
    <category term="debian" />
    <category term="howto" />
    <category term="repository" />
    <category term="technical" />
    <summary type="html"><![CDATA[<p>Up to now, whenever I&#8217;ve needed a backport or debian recompile, I&#8217;ve done it locally. But finally last night, instead of studying for this morning&#8217;s exam, I decided to do it properly.</p>

<p>The tool for producing a debian archive tree is <a href="http://mirrorer.alioth.debian.org/">reprepro</a>. There are a <a href="http://www.debian-administration.org/articles/286">few</a> <a href="http://my.opera.com/atomo64/blog/howto-create-and-maintain-a-repository-using-reprepro-and-debabaretools?prevpoll=1">howtos</a> out there for it, but none of them quite covered everything I needed. So this is <em>mine</em>. But we&#8217;ll get to that later, first we need to have some packages to put up.</p>

<p>For building packages, I decided to do it properly and use <a href="http://www.netfort.gr.jp/~dancer/software/pbuilder-doc/pbuilder-doc.html">pbuilder</a>. Just install it:</p>

<pre><code># aptitude install pbuilder cdebootstrap devscripts
</code></pre>

<p>Make the following changes to <code>/etc/pbuilderrc</code>:</p>

<pre><code>MIRRORSITE=http://ftp.uk.debian.org/debian
DEBEMAIL="Your Name &lt;you@example.com&gt;"
</code></pre>

<p>The first, to point to your local mirror, and the second to credit you in the packages.</p>

<p>Then, as root:</p>

<pre><code># pbuilder create --distribution etch --debootstrapopts --variant=buildd
</code></pre>

<p>Now, we can build a package, lets build the <a href="http://packages.debian.org/lenny/hello">hello</a> package:</p>

<pre><code>$ mkdir /tmp/packaging; cd /tmp/packaging
$ gpg --recv-key 3EF23CD6
$ dget -x http://ftp.uk.debian.org/debian/pool/main/h/hello/hello_2.2-2.dsc
dpkg-source: extracting hello in hello-2.2
dpkg-source: unpacking hello_2.2.orig.tar.gz
dpkg-source: applying ./hello_2.2-2.diff.gz
$ cd hello-2.2/
$ debchange -n
</code></pre>

<p>dget and debchange are neat little utilities from <code>devscripts</code>. You can configure them to know your name, e-mail address, etc. If you work with debian packages a lot, you&#8217;ll get to know them well. Future versions of debchange support <code>--bpo</code> for backports, but we use <code>-n</code> which means new package. You should edit the version number in the top line to be a backport version, i.e.:</p>

<pre><code>hello (2.2-2~bpo-sr.1) etch-backports; urgency=low

  * Rebuild for etch-backports.

 -- Your Name &lt;you@example.com&gt;  Wed,  2 Apr 2008 22:24:30 +0100
</code></pre>

<p>Now, let&#8217;s build it. We are only doing a backport, but if you were making any changes, you&#8217;d do them before the next stage, and list them in the changelog you just edited:</p>

<pre><code>$ cd ..
$ dpkg-source -sa -b hello-2.2-2~bpo/
$ sudo pbuilder build hello_2.2-2~bpo-sr.1.dsc
</code></pre>

<p>Assuming no errors, the built package will be sitting in <code>/var/cache/pbuilder/result/</code>.</p>

<p>Now, for the repository:</p>

<pre><code>$ mkdir ~/public_html/backports
$ cd ~/public_html/backports
$ mkdir conf
$ cat &gt; conf/distributions &lt;&lt; EOF
Origin: Your Name
Label: Your Name's Backports
Suite: stable-backports
Codename: etch-backports
Version: 4.0
Architectures: i386 all source
Components: main
Description: Your Name's repository of etch backports.
SignWith: ABCDABCD
NotAutomatic: yes
EOF
</code></pre>

<p>This file defines your repository. The codename will be the distribution you list in your <code>sources.list</code>. The version should match it. The architectures are the architectures you are going to carry - &#8220;all&#8221; refers to non-architecture-specific packages, and source to source packages. I added amd64 to mine. SignWith is the ID of the GPG key you are going to use with this repo. I created a new DSA key for the job. NotAutomatic is a good setting for a backports repo, it means that packages won&#8217;t be installed from here unless explicitly requested (via <code>package=version</code> or <code>-d etch-backports</code>).</p>

<p>Let&#8217;s start by importing our source package:</p>

<pre><code>$ cd /tmp/packaging
$ debsign -kABCDABCD hello_2.2-2~bpo-sr.1.dsc
$ cd ~/public_html/backports
$ reprepro -P optional -S devel --ask-passphrase -Vb . includedsc etch-backports /tmp/packaging/hello_2.2-2~bpo-sr.1.dsc
</code></pre>

<p>(There is currently a <a href="http://bugs.debian.org/473609">known bug</a> in reprepro&#8217;s command-line handling. <code>-S</code> and <code>-P</code> are swapped.)</p>

<p>Now, let&#8217;s import our binary package:</p>

<pre><code>$ reprepro --ask-passphrase -Vb . includedeb etch-backports /var/cache/pbuilder/result/hello_2.2-2~bpo-sr.1_i386.deb
</code></pre>

<p>Reprepro can be automated with it&#8217;s <code>processincoming</code> command, but that&#8217;s beyond the scope of this howto.</p>

<p>Test your new repository, add it to your <code>/etc/apt/sources.list</code></p>

<pre><code>deb http://example.com/~you/backports etch-backports main

# aptitude update
# aptitude install hello=2.2-2~bpo-sr.1
</code></pre>

<p>Enjoy. My backports repository can be found <a href="http://mirrors.tumbleweed.org.za/sr-backports/">here</a>.</p>
    ]]></summary>
    <content type="html"><![CDATA[<p>Up to now, whenever I&#8217;ve needed a backport or debian recompile, I&#8217;ve done it locally. But finally last night, instead of studying for this morning&#8217;s exam, I decided to do it properly.</p>

<p>The tool for producing a debian archive tree is <a href="http://mirrorer.alioth.debian.org/">reprepro</a>. There are a <a href="http://www.debian-administration.org/articles/286">few</a> <a href="http://my.opera.com/atomo64/blog/howto-create-and-maintain-a-repository-using-reprepro-and-debabaretools?prevpoll=1">howtos</a> out there for it, but none of them quite covered everything I needed. So this is <em>mine</em>. But we&#8217;ll get to that later, first we need to have some packages to put up.</p>

<p>For building packages, I decided to do it properly and use <a href="http://www.netfort.gr.jp/~dancer/software/pbuilder-doc/pbuilder-doc.html">pbuilder</a>. Just install it:</p>

<pre><code># aptitude install pbuilder cdebootstrap devscripts
</code></pre>

<p>Make the following changes to <code>/etc/pbuilderrc</code>:</p>

<pre><code>MIRRORSITE=http://ftp.uk.debian.org/debian
DEBEMAIL="Your Name &lt;you@example.com&gt;"
</code></pre>

<p>The first, to point to your local mirror, and the second to credit you in the packages.</p>

<p>Then, as root:</p>

<pre><code># pbuilder create --distribution etch --debootstrapopts --variant=buildd
</code></pre>

<p>Now, we can build a package, lets build the <a href="http://packages.debian.org/lenny/hello">hello</a> package:</p>

<pre><code>$ mkdir /tmp/packaging; cd /tmp/packaging
$ gpg --recv-key 3EF23CD6
$ dget -x http://ftp.uk.debian.org/debian/pool/main/h/hello/hello_2.2-2.dsc
dpkg-source: extracting hello in hello-2.2
dpkg-source: unpacking hello_2.2.orig.tar.gz
dpkg-source: applying ./hello_2.2-2.diff.gz
$ cd hello-2.2/
$ debchange -n
</code></pre>

<p>dget and debchange are neat little utilities from <code>devscripts</code>. You can configure them to know your name, e-mail address, etc. If you work with debian packages a lot, you&#8217;ll get to know them well. Future versions of debchange support <code>--bpo</code> for backports, but we use <code>-n</code> which means new package. You should edit the version number in the top line to be a backport version, i.e.:</p>

<pre><code>hello (2.2-2~bpo-sr.1) etch-backports; urgency=low

  * Rebuild for etch-backports.

 -- Your Name &lt;you@example.com&gt;  Wed,  2 Apr 2008 22:24:30 +0100
</code></pre>

<p>Now, let&#8217;s build it. We are only doing a backport, but if you were making any changes, you&#8217;d do them before the next stage, and list them in the changelog you just edited:</p>

<pre><code>$ cd ..
$ dpkg-source -sa -b hello-2.2-2~bpo/
$ sudo pbuilder build hello_2.2-2~bpo-sr.1.dsc
</code></pre>

<p>Assuming no errors, the built package will be sitting in <code>/var/cache/pbuilder/result/</code>.</p>

<p>Now, for the repository:</p>

<pre><code>$ mkdir ~/public_html/backports
$ cd ~/public_html/backports
$ mkdir conf
$ cat &gt; conf/distributions &lt;&lt; EOF
Origin: Your Name
Label: Your Name's Backports
Suite: stable-backports
Codename: etch-backports
Version: 4.0
Architectures: i386 all source
Components: main
Description: Your Name's repository of etch backports.
SignWith: ABCDABCD
NotAutomatic: yes
EOF
</code></pre>

<p>This file defines your repository. The codename will be the distribution you list in your <code>sources.list</code>. The version should match it. The architectures are the architectures you are going to carry - &#8220;all&#8221; refers to non-architecture-specific packages, and source to source packages. I added amd64 to mine. SignWith is the ID of the GPG key you are going to use with this repo. I created a new DSA key for the job. NotAutomatic is a good setting for a backports repo, it means that packages won&#8217;t be installed from here unless explicitly requested (via <code>package=version</code> or <code>-d etch-backports</code>).</p>

<p>Let&#8217;s start by importing our source package:</p>

<pre><code>$ cd /tmp/packaging
$ debsign -kABCDABCD hello_2.2-2~bpo-sr.1.dsc
$ cd ~/public_html/backports
$ reprepro -P optional -S devel --ask-passphrase -Vb . includedsc etch-backports /tmp/packaging/hello_2.2-2~bpo-sr.1.dsc
</code></pre>

<p>(There is currently a <a href="http://bugs.debian.org/473609">known bug</a> in reprepro&#8217;s command-line handling. <code>-S</code> and <code>-P</code> are swapped.)</p>

<p>Now, let&#8217;s import our binary package:</p>

<pre><code>$ reprepro --ask-passphrase -Vb . includedeb etch-backports /var/cache/pbuilder/result/hello_2.2-2~bpo-sr.1_i386.deb
</code></pre>

<p>Reprepro can be automated with it&#8217;s <code>processincoming</code> command, but that&#8217;s beyond the scope of this howto.</p>

<p>Test your new repository, add it to your <code>/etc/apt/sources.list</code></p>

<pre><code>deb http://example.com/~you/backports etch-backports main

# aptitude update
# aptitude install hello=2.2-2~bpo-sr.1
</code></pre>

<p>Enjoy. My backports repository can be found <a href="http://mirrors.tumbleweed.org.za/sr-backports/">here</a>.</p>
    ]]></content>
  </entry>
  <entry>
    <title>I&#039;m a Google Reader convert</title>
    <link rel="alternate" type="text/html" href="http://tumbleweed.org.za/2008/03/12/im-google-reader-convert" />
    <id>http://tumbleweed.org.za/2008/03/12/im-google-reader-convert</id>
    <published>2008-03-12T20:51:03+00:00</published>
    <updated>2008-03-12T20:51:03+00:00</updated>
    <author>
      <name>tumbleweed</name>
    </author>
    <category term="google" />
    <category term="google-reader" />
    <category term="internet" />
    <category term="rss" />
    <category term="technical" />
    <summary type="html"><![CDATA[<p>My blog hasn&#8217;t had much to say recently, but now that I&#8217;m feeling pressured by University assignments, I think it&#8217;s time to get back into one-post-per-day mode :-)</p>

<p>I remember once trying <a href="http://www.google.com/reader">Google Reader</a>, just after it launched, and very quickly deciding that I couldn&#8217;t stand it, and I&#8217;d stick to <a href="http://liferea.sourceforge.net/">Liferea</a>.</p>

<p>Recently, however, Liferea has been giving me trouble. It&#8217;s been incredibly unstable, and I&#8217;d often forgot to run a transparent proxy on my laptop when in restrictive environments, so it&#8217;d miss lots of posts and generally be un-happy. The instability I fixed by exporting an OPML list, wiping the configuration, and re-loading, but that was a ball-ache to do. While I was bitching about this, <a href="http://vhata.net/" title="Jonathan Hitchcock">Vhata</a> pushed me to try Google Reader again.</p>

<p>I was pleasantly surprised. It works well, and I didn&#8217;t find it oppressive. That doesn&#8217;t mean it&#8217;s perfect, I&#8217;d like to see the following things improved:</p>

<ul>
<li>Duplicate post detection (i.e. planetified &amp; origional posts, liferea does this)</li>
<li>Performance</li>
<li>Favicons (or something similar, to make it more clear where a post comes from)</li>
<li>On that note, maybe configurable colour borders for important feeds?</li>
<li>Automatic refreshing (i.e. &#8220;r&#8221;)</li>
<li>More viewable area</li>
<li>A key press for opening a post in a <em>backgrounded</em> new tab &#8220;v&#8221; changes your focus to the new tab, which is against the principles of tabbed browsing.</li>
</ul>

<p>Some cool things it does that lifera doesn&#8217;t:</p>

<ul>
<li>Clicking on a folder shows you the all the posts from the feeds in that folder</li>
<li>&#8220;river of posts&#8221; view, which lets me get through my reading a <em>lot</em> faster</li>
<li>preloading images for posts that I haven&#8217;t got to yet (this contributes a fair whack to the reading speed, given the slow interwebs in ZA)</li>
<li>Shared items</li>
<li>Access from multiple machines (OX, X-forwarding worked, but this is neater)</li>
<li>Doesn&#8217;t crash (sorry lifrea&#8230;)</li>
</ul>

<p>I&#8217;m converted. Google Reader <em>really</em> is good.</p>

<p>/me gets on with reading feeds&#8230;</p>
    ]]></summary>
    <content type="html"><![CDATA[<p>My blog hasn&#8217;t had much to say recently, but now that I&#8217;m feeling pressured by University assignments, I think it&#8217;s time to get back into one-post-per-day mode :-)</p>

<p>I remember once trying <a href="http://www.google.com/reader">Google Reader</a>, just after it launched, and very quickly deciding that I couldn&#8217;t stand it, and I&#8217;d stick to <a href="http://liferea.sourceforge.net/">Liferea</a>.</p>

<p>Recently, however, Liferea has been giving me trouble. It&#8217;s been incredibly unstable, and I&#8217;d often forgot to run a transparent proxy on my laptop when in restrictive environments, so it&#8217;d miss lots of posts and generally be un-happy. The instability I fixed by exporting an OPML list, wiping the configuration, and re-loading, but that was a ball-ache to do. While I was bitching about this, <a href="http://vhata.net/" title="Jonathan Hitchcock">Vhata</a> pushed me to try Google Reader again.</p>

<p>I was pleasantly surprised. It works well, and I didn&#8217;t find it oppressive. That doesn&#8217;t mean it&#8217;s perfect, I&#8217;d like to see the following things improved:</p>

<ul>
<li>Duplicate post detection (i.e. planetified &amp; origional posts, liferea does this)</li>
<li>Performance</li>
<li>Favicons (or something similar, to make it more clear where a post comes from)</li>
<li>On that note, maybe configurable colour borders for important feeds?</li>
<li>Automatic refreshing (i.e. &#8220;r&#8221;)</li>
<li>More viewable area</li>
<li>A key press for opening a post in a <em>backgrounded</em> new tab &#8220;v&#8221; changes your focus to the new tab, which is against the principles of tabbed browsing.</li>
</ul>

<p>Some cool things it does that lifera doesn&#8217;t:</p>

<ul>
<li>Clicking on a folder shows you the all the posts from the feeds in that folder</li>
<li>&#8220;river of posts&#8221; view, which lets me get through my reading a <em>lot</em> faster</li>
<li>preloading images for posts that I haven&#8217;t got to yet (this contributes a fair whack to the reading speed, given the slow interwebs in ZA)</li>
<li>Shared items</li>
<li>Access from multiple machines (OX, X-forwarding worked, but this is neater)</li>
<li>Doesn&#8217;t crash (sorry lifrea&#8230;)</li>
</ul>

<p>I&#8217;m converted. Google Reader <em>really</em> is good.</p>

<p>/me gets on with reading feeds&#8230;</p>
    ]]></content>
  </entry>
  <entry>
    <title>*Camp Videos</title>
    <link rel="alternate" type="text/html" href="http://tumbleweed.org.za/2008/02/25/camp-videos" />
    <id>http://tumbleweed.org.za/2008/02/25/camp-videos</id>
    <published>2008-02-25T22:13:40+00:00</published>
    <updated>2008-02-25T22:13:40+00:00</updated>
    <author>
      <name>tumbleweed</name>
    </author>
    <category term="starcamp" />
    <category term="video" />
    <summary type="html"><![CDATA[<p>I&#8217;ve (finally) finished encoding the ~6 hours of *camp video. They can be found on <a href="http://www.archive.org/details/starcamp-cpt-2007">archive.org</a>. As usual, 3 qualities.</p>

<p>I&#8217;ve probably screwed up at least one of them, so if anyone spots a problem, please let me know soon, before I delete the source material.</p>
    ]]></summary>
    <content type="html"><![CDATA[<p>I&#8217;ve (finally) finished encoding the ~6 hours of *camp video. They can be found on <a href="http://www.archive.org/details/starcamp-cpt-2007">archive.org</a>. As usual, 3 qualities.</p>

<p>I&#8217;ve probably screwed up at least one of them, so if anyone spots a problem, please let me know soon, before I delete the source material.</p>
    ]]></content>
  </entry>
  <entry>
    <title>Irssi libnotify integration</title>
    <link rel="alternate" type="text/html" href="http://tumbleweed.org.za/2008/02/24/irssi-lbinotiy-integreation" />
    <id>http://tumbleweed.org.za/2008/02/24/irssi-lbinotiy-integreation</id>
    <published>2008-02-24T22:20:24+00:00</published>
    <updated>2008-02-25T07:29:48+00:00</updated>
    <author>
      <name>tumbleweed</name>
    </author>
    <category term="irc" />
    <category term="irssi" />
    <category term="jabber" />
    <category term="libnotify" />
    <category term="technical" />
    <category term="xmpp" />
    <summary type="html"><![CDATA[<p>I came across irssi-libnotify integration in <a href="http://www.siltala.net/wp-content/uploads/2008/02/oskar-080218.png">a picture</a> in blog post I read this morning.</p>

<p>I thought about this, and decided that this was something I had to have. I often don&#8217;t pay attention to my IRC while I&#8217;m busy with something else, and miss out on a conversation that I&#8217;m being hailed in. (By something else, I&#8217;m meaning non-important, non-masked-interrupts-something-else.)</p>

<p>It isn&#8217;t an easy problem to solve, though. Irssi is running on a remote machine inside screen. I&#8217;ll be accessing it from one of many machines, possibly NATed, and possibly unable to receive incoming TCP connections.</p>

<p>I googled around a bit, and came across 3 main classes of solution to this problem:</p>

<ol>
<li>Run libnotify directly on the irssi-box, and use ssh&#8217;s X-forwarding to display it on my client. This is sub-optimal, because your X server isn&#8217;t always available. Example: <a href="http://code.google.com/p/irssi-libnotify/">irssi-libnotify</a> (which requires the module to be reloaded every time you re-attach screen)</li>
<li>Output all hilighted messages to a log file (using fnotfiy), and tail that log file with a second ssh session into a local script that calls libnotify. Sub-optimal, because it requires manually running a second ssh session, and restarting it in the event of network issues. <a href="http://pthree.org/2007/03/21/irssi-gui-notify/">Example</a></li>
<li>Send notify events down the Print Channel of the terminal. This will pass through screen, and pop out at your terminal-emulator. xterm and rxvt are both capable of then sending them to an arbitrary command (which could call libnotify). This is quite a clever hack, except that gnome-terminal doesn&#8217;t support it. <a href="http://jaredquinn.info/it-related/technical/unix/2007.09.25/libnotify-with-irssi-over-ssh/">Example</a></li>
</ol>

<p>As you can see, they all have major short-comings, and I wasn&#8217;t about to implement any of them.</p>

<p>Finally, I realized that Jabber would be a good way to hail me. My laptop / desktop / n800 / foo all run jabber clients. Perfect. I googled, and found a few pre-canned solutions. I settled for <a href="http://da.weeno.net/code/irssi/jabber_hilight_notify/">jabber-hilight-notify</a>. It runs a jabber client in a perl irssi script. This then sends me a message whenever a hilighted line crops up. (Assuming I&#8217;m not in &#8220;Do Not Distrub&#8221; mode)</p>

<p>I initially had some problems with getting jabber-hilight-notify working. It turns out that setting a custom resource string is a bad idea. My final config was:</p>

<pre><code>jabber_hilight_notify_target = stefano@rivera.za.net
jabber_password = xxxxxxxx
jabber_id = irssi@rivera.za.net
jabber_server_reconnect_time = 60
jabber_hilight_notify_target_presence = online chat away xa
jabber_hilight_notify_when_away = OFF
</code></pre>

<p>My Pidgin provides the libnotify integration, although jabber-hilight-notify&#8217;s designed to work with <a href="http://da.weeno.net/code/tavu/">Tavu</a> (a desktop-notification frontend for KDE). I think a better approach would be to use Telepathy. If such a general telepathy-based solution could be found, then it would be easy to have multiple remote daemons send notifications to you via jabber transport.</p>

<p>Now to see if I&#8217;m still happy with it after a week of it interrupting me.</p>
    ]]></summary>
    <content type="html"><![CDATA[<p>I came across irssi-libnotify integration in <a href="http://www.siltala.net/wp-content/uploads/2008/02/oskar-080218.png">a picture</a> in blog post I read this morning.</p>

<p>I thought about this, and decided that this was something I had to have. I often don&#8217;t pay attention to my IRC while I&#8217;m busy with something else, and miss out on a conversation that I&#8217;m being hailed in. (By something else, I&#8217;m meaning non-important, non-masked-interrupts-something-else.)</p>

<p>It isn&#8217;t an easy problem to solve, though. Irssi is running on a remote machine inside screen. I&#8217;ll be accessing it from one of many machines, possibly NATed, and possibly unable to receive incoming TCP connections.</p>

<p>I googled around a bit, and came across 3 main classes of solution to this problem:</p>

<ol>
<li>Run libnotify directly on the irssi-box, and use ssh&#8217;s X-forwarding to display it on my client. This is sub-optimal, because your X server isn&#8217;t always available. Example: <a href="http://code.google.com/p/irssi-libnotify/">irssi-libnotify</a> (which requires the module to be reloaded every time you re-attach screen)</li>
<li>Output all hilighted messages to a log file (using fnotfiy), and tail that log file with a second ssh session into a local script that calls libnotify. Sub-optimal, because it requires manually running a second ssh session, and restarting it in the event of network issues. <a href="http://pthree.org/2007/03/21/irssi-gui-notify/">Example</a></li>
<li>Send notify events down the Print Channel of the terminal. This will pass through screen, and pop out at your terminal-emulator. xterm and rxvt are both capable of then sending them to an arbitrary command (which could call libnotify). This is quite a clever hack, except that gnome-terminal doesn&#8217;t support it. <a href="http://jaredquinn.info/it-related/technical/unix/2007.09.25/libnotify-with-irssi-over-ssh/">Example</a></li>
</ol>

<p>As you can see, they all have major short-comings, and I wasn&#8217;t about to implement any of them.</p>

<p>Finally, I realized that Jabber would be a good way to hail me. My laptop / desktop / n800 / foo all run jabber clients. Perfect. I googled, and found a few pre-canned solutions. I settled for <a href="http://da.weeno.net/code/irssi/jabber_hilight_notify/">jabber-hilight-notify</a>. It runs a jabber client in a perl irssi script. This then sends me a message whenever a hilighted line crops up. (Assuming I&#8217;m not in &#8220;Do Not Distrub&#8221; mode)</p>

<p>I initially had some problems with getting jabber-hilight-notify working. It turns out that setting a custom resource string is a bad idea. My final config was:</p>

<pre><code>jabber_hilight_notify_target = stefano@rivera.za.net
jabber_password = xxxxxxxx
jabber_id = irssi@rivera.za.net
jabber_server_reconnect_time = 60
jabber_hilight_notify_target_presence = online chat away xa
jabber_hilight_notify_when_away = OFF
</code></pre>

<p>My Pidgin provides the libnotify integration, although jabber-hilight-notify&#8217;s designed to work with <a href="http://da.weeno.net/code/tavu/">Tavu</a> (a desktop-notification frontend for KDE). I think a better approach would be to use Telepathy. If such a general telepathy-based solution could be found, then it would be easy to have multiple remote daemons send notifications to you via jabber transport.</p>

<p>Now to see if I&#8217;m still happy with it after a week of it interrupting me.</p>
    ]]></content>
  </entry>
  <entry>
    <title>Just what is Universally Unique</title>
    <link rel="alternate" type="text/html" href="http://tumbleweed.org.za/2008/02/16/just-what-universally-unique" />
    <id>http://tumbleweed.org.za/2008/02/16/just-what-universally-unique</id>
    <published>2008-02-16T20:31:25+00:00</published>
    <updated>2008-02-16T20:34:44+00:00</updated>
    <author>
      <name>tumbleweed</name>
    </author>
    <category term="bug" />
    <category term="linux" />
    <category term="technical" />
    <category term="ubuntu" />
    <summary type="html"><![CDATA[<p>I had an interesting discussion with &#8220;bonnyrsa&#8221; in #ubuntu-za today. He&#8217;d re-arranged his partitions with gparted, and copied and pasted his / partition, so that he could move it to the end of the disk.</p>

<p>However this meant that he now had two partitions with the same <a href="http://en.wikipedia.org/wiki/UUID">UUID</a>. While you can imagine that this is the correct result of a copy &amp; paste operation, it now means that your <em>universally unique</em> ID is totally non-unique. Not in your PC, and no even on it&#8217;s home drive.</p>

<p>Ubuntu mounts by UUID, so now how do we know which partition is being mounted?</p>

<ul>
<li>&#8220;mount&#8221; said /dev/sda2</li>
<li>/proc/mounts said /dev/disk/by-uuid/c087bad7-5021-4f65-bb97-e0d3ea9d01a6 which was a symlink to /dev/sda2.</li>
</ul>

<p>However neither were correct.</p>

<p>Mounting /dev/sda4 (ro) produced &#8220;/dev/sda4 already mounted or /mnt busy&#8221;.</p>

<p>Aha, so we must be running from /dev/sda4.</p>

<p>/dev/sda2 mounted fine, but then wouldn&#8217;t unmount: &#8220;it seems /dev/sda2 is mounted multiple times&#8221;.</p>

<p>Aaaargh!</p>

<p>I got him to reboot, change /dev/sda2s UUID, and reboot again (sucks). Then everything was better.</p>

<p>This shouldn&#8217;t have happened. Non-unique UUIDs is a really crap situation to be in. It brings out bugs in all sorts of unexpected places. I think parted should (by default) change the UUID of a copied partition (although if you are copying an entire disk, it shouldn&#8217;t).</p>

<p>I&#8217;ve filed a <a href="https://bugs.launchpad.net/bugs/192471">bug</a> on Launchpad, let&#8217;s see if anyone bites.</p>

<p>PS: All UUIDs in this post have been changed to protect the identity of innocent Ubuntu systems (who aren&#8217;t expecting a sudden attack of non-uniqueness).</p>
    ]]></summary>
    <content type="html"><![CDATA[<p>I had an interesting discussion with &#8220;bonnyrsa&#8221; in #ubuntu-za today. He&#8217;d re-arranged his partitions with gparted, and copied and pasted his / partition, so that he could move it to the end of the disk.</p>

<p>However this meant that he now had two partitions with the same <a href="http://en.wikipedia.org/wiki/UUID">UUID</a>. While you can imagine that this is the correct result of a copy &amp; paste operation, it now means that your <em>universally unique</em> ID is totally non-unique. Not in your PC, and no even on it&#8217;s home drive.</p>

<p>Ubuntu mounts by UUID, so now how do we know which partition is being mounted?</p>

<ul>
<li>&#8220;mount&#8221; said /dev/sda2</li>
<li>/proc/mounts said /dev/disk/by-uuid/c087bad7-5021-4f65-bb97-e0d3ea9d01a6 which was a symlink to /dev/sda2.</li>
</ul>

<p>However neither were correct.</p>

<p>Mounting /dev/sda4 (ro) produced &#8220;/dev/sda4 already mounted or /mnt busy&#8221;.</p>

<p>Aha, so we must be running from /dev/sda4.</p>

<p>/dev/sda2 mounted fine, but then wouldn&#8217;t unmount: &#8220;it seems /dev/sda2 is mounted multiple times&#8221;.</p>

<p>Aaaargh!</p>

<p>I got him to reboot, change /dev/sda2s UUID, and reboot again (sucks). Then everything was better.</p>

<p>This shouldn&#8217;t have happened. Non-unique UUIDs is a really crap situation to be in. It brings out bugs in all sorts of unexpected places. I think parted should (by default) change the UUID of a copied partition (although if you are copying an entire disk, it shouldn&#8217;t).</p>

<p>I&#8217;ve filed a <a href="https://bugs.launchpad.net/bugs/192471">bug</a> on Launchpad, let&#8217;s see if anyone bites.</p>

<p>PS: All UUIDs in this post have been changed to protect the identity of innocent Ubuntu systems (who aren&#8217;t expecting a sudden attack of non-uniqueness).</p>
    ]]></content>
  </entry>
  <entry>
    <title>Madwifi regdomain issues</title>
    <link rel="alternate" type="text/html" href="http://tumbleweed.org.za/2008/02/11/madwifi-regdomain-issues" />
    <id>http://tumbleweed.org.za/2008/02/11/madwifi-regdomain-issues</id>
    <published>2008-02-11T22:39:49+00:00</published>
    <updated>2008-02-12T08:46:35+00:00</updated>
    <author>
      <name>tumbleweed</name>
    </author>
    <category term="countrycode" />
    <category term="fcc" />
    <category term="linux" />
    <category term="macbook" />
    <category term="madwifi" />
    <category term="regdomain" />
    <category term="technical" />
    <category term="uct" />
    <category term="wireless" />
    <summary type="html"><![CDATA[<p>The <a href="http://www.cs.uct.ac.za/">CS Department</a> at <a href="http://www.uct.ac.za/">UCT</a> has some Wireless APs on <a href="http://en.wikipedia.org/wiki/List_of_WLAN_channels">Channel 13</a>. This is quite cool (for geeky reasons), but my MacBook (purchased in the US) did not agree. As far as it is concerned, the only 802.11g channels in existence are 1-11.</p>

<p>The reason for this is that my <a href="http://www.atheros.com/">Atheros</a> (<a href="http://madwifi.org/">madwifi</a>) network card is a <a href="http://en.wikipedia.org/wiki/Software-defined_radio">software-defined radio</a>. Atheros interprets the FCC regulations to mean that it cannot provide an Open Source driver for this card, allowing it broadcast on any random channel. Thus the madwifi driver contains a binary HAL, produced by Atheros, which is responsible for regulating frequencies and power levels. (This HAL has been <a href="http://madwifi.org/wiki/About/ath5k">reverse-engineered</a> by the OpenBSD people, but not for my card, unfortunately).</p>

<p>The card has two values stored in it&#8217;s EEPROM, a &#8220;countrycode&#8221;, and a &#8220;regdomain&#8221;. The <a href="http://madwifi.org/wiki/UserDocs/CountryCode">countrycode</a> is overrideable in software (you <code>modprobe ath_pci countrycode=710</code>), but only if the countrycode you specify is valid for the card&#8217;s regdomain. Some cards have a 0x00 or 0xFF regdomain (wildcard values), but mine had 0x64. This meant that whenever I tried to specify a country code, I&#8217;d get an error, and the madwifi module would refuse to load:</p>

<pre><code>Feb 11 11:34:11 beethoven kernel: [ 2047.669023] MadWifi: ath_getchannels: Unable to collect channel list from HAL; regdomain likely 100 country code 710
</code></pre>

<p>There has been some success with changing the regdomain in the EEPROM, using the hard-to-find <code>ar5k</code> utility (or possible the <code>ath_info</code> utility?). However, <em>again</em> this didn&#8217;t work with my model. But I found <a href="https://lists.ath5k.org/pipermail/ath5k-devel/2007-December/000371.html">an e-mail</a> from somebody who&#8217;d been playing with similar stuff. I mailed Salvatore, and he replied almost instantly, pointing me to a <a href="http://www.tamos.com/products/commwifi/faq.php#q75">public Windows utility</a> for changing regdomains. It depends on a special driver, available in the demo of &#8220;<a href="http://www.tamos.com/products/commwifi/">CommView for Wireless</a>&#8221;.</p>

<p>I installed Windows in my swap partition (it&#8217;s not an operating system I normally have around). (Naturally, I forgot to have an Ubuntu CD handy, to rebuild my grub, but that was easily remedied.). After a few blue screens of death (install all necessary drivers first), I got my regdomain changed to 0x37, which is the regdomain for South Africa &amp; Europe.</p>

<p>Now, I&#8217;m writing this from a couch in the CS department, using a channel 13 AP. Success.</p>
    ]]></summary>
    <content type="html"><![CDATA[<p>The <a href="http://www.cs.uct.ac.za/">CS Department</a> at <a href="http://www.uct.ac.za/">UCT</a> has some Wireless APs on <a href="http://en.wikipedia.org/wiki/List_of_WLAN_channels">Channel 13</a>. This is quite cool (for geeky reasons), but my MacBook (purchased in the US) did not agree. As far as it is concerned, the only 802.11g channels in existence are 1-11.</p>

<p>The reason for this is that my <a href="http://www.atheros.com/">Atheros</a> (<a href="http://madwifi.org/">madwifi</a>) network card is a <a href="http://en.wikipedia.org/wiki/Software-defined_radio">software-defined radio</a>. Atheros interprets the FCC regulations to mean that it cannot provide an Open Source driver for this card, allowing it broadcast on any random channel. Thus the madwifi driver contains a binary HAL, produced by Atheros, which is responsible for regulating frequencies and power levels. (This HAL has been <a href="http://madwifi.org/wiki/About/ath5k">reverse-engineered</a> by the OpenBSD people, but not for my card, unfortunately).</p>

<p>The card has two values stored in it&#8217;s EEPROM, a &#8220;countrycode&#8221;, and a &#8220;regdomain&#8221;. The <a href="http://madwifi.org/wiki/UserDocs/CountryCode">countrycode</a> is overrideable in software (you <code>modprobe ath_pci countrycode=710</code>), but only if the countrycode you specify is valid for the card&#8217;s regdomain. Some cards have a 0x00 or 0xFF regdomain (wildcard values), but mine had 0x64. This meant that whenever I tried to specify a country code, I&#8217;d get an error, and the madwifi module would refuse to load:</p>

<pre><code>Feb 11 11:34:11 beethoven kernel: [ 2047.669023] MadWifi: ath_getchannels: Unable to collect channel list from HAL; regdomain likely 100 country code 710
</code></pre>

<p>There has been some success with changing the regdomain in the EEPROM, using the hard-to-find <code>ar5k</code> utility (or possible the <code>ath_info</code> utility?). However, <em>again</em> this didn&#8217;t work with my model. But I found <a href="https://lists.ath5k.org/pipermail/ath5k-devel/2007-December/000371.html">an e-mail</a> from somebody who&#8217;d been playing with similar stuff. I mailed Salvatore, and he replied almost instantly, pointing me to a <a href="http://www.tamos.com/products/commwifi/faq.php#q75">public Windows utility</a> for changing regdomains. It depends on a special driver, available in the demo of &#8220;<a href="http://www.tamos.com/products/commwifi/">CommView for Wireless</a>&#8221;.</p>

<p>I installed Windows in my swap partition (it&#8217;s not an operating system I normally have around). (Naturally, I forgot to have an Ubuntu CD handy, to rebuild my grub, but that was easily remedied.). After a few blue screens of death (install all necessary drivers first), I got my regdomain changed to 0x37, which is the regdomain for South Africa &amp; Europe.</p>

<p>Now, I&#8217;m writing this from a couch in the CS department, using a channel 13 AP. Success.</p>
    ]]></content>
  </entry>
  <entry>
    <title>A telecoms rant</title>
    <link rel="alternate" type="text/html" href="http://tumbleweed.org.za/2008/02/10/telecoms-rant" />
    <id>http://tumbleweed.org.za/2008/02/10/telecoms-rant</id>
    <published>2008-02-10T12:43:49+00:00</published>
    <updated>2008-02-10T12:43:49+00:00</updated>
    <author>
      <name>tumbleweed</name>
    </author>
    <category term="rant" />
    <category term="south-africa" />
    <category term="telecoms" />
    <category term="telkom" />
    <category term="vodacom" />
    <summary type="html"><![CDATA[<p>You&#8217;d think that telecoms (esp in South Africa, where being one is a license to print money) would do everything they could to get you to spend money with them? If only.</p>

<p>Cellphones (at least Vodacom) have always required you to manually enable International phone calls &amp; International roaming, by giving them a call and requesting it. This is a pain, to say the least. And you normally forget until you are already in another country.</p>

<p>But Telkom have taken this to a new level. I got a new phone line last month (which still doesn&#8217;t have working DSL, grr!), and just noticed that I can&#8217;t make International calls on it. So I phone telkom. Amazingly I didn&#8217;t have to wait on hold at all (something never before experienced when calling the beast), and the lady I spoke to told me I have to &#8220;Visit a Telkom Shop with my ID&#8221;. WTF? How hard are they making it to spend money on them?</p>

<p>Is there any legitimate reason that international calls are blocked? With our pricing, it&#8217;s easy to knock up a multi-k-ZAR bill without even thinking about dialling an international number, so they aren&#8217;t protecting anyone.</p>

<p>In related news, the reason you can&#8217;t have incoming connections on Vodacom 3G (even with &#8220;internetvpn&#8221;) is because then you&#8217;d be liable for the cost of any DOS you received. Isn&#8217;t this a problem that hosting providers and ISPs already have to deal with? Why are mobile operators special? We need some Internet Neutrality and Telecoms sense in this country&#8230;</p>
    ]]></summary>
    <content type="html"><![CDATA[<p>You&#8217;d think that telecoms (esp in South Africa, where being one is a license to print money) would do everything they could to get you to spend money with them? If only.</p>

<p>Cellphones (at least Vodacom) have always required you to manually enable International phone calls &amp; International roaming, by giving them a call and requesting it. This is a pain, to say the least. And you normally forget until you are already in another country.</p>

<p>But Telkom have taken this to a new level. I got a new phone line last month (which still doesn&#8217;t have working DSL, grr!), and just noticed that I can&#8217;t make International calls on it. So I phone telkom. Amazingly I didn&#8217;t have to wait on hold at all (something never before experienced when calling the beast), and the lady I spoke to told me I have to &#8220;Visit a Telkom Shop with my ID&#8221;. WTF? How hard are they making it to spend money on them?</p>

<p>Is there any legitimate reason that international calls are blocked? With our pricing, it&#8217;s easy to knock up a multi-k-ZAR bill without even thinking about dialling an international number, so they aren&#8217;t protecting anyone.</p>

<p>In related news, the reason you can&#8217;t have incoming connections on Vodacom 3G (even with &#8220;internetvpn&#8221;) is because then you&#8217;d be liable for the cost of any DOS you received. Isn&#8217;t this a problem that hosting providers and ISPs already have to deal with? Why are mobile operators special? We need some Internet Neutrality and Telecoms sense in this country&#8230;</p>
    ]]></content>
  </entry>
  <entry>
    <title>Vodacom: internetvpn APN</title>
    <link rel="alternate" type="text/html" href="http://tumbleweed.org.za/2008/02/03/vodacom-internetvpn-apn" />
    <id>http://tumbleweed.org.za/2008/02/03/vodacom-internetvpn-apn</id>
    <published>2008-02-03T16:40:49+00:00</published>
    <updated>2008-02-03T16:47:50+00:00</updated>
    <author>
      <name>tumbleweed</name>
    </author>
    <category term="3g" />
    <category term="south-africa" />
    <category term="technical" />
    <category term="vodacom" />
    <summary type="html"><![CDATA[<p>A quick tip for <a href="http://www.vodacom.co.za/">Vodacom</a> 3G / GPRS / EDGE users in South Africa.</p>

<p>There is a special <a href="http://en.wikipedia.org/wiki/Access_Point_Name">APN</a> called &#8220;internetvpn&#8221; for laptop users who connect to corporate VPNs. While this probably doesn&#8217;t interest most readers, it is a useful APN to use because:</p>

<ul>
<li>You get a real Public IP address, not a private NATted one.</li>
<li>You get lower latency.</li>
<li>The cost is the same. (i.e. regular data bundles work fine)</li>
</ul>

<p>If you use a VPN, this will probably make it more reliable, and if you don&#8217;t it will at least make your ssh use more comfortable.</p>

<p>Unfortunately, the following vodacom issues will still be present:</p>

<ul>
<li>No incoming TCP connections (i.e. you can&#8217;t serve web pages from or ssh into your laptop)</li>
<li>Often you get &#8220;martian&#8221; DNS servers (10.11.12.13 and 10.11.12.14). Either reconnect, or manually set your DNS servers to 196.43.46.190 (SAIX) and 196.207.40.165 (Vodacom).</li>
<li>TCP connections are regularly reset. (Overloaded NAT/Firewall hardware?)</li>
</ul>

<h1>How to get it:</h1>

<ol>
<li>Call vodacom customer care (111).</li>
<li>Follow the IVR menu options in the directions of data cards.</li>
<li>Ask them to enable the &#8220;internetvpn APN&#8221; (you might have to explain it to them)</li>
<li>Reconfigure your phone / chat script / &#8220;data card driver&#8221; to use &#8220;internetvpn&#8221; instead of &#8220;internet&#8221;</li>
<li>Profit! :-)</li>
</ol>
    ]]></summary>
    <content type="html"><![CDATA[<p>A quick tip for <a href="http://www.vodacom.co.za/">Vodacom</a> 3G / GPRS / EDGE users in South Africa.</p>

<p>There is a special <a href="http://en.wikipedia.org/wiki/Access_Point_Name">APN</a> called &#8220;internetvpn&#8221; for laptop users who connect to corporate VPNs. While this probably doesn&#8217;t interest most readers, it is a useful APN to use because:</p>

<ul>
<li>You get a real Public IP address, not a private NATted one.</li>
<li>You get lower latency.</li>
<li>The cost is the same. (i.e. regular data bundles work fine)</li>
</ul>

<p>If you use a VPN, this will probably make it more reliable, and if you don&#8217;t it will at least make your ssh use more comfortable.</p>

<p>Unfortunately, the following vodacom issues will still be present:</p>

<ul>
<li>No incoming TCP connections (i.e. you can&#8217;t serve web pages from or ssh into your laptop)</li>
<li>Often you get &#8220;martian&#8221; DNS servers (10.11.12.13 and 10.11.12.14). Either reconnect, or manually set your DNS servers to 196.43.46.190 (SAIX) and 196.207.40.165 (Vodacom).</li>
<li>TCP connections are regularly reset. (Overloaded NAT/Firewall hardware?)</li>
</ul>

<h1>How to get it:</h1>

<ol>
<li>Call vodacom customer care (111).</li>
<li>Follow the IVR menu options in the directions of data cards.</li>
<li>Ask them to enable the &#8220;internetvpn APN&#8221; (you might have to explain it to them)</li>
<li>Reconfigure your phone / chat script / &#8220;data card driver&#8221; to use &#8220;internetvpn&#8221; instead of &#8220;internet&#8221;</li>
<li>Profit! :-)</li>
</ol>
    ]]></content>
  </entry>
  <entry>
    <title>SugarCRM to Mozilla LDAP contact slurper</title>
    <link rel="alternate" type="text/html" href="http://tumbleweed.org.za/code/sugarcrm-contacts-ldap" />
    <id>http://tumbleweed.org.za/code/sugarcrm-contacts-ldap</id>
    <published>2008-01-29T13:50:03+00:00</published>
    <updated>2008-01-30T07:51:57+00:00</updated>
    <author>
      <name>tumbleweed</name>
    </author>
    <category term="code" />
    <category term="Howto" />
    <category term="ldap" />
    <category term="python" />
    <category term="sugarcrm" />
    <summary type="html"><![CDATA[<p>Seeing as <a href="http://www.sugarforge.org/">SugarCRM</a> is now truly Open Source, I decided to support them buy using SugarCRM as a contact database for a client.</p>

<p>This script extracts contact data from Sugar, and imports it into an LDAP tree, so that Thunderbird clients can use it as an address book.</p>

<p>It&#8217;s written for Sugar 5.0, and a suitable LDAP installation with the <a href="http://wiki.mozilla.org/MailNews:Mozilla_LDAP_Address_Book_Schema">Mozilla Schema</a></p>

<p>A suitable VIEW for printing out a contact directory would look like:</p>

<pre><code>CREATE OR REPLACE VIEW sugarab AS
SELECT c.id, c.description, salutation, first_name, last_name, title, department,
do_not_call, phone_home, phone_mobile, phone_work, phone_other, c.phone_fax,
primary_address_street, primary_address_city, primary_address_state,
primary_address_postalcode, primary_address_country, alt_address_street,
alt_address_city, alt_address_state, alt_address_postalcode, alt_address_country,
assistant, assistant_phone, lead_source, birthdate,
a.name AS account_name,
e1.email_address AS primary_email, e2.email_address AS secondary_email
FROM contacts AS c
LEFT OUTER JOIN accounts_contacts AS j ON (c.id = j.contact_id AND j.deleted = 0)
LEFT OUTER JOIN accounts AS a ON (j.account_id = a.id AND a.deleted = 0)
LEFT OUTER JOIN email_addr_bean_rel as eb ON (eb.bean_id = c.id AND eb.deleted = 0)
LEFT OUTER JOIN email_addresses as e1 ON (eb.email_address_id = e1.id AND eb.primary_address = 1 AND e1.deleted = 0)
LEFT OUTER JOIN email_addresses as e2 ON (eb.email_address_id = e2.id AND e1.id != e2.id AND e2.deleted = 0)
WHERE c.deleted = 0;
</code></pre>
    ]]></summary>
    <content type="html"><![CDATA[<p>Seeing as <a href="http://www.sugarforge.org/">SugarCRM</a> is now truly Open Source, I decided to support them buy using SugarCRM as a contact database for a client.</p>

<p>This script extracts contact data from Sugar, and imports it into an LDAP tree, so that Thunderbird clients can use it as an address book.</p>

<p>It&#8217;s written for Sugar 5.0, and a suitable LDAP installation with the <a href="http://wiki.mozilla.org/MailNews:Mozilla_LDAP_Address_Book_Schema">Mozilla Schema</a></p>

<p>A suitable VIEW for printing out a contact directory would look like:</p>

<pre><code>CREATE OR REPLACE VIEW sugarab AS
SELECT c.id, c.description, salutation, first_name, last_name, title, department,
do_not_call, phone_home, phone_mobile, phone_work, phone_other, c.phone_fax,
primary_address_street, primary_address_city, primary_address_state,
primary_address_postalcode, primary_address_country, alt_address_street,
alt_address_city, alt_address_state, alt_address_postalcode, alt_address_country,
assistant, assistant_phone, lead_source, birthdate,
a.name AS account_name,
e1.email_address AS primary_email, e2.email_address AS secondary_email
FROM contacts AS c
LEFT OUTER JOIN accounts_contacts AS j ON (c.id = j.contact_id AND j.deleted = 0)
LEFT OUTER JOIN accounts AS a ON (j.account_id = a.id AND a.deleted = 0)
LEFT OUTER JOIN email_addr_bean_rel as eb ON (eb.bean_id = c.id AND eb.deleted = 0)
LEFT OUTER JOIN email_addresses as e1 ON (eb.email_address_id = e1.id AND eb.primary_address = 1 AND e1.deleted = 0)
LEFT OUTER JOIN email_addresses as e2 ON (eb.email_address_id = e2.id AND e1.id != e2.id AND e2.deleted = 0)
WHERE c.deleted = 0;
</code></pre>
    ]]></content>
  </entry>
  <entry>
    <title>Aggregator noise and growth</title>
    <link rel="alternate" type="text/html" href="http://tumbleweed.org.za/2008/01/21/aggregator-noise-and-growth" />
    <id>http://tumbleweed.org.za/2008/01/21/aggregator-noise-and-growth</id>
    <published>2008-01-21T11:23:53+00:00</published>
    <updated>2008-01-21T11:34:06+00:00</updated>
    <author>
      <name>tumbleweed</name>
    </author>
    <category term="clug" />
    <category term="clug-park" />
    <category term="community" />
    <category term="planet" />
    <summary type="html"><![CDATA[<p>For the bloggers on <a href="http://park.clug.org.za/">Clug Park</a>, who don&#8217;t deign to follow <a href="http://wiki.clug.org.za/wiki/CLUG_Mailing_Lists">clug-chat</a> or #clug, there have been <a href="http://lists.clug.org.za/pipermail/clug-chat/2008-January/024346.html">recent discussions</a> about creating a separate, filtered park for readers with less free time.</p>

<p>The problem is basically that some people post a lot of posts. Sometimes as much as half of the park is dominated by one poster. While this isn&#8217;t a problem per se (some people clearly have more blogging time), it means readers have more to wade through, and can feel swamped my the prolific posters. Many would prefer something with a higher signal-to-noise ratio, and lower volume.</p>

<p>As communities grow, the signal-to-noise ratio often suffers, and the higher volume is too much for some readers. Rather than lose the readers, we&#8217;d like to provide an alternative, filtered park. It&#8217;s currently being prepared <a href="http://park.clug.org.za/tech/">here</a>. Personally, I&#8217;ll still use the old park, as will many other prolific RSS-feed-followers.</p>

<p>What we need is for all the CLUG Parkers to create a &#8220;technical&#8221; tag, and tag all relevant posts as such.  Then send me the URL of your new tag, and I&#8217;ll include it in the &#8220;park-tech&#8221;. (Or assure me that you don&#8217;t post too prolifically, and only tech-related posts, and we&#8217;ll carry your entire feed).</p>

<p>Lets see if we can make it work.</p>
    ]]></summary>
    <content type="html"><![CDATA[<p>For the bloggers on <a href="http://park.clug.org.za/">Clug Park</a>, who don&#8217;t deign to follow <a href="http://wiki.clug.org.za/wiki/CLUG_Mailing_Lists">clug-chat</a> or #clug, there have been <a href="http://lists.clug.org.za/pipermail/clug-chat/2008-January/024346.html">recent discussions</a> about creating a separate, filtered park for readers with less free time.</p>

<p>The problem is basically that some people post a lot of posts. Sometimes as much as half of the park is dominated by one poster. While this isn&#8217;t a problem per se (some people clearly have more blogging time), it means readers have more to wade through, and can feel swamped my the prolific posters. Many would prefer something with a higher signal-to-noise ratio, and lower volume.</p>

<p>As communities grow, the signal-to-noise ratio often suffers, and the higher volume is too much for some readers. Rather than lose the readers, we&#8217;d like to provide an alternative, filtered park. It&#8217;s currently being prepared <a href="http://park.clug.org.za/tech/">here</a>. Personally, I&#8217;ll still use the old park, as will many other prolific RSS-feed-followers.</p>

<p>What we need is for all the CLUG Parkers to create a &#8220;technical&#8221; tag, and tag all relevant posts as such.  Then send me the URL of your new tag, and I&#8217;ll include it in the &#8220;park-tech&#8221;. (Or assure me that you don&#8217;t post too prolifically, and only tech-related posts, and we&#8217;ll carry your entire feed).</p>

<p>Lets see if we can make it work.</p>
    ]]></content>
  </entry>
</feed>
