Index: /tools/openfire2ejabberd
===================================================================
--- /tools/openfire2ejabberd	(revision 300)
+++ /tools/openfire2ejabberd	(revision 300)
@@ -0,0 +1,155 @@
+#!/usr/bin/env ruby
+
+require 'rubygems'
+require 'rexml/document'
+require 'activerecord'
+require 'uri'
+
+include REXML
+include ActiveRecord
+
+class Ejabberd < Base
+	class User < Ejabberd; set_table_name "users"; end
+	class Roster < Ejabberd; set_table_name "rosterusers"; end
+	class RosterGroup < Ejabberd; set_table_name "rostergroups"; end
+end
+
+def usage
+	$stderr << "Usage: #{$0} [-dhv] <from-file> <to-uri>
+
+Options
+    d      Debug database queries
+    h      Show this help
+    v      Be verbose
+
+Example
+$ #{$0} -v example.com.xml mysql://root:passwd@localhost/ejabberd
+
+"
+	exit 1
+end
+
+STATES = {
+	'3 -1 -1' => [ 'B', 'N', 'N' ],
+	'2 0 -1' => [ 'F', 'O', 'N' ],
+	'2 -1 -1' => [ 'F', 'N', 'N' ],
+	'1 -1 -1' => [ 'T', 'N', 'N' ],
+	'0 -1 -1' => [ 'N', 'N', 'N' ],
+	'0 0 -1' => [ 'N', 'O', 'N' ],
+	'0 -1 2' => [ 'N', 'I', 'N' ],
+	'2 1 -1' => [ 'F', 'U', 'N' ] # fun!!1
+#	'0 -1 1' => [ 'N', ?, 'N'? ] # sordid
+}
+
+debug = false
+verbose = false
+
+if ARGV.size == 2
+	xmlfile = ARGV[1]
+	mysql = ARGV[2]
+elsif ARGV.size == 3
+	options = ARGV[1]
+	xmlfile = ARGV[2]
+	mysql = ARGV[3]
+else
+	usage
+end
+
+if options[0,1] == '-'
+	options.split( // ).each do |c|
+		case c
+			when 'd': debug = true; verbose = true
+			when 'v': verbose = true
+		end
+	end
+end
+
+users = {}
+inxml = Document.new( File.new( xmlfile ) )
+inxml.root.each_element( '//User' ) do |user|
+	users[user.elements['Username'].text] = user
+end
+
+if debug
+	$stderr << "--- debug mode on\n"
+	Base.logger = Logger.new( STDERR )
+	Base.colorize_logging = false
+end
+
+uri = URI.parse( mysql )
+
+Ejabberd.establish_connection(
+	:adapter => 'mysql', :host => uri.host,
+	:user => uri.user, :password => uri.password,
+	:database => uri.path[1..-1]
+)
+
+ObjectSpace.each_object(Module) do |o|
+	if o.to_s.include?( 'Ejabberd::' )
+		if not o.table_exists?
+			$stderr << "Could not find table \"#{o.table_name}\".\n"
+			exit 1
+		else
+			print( "Found table #{o.table_name}.\n" ) if verbose
+		end
+	end
+end
+
+users.each do |username, data|
+	password = data.elements['Password'].text
+	roster = data.elements['Roster']
+	count = 0
+	
+	if not Ejabberd::User.find_by_username( username )
+		Ejabberd::User.create(
+			:username => username, :password => password
+		)
+		print( "Created user \"#{username}\".\n" ) if verbose
+	else
+		print( "User \"#{username}\" already exists.\n" ) if verbose
+	end
+
+	roster.each_element do |item|
+		jid = item.attribute( 'jid' ).value
+
+#		if not Ejabberd::Roster.find( :all, :conditions => { :jid => jid, :username => username } )
+			nick = item.attribute( 'name' ) ? item.attribute( 'name' ).value : ''
+
+			sub = item.attribute( 'substatus' ).value
+			ask = item.attribute( 'askstatus' ).value
+			recv = item.attribute( 'recvstatus' ).value
+
+			group = item.elements['Group'].none? ? false : item.elements['Group'].first.value
+
+			state = "#{sub} #{ask} #{recv}"
+			ostate = "ask:#{ask} recv:#{recv} sub:#{sub}"
+
+			if STATES[state]
+				sub = STATES[state][0]
+				ask = STATES[state][1]
+				recv = STATES[state][2]
+			else
+				$stderr << "Unknown roster item status for \"#{jid}\": \"#{ostate}\".\n"
+				exit 1
+			end
+
+			Ejabberd::Roster.create(
+				:username => username,
+				:jid => jid, :nick => nick,
+				:ask => ask, :askmessage => '',
+				:server => recv, :subscription => sub
+			)
+
+			if group
+				Ejabberd::RosterGroup.create(
+					:username => username,
+					:jid => jid, :grp => group
+				)
+			end
+
+			count += 1
+#		end
+	end
+
+	print( "Saved #{count} roster items for \"#{username}\".\n" ) if verbose
+end
