You know Vista's in trouble when you suddenly find this in your inbox:

When WebClip was first demoed I thought it was the coolest thing ever. About a year (?) later, I finally found a use for it - a lightweight last.fm radio player.
- Go to your last.fm > Listen
- File > Open in Dashboard
- Hover over the Flash player, click + Enter
- Flip the widget and uncheck "Only play audio in Dashboard"

This site has been majorly downgraded today. I ditched the old XML-RPC blog engine and replaced it with a shiny, yet totally oldschool text file based solution. Sure, it doesn't have comments or categories, but there's something incredibly liberating to sit here and blog using nano over SSH.
The RSS should work, and an Apache Redirect makes sure the old RSS links still work, but previous links to old stories have not been remapped (the new system just uses the text file's mtime's timestamp as the ID, while the old one used a counter). Also direct links to posts are broken for now.
I don't even feel terribly bad about not having comments either - most of the stuff here is just inane technobabble anyways. If you do feel like commenting or sending a suggestion, then feel free to do so at filipp@mechmail.net.
The new blogging engine is about a whopping 30 lines of PHP.
It's surprisingly difficult to transfer entire wikis between groups since it's not just a matter of copying static HTML files as I thought previously. Here's a rough sketch of the process. It worked for me, but might not for everyone.
# wikimove from to
SRC=$1; DST=$2
cd /Library/Collaboration/Groups
# Take a backup
cp -r $SRC $SRC.bak; cp -r $DST $DST.bak
# Transfer the old search indices
sqlite3 $SRC/wiki/index.db .dump | sed 's/groups\/$SRC\//groups\/$DST\//' | sqlite3 $DST/wiki/index.db
chown teamsserver $DST/wiki/index.db;
chmod 0750 $DST/wiki/index.db
sed 's/groups\/$SRC\//groups\/$DST\//' $SRC/extrainfo >> $DST/extrainfo
# Transfer the actual documents and metadata
mv $SRC/wiki/*.page $DST/wiki/
cd $DST/wiki
for p in *.page ; do sed -i '' 's/groups\/$SRC\//groups\/$DST\//g' $p/page.html; done
for p in *.page ; do sed -i '' 's/groups\/$SRC\//groups\/$DST\//g' $p/page.plist; done
Don't forget to clean those .bak directories or else wikid will not start due to permissions errors. You'll still have references to your old group wiki inside the revisions.db files which you can get rid of with:
for p in *.page ;
do sqlite3 $p/revisions.db .dump | sed 's/groups\/$SRC\//groups\/$DST\//g' > /tmp/revisions.sql
rm $p/revisions.db
sqlite3 $p/revisions.db < /tmp/revisions.sql
done
srm /tmp/revisions.sql
Disaster recovery
If you accidentally hose a group wiki's page.plist and page.html files, it's possible to recover the latest versions of the pages, if you still have the revisions.db files intact. Here's how I did it:
cd group/wiki
for p in *.page ;
do sqlite3 $p/revisions.db "select content from revisions order by revision desc limit 1" > /tmp/wikitmp.plist
defaults read /tmp/wikitmp content > $p/page.html;
defaults delete /tmp/wikitmp content;
defaults write /tmp/wikitmp 'modifiedDate' -date $(defaults read /tmp/wikitmp modifiedDate | cut -d . -f 1)
plutil -convert xml1 /tmp/wikitmp.plist -o $p/page.plist;
done
srm /tmp/wikitmp.plist
This breaks things like accented characters (replaced by codes returned from defaults), but it sure beats rewriting every single page. :P
I learned about Expect from a past ADC video session about OS X deployment. Here's a very practical use for it - testing an SMTP server. Just run it with expect filename.
spawn telnet smtpserver 25
expect "220 "
send "MAIL FROM:test@example.comr"
expect "250 Ok$"
send "RCPT TO:testuser@serverr"
expect "250 Ok$"
send "DATAr"
expect "354"
send "From: "SMTP Test" <test@example.com>
Subject: This is a test
Date: Wed, 02 Jul 2008 15:08:43 +0000
Body of test message r.r"
expect "250 Ok$"
send "QUITr"
Just some observations on how 10.5.4 server handles group mails and aliases:
- Mail > Settings > Mailing Lists > Enable server group ... tells the server to scan all groups that have "Mailing list" enabled and update group member addresses into /etc/postfix/aliases. It uses the user record's Info > Email data. I would suggest setting the scanning to 1 min when setting things up.
- It uses /etc/postfix/aliases
- Nested groups are not expanded :(
- Users with only the Primary Group ID set to a mailinglist-enabled group will not be included in the postfix alias. Ie you should set the primary group to Staff and add all you meaningful groups as Other Groups. This looks like a bug to me...
- The teamsserver@server entry is added whenever you enable "Mailing list web archive"
- Teamsserver@server is actually delivered to /usr/share/wikid/bin/bundleMail.py
- It's now possible to handle group aliases using WGM if you don't use nested groups!
I don't like .forward files. They destroy any hope of having any kind of idea what aliases are being used. Postfix aliases are pretty bad too, but at least they're all in the same place. Here's a handy and very simple PHP snippet that converts .forward files to postfix aliases. It's not perfect, especially if you have vacation autoresponses enabled (ie |/bin/vacation -a ...), but it does save time:
#!/usr/bin/env php
<?php
# "Convert" .forward files to postfix aliases
if (!is_dir ($argv[1])) {
exit (sprintf ("usage: %s dirn", basename ($argv[0])));
}
$fws = trim (`find $argv[1] -maxdepth 2 -name .forward`);
printf ("# postfix aliases %s by %sn", date ('d.m.y'), `whoami`);
foreach (explode ("n", $fws) as $f)
{
$b = basename (dirname ($f));
# Trim empty lines
$u = preg_replace ("/^$/", "", file_get_contents ($f));
$u = str_replace ("n", ", ", $u);
printf ("%s t:t %sn", $b, rtrim ($u, ", "));
}
?>
A while back I presented a solution to a pretty icky problem - how to test for intermittent power issues. Here's a slightly improved version of that script. It keeps the machine on for 2 minutes before shutting down and also keeps an activity log. The delay is also used as the power on interval.
if [[ $USER != "root" ]]; then
echo "This must be run as root"
exit 1
fi
ROOTPW="1234"
DELAY=120
LOGFILE=~/Desktop/poweron.command.log
osascript -e "delay $DELAY"
TIMESTAMP=$(php -r "echo date ('H:i:s"', time() + $DELAY);")
echo $ROOTPW | sudo -S pmset repeat poweron MTWRFSU $TIMESTAMP
echo -n $(date "+%d.%m.%y @ %H:%I:%S") >> $LOGFILE
echo " " $(wc -l $LOGFILE) >> $LOGFILE
osascript -e "tell application "Finder" to shut down"
exit 0
Here's a pretty neat little AppleScript (did I just say that?!) for backing up random bits of your home folder. Just flag anything with the Purple Label in the Finder and PurpleSync will pick it up and back it up to a destination of your choosing, which it will prompt for only once (delete the pref file to reset).
If you only have Apple's rsync (2.6.3), then this will unfortunately butcher the extended attributes (like the label) and ACLs, since it does not understand the -X and -A arguments. Version 3.0 from MacPorts works better.
I kinda like the idea that, instead of defining stuff that I don't want backed up (ala TimeMachine), I just label the ones I do. Labels are very easy to use and audit and don't require special software.
The script itself is a whopping 11 lines long:
set dst to ""
set homedir to POSIX path of (path to home folder)
try
set dst to do shell script "defaults read " & homedir & "/Library/Preferences/com.firstpartysoftware.purplesync syncDestination"
on error
set dst to quoted form of POSIX path of (choose folder)
do shell script "defaults write " & homedir & "/Library/Preferences/com.firstpartysoftware.purplesync syncDestination " & dst
end try
do shell script "rsync -paz --delete --exclude=" & dst & " $(mdfind -onlyin " & homedir & " kMDItemFSLabel=3) " & dst
Stick it into iCal to have it run automagically.
The inability to create user accounts from the command line is something that every Mac SA runs into at some point. Then we write our own scripts (here's mine, here's dre's, for example).
But then today I discovered this:
zulu-30:~ admin$ /Library/Receipts/RemoteDesktopClient.pkg/Contents/Resources/makeuser
ERROR: You must be root to run this tool.
ERROR: --longname not provided.
ERROR: Flag --shortname not provided.
makeuser -r "<volume path>" [ -0 -v -h ] {other options}
General Options:
----------------
-h | --help : Print command help.
-v | --verbose : Verbose output.
Required Account Settings Options:
----------------------------------
-n | --longname "<string>" : User long name.
-s | --shortname "<string>" : User short name.
Optional Account Settings Options:
----------------------------------
-l | --loginpic "<file>" : Choose login picture.
-c | --cryptpassword "<string>" : Cryt password for this user.
The weird thing is there's different versions of this tool on the same OS X versions. The previous one was run on 10.4.11, as is the following:
flipbook:~ filipp$ /Library/Receipts/RemoteDesktopClient.pkg/Contents/Resources/makeuser
makeuser - scripted user creation under Mac OS X 10.2 or later
Usage: makeuser -user <user> -realname <realname> [ -password <shadowpass> | -cryptpass <cryptpass> ] [<opts>]
....
10.5 behaves like the latter. Notice that this is all indeed inside the receipt package. :) While makeuser is far from being as nice as dre's adduser, most of the time, it's good enough.