Thursday, November 25, 2010

xscreensaver and empathy presence notification

xscreensaver doesn't support d-bus - and therefore when screensaver activates, empathy (IM client) doesn't change status to "Away", like it does with gnome-screensaver.

The xscreensaver man page includes a nice perl script which you can use to accomplish the same thing.  So here is "watchx.pl" script:

#!/usr/bin/perl

my $blanked = 0;
 open (IN, "xscreensaver-command -watch |");
 while () {
     if (m/^(BLANK|LOCK)/) {
         if (!$blanked) {
             system "/usr/local/bin/empathy-away.sh";
             $blanked = 1;
         }
     } elsif (m/^UNBLANK/) {
         system "/usr/local/bin/empathy-avail.sh";
         $blanked = 0;
     }
 }
Then, using dbus-send, you can set status in empathy.. I use the following scripts "empathy-away.sh":

#!/bin/bash
USER=`whoami`
service=`qdbus | grep $USER | sed -e "s/ //g"`
path=`echo $service | sed -e "s/\./\//g"`
dbus-send --dest=$service /$path org.freedesktop.Telepathy.Connection.Interface.SimplePresence.SetPresence string:"away" string:"Away from keyboard"
and "empathy-avail.sh":

#!/bin/bash
USER=`whoami`
service=`qdbus | grep $USER | sed -e "s/ //g"`
path=`echo $service | sed -e "s/\./\//g"`
dbus-send --dest=$service /$path org.freedesktop.Telepathy.Connection.Interface.SimplePresence.SetPresence string:"available" string:"Available"

NOTE:  This is designed for one empathy account.. and that account name containing the users login name.  Works on ubuntu lucid.  Also - that dbus-send command is all on one line.

And to have it launch at login... create the following "watchx.desktop" file and place it in /etc/xdg/autostart:

[Desktop Entry]
Type=Application
Exec=/usr/local/bin/watchx.pl
Hidden=false
NoDisplay=false
X-GNOME-Autostart-enabled=true
Name[en_US]=Watch screen saver
Name=Watch screen saver
Comment[en_US]=Watch screen saver
Comment=Watch screen saver

Tuesday, August 3, 2010

NETCONSOLE to the rescue

On a headless server, when you get a kernel panic and the system is totally locked up, and there is no sync of kernel log, its extremely frustrating trying to debug.

Discovered a wonderful kernel module/feature called NETCONSOLE.  From netconsole.txt - "This module logs kernel printk messages over UDP allowing debugging of problem where disk logging fails and serial consoles are impractical."

Using this usefull howto as a basis I got this working on ubuntu 10.04, which already has netconsole built as a module.

On the source system where you want to trap the messages:

modprobe netconsole netconsole=<sport>@<saddr>/<dev>,<dport>@<daddr>/<dmac>

where sport is the source port, saddr is the source address, dev is interface, dport is destination port, daddr is destination address and dmac is destination mac address.

On the remote end, install netcat, and do:

netcat -ul <dport>  >> /var/log/netconsole



So easy.. and so useful..

Note: This is different than remote syslogd - which will capture kernel messages over the network - since netconsole is at the kernel level and thus more capable of capturing panics.

Friday, May 7, 2010

Migrating from Palm Treo 680 to Nokia E71 OTA with Funambol

Lets say you want to be able to migrate contacts, calendars, tasks and notes from your Treo to a Nokia E71 (or other newer S60 device), and you don't want to go the "Windows/Palm desktop - export/Outlook import -> Nokia Suite -> device" route.  I don't use Windows, and I wanted an OTA (over-the-air) sync solution.

This turned out to be quite simple, thanks to Funambol and SyncML

There are 3 parts to this - (1) funambol server setup, (2) Funambol client on E71, and (3) Synthesis SyncML client on Palm Treo

Funambol Server
https://www.forge.funambol.org/download/

Simply download, install and launch
-you must have an internet accessible interface

Next, launch the Funambol Admin Tool : /opt/Funambol/admin/bin/funamboladmin
-login.. open up server properties, and set the URL:   http://xx.xx.xx.xx:8080/funambol/ds
  (where xx.xx.xx.xx is your public IP)
-click on save

(you may also want to change the admin password)

Done!

Funambol Client on Nokia E71
-you can download from funambol.org or via www.ovi.mobi
-install and configure 3 things
  -username
  -password
  -URL  (use same as established on server obviously)

note: by default, the funambol server does auto-provisioning, so the username/password above is going to be "created" on the server, so choose whatever you wish.

-perform initial sync

Synthesis SyncML client
You can download 30-day trial here:
http://www.synthesis.ch/dl_client.php?lang=e&lay=desk&bp=CPDA&pv=PALM#dlds_CPDA1

-start client, goto Options -> Settings...
-set SyncML Server URL (as per above)
-set username/password (as per above)
-click "options" button
  -Server version -> SyncML 1.2 /OMA
  -OK
-select databases to sync - and set sync modes to "slow"

NOTE:  database names are set for a specific "SyncML Server", you need to change them using "more.." buttons

Contacts:  server path:  card
Events: server path: event
Tasks: server path: task
Notes: server path: note

-perform sync - this will push everything OTA to funambol server

Final Step

-re-sync your Nokia to grab data from funambol server OTA

Monday, April 12, 2010

Trixbox 2.8 CE install via USB

Bought an  Acer Aspire R1600 for a trixbox install.  Nice small form factor, but no cdrom, so the only install options are via USB or network.

I've used unetbootin for converting ISOs to make bootable USBs before.. never with a problem.  But with trixbox.. not so simple - things "seem" to install, but the system ends up being very broken, as the install scripts won't complete properly.  There is hard-coded reference to cdrom device in the install config files (anaconda/kickstart).   In 2010, its almost inconceivable that there is no install from USB option in trixbox (or asterisknow).  I've been administering linux systems (many distros) since 1996, and I've never had such a difficult time with an install.

I could not find any definitive solution anywhere (even tried the trixbox 2.6 usb install howto, which didn't work - plus its ludicrous that you should need Windows in order to install linux), so I struggled through dozens of reboots until I *finally* got a working trixbox system.

Unfortunately the Aspire R1600 has some proprietary nvidia NIC, which is not supported by the forcedeth 0.60 module which is supplied with trixbox.  I had to find a 0.62 version of kmod-forcedeth which installed on trixbox.  But this is no fault of trixbox, but of Acer for making such a stupid decision on NIC.

Ok, so this is how I did it.  If anyone has a simpler solution, please comment.

1)  Use unetbootin ( http://unetbootin.sourceforge.net/ ) with trixbox 2.8 ce ISO to create bootable USB drive
2)  remove the trixbox directory from USB drive (its not needed, and I only had 1G, so needed room)
3)  copy the trixbox 2.8 ce ISO to the USB drive
4)  on USB drive, edit isolinux/ks.cfg     comment out "cdrom" line

5) place USB drive in target system, and configure BIOS to boot from USB, and boot
6) when grub menu presents, scroll down to "default", and press [Tab] to edit command line
      - change "ks=cdrom:/isolinux/ks.cfg" to "ks=hd:sdb1:/isolinux/ks.cfg" and press enter to boot

  NOTE:  this should work for most.. if you have one drive as sda.. USB drive typcially becomes sdb

7) installer will proceed, but may try to read from sdb1 prior to kernel detecting device.. it will prompt for kickstart file.. you can just retry.. check Alt-F4 for sdb detection.. (Alt-F1 to get back).  Next it will ask for location of ISO... select /dev/sdb1 and continue with install

For me there was complaint about kmod-dahdi, but in the end.. all install scripts executed fine, and the system was completely operational.

NOTE:  I tried the same type of solution with AsteriskNOW, to no avail.. there was a fatal error as it tried to re-mount a mounted filesystem, and installation aborted.

Monday, March 22, 2010

Extracting OpenOffice.org Calc cells from the command line

In theory it should be simple... get cell value from ODS file, sheet x, row y, column z.

With OpenDocument format, content.xml stores spreadsheet data with the following schema:

<table:table>
  <table:table-row>
    <table:table-cell> ....

So a simple XPath expression like //table:table[1]/table:table-row[5]/table:table-cell[3]  should give me "Sheet1:C5".

With xmlstarlet command would be:

xmlstarlet sel -N office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" -N table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" -t -v "//table:table[1]/table:table-row[5]/table:table-cell[3]" content.xml

BUT.. in order to save space, blank rows and columns are not stored.. instead an attribute is used to indicate how many blank rows or columns, so you can see something like <table:table-row table:number-rows-repeated=10/>.

This breaks the easy XPath expression above, and makes it difficult to find specific co-ordinates.

I've developed an XSLT transformation that will take content.xml and expand it to be indexable.


<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
   xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0"
   xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0"
   xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0">



<xsl:output method = "xml" indent = "yes" encoding = "UTF-8" omit-xml-declaration = "no"/>

<xsl:template match="table:table-cell">
 
        <xsl:choose>
        <xsl:when test="@table:number-columns-repeated">
          <xsl:variable name="numcols" select="number(@table:number-columns-repeated)"/>
          <xsl:choose>
          <xsl:when test="$numcols > 1000">
              <xsl:call-template name="processcol">
            <xsl:with-param name="currentCol" select="0"/>
            <xsl:with-param name="totalCols" select="1"/>
              </xsl:call-template>
          </xsl:when>
          <xsl:otherwise>
              <xsl:call-template name="processcol">
            <xsl:with-param name="currentCol" select="0"/>
            <xsl:with-param name="totalCols" select="$numcols"/>
              </xsl:call-template>
          </xsl:otherwise>
          </xsl:choose>
        </xsl:when>
        <xsl:otherwise>
          <xsl:copy-of select="."/>
        </xsl:otherwise>
        </xsl:choose>
</xsl:template>

<xsl:template match="table:table-row">
 
        <xsl:choose>
        <xsl:when test="@table:number-rows-repeated">
      <xsl:variable name="numrows" select="number(@table:number-rows-repeated)"/>
          <xsl:choose>
          <xsl:when test="$numrows > 3000">
              <xsl:call-template name="processrow">
            <xsl:with-param name="currentRow" select="0"/>
            <xsl:with-param name="totalRows" select="1"/>
                 </xsl:call-template>
          </xsl:when>
          <xsl:otherwise>
              <xsl:call-template name="processrow">
            <xsl:with-param name="currentRow" select="0"/>
            <xsl:with-param name="totalRows" select="$numrows"/>
              </xsl:call-template>
          </xsl:otherwise>
          </xsl:choose>
    </xsl:when>
        <xsl:otherwise>
          <xsl:call-template name="processrow">
        <xsl:with-param name="currentRow" select="0"/>
        <xsl:with-param name="totalRows" select="1"/>
          </xsl:call-template>
        </xsl:otherwise>
        </xsl:choose>

</xsl:template>

<xsl:template match="@*|*">
   <xsl:copy>
     <xsl:apply-templates select="@*|node()"/>
   </xsl:copy>
</xsl:template>

<xsl:template name="processrow">
    <xsl:param name="currentRow"/>
    <xsl:param name="totalRows"/>
        <xsl:choose>
    <xsl:when test="$currentRow < $totalRows">
<xsl:copy>
<xsl:apply-templates select="table:table-cell"/>
</xsl:copy>
        <xsl:call-template name="processrow">
        <xsl:with-param name="currentRow" select="$currentRow + 1"/>
        <xsl:with-param name="totalRows" select="$totalRows"/>
        </xsl:call-template>
    </xsl:when>
    </xsl:choose>
</xsl:template>

<xsl:template name="processcol">
    <xsl:param name="currentCol"/>
    <xsl:param name="totalCols"/>
        <xsl:choose>
    <xsl:when test="$currentCol < $totalCols">
<xsl:copy-of select="."/>
        <xsl:call-template name="processcol">
        <xsl:with-param name="currentCol" select="$currentCol + 1"/>
        <xsl:with-param name="totalCols" select="$totalCols"/>
        </xsl:call-template>
    </xsl:when>
    </xsl:choose>
</xsl:template>

</xsl:stylesheet>

This can be called simply using : xmlstarlet tr /usr/local/bin/expand.xslt content.xml > output.xml

and then queried using: xmlstarlet sel -N office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" -N table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" -t -v "//table:table[1]/table:table-row[5]/table:table-cell[3]" output.xml

NOTE: Since this is using recursive XSLT, I put a cap on 3000 repeated rows, and 1000 repeated columns.  So this will work *unless* you have a spreadsheet with over 3000 blank rows (and you want to query row 3005), OR over 1000 blank columns (and you want to query column 1001) .


Putting this all together in a bash script we have:
#!/bin/bash

# $1  ods file
# $2  sheet #
# $3  row #
# $4  column #

tmpdir=/tmp/ods.$$
mkdir $tmpdir
cp "$1" $tmpdir
cd $tmpdir
IFS="|"
filename=`basename "$1"`

unzip -qq "$tmpdir/$filename"

xmlstarlet tr /usr/local/bin/expand.xslt content.xml > output.xml

xmlstarlet sel -N office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" -N table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" -t -v "//table:table[$2]/table:table-row[$3]/table:table-cell[$4]" output.xml

cd - &>/dev/null
rm -rf $tmpdir
Invocation looks like this:

oo_extract_cell.sh Test.ods 1 5 3

Wednesday, February 17, 2010

PXE chaining to modernize legacy PXE NICs

Ok - so we have faulty/legacy PXE implementation in some onboard NICs, that don't support "next-server"...  Here is how to fix...   VERY cool!  It basically replaces the faulty PXE with a modern gPXE.

Following these instructions.. build undionly.kpxe and place in local /tftpboot/

http://etherboot.org/wiki/pxechaining

Then do something like the following in dhcpd.conf:

group {
        allow booting;
        option root-path "192.168.202.4:/opt/ltsp/i386";

        host ws042 {
                hardware ethernet 00:06:29:DF:2C:52;
                fixed-address ws042.dainty.ca;
                option host-name "ws042";

                if substring (option vendor-class-identifier, 0, 9) = "PXEClient" {
                        if exists user-class and option user-class = "gPXE" {
                                next-server 192.168.202.4;
                                filename "/ltsp/i386/pxelinux.0"; #secondary PXEclient
                        } else {
                        filename  "/tftpboot/undionly.kpxe"; #first boot.. loads gPXE
                        }
                } else {
                        next-server 192.168.202.4;
                        filename  "/ltsp/i386/nbi.img";  #normal boot image
                 }

        }
}