summaryrefslogtreecommitdiffstats
path: root/network/ClusterSSH/patches/00-4.01_05.diff
blob: d7b05cf631406c0b48469f495c9c9ca2e84352ba (plain)
diff --git a/Build.PL b/Build.PL
index be3afb3..467c201 100644
--- a/Build.PL
+++ b/Build.PL
@@ -6,7 +6,7 @@ use Module::Build;
 my $build = Module::Build->new(
     meta_merge => {
         resources => {
-            repository => [
+            Repository => [
                 'http://clusterssh.git.sourceforge.net/',
                 'http://github.com/duncs/clusterssh',
             ],
@@ -34,6 +34,10 @@ my $build = Module::Build->new(
         'File::Which'         => 0,
         'File::Temp'          => 0,
         'Test::DistManifest'  => 0,
+        'Test::Differences'   => 0,
+    },
+    configure_requires => {
+        'Module::Build' => 0,
     },
     add_to_cleanup     => ['App-ClusterSSH-*'],
     create_makefile_pl => 'traditional',
diff --git a/Changes b/Changes
index c1fe7e9..485932d 100644
--- a/Changes
+++ b/Changes
@@ -1,3 +1,34 @@
+2013-03-05 Duncan Ferguson <duncan_ferguson@user.sf.net> - v4.01_05
+- New option (-m, --unique-servers) to remove repeated servers when openeing terminals (Thanks to Oliver Meissner)
+- Drop MYMETA.yml and .json files from the distribution
+- Do not set default user name to prevent overriding ssh configuration
+
+2013-02-26 Duncan Ferguson <duncan_ferguson@user.sf.net> - v4.01_04
+- Fixed 'ccon' not calling the correct command (Sf bug 3605002)
+- Fixed clusters not being defined correctly within the .clusterssh/config file (Sf bug 3605675)
+
+2013-02-15 Duncan Ferguson <duncan_ferguson@user.sf.net> - v4.01_03
+* Correct documentation for references to $HOME/.clusterssh/config
+* Re-add user back into the configurartion file
+* Add in missing newline for some error messages
+* Allow the path to rsh/ssh/telnet to be defined in the configuration file
+* Move .csshrc to .csshrc.DISABLED since it should no longer be used
+* Error emitted when adding a host via the "Hosts" drop-down (Debian bug ID #578208)
+* Pastes uses a strange keyboard layout (Debian bug ID #364565)
+* Cope with being invoked by 'clusterssh' (Debian bug ID #644368)
+* Fix migration of .csshrc when not working as expected (Debian bug ID #673507)
+* Remove doc references to 'always_tile' as renamed 'window_tiling' (Debian bug ID #697371)
+* Updated manpage whatis entries (patch by Tony Mancill)
+* Fix watch line expression to catch 4.x series tarballs (Debian patch LP ID #1076897)
+* Allow tests to pass successfully when run as root
+* Fix cssh starting if xterm is not installed (Sf bug 3494988)
+* Set WM_CLASS on windows to 'cssh' (Sf bug 3187736)
+
+2012-12-09 Duncan Ferguson <duncan_ferguson@user.sf.net> - v4.01_02
+* Fix logic when using 'autoclose' on the command line or config file
+* Fix $HOME/.clusterssh/clusters being read in
+* Fix 'ctel', 'crsh' and 'ccon'so they work as expected
+
 2011-12-09 Duncan Ferguson <duncan_ferguson@user.sf.net> - v4.01_01
 * Include missing files from release tarballs
 
diff --git a/MANIFEST b/MANIFEST
index cebe4b1..a4b4983 100644
--- a/MANIFEST
+++ b/MANIFEST
@@ -14,13 +14,11 @@ lib/App/ClusterSSH/Helper.pm
 lib/App/ClusterSSH/Host.pm
 lib/App/ClusterSSH/L10N.pm
 lib/App/ClusterSSH/L10N/en.pm
-Makefile
-Makefile.old
 Makefile.PL
 MANIFEST
 MANIFEST.SKIP
+META.json
 META.yml
-MYMETA.json
 README
 t/00-load.t
 t/01l10n.t
diff --git a/MANIFEST.SKIP b/MANIFEST.SKIP
index 3753e38..4900842 100644
--- a/MANIFEST.SKIP
+++ b/MANIFEST.SKIP
@@ -4,7 +4,11 @@
 ^Build$
 ^.git/
 ^.gitignore
+^Makefile$
+^Makefile.old$
 ^MANIFEST\.bak$
-^MYMETA.yml$
+MYMETA.json
+MYMETA.yml
+pm_to_blib
 .*\.swp$
 ^WIP_TASKS$
diff --git a/META.json b/META.json
new file mode 100644
index 0000000..26b6d74
--- /dev/null
+++ b/META.json
@@ -0,0 +1,94 @@
+{
+   "abstract" : "A container for functions of the ClusterSSH programs",
+   "author" : [
+      "Duncan Ferguson <duncan_j_ferguson@yahoo.co.uk>"
+   ],
+   "dynamic_config" : 1,
+   "generated_by" : "Module::Build version 0.4003, CPAN::Meta::Converter version 2.112621",
+   "license" : [
+      "perl_5"
+   ],
+   "meta-spec" : {
+      "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec",
+      "version" : "2"
+   },
+   "name" : "App-ClusterSSH",
+   "prereqs" : {
+      "build" : {
+         "requires" : {
+            "File::Temp" : 0,
+            "File::Which" : 0,
+            "Readonly" : 0,
+            "Test::Differences" : 0,
+            "Test::DistManifest" : 0,
+            "Test::Pod" : 0,
+            "Test::Pod::Coverage" : 0,
+            "Test::Trap" : 0
+         }
+      },
+      "configure" : {
+         "requires" : {
+            "Module::Build" : 0
+         }
+      },
+      "runtime" : {
+         "requires" : {
+            "Exception::Class" : "1.31",
+            "Locale::Maketext" : 0,
+            "Tk" : "800.022",
+            "Try::Tiny" : 0,
+            "X11::Protocol" : "0.56",
+            "version" : 0
+         }
+      }
+   },
+   "provides" : {
+      "App::ClusterSSH" : {
+         "file" : "lib/App/ClusterSSH.pm",
+         "version" : "4.01_05"
+      },
+      "App::ClusterSSH::Base" : {
+         "file" : "lib/App/ClusterSSH/Base.pm",
+         "version" : "0.02"
+      },
+      "App::ClusterSSH::Cluster" : {
+         "file" : "lib/App/ClusterSSH/Cluster.pm",
+         "version" : "0.01"
+      },
+      "App::ClusterSSH::Config" : {
+         "file" : "lib/App/ClusterSSH/Config.pm",
+         "version" : "0.02"
+      },
+      "App::ClusterSSH::Helper" : {
+         "file" : "lib/App/ClusterSSH/Helper.pm",
+         "version" : "0.02"
+      },
+      "App::ClusterSSH::Host" : {
+         "file" : "lib/App/ClusterSSH/Host.pm",
+         "version" : "0.03"
+      },
+      "App::ClusterSSH::L10N" : {
+         "file" : "lib/App/ClusterSSH/L10N.pm",
+         "version" : 0
+      },
+      "App::ClusterSSH::L10N::en" : {
+         "file" : "lib/App/ClusterSSH/L10N/en.pm",
+         "version" : 0
+      }
+   },
+   "release_status" : "testing",
+   "resources" : {
+      "bugtracker" : {
+         "web" : "http://sourceforge.net/tracker/?group_id=89139"
+      },
+      "homepage" : "http://clusterssh.sourceforge.net/",
+      "license" : [
+         "http://dev.perl.org/licenses/"
+      ],
+      "x_Repository" : [
+         "http://clusterssh.git.sourceforge.net/",
+         "http://github.com/duncs/clusterssh"
+      ]
+   },
+   "version" : "4.01_05"
+}
diff --git a/META.yml b/META.yml
index bdf1020..7e93bb8 100644
--- a/META.yml
+++ b/META.yml
@@ -6,13 +6,15 @@ build_requires:
   File::Temp: 0
   File::Which: 0
   Readonly: 0
+  Test::Differences: 0
   Test::DistManifest: 0
   Test::Pod: 0
   Test::Pod::Coverage: 0
   Test::Trap: 0
 configure_requires:
-  Module::Build: 0.36
-generated_by: 'Module::Build version 0.3603'
+  Module::Build: 0
+dynamic_config: 1
+generated_by: 'Module::Build version 0.4003, CPAN::Meta::Converter version 2.112621'
 license: perl
 meta-spec:
   url: http://module-build.sourceforge.net/META-spec-v1.4.html
@@ -21,7 +23,7 @@ name: App-ClusterSSH
 provides:
   App::ClusterSSH:
     file: lib/App/ClusterSSH.pm
-    version: 4.01_01
+    version: 4.01_05
   App::ClusterSSH::Base:
     file: lib/App/ClusterSSH/Base.pm
     version: 0.02
@@ -30,17 +32,19 @@ provides:
     version: 0.01
   App::ClusterSSH::Config:
     file: lib/App/ClusterSSH/Config.pm
-    version: 0.01
+    version: 0.02
   App::ClusterSSH::Helper:
     file: lib/App/ClusterSSH/Helper.pm
-    version: 0.01
+    version: 0.02
   App::ClusterSSH::Host:
     file: lib/App/ClusterSSH/Host.pm
     version: 0.03
   App::ClusterSSH::L10N:
     file: lib/App/ClusterSSH/L10N.pm
+    version: 0
   App::ClusterSSH::L10N::en:
     file: lib/App/ClusterSSH/L10N/en.pm
+    version: 0
 requires:
   Exception::Class: 1.31
   Locale::Maketext: 0
@@ -52,7 +56,7 @@ resources:
   bugtracker: http://sourceforge.net/tracker/?group_id=89139
   homepage: http://clusterssh.sourceforge.net/
   license: http://dev.perl.org/licenses/
-  repository:
+  x_Repository:
     - http://clusterssh.git.sourceforge.net/
     - http://github.com/duncs/clusterssh
-version: 4.01_01
+version: 4.01_05
diff --git a/Makefile.PL b/Makefile.PL
index 4e126ef..059ea01 100644
--- a/Makefile.PL
+++ b/Makefile.PL
@@ -1,32 +1,33 @@
-# Note: this file was auto-generated by Module::Build::Compat version 0.3603
+# Note: this file was auto-generated by Module::Build::Compat version 0.4003
 use ExtUtils::MakeMaker;
 WriteMakefile
 (
-          'NAME' => 'App::ClusterSSH',
-          'VERSION_FROM' => 'lib/App/ClusterSSH.pm',
-          'PREREQ_PM' => {
-                           'Exception::Class' => '1.31',
-                           'File::Temp' => 0,
-                           'File::Which' => 0,
-                           'Locale::Maketext' => 0,
-                           'Readonly' => 0,
-                           'Test::DistManifest' => 0,
-                           'Test::Pod' => 0,
-                           'Test::Pod::Coverage' => 0,
-                           'Test::Trap' => 0,
-                           'Tk' => '800.022',
-                           'Try::Tiny' => 0,
-                           'X11::Protocol' => '0.56',
-                           'version' => '0'
-                         },
-          'INSTALLDIRS' => 'site',
-          'EXE_FILES' => [
-                           'bin/ccon',
-                           'bin/crsh',
-                           'bin/cscp',
-                           'bin/cssh',
-                           'bin/ctel'
-                         ],
-          'PL_FILES' => {}
-        )
+  'NAME' => 'App::ClusterSSH',
+  'VERSION_FROM' => 'lib/App/ClusterSSH.pm',
+  'PREREQ_PM' => {
+                   'Exception::Class' => '1.31',
+                   'File::Temp' => 0,
+                   'File::Which' => 0,
+                   'Locale::Maketext' => 0,
+                   'Readonly' => 0,
+                   'Test::Differences' => 0,
+                   'Test::DistManifest' => 0,
+                   'Test::Pod' => 0,
+                   'Test::Pod::Coverage' => 0,
+                   'Test::Trap' => 0,
+                   'Tk' => '800.022',
+                   'Try::Tiny' => 0,
+                   'X11::Protocol' => '0.56',
+                   'version' => '0'
+                 },
+  'INSTALLDIRS' => 'site',
+  'EXE_FILES' => [
+                   'bin/ccon',
+                   'bin/crsh',
+                   'bin/cscp',
+                   'bin/cssh',
+                   'bin/ctel'
+                 ],
+  'PL_FILES' => {}
+)
 ;
diff --git a/THANKS b/THANKS
index 3af7cd0..bc2b3f7 100644
--- a/THANKS
+++ b/THANKS
@@ -40,3 +40,4 @@ Simon Fraser
 Stefan Steiner
 Ryan Brown
 Brandon Perkins
+Oliver Meissner
diff --git a/bin/cssh b/bin/cssh
index 3a11dc1..6b95202 100755
--- a/bin/cssh
+++ b/bin/cssh
@@ -66,12 +66,12 @@ that host.  Re-selecting it will plug it back in.
 =item *
 
 If your window manager menu bars are obscured by terminal windows see
-the C<screen_reserve_XXXXX> options in the F<csshrc> file (see L</"FILES">).
+the C<screen_reserve_XXXXX> options in the F<$HOME/.clusterssh/config> file (see L</"FILES">).
 
 =item *
 
 If the terminals overlap too much see the C<terminal_reserve_XXXXX> 
-options in the F<csshrc> file (see L</"FILES">).
+options in the F<$HOME/.clusterssh/config> file (see L</"FILES">).
 
 =item *
 
@@ -115,7 +115,7 @@ be due to either the C<-xrm> terminal option which enables C<AllowSendEvents>
 (some terminal do not require this option, other terminals have another 
 method for enabling it - see your terminal documention) or the 
 C<ConnectTimeout> ssh option (see the configuration option C<-o> or file 
-C<csshrc> below to resolve this).
+C<$HOME/.clusterssh/config> below to resolve this).
 
 =back
 
@@ -201,7 +201,7 @@ F<$HOME/.ssh/config>).
 =item --output-config,-u
 
 Output the current configuration in the same format used by the 
-F<$HOME/.csshrc> file.
+F<$HOME/.clusterssh/config> file.
 
 =item --port,-p <port>
 
@@ -224,6 +224,10 @@ Enable|Disable window tiling (overriding the config file)
 
 Specify the initial part of the title used in the console and client windows
 
+=item --unique-servers,-m
+
+Connect to each host only once
+
 =item --use_all_a_records,-A
 
 If a hostname resolves to multiple IP addresses, toggle whether or not to 
@@ -255,7 +259,7 @@ on standard port (e.g not listening on port 22) and ssh_config cannot be used.
 =item <tag> ...
 
 Open a series of xterms defined by <tag> within either /etc/clusters or
-F<$HOME/.csshrc> (see L</"FILES">).
+F<$HOME/.clusterssh/config> (see L</"FILES">).
 
 Note: specifying a username on a cluster tag will override any usernames 
 defined in the cluster
@@ -354,13 +358,13 @@ nested, but be aware of recursive tags which are not checked for.
 
 Clusters may also be specified either directly (see C<clusters> configuration
 options) or indirectly (see C<extra_cluster_file> configuration option) 
-in the users F<$HOME/.csshrc> file.
+in the users F<$HOME/.clusterssh/config> file.
 
 NOTE: there is a special cluster tag called C<default> - any tags or hosts
 included within this tag will be automatically opened if no other tags
 are specified on the command line.
 
-=item F</etc/csshrc> & F<$HOME/.csshrc>
+=item F</etc/csshrc> & F<$HOME/.clusterssh/config>
 
 This file contains configuration overrides - the defaults are as marked.
 Default options are overwritten first by the global file, and then by the
@@ -377,10 +381,6 @@ should be written as
 
 =over
 
-=item always_tile = yes
-
-Setting to anything other than C<yes> does not perform window tiling (see also -G).
-
 =item auto_close = 5
 
 Close terminal window after this many seconds.  If set to 0 will instead wait 
@@ -472,10 +472,21 @@ program start
 Default key sequence to paste text into the console window using the mouse.  
 See below notes on shortcuts.
 
+=item rsh = rsh
+
+=item ssh = ssh
+
+=item telnet = telnet
+
+Set the path to the specific binary to use for the communication method, else 
+uses the first match found in $PATH
+
 =item rsh_args = <blank>
 
 =item ssh_args = "-x -o ConnectTimeout=10" 
 
+=item telnet_args = <blank>
+
 Sets any arguments to be used with the communication method (defaults to ssh
 arguments).  
 
@@ -725,7 +736,7 @@ If you have issues running cssh, first try:
 C<< cssh -e [user@]<hostname>[:port] >>
 
 This performs two tests to confirm cssh is able to work properly with the
-settings provided within the F<.csshrc> file (or internal defaults).
+settings provided within the F<$HOME/.clusterssh/config> file (or internal defaults).
 
 	1. test the terminal window works with the options provided
 
@@ -734,7 +745,7 @@ settings provided within the F<.csshrc> file (or internal defaults).
 Configuration options to watch for in ssh are
 
 	- Doesnt understand "-o ConnectTimeout=10" - remove the option 
-	  in the F<.csshrc> file
+	  in the F<$HOME/.clusterssh/config> file
 
 	- OpenSSH-3.8 using untrusted ssh tunnels - use "-Y" instead of "-X"
 	  or use "ForwardX11Trusted yes' in ssh_config (if you change the
@@ -751,7 +762,7 @@ C<< perl -MTk -e 'print $Tk::VERSION,$/' >>
 
 C<< perl -MX11::Protocol -e 'print $X11::Protocol::VERSION,$/' >>
 
-C<< cat /etc/csshrc $HOME/.csshrc >>
+C<< cat /etc/csshrc $HOME/.clusterssh/config >>
 
 =item *
 
diff --git a/lib/App/ClusterSSH.pm b/lib/App/ClusterSSH.pm
index 793de94..ec568fc 100644
--- a/lib/App/ClusterSSH.pm
+++ b/lib/App/ClusterSSH.pm
@@ -3,7 +3,7 @@ package App::ClusterSSH;
 use 5.008.004;
 use warnings;
 use strict;
-use version; our $VERSION = version->new('4.01_01');
+use version; our $VERSION = version->new('4.01_05');
 
 use Carp;
 
@@ -116,12 +116,13 @@ my @options_spec = (
     'font|f=s',
     'list|L',
     'use_all_a_records|A',
+    'unique-servers|m',
 );
 my %options;
-my %windows;     # hash for all window definitions
-my %menus;       # hash for all menu definitions
-my @servers;     # array of servers provided on cmdline
-my %servers;     # hash of server cx info
+my %windows;    # hash for all window definitions
+my %menus;      # hash for all menu definitions
+my @servers;    # array of servers provided on cmdline
+my %servers;    # hash of server cx info
 my $xdisplay;
 my %keyboardmap;
 my $sysconfigdir = "/etc";
@@ -277,53 +278,68 @@ sub load_keyboard_map() {
 
     logmsg( 1, "Loading keymaps and keycodes" );
 
-    foreach ( 0 .. $#keyboard ) {
-        if ( defined $keyboard[$_][3] ) {
-            if ( defined( $keycodetosym{ $keyboard[$_][3] } ) ) {
-                $keyboardmap{ $keycodetosym{ $keyboard[$_][3] } }
-                    = 'sa' . ( $_ + $min );
-            }
-            else {
-                logmsg( 2, "Unknown keycode ", $keyboard[$_][3] )
-                    if ( $keyboard[$_][3] != 0 );
-            }
-        }
-        if ( defined $keyboard[$_][2] ) {
-            if ( defined( $keycodetosym{ $keyboard[$_][2] } ) ) {
-                $keyboardmap{ $keycodetosym{ $keyboard[$_][2] } }
-                    = 'a' . ( $_ + $min );
-            }
-            else {
-                logmsg( 2, "Unknown keycode ", $keyboard[$_][2] )
-                    if ( $keyboard[$_][2] != 0 );
-            }
-        }
-        if ( defined $keyboard[$_][1] ) {
-            if ( defined( $keycodetosym{ $keyboard[$_][1] } ) ) {
-                $keyboardmap{ $keycodetosym{ $keyboard[$_][1] } }
-                    = 's' . ( $_ + $min );
-            }
-            else {
-                logmsg( 2, "Unknown keycode ", $keyboard[$_][1] )
-                    if ( $keyboard[$_][1] != 0 );
-            }
-        }
-        if ( defined $keyboard[$_][0] ) {
-            if ( defined( $keycodetosym{ $keyboard[$_][0] } ) ) {
-                $keyboardmap{ $keycodetosym{ $keyboard[$_][0] } }
-                    = 'n' . ( $_ + $min );
+    my %keyboard_modifier_priority = (
+        'sa' => 3,    # lowest
+        'a'  => 2,
+        's'  => 1,
+        'n'  => 0,    # highest
+    );
+
+    my %keyboard_stringlike_modifiers = reverse %keyboard_modifier_priority;
+
+  # try to associate $keyboard=X11->GetKeyboardMapping table with X11::Keysyms
+    foreach my $i ( 0 .. $#keyboard ) {
+        for my $modifier ( 0 .. 3 ) {
+            if ( defined( $keycodetosym{ $keyboard[$i][$modifier] } ) ) {
+
+                # keyboard layout contains the keycode at $modifier level
+                if (defined(
+                        $keyboardmap{ $keycodetosym{ $keyboard[$i][$modifier]
+                                } }
+                    )
+                    )
+                {
+
+# we already have a mapping, let's see whether current one is better (lower shift state)
+                    my ( $mod_code, $key_code )
+                        = $keyboardmap{ $keycodetosym{ $keyboard[$i]
+                                [$modifier] } } =~ /^(\D+)(\d+)$/;
+
+      # it is not easy to get around our own alien logic storing modifiers ;-)
+                    if ( $modifier < $keyboard_modifier_priority{$mod_code} )
+                    {
+
+                     # YES! current keycode have priority over old one (phew!)
+                        $keyboardmap{ $keycodetosym{ $keyboard[$i][$modifier]
+                                } }
+                            = $keyboard_stringlike_modifiers{$modifier}
+                            . ( $i + $min );
+                    }
+                }
+                else {
+
+                    # we don't yet have a mapping... piece of cake!
+                    $keyboardmap{ $keycodetosym{ $keyboard[$i][$modifier] } }
+                        = $keyboard_stringlike_modifiers{$modifier}
+                        . ( $i + $min );
+                }
             }
             else {
-                logmsg( 2, "Unknown keycode ", $keyboard[$_][0] )
-                    if ( $keyboard[$_][0] != 0 );
+
+                # we didn't get the code from X11::Keysyms
+                if ( $keyboard[$i][$modifier] != 0 ) {
+
+                    # ignore code=0
+                    logmsg( 2, "Unknown keycode ", $keyboard[$i][$modifier] );
+                }
             }
         }
-
-        # dont know these two key combs yet...
-        #$keyboardmap{ $keycodetosym { $keyboard[$_][4] } } = $_ + $min;
-        #$keyboardmap{ $keycodetosym { $keyboard[$_][5] } } = $_ + $min;
     }
 
+    # dont know these two key combs yet...
+    #$keyboardmap{ $keycodetosym { $keyboard[$_][4] } } = $_ + $min;
+    #$keyboardmap{ $keycodetosym { $keyboard[$_][5] } } = $_ + $min;
+
     #print "$_ => $keyboardmap{$_}\n" foreach(sort(keys(%keyboardmap)));
     #print "keysymtocode: $keysymtocode{o}\n";
     #die;
@@ -383,8 +399,9 @@ sub resolve_names(@) {
             if ( defined($hostobj) ) {
                 my @alladdrs = map { inet_ntoa($_) } @{ $hostobj->addr_list };
                 if ( $#alladdrs > 0 ) {
-                    $self->cluster->register_tag($dirty, @alladdrs);
-                    logmsg( 3, 'Expanded to ', $self->cluster->get_tag($dirty) );
+                    $self->cluster->register_tag( $dirty, @alladdrs );
+                    logmsg( 3, 'Expanded to ',
+                        $self->cluster->get_tag($dirty) );
                 }
                 else {
                     logmsg( 3, 'Only one A record' );
@@ -407,11 +424,22 @@ sub resolve_names(@) {
     # now clean the array up
     @servers = grep { $_ !~ m/^$/ } @servers;
 
+    if ($self->config->{unique_servers}) {
+        logmsg( 3, 'removing duplicate server names' );
+        @servers=remove_repeated_servers(@servers);
+    }
+
     logmsg( 3, 'leaving with ', $_ ) foreach (@servers);
     logmsg( 2, 'Resolving cluster names: completed' );
     return (@servers);
 }
 
+sub remove_repeated_servers {
+    my %all=();
+    @all{@_}=1;
+    return (keys %all);
+}
+
 sub change_main_window_title() {
     my ($self) = @_;
     my $number = keys(%servers);
@@ -588,7 +616,7 @@ sub open_client_windows(@) {
         my $server_object = App::ClusterSSH::Host->parse_host_string($_);
 
         my $username = $server_object->get_username();
-        $username = $self->config->{user} if ( $self->config->{user} );
+        $username = $self->config->{user} if ( !$username && $self->config->{user} );
         my $port = $server_object->get_port();
         $port = $self->config->{port} if ( $self->config->{port} );
         my $server = $server_object->get_hostname();
@@ -751,7 +779,7 @@ sub get_font_size() {
 
     eval { (%font_info) = $xdisplay->QueryFont($font); }
         || die( "Fatal: Unrecognised font used ($terminal_font).\n"
-            . "Please amend \$HOME/.csshrc with a valid font (see man page).\n"
+            . "Please amend \$HOME/.clusterssh/config with a valid font (see man page).\n"
         );
 
     $self->config->{internal_font_width}
@@ -763,7 +791,7 @@ sub get_font_size() {
         || !$self->config->{internal_font_height} )
     {
         die(      "Fatal: Unrecognised font used ($terminal_font).\n"
-                . "Please amend \$HOME/.csshrc with a valid font (see man page).\n"
+                . "Please amend \$HOME/.clusterssh/config with a valid font (see man page).\n"
         );
     }
 
@@ -1134,7 +1162,7 @@ sub add_host_by_name() {
         $self->open_client_windows(@names);
     }
 
-    if ( $menus{listbox}->curselection() ) {
+    if ( defined $menus{listbox} && $menus{listbox}->curselection() ) {
         my @hosts = $menus{listbox}->get( $menus{listbox}->curselection() );
         logmsg( 2, "host=", join( ' ', @hosts ) );
         $self->open_client_windows( $self->resolve_names(@hosts) );
@@ -1265,7 +1293,8 @@ sub setup_repeat() {
 sub create_windows() {
     my ($self) = @_;
     logmsg( 2, "create_windows: started" );
-    $windows{main_window} = MainWindow->new( -title => "ClusterSSH" );
+    $windows{main_window}
+        = MainWindow->new( -title => "ClusterSSH", -class => 'cssh', );
     $windows{main_window}->withdraw;    # leave withdrawn until needed
 
     if ( defined( $self->config->{console_position} )
@@ -1279,6 +1308,7 @@ sub create_windows() {
         -textvariable      => \$menus{entrytext},
         -insertborderwidth => 4,
         -width             => 25,
+        -class             => 'cssh',
         )->pack(
         -fill   => "x",
         -expand => 1,
@@ -1291,6 +1321,7 @@ sub create_windows() {
         -height            => $self->config->{history_height},
         -state             => 'normal',
         -takefocus         => 0,
+        -class             => 'cssh',
     );
     $windows{history}->bindtags(undef);
 
@@ -1353,6 +1384,7 @@ sub create_windows() {
         -popover    => $windows{main_window},
         -overanchor => "c",
         -popanchor  => "c",
+        -class      => 'cssh',
         -font       => [
             -family => "interface system",
             -size   => 10,
@@ -1367,6 +1399,7 @@ sub create_windows() {
         -overanchor => "c",
         -title      => "Cssh Documentation",
         -buttons    => ['Close'],
+        -class      => 'cssh',
     );
 
     my $manpage = `pod2text -l -q=\"\" $0 2>/dev/null`;
@@ -1385,17 +1418,19 @@ sub create_windows() {
         -title          => "Add Host(s) or Cluster(s)",
         -buttons        => [ 'Add', 'Cancel' ],
         -default_button => 'Add',
+        -class          => 'cssh',
     );
 
     if ( $self->config->{max_addhost_menu_cluster_items}
-        && scalar $self->cluster->list_tags()  )
+        && scalar $self->cluster->list_tags() )
     {
-        if (scalar
-            scalar $self->cluster->list_tags() < $self->config->{max_addhost_menu_cluster_items} )
+        if (scalar scalar $self->cluster->list_tags()
+            < $self->config->{max_addhost_menu_cluster_items} )
         {
             $menus{listbox} = $windows{addhost}->Listbox(
                 -selectmode => 'extended',
                 -height     => scalar $self->cluster->list_tags(),
+                -class      => 'cssh',
             )->pack();
         }
         else {
@@ -1404,6 +1439,7 @@ sub create_windows() {
                 -scrollbars => 'e',
                 -selectmode => 'extended',
                 -height => $self->config->{max_addhost_menu_cluster_items},
+                -class  => 'cssh',
             )->pack();
         }
         $menus{listbox}->insert( 'end', sort $self->cluster->list_tags() );
@@ -1415,6 +1451,7 @@ sub create_windows() {
         -width        => 20,
         -label        => 'Host',
         -labelPack    => [ -side => 'left', ],
+        -class        => 'cssh',
     )->pack( -side => 'left' );
     logmsg( 2, "create_windows: completed" );
 
@@ -1543,7 +1580,7 @@ sub key_event {
 
             logmsg( 3, "key=:$key:" );
             if ( $combo =~ /^$key$/ ) {
-                logmsg(3, "matched combo");
+                logmsg( 3, "matched combo" );
                 if ( $event eq "KeyRelease" ) {
                     logmsg( 2, "Received hotkey: $hotkey" );
                     send_text_to_all_servers('%s')
@@ -1600,8 +1637,8 @@ sub key_event {
 sub create_menubar() {
     my ($self) = @_;
     logmsg( 2, "create_menubar: started" );
-    $menus{bar} = $windows{main_window}->Menu;
-    $windows{main_window}->configure( -menu => $menus{bar} );
+    $menus{bar} = $windows{main_window}->Menu();
+    $windows{main_window}->configure( -menu => $menus{bar}, );
 
     $menus{file} = $menus{bar}->cascade(
         -label     => 'File',
@@ -1626,22 +1663,22 @@ sub create_menubar() {
         -menuitems => [
             [   "command",
                 "Retile Windows",
-                -command     => sub{ $self->retile_hosts },
+                -command => sub { $self->retile_hosts },
                 -accelerator => $self->config->{key_retilehosts},
             ],
 
 #         [ "command", "Capture Terminal",    -command => \&capture_terminal, ],
             [   "command",
                 "Toggle active state",
-                -command => sub{ $self->toggle_active_state() },
+                -command => sub { $self->toggle_active_state() },
             ],
             [   "command",
                 "Close inactive sessions",
-                -command => sub{ $self->close_inactive_sessions() },
+                -command => sub { $self->close_inactive_sessions() },
             ],
             [   "command",
                 "Add Host(s) or Cluster(s)",
-                -command     => sub{ $self->add_host_by_name, },
+                -command => sub { $self->add_host_by_name, },
                 -accelerator => $self->config->{key_addhost},
             ],
             '',
@@ -1667,7 +1704,8 @@ sub create_menubar() {
     );
 
     $windows{main_window}->bind( '<KeyPress>' => [ $self => 'key_event' ], );
-    $windows{main_window}->bind( '<KeyRelease>' => [ $self => 'key_event' ], );
+    $windows{main_window}
+        ->bind( '<KeyRelease>' => [ $self => 'key_event' ], );
     logmsg( 2, "create_menubar: completed" );
 }
 
@@ -1797,12 +1835,15 @@ sub run {
     }
 
     if ( $options{action} ) {
-        $self->config->{command} = $options{action} ;
+        $self->config->{command} = $options{action};
     }
 
+    $self->config->{unique_servers} = 1 if $options{'unique-servers'};
+
     $self->config->{auto_quit} = "yes" if $options{autoquit};
     $self->config->{auto_quit} = "no"  if $options{'no-autoquit'};
-    $self->config->{auto_close} = $options{autoclose} if $options{'autoclose'};
+    $self->config->{auto_close} = $options{autoclose}
+        if defined $options{'autoclose'};
 
     $self->config->{window_tiling} = "yes" if $options{tile};
     $self->config->{window_tiling} = "no"  if $options{'no-tile'};
@@ -1815,7 +1856,7 @@ sub run {
 
     $self->config->{terminal_font} = $options{font} if ( $options{font} );
     $self->config->{terminal_args} = $options{'term-args'}
-            if ( $options{'term-args'} );
+        if ( $options{'term-args'} );
     if ( $self->config->{terminal_args} =~ /-class (\w+)/ ) {
         $self->config->{terminal_allow_send_events}
             = "-xrm '$1.VT100.allowSendEvents:true'";
@@ -1998,6 +2039,8 @@ the code until this time.
 
 =item  populate_send_menu_entries_from_xml
 
+=item remove_repeated_servers
+
 =item  resolve_names
 
 =item  retile_hosts
diff --git a/lib/App/ClusterSSH/Base.pm b/lib/App/ClusterSSH/Base.pm
index 95a92ed..e99cca4 100644
--- a/lib/App/ClusterSSH/Base.pm
+++ b/lib/App/ClusterSSH/Base.pm
@@ -157,7 +157,7 @@ sub set_config {
 
 =head1 NAME
 
-App::ClusterSSH::Base
+App::ClusterSSH::Base - Base object provding utility functions
 
 =head1 SYNOPSIS
 
diff --git a/lib/App/ClusterSSH/Cluster.pm b/lib/App/ClusterSSH/Cluster.pm
index aabbbe8..3724b31 100644
--- a/lib/App/ClusterSSH/Cluster.pm
+++ b/lib/App/ClusterSSH/Cluster.pm
@@ -26,7 +26,7 @@ sub new {
 sub get_clusters {
     my ( $self, @files ) = @_;
 
-    for my $file ( '/etc/clusters', @files ) {
+    for my $file ( '/etc/clusters', $ENV{HOME}.'/.clusterssh/clusters',@files ) {
         $self->debug(3, 'Loading in config from: ', $file);
         $self->read_cluster_file($file);
     }
@@ -118,7 +118,7 @@ sub list_tags {
 
 =head1 NAME
 
-App::ClusterSSH::Cluster
+App::ClusterSSH::Cluster - Object representing cluster configuration
 
 =head1 SYNOPSIS
 
diff --git a/lib/App/ClusterSSH/Config.pm b/lib/App/ClusterSSH/Config.pm
index dbe7c42..0c2fef0 100644
--- a/lib/App/ClusterSSH/Config.pm
+++ b/lib/App/ClusterSSH/Config.pm
@@ -4,20 +4,25 @@ use strict;
 use warnings;
 
 use version;
-our $VERSION = version->new('0.01');
+our $VERSION = version->new('0.02');
 
 use Carp;
 use Try::Tiny;
 
 use FindBin qw($Script);
+use File::Copy;
 
 use base qw/ App::ClusterSSH::Base /;
 use App::ClusterSSH::Cluster;
 
 my $clusters;
 my %old_clusters;
-my @app_specific   = (qw/ command title comms method ssh rsh telnet ccon /);
-my %default_config = (
+my @app_specific = (qw/ command title comms method /);
+
+# list of config items to not write out when writing the default config
+my @ignore_default_config = (qw/ user /);
+
+my %default_config        = (
     terminal                   => "xterm",
     terminal_args              => "",
     terminal_title_opt         => "-T",
@@ -54,9 +59,14 @@ my %default_config = (
     terminal_decoration_height => 10,
     terminal_decoration_width  => 8,
 
-    rsh_args    => "",
-    telnet_args => "",
-    ssh_args    => "",
+    console      => 'console',
+    console_args => '',
+    rsh          => 'rsh',
+    rsh_args     => "",
+    telnet       => 'telnet',
+    telnet_args  => "",
+    ssh          => 'ssh',
+    ssh_args     => "",
 
     extra_cluster_file => "",
 
@@ -76,6 +86,9 @@ my %default_config = (
     use_all_a_records => 0,
 
     send_menu_xml_file => $ENV{HOME} . '/.csshrc_send_menu',
+
+    # don't set username here as takes precendence over ssh config
+    user => '', 
 );
 
 sub new {
@@ -84,21 +97,19 @@ sub new {
     my $self = $class->SUPER::new(%default_config);
 
     ( my $comms = $Script ) =~ s/^c//;
-    $self->{comms} = $comms;
+
+    $comms = 'telnet'  if ( $comms eq 'tel' );
+    $comms = 'console' if ( $comms eq 'con' );
+    $comms = 'ssh'     if ( $comms eq 'lusterssh' );
 
     # list of allowed comms methods
-    if ( 'ssh rsh telnet console' !~ m/\B$comms\B/ ) {
+    if ( 'ssh rsh telnet console' !~ m/\b$comms\b/ ) {
         $self->{comms} = 'ssh';
     }
-
-    if ( $self->{comms}
-        && ( !$self->{ $self->{comms} } || !-e $self->{ $self->{comms} } ) )
-    {
-        $self->{ $self->{comms} } = $self->find_binary( $self->{comms} );
+    else {
+        $self->{comms} = $comms;
     }
 
-    $self->{terminal} = $self->find_binary( $self->{terminal} );
-
     $self->{title} = uc($Script);
 
     $clusters = App::ClusterSSH::Cluster->new();
@@ -131,13 +142,39 @@ sub validate_args {
             App::ClusterSSH::Exception::Config->throw(
                 unknown_config => \@unknown_config,
                 error          => $self->loc(
-                    'Unknown configuration parameters: [_1]',
+                    'Unknown configuration parameters: [_1]' . $/,
                     join( ',', @unknown_config )
                 )
             )
         );
     }
 
+    if ( !$self->{comms} ) {
+        croak(
+            App::ClusterSSH::Exception::Config->throw(
+                error => $self->loc( 'Invalid variable: comms' . $/ ),
+            ),
+        );
+    }
+
+    if ( !$self->{ $self->{comms} } ) {
+        croak(
+            App::ClusterSSH::Exception::Config->throw(
+                error => $self->loc(
+                    'Invalid variable: [_1]' . $/,
+                    $self->{comms}
+                ),
+            ),
+        );
+    }
+
+    #    # Don't search for the path to the binary - assume it is on the path
+    #    # or defined correctly in the config.
+    #    if( !-e $self->{ $self->{comms} } )
+    #    {
+    #        $self->{ $self->{comms} } = $self->find_binary( $self->{comms} );
+    #    }
+
     return $self;
 }
 
@@ -150,7 +187,8 @@ sub parse_config_file {
         croak(
             App::ClusterSSH::Exception::Config->throw(
                 error => $self->loc(
-                    'File [_1] does not exist or cannot be read', $config_file
+                    'File [_1] does not exist or cannot be read' . $/,
+                    $config_file
                 ),
             ),
         );
@@ -182,12 +220,13 @@ sub parse_config_file {
     }
     close(CFG);
 
-    # grab any c'lusters from the config before validating it
+    # grab any clusters from the config before validating it
     if ( $read_config{clusters} ) {
         $self->debug( 3, "Picked up clusters defined in $config_file" );
         foreach my $cluster ( sort split / /, $read_config{clusters} ) {
             if ( $read_config{$cluster} ) {
-                $clusters->register_tag( $cluster, $read_config{$cluster} );
+                $clusters->register_tag( $cluster,
+                    split( / /, $read_config{$cluster} ) );
                 $old_clusters{$cluster} = $read_config{$cluster};
                 delete( $read_config{$cluster} );
             }
@@ -205,16 +244,6 @@ sub parse_config_file {
 sub load_configs {
     my ( $self, @configs ) = @_;
 
-    if ( -e $ENV{HOME} . '/.csshrc' ) {
-        warn(
-            $self->loc(
-                'NOTICE: [_1] is no longer used - please see documentation and remove',
-                $ENV{HOME} . '/.csshrc'
-            ),
-            $/
-        );
-    }
-
     for my $config (
         '/etc/csshrc',
         $ENV{HOME} . '/.csshrc',
@@ -248,6 +277,30 @@ sub load_configs {
 sub write_user_config_file {
     my ($self) = @_;
 
+    # attempt to move the old config file to one side
+    if ( -f "$ENV{HOME}/.csshrc" ) {
+        eval { move( "$ENV{HOME}/.csshrc", "$ENV{HOME}/.csshrc.DISABLED" ) };
+
+        if ($@) {
+            croak(
+                App::ClusterSSH::Exception::Config->throw(
+                    error => $self->loc(
+                        'Unable to move [_1] to [_2]: [_3]' . $/,
+                        '$HOME/.csshrc', '$HOME/.csshrc.DISABLED', $@
+                    ),
+                )
+            );
+        }
+        else {
+            warn(
+                $self->loc(
+                    'Moved [_1] to [_2]' . $/, '$HOME/.csshrc',
+                    '$HOME/.csshrc.DISABLED'
+                ),
+            );
+        }
+    }
+
     return if ( -f "$ENV{HOME}/.clusterssh/config" );
 
     if ( !-d "$ENV{HOME}/.clusterssh" ) {
@@ -255,7 +308,7 @@ sub write_user_config_file {
             croak(
                 App::ClusterSSH::Exception::Config->throw(
                     error => $self->loc(
-                        'Unable to create directory [_1]: [_2]',
+                        'Unable to create directory [_1]: [_2]' . $/,
                         '$HOME/.clusterssh', $!
                     ),
                 ),
@@ -264,34 +317,58 @@ sub write_user_config_file {
         }
     }
 
+    # Debian #673507 - migrate clusters prior to writing ~/.clusterssh/config
+    # in order to update the extra_cluster_file property
+    if (%old_clusters) {
+        if ( open( my $fh, ">", "$ENV{HOME}/.clusterssh/clusters" ) ) {
+            print $fh '# '
+                . $self->loc('Tag definitions moved from old .csshrc file'),
+                $/;
+            foreach ( sort( keys(%old_clusters) ) ) {
+                print $fh $_, ' ', join( ' ', $old_clusters{$_} ), $/;
+            }
+            close($fh);
+        }
+        else {
+            croak(
+                App::ClusterSSH::Exception::Config->throw(
+                    error => $self->loc(
+                        'Unable to write [_1]: [_2]' . $/,
+                        '$HOME/.clusterssh/clusters',
+                        $!
+                    ),
+                ),
+            );
+        }
+    }
+
     if ( open( CONFIG, ">", "$ENV{HOME}/.clusterssh/config" ) ) {
         foreach ( sort( keys(%$self) ) ) {
-            print CONFIG "$_=$self->{$_}\n";
+            my $comment='';
+            if ( grep /$_/, @ignore_default_config ) {
+                $comment='#';
+            }
+            print CONFIG ${comment},$_,'=',$self->{$_},$/;
         }
         close(CONFIG);
+        warn(
+            $self->loc(
+                'Created new configuration file within [_1]' . $/,
+                '$HOME/.clusterssh/'
+            )
+        );
     }
     else {
         croak(
             App::ClusterSSH::Exception::Config->throw(
                 error => $self->loc(
-                    'Unable to write default [_1]: [_2]',
-                    '$HOME/.clusterssh/config',
-                    $!
+                    'Unable to write default [_1]: [_2]' . $/,
+                    '$HOME/.clusterssh/config', $!
                 ),
             ),
         );
     }
 
-    return $self if ( !%old_clusters );
-
-    if ( open( my $fh, ">", "$ENV{HOME}/.clusterssh/clusters" ) ) {
-        print $fh '# '
-            . $self->loc('Tag definitions moved from old .csshrc file'), $/;
-        foreach ( sort( keys(%old_clusters) ) ) {
-            print $fh $_, ' ', join( ' ', $old_clusters{$_} ), $/;
-        }
-        close($fh);
-    }
     return $self;
 }
 
@@ -303,7 +380,7 @@ sub find_binary {
     if ( !$binary ) {
         croak(
             App::ClusterSSH::Exception::Config->throw(
-                error => $self->loc('argument not provided'),
+                error => $self->loc('argument not provided') . $/,
             ),
         );
     }
@@ -355,7 +432,8 @@ sub find_binary {
         croak(
             App::ClusterSSH::Exception::Config->throw(
                 error => $self->loc(
-                    '"[_1]" binary not found - please amend $PATH or the cssh config file',
+                    '"[_1]" binary not found - please amend $PATH or the cssh config file'
+                        . $/,
                     $binary
                 ),
             ),
@@ -373,10 +451,14 @@ sub dump {
     print( '# Configuration dump produced by "cssh -u"', $/ );
 
     foreach my $key ( sort keys %$self ) {
+        my $comment='';
         if ( grep /$key/, @app_specific ) {
             next;
         }
-        print $key, '=', $self->{$key}, $/;
+        if ( grep /$key/, @ignore_default_config ) {
+            $comment='#';
+        }
+        print $comment, $key, '=', $self->{$key}, $/;
     }
 
     $self->exit if ( !$no_exit );
@@ -396,7 +478,7 @@ sub dump {
 
 =head1 NAME
 
-ClusterSSH::Config
+ClusterSSH::Config - Object representing application configuration
 
 =head1 SYNOPSIS
 
diff --git a/lib/App/ClusterSSH/Helper.pm b/lib/App/ClusterSSH/Helper.pm
index 07c5898..4289e77 100644
--- a/lib/App/ClusterSSH/Helper.pm
+++ b/lib/App/ClusterSSH/Helper.pm
@@ -4,7 +4,7 @@ use strict;
 use warnings;
 
 use version;
-our $VERSION = version->new('0.01');
+our $VERSION = version->new('0.02');
 
 use Carp;
 use Try::Tiny;
@@ -22,12 +22,12 @@ sub new {
 sub script {
     my ($self, $config ) = @_;
 
-    my $comms = $config->{comms};
-    my $comms_args = $config->{$comms.'_args'};
-    my $command = $config->{command};
+    my $comms = $config->{ $config->{comms} };
+    my $comms_args = $config->{ $config->{comms} . '_args'};
+    my $config_command = $config->{command};
     my $autoclose = $config->{auto_close};
 
-    my $postcommand = $autoclose ? "echo Press RETURN to continue; read IGNORE" : "sleep $autoclose";
+    my $postcommand = $autoclose ? "echo Sleeping for $autoclose seconds; sleep $autoclose" : "echo Press RETURN to continue; read IGNORE"; # : "sleep $autoclose";
 
 #    # P = pipe file
 #    # s = server
@@ -119,7 +119,10 @@ sub script {
                  \$command .= "\$svr";
                }
            }
-           \$command .= " \\\"$command\\\" ; $postcommand";
+           if("$config_command") {
+            \$command .= " \\\"$config_command\\\"";
+           }
+           \$command .= " ; $postcommand";
            warn("Running:\$command\\n"); # for debug purposes
            exec(\$command);
     HERE
@@ -145,7 +148,7 @@ sub script {
 
 =head1 NAME
 
-ClusterSSH::Helper
+ClusterSSH::Helper - Object representing helper script
 
 =head1 SYNOPSIS
 
diff --git a/lib/App/ClusterSSH/Host.pm b/lib/App/ClusterSSH/Host.pm
index c9c00be..7d352e5 100644
--- a/lib/App/ClusterSSH/Host.pm
+++ b/lib/App/ClusterSSH/Host.pm
@@ -301,7 +301,7 @@ use overload (
 
 =head1 NAME
 
-ClusterSSH::Host
+ClusterSSH::Host - Object representing a host.
 
 =head1 SYNOPSIS
 
diff --git a/t/15config.t b/t/15config.t
index 81d8f70..cce91a6 100644
--- a/t/15config.t
+++ b/t/15config.t
@@ -8,6 +8,7 @@ use Test::More;
 use Test::Trap;
 use File::Which qw(which);
 use File::Temp qw(tempdir);
+use Test::Differences;
 
 use Readonly;
 
@@ -21,7 +22,7 @@ $config = App::ClusterSSH::Config->new();
 isa_ok( $config, 'App::ClusterSSH::Config' );
 
 Readonly::Hash my %default_config => {
-    terminal                   => "/usr/bin/xterm",
+    terminal                   => "xterm",
     terminal_args              => "",
     terminal_title_opt         => "-T",
     terminal_colorize          => 1,
@@ -59,9 +60,14 @@ Readonly::Hash my %default_config => {
 
     ssh => '/usr/bin/ssh',
 
-    rsh_args    => "",
-    telnet_args => "",
-    ssh_args    => "",
+    console      => 'console',
+    console_args => '',
+    rsh          => 'rsh',
+    rsh_args     => "",
+    telnet       => 'telnet',
+    telnet_args  => "",
+    ssh          => 'ssh',
+    ssh_args     => "",
 
     extra_cluster_file => "",
 
@@ -72,8 +78,8 @@ Readonly::Hash my %default_config => {
     history_height => 10,
 
     command             => q{},
-    title             => q{15CONFIG.T},
-    comms             => q{ssh},
+    title               => q{15CONFIG.T},
+    comms               => q{ssh},
     max_host_menu_items => 30,
 
     max_addhost_menu_cluster_items => 6,
@@ -88,6 +94,7 @@ Readonly::Hash my %default_config => {
     debug => 0,
     lang  => 'en',
 
+    user => '',
 };
 my %expected = %default_config;
 is_deeply( $config, \%expected, 'default config is correct' );
@@ -101,7 +108,7 @@ trap {
 };
 isa_ok( $trap->die, 'App::ClusterSSH::Exception::Config' );
 is( $trap->die,
-    'Unknown configuration parameters: doesnt_exist,whoops',
+    'Unknown configuration parameters: doesnt_exist,whoops' . $/,
     'got correct error message'
 );
 is_deeply(
@@ -134,7 +141,7 @@ trap {
 };
 isa_ok( $trap->die, 'App::ClusterSSH::Exception::Config' );
 is( $trap->die,
-    "File $file does not exist or cannot be read",
+    "File $file does not exist or cannot be read" . $/,
     'got correct error message'
 );
 
@@ -166,7 +173,7 @@ trap {
 is( $trap->leaveby, 'die', 'died ok' );
 isa_ok( $trap->die, 'App::ClusterSSH::Exception::Config' );
 is( $trap->die,
-    'Unknown configuration parameters: missing,rubbish',
+    'Unknown configuration parameters: missing,rubbish' . $/,
     'die message correct'
 );
 isa_ok( $config, "App::ClusterSSH::Config" );
@@ -197,7 +204,7 @@ trap {
 is( $trap->leaveby, 'die', 'died ok' );
 isa_ok( $trap->die, 'App::ClusterSSH::Exception::Config' );
 isa_ok( $config,    "App::ClusterSSH::Config" );
-is( $trap->die, 'argument not provided', 'die message correct' );
+is( $trap->die, 'argument not provided' . $/, 'die message correct' );
 isa_ok( $config, "App::ClusterSSH::Config" );
 is( $trap->stdout, q{}, 'Expecting no STDOUT' );
 is( $trap->stderr, q{}, 'Expecting no STDERR' );
@@ -210,7 +217,8 @@ is( $trap->leaveby, 'die', 'died ok' );
 isa_ok( $trap->die, 'App::ClusterSSH::Exception::Config' );
 isa_ok( $config,    "App::ClusterSSH::Config" );
 is( $trap->die,
-    '"missing" binary not found - please amend $PATH or the cssh config file',
+    '"missing" binary not found - please amend $PATH or the cssh config file'
+        . $/,
     'die message correct'
 );
 isa_ok( $config, "App::ClusterSSH::Config" );
@@ -241,11 +249,11 @@ is( $trap->stdout, q{}, 'Expecting no STDOUT' );
 is( $trap->stderr, q{}, 'Expecting no STDERR' );
 is_deeply( $config, \%expected, 'amended config is correct' );
 is( $path, which('ls'), 'Found correct path to "ls"' );
-is( $path, $newpath, 'No change made from find_binary');
+is( $path, $newpath,    'No change made from find_binary' );
 
 # give false path to force another search
 trap {
-    $newpath = $config->find_binary('/does/not/exist/'.$path);
+    $newpath = $config->find_binary( '/does/not/exist/' . $path );
 };
 is( $trap->leaveby, 'return', 'returned ok' );
 isa_ok( $config, "App::ClusterSSH::Config" );
@@ -254,7 +262,7 @@ is( $trap->stdout, q{}, 'Expecting no STDOUT' );
 is( $trap->stderr, q{}, 'Expecting no STDERR' );
 is_deeply( $config, \%expected, 'amended config is correct' );
 is( $path, which('ls'), 'Found correct path to "ls"' );
-is( $path, $newpath, 'No change made from find_binary');
+is( $path, $newpath,    'No change made from find_binary' );
 
 note('Checks on loading configs');
 note('empty dir');
@@ -268,7 +276,10 @@ isa_ok( $config, "App::ClusterSSH::Config" );
 isa_ok( $config, "App::ClusterSSH::Config" );
 is( $trap->die,    undef, 'die message correct' );
 is( $trap->stdout, q{},   'Expecting no STDOUT' );
-is( $trap->stderr, q{},   'Expecting no STDERR' );
+is( $trap->stderr,
+    'Created new configuration file within $HOME/.clusterssh/' . $/,
+    'Got correct STDERR output for .csshrc'
+);
 
 #note(qx/ls -laR $ENV{HOME}/);
 ok( -d $ENV{HOME} . '/.clusterssh',        '.clusterssh dir exists' );
@@ -292,9 +303,9 @@ isa_ok( $config, "App::ClusterSSH::Config" );
 is( $trap->die,    undef, 'die message correct' );
 is( $trap->stdout, q{},   'Expecting no STDOUT' );
 is( $trap->stderr,
-    'NOTICE: '
-        . $ENV{HOME}
-        . '/.csshrc is no longer used - please see documentation and remove'
+    'Moved $HOME/.csshrc to $HOME/.csshrc.DISABLED' 
+        . $/
+        . 'Created new configuration file within $HOME/.clusterssh/'
         . $/,
     'Got correct STDERR output for .csshrc'
 );
@@ -303,6 +314,12 @@ ok( -f $ENV{HOME} . '/.clusterssh/config', '.clusterssh config file exists' );
 is_deeply( $config, \%expected, 'amended config is correct' );
 
 note('.csshrc warning and .clusterssh dir plus config');
+
+# need to recreate .csshrc as it was just moved
+open( $csshrc, '>', $ENV{HOME} . '/.csshrc' );
+print $csshrc 'auto_quit = no', $/;
+close($csshrc);
+$expected{auto_quit} = 'no';
 open( $csshrc, '>', $ENV{HOME} . '/.clusterssh/config' );
 print $csshrc 'window_tiling = no', $/;
 close($csshrc);
@@ -317,10 +334,7 @@ isa_ok( $config, "App::ClusterSSH::Config" );
 is( $trap->die,    undef, 'die message correct' );
 is( $trap->stdout, q{},   'Expecting no STDOUT' );
 is( $trap->stderr,
-    'NOTICE: '
-        . $ENV{HOME}
-        . '/.csshrc is no longer used - please see documentation and remove'
-        . $/,
+    'Moved $HOME/.csshrc to $HOME/.csshrc.DISABLED' . $/,
     'Got correct STDERR output for .csshrc'
 );
 ok( -d $ENV{HOME} . '/.clusterssh',        '.clusterssh dir exists' );
@@ -395,7 +409,7 @@ is( $trap->leaveby, 'die', 'died ok' );
 isa_ok( $trap->die, 'App::ClusterSSH::Exception::Config' );
 isa_ok( $config,    "App::ClusterSSH::Config" );
 is( $trap->die,
-    'Unable to create directory $HOME/.clusterssh: File exists',
+    'Unable to create directory $HOME/.clusterssh: File exists' . $/,
     'die message correct'
 );
 isa_ok( $config, "App::ClusterSSH::Config" );
@@ -414,7 +428,7 @@ is( $trap->leaveby, 'die', 'died ok' );
 isa_ok( $trap->die, 'App::ClusterSSH::Exception::Config' );
 isa_ok( $config,    "App::ClusterSSH::Config" );
 is( $trap->die,
-    'Unable to write default $HOME/.clusterssh/config: Is a directory',
+    'Unable to write default $HOME/.clusterssh/config: Is a directory' . $/,
     'die message correct'
 );
 isa_ok( $config, "App::ClusterSSH::Config" );
@@ -434,7 +448,7 @@ is( $trap->leaveby, 'return', 'died ok' );
 isa_ok( $config, "App::ClusterSSH::Config" );
 is( $trap->stdout, q{}, 'Expecting no STDOUT' );
 is( $trap->stderr,
-    q{Unable to create directory $HOME/.clusterssh: File exists} . $/,
+    q{Unable to create directory $HOME/.clusterssh: File exists} . $/ . $/,
     'Expecting no STDERR'
 );
 
@@ -451,19 +465,23 @@ isa_ok( $config, "App::ClusterSSH::Config" );
 isa_ok( $config, "App::ClusterSSH::Config" );
 is( $trap->stdout, q{}, 'Expecting no STDOUT' );
 is( $trap->stderr,
-    q{Unable to write default $HOME/.clusterssh/config: Is a directory} . $/,
+    q{Unable to write default $HOME/.clusterssh/config: Is a directory} 
+        . $/
+        . $/,
     'Expecting no STDERR'
 );
 
 note('Checking dump');
-$config = App::ClusterSSH::Config->new();
+$config = App::ClusterSSH::Config->new(
+    send_menu_xml_file => $ENV{HOME} . '/.csshrc_send_menu' );
 trap {
     $config->dump();
 };
-my $expected = <<'EOF';
-# Configuration dump produced by "cssh -u"
+my $expected = qq{# Configuration dump produced by "cssh -u"
 auto_close=5
 auto_quit=yes
+console=console
+console_args=
 console_position=
 debug=0
 extra_cluster_file=
@@ -481,16 +499,19 @@ max_host_menu_items=30
 menu_host_autotearoff=0
 menu_send_autotearoff=0
 mouse_paste=Button-2
+rsh=rsh
 rsh_args=
 screen_reserve_bottom=60
 screen_reserve_left=0
 screen_reserve_right=0
 screen_reserve_top=0
-send_menu_xml_file=/home/dferguson/.csshrc_send_menu
+send_menu_xml_file=} . $ENV{HOME} . qq{/.csshrc_send_menu
 show_history=0
+ssh=ssh
 ssh_args=
+telnet=telnet
 telnet_args=
-terminal=/usr/bin/xterm
+terminal=xterm
 terminal_allow_send_events=-xrm '*.VT100.allowSendEvents:true'
 terminal_args=
 terminal_bg_style=dark
@@ -507,12 +528,14 @@ terminal_title_opt=-T
 unmap_on_redraw=no
 use_all_a_records=0
 use_hotkeys=yes
+#user=
 window_tiling=yes
 window_tiling_direction=right
-EOF
+};
+
 isa_ok( $config, "App::ClusterSSH::Config" );
-is( $trap->die,    undef,     'die message correct' );
-is( $trap->stdout, $expected, 'Expecting no STDOUT' );
-is( $trap->stderr, q{},       'Expecting no STDERR' );
+is( $trap->die, undef, 'die message correct' );
+eq_or_diff( $trap->stdout, $expected, 'Expecting no STDOUT' );
+is( $trap->stderr, q{}, 'Expecting no STDERR' );
 
 done_testing();
diff --git a/t/30cluster.t b/t/30cluster.t
index 487bbfc..1beadec 100644
--- a/t/30cluster.t
+++ b/t/30cluster.t
@@ -8,6 +8,7 @@ use Test::More;
 use Test::Trap;
 use File::Which qw(which);
 use File::Temp qw(tempdir);
+use English '-no_match_vars';
 
 use Readonly;
 
@@ -27,24 +28,33 @@ $cluster1->register_tag( 'people', @expected );
 
 my @got = $cluster2->get_tag('people');
 
-is_deeply( \@got, \@expected,
-    'Shared cluster object' );
+is_deeply( \@got, \@expected, 'Shared cluster object' );
 
 # should pass without issue
 trap {
     $cluster1->read_cluster_file( $Bin . '/30cluster.doesnt exist' );
 };
-is( ! $trap, '', 'coped with missing file ok' );
+is( !$trap, '', 'coped with missing file ok' );
 isa_ok( $cluster1, 'App::ClusterSSH::Cluster' );
 
-my $no_read=$Bin . '/30cluster.cannot_read';
-chmod 0000, $no_read;
-trap {
-    $cluster1->read_cluster_file( $no_read );
-};
-chmod 0644, $no_read;
-isa_ok( $trap->die, 'App::ClusterSSH::Exception::Cluster' );
-is( $trap->die, "Unable to read file $no_read: Permission denied", 'Error on reading an existing file ok');
+# no point running this test as root since root cannot be blocked
+# from accessing the file
+if ( $EUID != 0 ) {
+    my $no_read = $Bin . '/30cluster.cannot_read';
+    chmod 0000, $no_read;
+    trap {
+        $cluster1->read_cluster_file($no_read);
+    };
+    chmod 0644, $no_read;
+    isa_ok( $trap->die, 'App::ClusterSSH::Exception::Cluster' );
+    is( $trap->die,
+        "Unable to read file $no_read: Permission denied",
+        'Error on reading an existing file ok'
+    );
+}
+else {
+    pass('Cannot test for lack of read access when run as root');
+}
 
 @expected = ('host1');
 $cluster1->read_cluster_file( $Bin . '/30cluster.file1' );
@@ -53,18 +63,15 @@ is_deeply( \@got, \@expected, 'read simple file OK' );
 
 @expected = ('host1');
 $cluster1->read_cluster_file( $Bin . '/30cluster.file2' );
-@got=$cluster1->get_tag('tag1');
-is_deeply( \@got,
-    \@expected, 'read more complex file OK' );
+@got = $cluster1->get_tag('tag1');
+is_deeply( \@got, \@expected, 'read more complex file OK' );
 
 @expected = ('host2');
-@got=$cluster1->get_tag('tag2');
-is_deeply( \@got,
-    \@expected, 'read more complex file OK' );
+@got      = $cluster1->get_tag('tag2');
+is_deeply( \@got, \@expected, 'read more complex file OK' );
 
 @expected = ( 'host3', 'host4' );
-@got=$cluster1->get_tag('tag3');
-is_deeply( \@got,
-    \@expected, 'read more complex file OK' );
+@got = $cluster1->get_tag('tag3');
+is_deeply( \@got, \@expected, 'read more complex file OK' );
 
 done_testing();