Code

warning: Creating default object from empty value in /var/www/drupal6.pyxos.net/drupal-6.28/modules/taxonomy/taxonomy.pages.inc on line 33.

Nagios utils.php script for PHP plugins

I couldn't find a "utils.php" script for making it easier to write nagios plugins in PHP so I thought I'd whip one up.  This is a combination of the utils.php from CVS I found laying around the web and a port of Nagios::Plugin::Range perl module.  It seems to pass all the tests that I found for the nagios plugins range documentation.

<?php
/*
 * Created on Sep 14, (c) 2006 by Marcel K�hn
 * GPL licensed, marcel@kuehns.org
 * 
 * Ported nagios range checking from Nagios::Plugin::Range
 * by Doug Warner <doug@warner.fm>
 */
 
#Configuration
 
define('STATE_OK',0);
define('STATE_WARNING',1);
define('STATE_CRITICAL',2);
define('STATE_UNKNOWN',3);
define('STATE_DEPENDENT',4);
 
define('SNMPWALK','/usr/bin/snmpwalk');
 
function detectOS(){
	$arr	=	posix_uname();
	return strtolower($arr["sysname"]);
}
 
function verifyOS($supportedOSarray){
	$runningOS	=	detectOS();
	if(in_array($runningOS,$supportedOSarray)){
		return TRUE;
	}
	else{
		return FALSE;
	}	
}
 
function machineName(){
	$arr	=	posix_uname();
	return strtolower($arr["nodename"]);
}
 
class Nagios_Plugin_Range {
	const INSIDE = 1;
	const OUTSIDE = 0;
	protected $range;
	protected $start = 0;
	protected $end = 0;
	protected $start_infinity = false;
	protected $end_infinity = false;
	protected $alert_on;
 
	public function __construct($range) {
		$this->range = $range;
		$this->parse_range_string($range);
	}
 
	public function valid() {
		return isset($this->alert_on);
	}
 
	public function check_range($value) {
		$false = false;
		$true = true;
		if ($this->alert_on == self::INSIDE) {
			$false = true;
			$true = false;
		}
 
		/* DEBUG
		echo "  R:$this->range; V:$value; S:$this->start, E:$this->end, ".
			"SI: " . ( $this->start_infinity ? 'T' : 'F') . ', ' .
			"EI: " . ( $this->end_infinity ? 'T' : 'F') . ', ' .
			"InOut: " . ( $this->alert_on == self::INSIDE ? 'I' : 'O') . '; ' .
			"\n";
		*/
		if (!$this->end_infinity && !$this->start_infinity ) {
			if ($this->start <= $value && $value <= $this->end) {
				return $false;
			} else {
				return $true;
			}
		}
		elseif (!$this->start_infinity && $this->end_infinity) {
			if ( $value >= $this->start ) {
				return $false;
			} else {
				return $true;
			}
		}
		elseif ($this->start_infinity && !$this->end_infinity) {
			if ($value <= $this->end) {
				return $false;
			} else {
				return $true;
			}
		}
		else {
			return $false;
		}
	}
 
	# Returns a N::P::Range object if the string is a conforms to a Nagios Plugin range string, otherwise null
	protected function parse_range_string($string) {
		$valid = 0;
		$alert_on = self::OUTSIDE;
 
		$string = preg_replace('/\s/', '', $string);
 
		$value = "[-+]?[\d\.]+";
		$value_re = "${value}(?:e${value})?";
 
		# check for valid range definition
		if ( !preg_match('/[\d~]/', $string)
			|| !preg_match("/^\@?(${value_re}|~)?(:(${value_re})?)?$/", $string)) {
			echo "invalid range definition '$string'";
			exit(STATE_UNKNOWN);
		}
 
		if (preg_match('/^\@/', $string)) {
			$string = preg_replace('/^\@/', '', $string);
			$alert_on = self::INSIDE;
		}
 
		 # '~:x'
		if (preg_match('/^~/', $string)) {
			$string = preg_replace('/^~/', '', $string);
			$this->start_infinity = true;
		}
 
		# '10:'
		if (preg_match("/^(${value_re})?:/", $string, $matches)) {
			if (!empty($matches[1])) {
				$this->set_range_start($matches[1]);
			}
			$this->end_infinity = true;  # overridden below if there's an end specified
			$string = preg_replace("/^(${value_re})?:/", '', $string);
			$valid++;
		}
 
		# 'x:10' or '10'
		if (preg_match("/^(${value_re})$/", $string)) {
			$this->set_range_end($string);
			$valid++;
		}
 
		if ($valid
			&& ($this->start_infinity || $this->end_infinity || $this->start <= $this->end)) {
			$this->alert_on = $alert_on;
		}
	}
 
	protected function set_range_start($value) {
		$this->start = (integer) $value;
		if (empty($this->start)) {
			$this->start = 0;
		}
		$this->start_infinity = false;
	}
 
	protected function set_range_end($value) {
		$this->end = (integer) $value;
		if (empty($this->end)) {
			$this->end = 0;
		}
		$this->end_infinity = false;
	}
}

KeePassX XML Generator in PHP - Convert PWManager to KeePassX

I couldn't get KeePassX to import my PWManager files natively, so I needed a way to do this in a multi-step fashion (I want to use keepass format so I can have the same password program/database on my computer and G1).  The easiest appeared to be:

  1. Export from pwmanager as CSV
  2. Custom script to convert from CSV to keepassx XML format
  3. Import in keepassx

So this "step 2" was the problem.

I found a forum post on the keepass xml format, so the next step was writing something to convert it, and so we have the PHP KeePassX XML Generator.

Currently it's set up to convert the CSV file generated by pwmanager (entered on stdin, xml dumped on stdout).  But I created a set of classes that should be easy to use for generating a valid keepassx xml file.

gajim-pinger

I've written a little shell script I'm calling gajim-pinger.  If you use gajim for IM and ping.fm for updating your social networks, this simplifies things by:

  1. updating ping.fm
  2. updating your gajim status message

It does this by using zenity to ask you what you're doing, then gajim-remote to send a message to the ping.fm xmpp bot (which you need to have added to your roster before-hand) and also using gajim-remote to update your status message there.

New Drupal/Gallery2.2 plugin configuration challenges

I like to my rewrite rules performed in the central Apache config (well, individual vhost files) so it can be revision controlled and centrally managed. The recent upgrade to the Gallery 5.x-2.0 module broke the rewriting rules I was using. Below are my new rewrite rules for a site-wide Gallery/Drupal install, but first the main snipped and differences of what was changed. For reference, my gallery install is at /photo.

The recommended URL rewrite rules would look like this:
RewriteCond %{THE_REQUEST} /gallery/([0-9]+)-([0-9]+)/([^/?]+)(\?.|\ .)
RewriteCond %{REQUEST_URI} !/index\.php$
RewriteRule . /photo/main.php?g2_view=core.DownloadItem&g2_itemId=%1&g2_serialNumber=%2&g2_fileName=%3 [QSA,L]
RewriteCond %{THE_REQUEST} /gallery/([^?]+)(\?.|\ .)
RewriteCond %{REQUEST_URI} !/index\.php$
RewriteRule . /index.php?q=gallery&g2_path=%1 [QSA,L]

I had to modify/remove the emphasized parts; I needed to change %{THE_REQUEST} to %{REQUEST_URI} because the path /gallery is also in drupal's admin paths. I wanted to anchor the /gallery gallery path, but can't do that with %{REQUEST_URI}. Also, because I removed %{REQUEST_URI}, I needed to remove the (\?.|\ .) match from the end since there would no longer be those characters after the URL.

My modified version would like like this (emphasis added to show changes):
RewriteCond %{REQUEST_URI} ^/gallery/([0-9]+)-([0-9]+)/([^/?]+)
RewriteCond %{REQUEST_URI} !/index\.php$
RewriteRule . /photo/main.php?g2_view=core.DownloadItem&g2_itemId=%1&g2_serialNumber=%2&g2_fileName=%3 [QSA,L]
RewriteCond %{REQUEST_URI} ^/gallery/([^?]+)
RewriteCond %{REQUEST_URI} !/index\.php$
RewriteRule . /index.php?q=gallery&g2_path=%1 [QSA,L]

This wasn't good enough for me, though, as I wanted the clean URLs I had for most gallery paths in gallery 2.1. So my final Gallery2.2/Drupal config looks like the following:

# drupal/gallery integration
RewriteCond %{REQUEST_URI} ^/gallery/popular
RewriteCond %{REQUEST_URI} !/index\.php$
RewriteRule . /index.php?q=gallery&g2_view=dynamicalbum.PopularAlbum [QSA,L]
RewriteCond %{REQUEST_URI} ^/gallery/updates
RewriteCond %{REQUEST_URI} !/index\.php$
RewriteRule . /index.php?q=gallery&g2_view=dynamicalbum.UpdatesAlbum [QSA,L]
RewriteCond %{REQUEST_URI} ^/gallery/random
RewriteCond %{REQUEST_URI} !/index\.php$
RewriteRule . /index.php?q=gallery&g2_view=dynamicalbum.RandomAlbum [QSA,L]
RewriteCond %{REQUEST_URI} ^/gallery/d/([0-9]+)-([0-9]+)/([^/?]+)
RewriteCond %{REQUEST_URI} !/index\.php$
RewriteRule . /photo/main.php?g2_view=core.DownloadItem&g2_itemId=%1&g2_serialNumber=%2&g2_fileName=%3 [QSA,L]
RewriteCond %{REQUEST_URI} ^/gallery/v/([^?]+)/slideshow\.html
RewriteCond %{REQUEST_URI} !/index\.php$
RewriteRule . /index.php?q=gallery&g2_view=slideshow.Slideshow&g2_path=%1 [QSA,L]
RewriteCond %{REQUEST_URI} ^/gallery/c/view/([0-9]+)\.html
RewriteCond %{REQUEST_URI} !/index\.php$
RewriteRule . /index.php?q=gallery&g2_view=comment.ShowAllComments&g2_itemId=%1 [QSA,L]
RewriteCond %{REQUEST_URI} ^/gallery/c/add/([0-9]+)\.html
RewriteCond %{REQUEST_URI} !/index\.php$
RewriteRule . /index.php?q=gallery&g2_view=comment.AddComment&g2_itemId=%1 [QSA,L]
RewriteCond %{REQUEST_URI} ^/gallery/v/([^?]+)\.davmount
RewriteCond %{REQUEST_URI} !/index\.php$
RewriteRule . /index.php?q=gallery&g2_view=webdav.DownloadDavMount&g2_path=%1 [QSA,L]
RewriteCond %{REQUEST_URI} ^/gallery/rating/([^?/]+)
RewriteCond %{REQUEST_URI} !/index\.php$
RewriteRule . /index.php?q=gallery&g2_view=rating.RatingAlbum&g2_limit=%1 [QSA,L]
RewriteCond %{REQUEST_URI} ^/gallery/rss/([^\/\?]+)
RewriteCond %{REQUEST_URI} !/index\.php$
RewriteRule . /index.php?q=gallery&g2_view=rss.Render&g2_name=%1 [QSA,L]
RewriteCond %{REQUEST_URI} ^/gallery/srss/([0-9]+)
RewriteCond %{REQUEST_URI} !/index\.php$
RewriteRule . /index.php?q=gallery&g2_view=rss.SimpleRender&g2_itemId=%1 [QSA,L]
RewriteCond %{REQUEST_URI} ^/gallery/key/([^?/]+)
RewriteCond %{REQUEST_URI} !/index\.php$
RewriteRule . /index.php?q=gallery&g2_view=keyalbum.KeywordAlbum&g2_keyword=%1 [QSA,L]
RewriteCond %{REQUEST_URI} ^/gallery/w(/[^?]*)?
RewriteCond %{REQUEST_URI} !/index\.php$
RewriteRule . /index.php?q=gallery&g2_controller=webdav.WebDav&g2_path=%1 [QSA,L]
RewriteCond %{REQUEST_URI} ^/gallery/v/([^?]+)
RewriteCond %{REQUEST_URI} !/index\.php$
RewriteRule . /index.php?q=gallery&g2_path=%1 [QSA,L]

# drupal configuration
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_FILENAME} !-f
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !^/(photo|album|download)(/.*)?
RewriteRule ^(.*)$ /index.php?q=$1 [L,QSA]

rcsedit

I've had this little script laying around for awhile that I use as a wrapper for RCS to check out a group of files in one batch, edit them all, and commit them. So I setup repository for rcsedit in case others want to try it out.

It should be pretty easy to try out, just:

wget http://svn.silfreed.net/rcsedit/trunk/rcsedit

Should get you the script to use. I typically install it to /usr/local/bin. It will use your default $EDITOR if you have one defined, otherwise it will use vim. If the files exist it will check them all out (or only the ones that exist), edit them, and commit them as one batch (allows you to enter a log message once for all changes).

Let me know if you can think of any improvements.

A non-custom CMS!? What are you thinking!?

This is a big step for me. It's the first time I've used a non-custom CMS.

Since I've owned silfreed.net it's always been a custom app. I used jogger (then jolem, then blogstar) to create blog posts through a jabber/XMPP bot. However, this lacked the flexibility to create multiple tags. It was also getting difficult to maintain as my IM client of choice (Kopete) no longer has a subject bar, so I was relegated to starting up Psi then posting.

I'm sure you've read that I've been playing with Drupal a lot for Mozdev. The truth is I've learned to like it. A lot.

It might not be as lightweight as a custom CMS, but it makes up for it in flexibility. See those nice images over on the right-hand side? I've wanted to do that forever. See those multiple tags on this post? I've wanted to do that forever. See that trackback and pingback support? You get the idea.

Anyway, check it out and let me know if there are any broken links. I've tried to maintain historical links as much as possible, but I'm sure there are problems in places.

Look for much more blogging now that I can post with a lot less overhead.

Trackbacks Disabled

Due to comment spam, I've had to disable trackbacks. I don't think this is a big problem for anyone; the technical implementation was really bad. I don't have any approved trackbacks, but 1,938 non-approved trackbacks - all spam. This should hopefully slow down the flood of 'approve this comment!' emails I've been getting recently.

Site Update - Gallery 2.1

I've finally upgraded my photo album to Gallery 2.1rc1. I've been holding out on upgrading due to the fact that Gallery 2.0 didn't have an RSS module - now 2.1 does :-).
The theme was very easy to modify to include my custom header and footer to merge it right into my site layout - and I think the overall UI is very improved. I hear the real power is in the flexibility the modules provide, but I haven't really dug into that much yet.
In any case, feel free to try it out and let me know if any bugs pop up. It supposedly maintained my Gallery 1 mod_rewrite mappings, and seems to have done pretty well, so everyone's links should still be functioning. Drop me a line if you have any problems!

Killing Comment Spam

While some other blog software has had comment moderation before, since I use a completely hand-written CMS, I needed to implement it myself. I've been having quite the problem with comment spam recently (as any of you with RSS readers has seen, I'm sure), but hopefully my solution will fix it. Of course, I can't discuss it or it makes it very easy for the spammers to work around it. We'll just have to wait and see, I guess.

Packaging and Hacking

Although I'm not part of any cool group like RPMforge.net, I still do like to build packages. Unfortunately I've been a little lazy recently and have gotten behind in some that really should be done.
I've been working trying to get a bunch of different Jabber-related packages together like jabberd 2, jabberd 1.4, and aim-transport. I have a decent package for the first, a rough package for the 2nd (needs split into a devel package), and the 3rd is being a pain. Such is the life.
I've also been trying to get arpdetect working again on my laptop. I'm not sure where the problem is, but it hasn't been detecting when I change networks very reliably. I've started an attempt to close my pipe to the 'ifconfig' program nicer, and we'll see how far that gets us.
[Brady] came over and we tried to talk a little about [NetMRG] an the 80 open bugs we have, but we quickly got distracted by Star Wars. Oh well.

site updates

I recently upgraded both [NetMRG]'s and my own CVS repositories into subversion repositories. Everything seemed to go pretty smoothly. I setup ssh access for developers, and have both the webdav stuff setup for anonymous checkouts and the new ViewCVS setup for tree browsing. The only thing I recommend is that you use the 'fsfs' backend type so you don't need to give the Apache process write access to the repository.
I also built RPMs for FC3 for several packages that I didn't have. Mostly packages that I install on my servers that I haven't upgraded yet, but nice to have nonetheless. Feel free to let me know if there's a package you'd like updated to a newer version. I typically only update when I need to myself.

Mantis Source Control Integration is a pain

In NetMRG's bugtracker, I always thought it'd be nice to have a comment every time a commit to a bug was made. That way everyone involved would know when changes were being made, and what changes. Luckily, Mantis allows for this via its Source Control Integration.
If only it were that easy.
To make a long story short; whenever you start a project like this - use a separate CVSROOT - it will make your life much easier.
My loginfo
netmrg /usr/bin/php -q /path/to/mantisbt/core/checkin.php
ALL    /usr/local/bin/syncmail -S "NetMRG-CVS: " -R return@addr --quiet %%s to@addr
My mantisbt config_inc.php
$g_source_control_notes_view_status = VS_PUBLIC;
$g_source_control_account           = 'netmrgcvs';
$g_source_control_set_status_to     = OFF;
$g_source_control_regexp = "/bug\s*[#]{0,1}(\d+)/i";

website found in the wild

Yep, released another version of this website. Although I still think it needs some work, I'm much happier with it at this point than my old website, and wanted to stop looking at it. Feel free to leave me comments; I plan on updating it a bit more to fix colors and padding, but hopefully that won't take too long (read, months).

cvs access and jabber clients

In case you didn't notice, I now have CVS repository up for some of my projects. Most of them are small, but hopefully useful.

I've been playing w/ other jabber clients recently as well. I'm currently using gaim b/c I like how it works w/ AIM, but I'm missing my jabber features (like the ability to send a jabber normal message w/ subject, so I'm using tkabber to write this). I've tried kopete again as well (after spending an hour compiling it), but it now is missing the feature I mentioned! Very strange. So, I guess for now I'll keep using gaim since it's very nice just for chatting, but login w/ tkabber to update my blog. Kinda irritating.

photo album updated

It almost even works now! Things don't time out (thanks Daniel!), and it looks much better with everything else. In case you're wondering, I called the package 'phalbum', and I should be releasing it soon (once I get viewcvs setup). In the mean time, check out my online photo album.