Migrating Mailman Lists to Snow Leopard Server (10.6)

8 07 2010

Recently I was asked as part of my network/server admin duties to migrate a few mailing lists which had previously resided on a Debian system over to our OS X (10.6.4) system.

As it turned out this was a relatively trivial task but not without it’s hurdles.

The knowledge base for the Mailman system is quite extensive but due to the way Apple have messed with the setup of a lot of specific stuff like Mailman it turned out to be quite time consuming in the research, and a bit of trial and error to get it working correctly..

Just for clarification here are the differences between the folder structures.

Linux/Unix based systems generally keep all the Mailing list specifics, including bin and script files, archive and logs in subfolders of:
/var/lib/mailman

Whereas OS X really like to mix things up.
The archives, lists, logs, spam, data, locks and qfiles are all subfolders of:
/private/var/mailman/

The remaining folders including cgi-bin, messages, Mailman, cron, icons, scripts, bin, mail and templates are all subfolders of:
/usr/share/mailman/

Ok differences noted….

It should also be noted that the entire lists archive from the linux machine was transferred to the server and left in a temporary location as a .tar.bz2 file.

Open Server Admin and turn off the mail service.
Open the terminal and cd to where the Mailman archive was put
sudo su

Extract the archive
bzcat archive.tar.bz2 | tar xvf –

Enter the lists folder
cd var/lib/mailman/lists

Copy the required lists
rsync -a ./list-name /private/var/mailman/lists/
cd ../archives

Copy the required archives
rsync -a ./listName* /private/var/mailman/archives/private/

Fix the lists permissions and owner
cd /private/var/mailman/archives/private/
chmod -R 775 listname
chown -R nobody:_mailman listname
cd ../../lists
chmod -R 775 listname
chown -R nobody:_mailman listname

Create the public symlinks (if required)
cd ../archives/public
ln -s ../private/listname .

Fix the domain URL in the archives
cd /usr/share/mailman/bin/
./withlist -l -a -r fix_url — -v

Open Server Admin again and turn back on the mail service and you should see your new mailing lists listed in the appropriate tab under settings.

Note: If you have separate Virtual Domains you will need to change the withlist to:
./withlist -l -r fix_url listname -u url_host
and do each list in each different domain individually.

You can then test your Lists and your archives to make sure they work correctly.

Update 9/10
Further testing of the archives revealed that the ‘More Information’ links in the archive period and each thread page still pointed to the old server.

In the folder for each list there is an index.html which lists all the archive periods and a number of subfolders each named after the archive period they represent. These folders contain the html files that you see when you drill down through the archive.
These and the index.html contain hardcoded links to the server which contains the archive.

Easy to fix.
First make yourself su as regular users cannot access the lists folders
sudo su
cd to the private archives
sudo cd /private/var/mailman/archives/private/ListName
Replace the server name in the index.html
perl -pi -e ‘s/old.server/new.server/gi’ ./index.html
Replace the server name in all the sub folders html files
perl -pi -e ‘s/old.server/new.server/gi’ ./*/*.html

Alternatively if you moved a lot of lists and they are all on the same server domain you could do the replace from the private folder and replace all occurrences in all lists.
perl -pi -e ‘s/old.server/new.server/gi’ ./*/index.html
perl -pi -e ‘s/old.server/new.server/gi’ ./*/*/*.html

This worked for me and may require slight modification for your mailman archives.





Daisy Developments

21 05 2010

Well its been a while since I posted an update so here goes.

Due to my new-found skills in problem solving of reverse engineering Daisy Formats into navigable constructs, I was commissioned to write an iPhone (now iPad too) version of Olearia.  As it turned out the port to the iPhone platform was just not possible due to the nature (mainly memory consumption) of the NSXMLDocument structures Olearia uses and that they are not available in the iPhone API’s.  Sure there are open source frameworks which do similar stuff but in the end the set of options and variations of formats was just too complex.

Time for another tack.  So after a few meetings with different people and explaining the complexities and variations of the DAISY formats I had a brain wave (thanks Travis), seeing as all the id tags in a given book are unique why not build a parser that creates its own navigable context?

It took a while (and it’s still being updated) but now I have a parser which can load a book consisting of any number of smil files (usually between 1 and 40) which may contain up to several hundred elements. I have one book which has a single SMIL file containing just under 3000 lines. The parser also deals with the ncc.html, .NCX, and .OPF files.

All this parsing takes mere seconds (usually 2-3) which is pretty impressive IMHO on such a resource sparse device.

There were some bits like the SMIL time code transformer that came from Olearia but have since  undergone extensive changes to suit the different needs of the iPhone playback system.

I also added the ability to use other forms of navigation like goto page (assuming the book has page markups), phrase, sentence or word navigation depending on how the book was authored.

In progress is the recognition of “skippable items” like production notes and sidebars, etc.

That will be after the public release of DaisyWorm which is slated for the first week of June 2010.

Any other updates will take place after WWDC which should be a blast.

Thats it for now.

Back to the code😉





Sparkle Appcast Automation in XCode update

16 01 2010

I recently decided that because Olearia had reached 1.0 (finally) that I should implement  some sort of self update aka Sparkle to make my end users life easier.
Little did I realise that this would take me on a quest that would cover most of 2 days researching and testing to get it just right.

For starters I have to thank Allan Craig for his excellent extension
to Mark Liyanage’s initial setup of this automation.
Based on both of these I took it to the next level IMHO😉

This version has these new features over Allan Craigs

  • Makes an ‘item’ tag including a description that can be embedded directly into the appcast xml file
  • If the addition to the appcast file has been previously generated the script will only update the ‘enclosure’ tag in the file leaving any changes that have been made to the description alone.
  • Removed the need for the css and version html files due to the description being embedded in the appcast file.
  • Added the usage of the CFBundleShortVersionString due to the fact that I’m weird and like my subversion build numbers in my about box. This is easily rectified if you don’t use this feature.
  • Fixed the generation of the signing string for 10.6 (Snow Leopard). This will need to be changed if you are still using Leopard.
  • The script is now multi-project aware and will look in a common place for a config file named with the name of the current project. This means that the script can be copied from project to project on your system without any changes once it has been setup.

The following is an almost direct quote from Allan Craigs blog with changes where necessary.

INTRO:

IMPORTANT: You will need to read Marc’s article and make a secure note of the private key first before moving on. I would also recommend making the ‘Deployment’ Target as well.

IMPORTANT: This Script has been heavily modified from its original state and updated for Snow Leopard 10.6, if using this under 10.5 you will need
to change the multi-line ‘security’ back to its original form as per Marc or Allan’s posts.

INSTRUCTIONS:

Project Config YAML file
A YAML file is an editable text file and makes it easy to set up our
configuration information. It also enables us not to have to change the main
script once we have it the way we want it.

Create a ‘{Your_Project_Name}.yaml’ file and place it in the folder that contains
all of your other projects config files.
Personally I like to keep my things relatively organized so my path to my configs is ‘/Users/username/Code/Appcasts/configs/’
NOTE: see the configs_folder_path Variable below

include the following making the necessary changes.

—–
download_base_url: ‘http://www.your_website.com/app_folder/’
appcast_basefolder: ‘/users/user_name/desktop/app_name/’
appcast_xml_name: ‘add_to_appcast.xml’
keychain_privkey_name: ‘Sparkle Private Key’
—–

IMPORTANT: If you change the variable names here you also
need to change them in the script.

VARIABLE EXPLANATION

download_base_url:
Your website url where you will place your updated project

appcast_basefolder:
The base file is created for you and a project folder inside that with
the name of your project and version number.
example

     - ProjectName
          - ProjectName 1.0
          - add_to_appcast.xml (contains the 'item' info)
     - ProjectName 1.0.zip
          - ProjectName 1.1
          - add_to_appcast.xml (contains the 'item' info)
          - ProjectName 1.1.zip

The following file is created for you if they do not already exist.
appcast_xml_name:

Your archived project file is also copied to the project folder
AppName {version number}.zip

appcast_xml_name:
This file holds the results of the script. You will copy this into your appcast file.
Name to your liking.
NOTE: This file only has placeholders for description information you will need to edit this to complete your feature list before adding it to your appcast file.

keychain_privkey_name:
You should understand this after reading Marc’s article.
Name to your liking.

Once your project’s config file is created and placed in your configs folder,
edit the @configs_folder_path below in the initialize method to point to its correct location.
Now if you have not done this already, create a new aggregated Target named “Deployment”
in your XCode project and drag your current target into it.
Add this script as a ‘Run Script’ build phase on the “Deployment” Target, Marc has some nice pics showing how to do this.
Set the bash to /usr/bin/ruby and you are finished!

Now you can use the “Deployment” target with a release build mode to generate the initial files and sign your package.

NOTE: if you are a developer that does not use the CFBundleShortVersionString as I do in this case it is simply a matter of removing the ‘@short_version’ from the ‘instantiate_project_variables ‘ method then doing a search for ‘@short_version’ and replace with ‘@version’

Please bear with me as this was my first experience with Ruby which made for an interesting learning curve.

Leave a comments if you would like the script emailed or have any other queries, errata or issues.

Hope this helps Someone out there.


#!/usr/bin/env ruby -w

#################################################################################
#                                                                               #
#     appcast_builder.rb                                                        #
#                                                                               #
#     author:   Craig Williams                                                  #
#     created:  2009-01-09                                                      #
#                                                                               #
#	  modified and updated by: Kieren Eaton                                 #
#	  Date:	                   2010-01-14                                   #
#                                                                               #
#################################################################################
#                                                                               #
#     This program is free software: you can redistribute it and/or modify      #
#     it under the terms of the GNU General Public License as published by      #
#     the Free Software Foundation, either version 3 of the License, or         #
#     (at your option) any later version.                                       #
#                                                                               #
#     This program is distributed in the hope that it will be useful,           #
#     but WITHOUT ANY WARRANTY; without even the implied warranty of            #
#     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             #
#     GNU General Public License for more details.                              #
#                                                                               #
#     You should have received a copy of the GNU General Public License         #
#     along with this program.  If not, see <http://www.gnu.org/licenses/>.     #
#                                                                               #
#################################################################################

=begin
  INTRO:
    In his article, Marc uses a bash script to automate the process of signing your
    Sparkle enabled app and explains how to put your private and public keys in your
    keychain. I wrote a Ruby version that extends this functionality to
    include a few more options…

    IMPORTANT: You will need to read Marc's article first before moving forward.

	IMPORTANT: This Script has been heavily modified from its original state
				and updated for Snow Leopard 10.6, if using this under 10.5 you will need
				to change the

    Here is a quick list of updated features:

    	1. automatic selection of correct config file for a given project
    	2. Creates project release folder if it does not exist
    	3. Creates sub-folders based on version number
    	4. Creates xml file containing the basic '' info generated by the script
    	5. updates the pubDate and enclosure Tags if the basic item info already exists
    	6. Copies the newly created archive to the project folder

    The project release folder is not the 'Release' folder Xcode creates.
    This is a folder that contains this and future Sparkle release builds.
    See 'appcast_basefolder' below.

    INSTRUCTIONS:

    Config YAML file
    A YAML file is easily editable and is a good place for us to set up our
    configuration information. It also enables us not to have to change the
    script once we have it the way we want it.

    Create a 'Your_Project_Name.yaml' (where Your_Project_Name is the name of the project) file
    and place it in the folder that contains all of your other projects config files.
    NOTE: see the configs_folder_path Variable below

    include the following making the necessary changes.
    ---
    download_base_url:      'http://www.your_website.com/app_folder/'
    appcast_basefolder:     '/users/user_name/desktop/app_name/'
    appcast_xml_name:       'appcast.xml'
    keychain_privkey_name:  'Sparkle Private Key'

    IMPORTANT: If you change the variable names here you also
    need to change them in the script.

    VARIABLE EXPLANATION

    download_base_url:
      Your website url where you will place your updated project

    appcast_basefolder:
      The base file is created for you and a project folder inside that with
      the name of your project and version number.
    	eg  - ProjectName
      		  - ProjectName 1.0
    			    - appcast.xml (contains the '' info)
    			    - 1.0.html
    			    - rnotes.css
      			  - ProjectName 1.0.zip
      		  - ProjectName 1.1
      			  - appcast.xml (contains the '' info)
      			  - 1.1.html
      			  - rnotes.css
      			  - ProjectName 1.1.zip

    The following files are created for you if they do not already exist.
        appcast_xml_name:

    Your archived project file is also copied to the project folder
        AppName {version number}.zip

    appcast_xml_name:
      This file holds the results of the script. What is between the '' tags that
      you will copy into your complete appcast.xml file.
      Name to your liking.

    keychain_privkey_name:
      You should understand this after reading Marc's article.
      Name to your liking.

    Once your config.yaml file is created and placed in your projects 'Release' folder,
    edit the "" below in the initialize method to point to its correct location.
    Now create a new aggregated Target named "Deployment" in your XCode project and drag your
    current target into it. Add this script as a 'Run Script' build phase on the "Deployment" Target.
    Set the bash to /usr/bin/ruby and you are finished!

    Now you can use the "Deployment" target with a release build mode to generate the initial files and sign your package.

    If you have questions, ideas or bug reports please post them at:

    This script and methodology is based heavily on Allen Craig's blog posts:
    http://allancraig.net/blog/?p=65

=end

class AppCast
  require 'yaml'
  require 'tmpdir'
  require 'fileutils'

  MESSAGE_HEADER    = 'APPCAST BUILD MESSAGE'

  def initialize
    @signature = ''

   # ---------------------
    # edit this path to point to your folder that contains all your appcast application configs
    @configs_folder_path = '/Code/Appcasts/configs/'
    # ---------------------

   require_release_build
    instantiate_project_variables
    load_config_file
    instantiate_appcast_variables
  end

  def main_worker_bee
    create_appcast_folder_and_files
    remove_old_zip_create_new_zip
    file_stats
    create_key
    create_appcast_xml
    copy_archive_to_appcast_path
  end

  # Only works for Release builds
  # Exits upon failure
  def require_release_build
      if ENV[&quot;BUILD_STYLE&quot;] != 'Release'
        log_message(&quot;Deployment target requires 'Release' build style&quot;)
        exit
      end
  end

  # Exits if no config.yaml file found.
  def load_config_file
  	project_name = ENV['PROJECT_NAME']
  	config_file_path = &quot;#{@configs_folder_path}#{project_name}.yaml&quot;
	if !File.exists?(config_file_path)
      log_message("No '#{project_name}.yaml' file found in configs directory.")
      exit
    end
    @config = YAML.load_file(config_file_path)
  end

  def instantiate_project_variables
    @proj_dir               = ENV['BUILT_PRODUCTS_DIR']
    @proj_name              = ENV['PROJECT_NAME']
    @version                = `defaults read &quot;#{@proj_dir}/#{@proj_name}.app/Contents/Info&quot; CFBundleVersion`
    @version                = @version.gsub(/\D+/,&quot;&quot;)
    @short_version          = `defaults read &quot;#{@proj_dir}/#{@proj_name}.app/Contents/Info&quot; CFBundleShortVersionString`
    @archive_filename       = &quot;#{@proj_name} #{@short_version.chomp}.zip&quot;
    @archive_path           = &quot;#{@proj_dir}/#{@archive_filename}&quot;
  end

  def instantiate_appcast_variables
    @appcast_xml_name       = @config['appcast_xml_name'].chomp
    @appcast_basefolder     = @config['appcast_basefolder'].chomp
    @appcast_proj_folder    = &quot;#{@config['appcast_basefolder']}/#{@proj_name}_#{@short_version}&quot;.chomp
    @appcast_xml_path       = &quot;#{@appcast_proj_folder}/#{@appcast_xml_name}&quot;
    @download_base_url      = @config['download_base_url']
    @keychain_privkey_name  = @config['keychain_privkey_name']
    @download_url           = &quot;#{@download_base_url}#{@archive_filename}&quot;
  end

  def remove_old_zip_create_new_zip
    Dir.chdir(@proj_dir)
    `rm -f #{@proj_name}*.zip`
    `zip -qr &quot;#{@archive_filename}&quot; &quot;#{@proj_name}.app&quot;`
  end

  def copy_archive_to_appcast_path
    begin
      FileUtils.cp(@archive_path, @appcast_proj_folder)
    rescue
      log_message("There was an error copying the zip file to appcast folder\nError: #{$!}")
    end
  end

  def file_stats
    @size     = File.size(@archive_filename)
    @pubdate  = `date +"%a, %d %b %G %T %z"`
  end

  def create_key
    priv_key_path = &quot;#{Dir.tmpdir}/priv_key.pem&quot;
	intermed_file = &quot;#{Dir.tmpdir}/intermed_data&quot;
    temp = `security find-generic-password -g -s "#{@keychain_privkey_name}" 2>&1 1>/dev/null \
				| perl -pe '($_) = /"(.+)"/'`

	 File.open(intermed_file, 'w+') { |f| f.puts temp.split(&quot;\\012&quot;) }

	 key = `perl -MXML::LibXML -e 'print XML::LibXML->new()->parse_file("#{intermed_file}")->findvalue(q(//string[preceding-sibling::key[1] = "NOTE"]))'`

	log_message(key)
    if key == ''
      log_message(&quot;Unable to load signing private key with name '#{@keychain_privkey_name}' from keychain\nFor file #{@archive_filename}&quot;)
      exit
    end

   File.open(priv_key_path, 'w+') { |f| f.puts key }

   @signature = `openssl dgst -sha1 -binary < '#{@archive_path}' \
                   | openssl dgst -dss1 -sign '#{priv_key_path}' \
                   | openssl enc -base64`

    `rm -fP #{priv_key_path}`
	`rm -fP #{intermed_file}`
    log_message(@signature)

    if @signature == ''
      log_message(&quot;Unable to sign file #{@archive_filename}&quot;)
      exit
    end
  end

  def create_appcast_xml
   # if the file exists it may have already been edited
   # so dont overwrite it
   if !File.exists?(@appcast_xml_path)

     appcast_xml =
    &quot;&lt;item&gt;
	&lt;title&gt;Version #{@short_version.chomp}&lt;/title&gt;
	 <description><![CDATA[
		&lt;h2&gt;New in #{@short_version.chomp}&lt;/h2&gt;
		&lt;ul&gt;
                &lt;li&gt;Item 1&lt;/li&gt;
                &lt;li&gt;Item 2&lt;/li&gt;
         &lt;/ul&gt;

		]]&gt;&lt;/description&gt;
     &lt;pubDate&gt;#{@pubdate.chomp}&lt;/pubDate&gt;
	&lt;enclosure
		url=\&quot;#{@download_url.chomp}\&quot;
		sparkle:version=\&quot;#{@version.chomp}\&quot;
		sparkle:shortVersionString=\&quot;#{@short_version.chomp}\&quot;
		type=\&quot;application/octet-stream\&quot;
		length=\&quot;#{@size}\&quot;
		sparkle:dsaSignature=\&quot;#{@signature.chomp}\&quot;
	/&gt;
    &lt;/item&gt;&quot;

    File.open(@appcast_xml_path, 'w') { |f| f.puts appcast_xml }
	else
		update_appcast_xml
    end
  end

  def update_appcast_xml
  	new_enclosure = &quot;&lt;pubDate&gt;#{@pubdate.chomp}&lt;/pubDate&gt;
	&lt;enclosure
		url=\&quot;#{@download_url.chomp}\&quot;
		sparkle:version=\&quot;#{@version.chomp}\&quot;
		sparkle:shortVersionString=\&quot;#{@short_version.chomp}\&quot;
		type=\&quot;application/octet-stream\&quot;
		length=\&quot;#{@size}\&quot;
		sparkle:dsaSignature=\&quot;#{@signature.chomp}\&quot;
	/&gt;
    &lt;/item&gt;&quot;

    File.open(@appcast_xml_path, 'r+') do |f|
    lines = f.readlines
	count = 0
	# remove all lines after and including the pubDate tag
    lines.each do |it|
       	if it =~ /&lt;pubDate&gt;/
       		break
       	end
    	count += 1
    end
    lines.slice!(count..-1)
    f.pos = 0
    f.print lines
	# add the new enclosure tags and close item tag
    f.print new_enclosure
    f.truncate(f.pos)
	end

  end

  # Creates the appcast folder if it does not exist
  # or is accidently moved or deleted

  def create_appcast_folder_and_files
    base_folder = @appcast_basefolder
    project_folder = @appcast_proj_folder

    Dir.mkdir(base_folder)    if !File.exists?(base_folder)
    Dir.mkdir(project_folder) if !File.exists?(project_folder)
  end

  def log_message(msg)
    puts &quot;\n\n----------------------------------------------&quot;
    puts MESSAGE_HEADER
    puts msg
    puts &quot;----------------------------------------------\n\n&quot;
  end
end

if __FILE__ == $0
  newAppcast = AppCast.new
  newAppcast.main_worker_bee
  newAppcast.log_message(&quot;It appears all went well with the build script!&quot;)
end





Adding Perian supported Filetypes to Quicktime X

13 10 2009

After I upgraded to Snow Leopard (10.6.1) I found that I was no longer able to play .mkv files amongst others in the nice new quicktime player that comes with it.
After the “Perian’s Type Installer” failed and I dont know enough Applescript to fix it😦 I resorted to fixing it by hand.

I could still view the movies etc in Quicktime Player 7 which meant that the player had not been overwritten during the upgrade.

Ok lets cut to the chase….  open the info.plist  located at /Applications/Quicktime Player/Contents/info.plist

this contains all the filetypes that Quicktime Player will/can open.  We just have to add in the ones Perian adds support for.

Look right dow the bottom for the “Imported Type UTIs” array, if your editing the raw text the search for “UTImportedTypeDeclarations”.  Mine had only one type in it.

now paste the following inside that array, not inside the existing type.
Code Here

Save the file.
Note: you will probably have to give yourself write permissions to the Contents folder and the infor.plist file.

Open any .mkv file in quicktime Player X.

Apparently The Perian Devs are working on fixing this issue but until then this works fine.

Enjoy😉





NSarray, NSDictionary and NSPopupButton dilemmas

13 10 2009

Well I thought I knew and understood bindings well enough to fix some things in Olearia.

Apparently Not!

In a nutshell in the prefs controller I created an array of Dictionaries each holding the name and the identifier of all the available voices on the system.  This would then be used to populate the popup button in the Voices panel of the prefs window.

It turned out that it was fairly simple but a bit obscure as to why it works the way it does.

I basically followed this post and changed the “name” and “value” identifiers in the bindings panel to the ones I used in my dicts. I also didnt need the set Method for the popup as this was also implemented through the User Defaults.

I am not sure why having the array controller implimented in code works as against binding the content of the array controller in IB to the actual array of the class but I’m not complaining😉

More News on Olearia Coming soon….





Olearia Update Part 3

2 07 2009

I dont know what I should call these updates …..  by Date?  Part  xx?   Oh Well I will just have to see what fits when it comes time to do this again😉

Olearia is now nearing 1.0! Yay finally!

so far we have

  • Playback for 2.02, 2002, 2005 books with audio Content
  • A new window showing the text content of the Book
  • a window displaying the information about the book.
  • Automatic playback via the SMIL file (finer grain control of the audio segments and their tags)
  • User navigation through the Control file (ncc.html, .ncx) of Levels and reading elements
  • Saving of current playback position

I know it doesnt sound all that different at this stage feature wise from the 0.9.5.1 release, but trust me this is a lot simpler to add a feature than the previous version was ever going to be!

Still to come

Sooner Rather than later

  • Fast Forward and rewind across audio segments (basically just transferring code from framework into the plugins😉
  • Adding Support for Text only books
  • Support for BookShare and NIMAS formats.  (Currently they will open and information can be shown but no playback)
  • Along with the text only support will come over-ride of pre-recorded audio in full Audio+text books allowing the user to have the book read back to them with their choice of synthesized voice (great for books with synthesized audio that is not correctly pronounced)

Later Rather than Sooner

  • bookmarking and Go To functions (not sure how useful the Go To will be but time will tell)
  • possibly a structure window (Tree?) showing the table of Contents and allowing a user to choose a playback point  from there.
  • support for skippable items in the smil file
  • Ui Enhancements like a Path type browser showing the current location in the book.
  • Other UI enhancements like audio position tracking ala iTunes

Oh Yeah there will eventually be plugins available for Encrypted RFB&D Books and potentially ePub books to.  These will not be open source.

After All that (quite possibly before) there will be a port to the iPhone now that it has voiceover and zoom support.

Not too sure about the 2nd Gen iPod Touch as the 3.0 software for this does not have the accessibility side that I am aware of. (I still have yet to update to 3.0)

Well thats it for now.

Any body reading this that want to beta test (beta testers are always appreciated) can leave a comment noting this.

Ciao





Olearia Update 9/6

9 06 2009

Seeing as my contract finished and there has not been much on the job horizon I have had some time to spend on updating the core of Olearia.

So far I have implemented a full plugin style architecture which allows really easy adding of other formats via a set protocol.  I have managed to get the 5 standard book type to validate and load correctly via their individual plugins and get book info on each of them.

Navigation will probably be a simple matter of transferring most of the navpoint methods from 0.9.5.1 with minor adjustments for ivar changes in this new layout.

I am pretty happy with what I have achieved  so far. Most of it came from having a massive amount of down time while I was in hospital with my son for a week.

What else?….   ahh I have broken Olearia down into 3 separate projects, Olearia,  TalkingBook Framework and the standard plugins (2.02, 2002, 2005, Bookshare and NIMAS).

This was just an easier way of managing all the aspects of the projects themselvs and how they interact.  This should also make it easier for me to build a project for the iPhone/Touch which will be based on the framework.

More details will emerge as functionality is added.