#!/usr/bin/perl -w
# migrate your xchat settings from v1 to v2
#
# this contains just enough to work in my environment. In particular,
# server/network flags are incomplete, and various things like
# passwords, eom_cmds and per-server nicks aren't migrated because I
# don't use any of that.
#
# New files are created in .xchat-migrated; you will need to change
# this to .xchat2 or otherwise copy the files to .xchat2 in order to
# have them take effect. Obviously, don't do this while xchat is
# running.
use strict;
use File::Copy;

my $XCHAT_VERSION = "2.0.7";

my ( $old, $new ) = ( "$ENV{HOME}/.xchat", "$ENV{HOME}/.xchat-migrated" );

-d $new or mkdir $new;

my %upgrades =
  (
   "buttons.conf" => [ "buttons.conf", \&upgrade_commands ],
   "commands.conf" => [ "commands.conf", \&upgrade_commands ],
   "ctcpreply.conf" => [ "ctcpreply.conf", \&upgrade_commands ],
   "dlgbuttons.conf" => [ "dlgbuttons.conf", \&upgrade_commands ],
   "ignore.conf" => [ "ignore.conf" ], # not sure about this
   "keybindings.conf" => [ "keybindings.conf" ], # also not sure
   "notify.conf" => [ "notify.conf" ], # no idea
   "palette.conf" => [ "palette.conf" ],
   "pevents.conf" => [ "pevents.conf" ],
   "popup.conf" => [ "popup.conf", \&upgrade_commands ],
   "replace.conf" => [ "replace.conf" ], # also no idea
   "serverlist.conf" => [ "servlist_.conf", \&upgrade_servlist ],
   "urlhandlers.conf" => [ "urlhandlers.conf" ],
   "usermenu.conf" => [ "usermenu.conf" ],

   # Hmm.
   "url.save" => [ "url.save" ],

   "xchat.conf" => [ "xchat.conf", \&upgrade_xchat ],
  );

opendir( OLD, $old ) or die "$old: $!";
my @files = grep !/^\.\.?$/, readdir( OLD );
closedir( OLD );

for my $file ( @files ) {
    if ( -d "$old/$file" ) {
        print STDERR "skipping directory $file\n";
        next;
    }

    if ( !defined( $upgrades{$file})) {
        print STDERR "Don't know what to do with $file\n";
        next;
    }
    my ( $newname, $upfunc ) = @{$upgrades{$file}};
    if ( !defined( $upfunc )) {
        $upfunc = \&copy;
    }
    &$upfunc( "$old/$file", "$new/$newname" );
}

# serverlist file
sub upgrade_servlist {
    my ( $oldfile, $newfile ) = @_;
    open( F, "<$oldfile" ) or die "$oldfile: $!";

    my %conf = (
                networks => [],
               );

    while ( <F> ) {
        chomp;
        if ( /^\s*$/ ) {
            next;
        }

        my ( $key, $value ) = split( / = / );
        if ( !defined( $key )) {
            die "can't parse line $.:\n>$_\n";
        }
        if ( $key eq "version" ) {
            $conf{version} = $value;
        } elsif ( $key eq "servername" ) {
            if ( $value eq "SUB" ) {
                $conf{subnet} = 1;
                my %network = (
                               port => 6667,
                               flags => 0,
                               channel => "",
                               password => "",
                               nick => "",
                               comment => "",
                               eom_cmd => "",
                               servers => [],
                              );
                push @{$conf{networks}}, \%network;
            } elsif ( $value eq "ENDSUB" ) {
                # skip to the end of the block
                while (<F>) {
                    last if /^\s*$/;
                }
                next;
            } else {
                $conf{subnet} = 0;
                die "server outside network" if !defined( $conf{networks});
                my %server = ( 'servername' => $value, port => 6667 );
                push @{$conf{networks}->[-1]->{servers}}, \%server;
            }
        } elsif ( $key =~ /^(comment|port|flags|channel|password|nick|eom_cmd)$/) {
            if ( $conf{subnet}||0 ) {
                $conf{networks}->[-1]->{$key} = $value;
            } else {
                $conf{networks}->[-1]->{servers}->[-1]->{$key} = $value;
            }
        } else {
            die "unrecognised setting $key\n";
        }
    }

    delete $conf{subnet};

    # Now print it out in xchat 2 format
    open( N, ">$newfile" ) or die "$newfile: $!";

    print N "# extracted from version " . $conf{version} . "\n";
    print N "v=$XCHAT_VERSION\n\n"; # this is the version I'm working from
    for my $network ( @{$conf{networks}}) {
        # semantics have changed. used be that you could have
        # different servers belonging to the same 'network' but
        # connecting to different channels on startup. Now you need to
        # put them in separate networks.

        # let's find out if that's necessary!
        my $join = "";
        for my $server ( @{$network->{servers}}) {
            if ( $server->{channel} ||"" ) {
                if ( $join ) {
                    if ( $join ne $server->{channel}) {
                        $join = "split 'em, danno";
                    }
                } else {
                    $join = $server->{channel};
                }
            }
        }
        
        if ( $join ne "split 'em, danno" ) {
            print N "N=" . $network->{comment} . "\n";
            print N "F=" . $network->{flags} . "\n";
            print N "D=0\n"; # fixme - what's this?
            print N "J=$join\n" if $join;
        } else {
            print N "# " . $network->{comment} . "\n";
        }
        
        for my $server ( @{$network->{servers}}) {
            if ( $join eq "split 'em, danno" ) {
                print N "\nN=" . $server->{comment} . "\n";
                
                # new flags:
                # 8 => autoconnect
                # 1 => cycle until connected
                print N "F=";
                my $flags = 0;
                if ( $server->{flags} & 0x01 ) {
                    $flags |= 0x08;
                }
                print N $flags . "\n";
                
                print N "D=0\n"; # still no idea
                
                if ( $join eq "split 'em, danno" ) {
                    if ( $server->{channel}||"") {
                        print N "J=" . $server->{channel} . "\n";
                    }
                }
            }
            
            print N "S=" . $server->{servername};
            if ( $server->{port} != 6667 ) {
                print N "/" . $server->{port};
            }
            print N "\n";
        }
        
        print N "\n";
    }
    close( N );
}

# Commands no longer take a preceding slash
sub upgrade_commands {
    my ( $oldfile, $newfile ) = @_;

    open( F, "<$oldfile" ) or die "$oldfile: $!";
    open( N, ">$newfile" ) or die "$newfile: $!";
    while (my $line = <F>) {
        $line =~ s@(CMD\s+)/@$1@;
        print N $line;
    }
    close( N );
    close( F );
}

sub upgrade_xchat {
    my ( $oldfile, $newfile ) = @_;
    my @newconf;

    open( F, "<$oldfile" ) or die "$oldfile: $!";

    my @obsolete = (
                    # these no longer have separate controls
                    "dialog_indent_nicks",
                    "dialog_indent_pixels",
                    "dialog_show_separator",
                    "dialog_tint",
                    "dialog_tint_blue",
                    "dialog_tint_green",
                    "dialog_tint_red",
                    "dialog_transparent",
                    "dialog_wordwrap",
                    "background_dialog_pic",

                    # pango handles fonts
                    "font_normal",
                    "font_dialog_normal",
                    "font_shell",
                    "use_fontset",

                    # no translations
                    "trans_file",
                    "use_trans",

                    # don't seem to be around any more
                    "paned_userlist",
                    "treeview",
                    "truncchans",
                    "userhost",
                    "userlist_icons",
                    "windows_as_tabs",
                   );

    my @nochange = (
                    # these need investigation
                    "bluestring",
                    "channelbox",
                    "hilightnick",
                    "indent_nicks",
                    "indent_pixels",
                    "inputgad_superfocus",
                    "limitedtabhighlight",
                    "mail_check",
                    "nickcompletion",
                    "nickgad",
                    "persist_chans",
                    "show_invite_in_front_session",
                    "show_notify_in_front_session",

                    # yay!
                    "dcc_blocksize",
                    "dcc_ip",
                    "dcc_permissions",
                    "dcc_remove",
                    "dcc_send_fillspaces",
                    "dcc_stall_timeout",
                    "dcc_timeout",
                    "dnsprogram",
                    "notify_timeout",
                    );

    my %renamekey = (
                     "auto_indent" => "text_indent",
                     "auto_resume" => "dcc_auto_resume",
                     "auto_unmark_away" => "away_auto_unmark",
                     "autodccchat" => "dcc_auto_chat",
                     "autodccsend" => "dcc_auto_send",
                     "autodialog" => "gui_auto_open_dialog",
                     "autoopendccchatwindow" => "gui_auto_open_chat",
                     "autoopendccrecvwindow" => "gui_auto_open_recv",
                     "autoopendccsendwindow" => "gui_auto_open_send",
                     "autoreconnect" => "net_auto_reconnect",
                     "autoreconnectonfail" => "net_auto_reconnectonfail",
                     "autorejoin" => "irc_auto_rejoin",
                     "autosave" => "auto_save",
                     "autosaveurl" => "auto_save_url",
                     "awayreason" => "away_reason",
                     "ban_type" => "irc_ban_type",
                     "background_pic" => "text_background",
                     "beep_msg" => "input_beep_msg",
                     "beep_chans" => "input_beep_chans",
                     "chanmodebuttons" => "gui_mode_buttons",
                     "cmdchar" => "input_command_char",
                     "colorednicks" => "text_color_nicks",
                     "ctcp_number_limit" => "flood_ctcp_num",
                     "ctcp_time_limit" => "flood_ctcp_time",
                     "dccdir" => "dcc_dir",
                     "dccwithnick" => "dcc_save_nick",
                     "dialog_height" => "gui_dialog_height",
                     "dialog_width" => "gui_dialog_width",
                     "doubleclickuser" => "gui_ulist_doubleclick",
                     "fastdccsend" => "dcc_fast_send",
                     "filterbeep" => "input_filter_beep",
                     "first_dcc_send_port" => "dcc_port_first",
                     "fudgeservernotice" => "input_fudge_snotice",
                     "hide_version" => "irc_hide_version",
                     "hidemenu" => "gui_hide_menu",
                     "hideuserlist" => "gui_ulist_hide",
                     "hilight_notify" => "gui_ulist_hilight_notify",
                     "host_in_userlist" => "gui_ulist_show_hosts",
                     "hostname" => "net_bind_host",
                     "invisible" => "irc_invisibile",
                     "ip_from_server" => "dcc_ip_from_server",
                     "lagometer" => "gui_lagometer",
                     "last_dcc_send_port" => "dcc_port_last",
                     "logging" => "irc_logging",
                     "logmask" => "irc_logmask",
                     "mainwindow_height" => "gui_win_height",
                     "mainwindow_left" => "gui_win_left",
                     "mainwindow_save" => "gui_win_save",
                     "mainwindow_top" => "gui_win_top",
                     "mainwindow_width" => "gui_win_width",
                     "max_auto_indent" => "text_max_indent",
                     "max_lines" => "text_max_lines",
                     "msg_number_limit" => "flood_msg_num",
                     "msg_time_limit" => "flood_msg_time",
                     "newtabs_to_front" => "tab_new_to_front",
                     "nick_suffix" => "completion_suffix",
                     "nickname1" => "irc_nick1",
                     "nickname2" => "irc_nick2",
                     "nickname3" => "irc_nick3",
                     "notices_tabs" => "tab_notices",
                     "nu_color" => "notify_color",
                     "old_nickcompletion" => "completion_old",
                     "partreason" => "irc_part_reason",
                     "percascii" => "input_perc_ascii",
                     "perccolor" => "input_perc_color",
                     "perlwarnings" => "perl_warnings",
                     "pingtimeout" => "net_ping_timeout",
                     "priv_msg_tabs" => "tab_dialogs",
                     "proxy_host" => "net_proxy_host",
                     "proxy_port" => "net_proxy_port",
                     "proxy_type" => "net_proxy_type",
                     "proxy_auth" => "net_proxy_auth",
                     "proxy_user" => "net_proxy_user",
                     "proxy_pass" => "net_proxy_pass",
                     "quitreason" => "irc_quit_reason",
                     "raw_modes" => "irc_raw_modes",
                     "realname" => "irc_real_name",
                     "reconnect_delay" => "net_reconnect_delay",
                     "servernotice" => "irc_servernotice",
                     "show_away_message" => "away_show_message",
                     "show_away_once" => "away_show_once",
                     "show_separator" => "text_show_sep",
                     "skipmotd" => "irc_skip_motd",
                     "skipserverlist" => "gui_slist_skip",
                     "soundcmd" => "sound_command",
                     "sounddir" => "sound_dir",
                     "stamp_format" => "stamp_text_format",
                     "stripcolor" => "text_stripcolor",
                     "style_inputbox" => "gui_input_style",
                     "style_namelistgad" => "gui_ulist_style",
                     "tabchannels" => "tab_chans",
                     "tabs_position" => "tab_position",
                     "thin_separator" => "text_thin_sep",
                     "throttle" => "net_throttle",
                     "throttlemeter" => "gui_throttlemeter",
                     "timestamp" => "stamp_text",
                     "timestamp_logs" => "stamp_log",
                     "timestamp_log_format" => "stamp_log_format",
                     "tint" => "text_tint",
                     "tint_blue" => "text_tint_blue",
                     "tint_green" => "text_tint_green",
                     "tint_red" => "text_tint_red",
                     "topicbar" => "gui_topicbar",
                     "transparent" => "text_transparent",
                     "use_server_tab" => "tab_server",
                     "userlist_sort" => "gui_ulist_sort",
                     "userlistbuttons" => "gui_ulist_buttons",
                     "username" => "irc_user_name",
                     "wallops" => "irc_wallops",
                     "whois_on_notifyonline" => "notify_whois_online",
                     "wordwrap" => "text_wordwrap",
                    );

    while (<F>) {
        chomp;
        my ( $key, $value ) = split( / = / );

        if ( $key eq "version" ) {
            next;
        } elsif ( grep /^$key$/, @nochange  ) {
            # no change
        } elsif ( grep /^$key$/, @obsolete  ) {
            next;
        } elsif ( defined( $renamekey{$key})) {
            $key = $renamekey{$key};
        } else {
            die "no conversion for option $key ($value)\n";
        }
        push @newconf, "$key = $value\n";
    }

    # create the new config file
    open( N, ">$newfile" ) or die "$newfile: $!";
    print N "version = $XCHAT_VERSION\n";
    for my $line ( sort @newconf ) {
        print N $line;
    }
    close( N );
}
