diff --git a/appliance_setup/configuration.py b/appliance_setup/configuration.py
index 401ff88f3b987d339f2b906bbbb68b8eaa6450e8..d103922530b045e5bb9c03bb226fc8119d2662da 100644
--- a/appliance_setup/configuration.py
+++ b/appliance_setup/configuration.py
@@ -112,7 +112,10 @@ class Config:
     if (not cfg):
       cfg = self.cfgdata
     for (l, key, value) in cfg:
-      res += "%s %s:%s\n" % (l, key if verbose else "", value)
+      if (key != None):
+        res += "%s %s:%s\n" % (l, key if verbose else "", value)
+      else:
+        res += "%s:%s\n" % (l, value)
     return res
     
   def save (self, filename):
diff --git a/appliance_setup/hp2101nw_connect.py b/appliance_setup/hp2101nw_connect.py
new file mode 100755
index 0000000000000000000000000000000000000000..21b2bc2aa8552be4fac3f31a48869b16f420d4b9
--- /dev/null
+++ b/appliance_setup/hp2101nw_connect.py
@@ -0,0 +1,413 @@
+#!/usr/bin/python
+## hp2101nw_connect.py - version 0.01
+## 
+## Linux connection utility for the HP 2101nw wireless G USB print server.
+##
+## (C) 2012 Reinhold Kainhofer <reinhold@kainhofer.com>
+## License: GPL v2 or later
+
+## This script (hp2101nw_connect.py) provides a relatively easy way to identify and
+## connect to the HP 2101nw wireless USB print server on linux.
+## The device is not a real print server, but rather a USB port forwarder
+## over TCP/UDP. On Windows it creates a virtual USB port, so for Linux
+## support, we'll need a proper kernel module doing the USB port forwarding...
+##
+## This script "only" detects the device on the network, retrieves information and
+## optionally lock it. Once a kernel module is ready, this is the user-space
+## part of the driver.
+##
+## For the device protocol see:
+## http://wiki.kainhofer.com/hardware/hp2101nw_wlan_printserver
+
+## Supported devices:
+##    -) HP 2101nw wireless G USB print server (USB-id 03f0:cd02)
+
+
+#from device_types import *
+from user_interface import *
+from helpers import *
+from configuration import *
+import socket
+import struct
+import select
+import time
+
+
+VERSION=0.01;
+print """
+hp2101nw_connect.py - version %.2f
+Linux connection utility for the HP 2101nw wireless G USB print server.
+
+(C) 2012 Reinhold Kainhofer <reinhold@kainhofer.com>
+License: GPL v2 or later
+""" % (VERSION);
+
+
+
+#use IO::Socket;
+#use IO::Select;
+
+# Wait a maximum of 5 seconds for data:
+SOCK_TIMEOUT = 5
+
+
+# The PC always identifies itself as XXXXXXXX.
+thisboxname = "XXXXXXXX"
+port_information = 34444
+port_command = 34447
+port_usbnet = 34448
+
+SBSU_STATUS = 1
+SBSU_LOCK = 2
+SBSU_UNLOCK = 3
+SBSU_UNKNOWN = 7
+
+# USB vendor / product ids and descriptions of all supported devices
+supported_devices=[
+  {'vendor': 0x03f0, 'device': 0xcd02, 'desc': "HP 2101nw wireless G USB print server"}
+]
+
+
+
+
+
+###############################################################################
+##  USB DEVICE MANAGEMENT / COMMUNICATION FUNCTIONS
+###############################################################################
+
+def net_send_data (ui, sock, addr, data):
+  ui.debug ("Sending packet to : %s" % (addr,))
+  return sock.sendto(data, addr) \
+        or ui.error ("sending data to socket. Data was:\n%s" % data)
+
+
+def net_read_data (ui, sock):
+  s = select.select ([sock], [], [], SOCK_TIMEOUT)
+  if (len(s)>0):
+    return sock.recv (10240)
+  else:
+    ui.debug ("Unable to read data from socket %s." % sock)
+    return None
+
+def SBSU_create_buffer (cmd, data=""):
+  return "SBSU%s%s" % (struct.pack ("<h", cmd), data)
+
+
+## Read data into the second argument (output argument!), return 
+## size of data
+#sub SBSU_receive_data ($$$) {
+  #my $sock = shift;
+  #my $cmd = shift;
+
+#}
+
+def info_data_write (ui, dev, cfg):
+  sock = dev.get('socket-info')
+  cfgstring = cfg.to_string ()
+  l = len(cfgstring)
+  # Add the header (12 bytes): '@\0', packet length, boxname
+  request = "@\0%s%s%s" % (struct.pack ("<H", l), dev.get('device-name', ''), cfgstring)
+  return net_send_data (ui, sock, (dev.get('ip'), port_information), request);
+
+
+## Read USB bulk data into the second argument (output argument!), return 
+## size of data
+def info_data_read (ui, dev):
+  sock = dev.get('socket-info')
+  # TODO
+
+  data = net_read_data (ui, sock)
+  ui.debug ("Data read: %s" % data)
+  datalen = len(data)
+  if (not data.startswith ("@\0\0")):
+    ui.error ("reading data: Wrong header '%s', expected @\\0\\0\n" % data[0:3])
+    return None
+
+  ## data length as given in the header:
+  (header_datalen,) = struct.unpack ("<H", data[3:5])
+  datalen = datalen-13 # ignore 13 bytes header
+  ui.debug ("datalen: %d, header_datalen: %d" % (datalen, header_datalen))
+  if (header_datalen != datalen):
+    ui.error ("reading data: %d data bytes read, headers says %d bytes" % (datalen, header_datalen))
+    return None
+  boxname = data[5:13]
+  ## FIXME: Check the name of the box...
+  ## cut off the header:
+  return data[13:]
+
+def zerotrim(s):
+  return s.rstrip(' \t\n\x00')
+
+
+def SBSU_status_parse (ui, data):
+  # Check the first 6 header bytes (signature)
+  if (not data.startswith ("SBSU\1\0")):
+    ui.error ("reading data: Wrong header '%s', expected SBSU\\0\\1\n" % data[0:6]);
+    return None
+  #result = {'data': data}
+  result = {}
+  # TODO: what does byte 6 mean?
+  result['device-name']  = zerotrim (data[7:15])
+  result['printer-name'] = zerotrim (data[22:86])
+  result['locked-ip']    = zerotrim (data[86:102])  # TODO: Shall we call inet_aton on the string here?
+  result['locked-host']  = zerotrim (data[102:110])
+  # TODO: Bytes 112-168???
+  (serial, vid, pid) = struct.unpack ("<LHH", data[168:176])
+  result['serial']       = serial
+  result['vendor-id']    = vid
+  result['device-id']    = pid
+  #result['usb-descriptors'] = data[176:]
+  result['printer-plugged'] = (vid>0) and (pid>0)
+  usbcfg = {}
+  (iConf, bConfVal, bDescType, bNumInt) = struct.unpack ("<BBBB", data[176:180])
+  usbcfg['iConfiguration'] = iConf
+  usbcfg['bConfigurationValue'] = bConfVal
+  usbcfg['bDescriptorType'] = bDescType
+  usbcfg['bNumInterfaces'] = bNumInt
+  interfaces = {}
+  startindex = 180
+  for i in range(bNumInt):
+    (ifNr, ifClass, ifSubclass, ifProto) = struct.unpack ("<BBBB", data[startindex:startindex+4])
+    startindex += 4
+    interfaces[ifNr] = {'bInterfaceNumber': ifNr, 'bInterfaceClass': ifClass,
+                        'bInterfaceSubClass': ifSubclass, 'bInterfaceProtocol': ifProto}
+    
+  usbcfg['interfaces'] = interfaces
+  result['usb-configuration'] = usbcfg
+  return result
+
+
+
+def device_detect (ui):
+  request = SBSU_create_buffer (SBSU_STATUS)
+  result = {}
+  loop = 0
+  ui.debug ("Sending device detection request (UDP broadcast on port 34447)")
+  s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
+  s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, True)
+  s.settimeout(1)
+
+  while (loop <= 2 and len(result)<5):
+    loop += 1
+    ui.progress (".", False)
+    try:
+      s.sendto(request, ("<broadcast>", port_command))
+      while True: # Listen for all responses
+        data, (addr, port) = s.recvfrom (8096)
+        found = SBSU_status_parse (ui, data);
+        if found:
+          found['ip'] = addr
+          result[found['device-name']] = found
+
+    except socket.timeout, ValueError:
+      pass
+  s.close()
+
+  # setup the sockets
+  for i in result.keys ():
+    device = result.get(i,{})
+    peer = device.get('ip')
+    info_s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
+    info_s.settimeout(1)
+    device['socket-info'] = info_s
+    device['connected'] = False
+    info_data_write (ui, device, Config (ui, cfg=[("9801", None, "")]))
+    device['mac'] = info_data_read (ui, device)
+    ui.debug ("   Device %s, MAC %s" % (device.get('ip'), device.get('mac')))
+
+  return result
+
+
+
+def device_list (ui, devs):
+  d = []
+  dn = []
+  fmt = "%-18s%-15s%-6s%-30s"
+  for dd in devs.keys ():
+    devinfo = devs.get (dd)
+    d.append (fmt % (devinfo.get('device-name'), devinfo.get('ip'), 'X' if devinfo.get('connected') else '', devinfo.get('printer-name')))
+    dn.append (dd)
+
+  text = "The following devices were found:\n\n\t   " +\
+      fmt % ("Device", "IP", "Conn.", "Detected printer") + "\n" +\
+      "\t   ------------------------------------------------------------------------"
+
+  ui.progress ("\n%s" % text)
+  i = 1
+  for dd in d:
+    ui.progress ("\t%d) %s" % (i, dd))
+    i += 1
+
+#  if (len (d) == 1):
+#    ui.progress ("\n%s\n\t   %s" % (text, d[0]))
+#    choice = d[0]
+#  else:
+#    choice = ui.ask_choice (text, d, dn, dn[0])
+
+#  print "Selected device: ", devs.get(choice)
+#  return devs.get(choice)
+
+
+def pluggedin_info (ui, device):
+  info_data_write (ui, device, Config (ui, cfg=[("9010", None, "")]))
+  device['hardware-info'] = info_data_read (ui, device)
+  info_data_write (ui, device, Config (ui, cfg=[("9106", None, "")]))
+  device['wireless-info'] = info_data_read (ui, device)
+  info_data_write (ui, device, Config (ui, cfg=[("9971", None, "")]))
+  device['status'] = info_data_read (ui, device)
+  
+  del device['hardware-info']
+  del device['wireless-info']
+
+def update_connection_info (ui, device):
+  request = SBSU_create_buffer (SBSU_STATUS)
+  ui.debug ("Sending device information request (UDP port 34447)")
+  try:
+    s = device.get ('socket-info');
+    s.sendto(request, (device.get('ip'), port_command))
+    data = s.recv (8096)
+    found = SBSU_status_parse (ui, data)
+    device.update (found)
+    if (device.get('printer-plugged') and not device.get('hardware-info')):
+      # Printer was newly plugged in, so retrieve the hardware info
+      pluggedin_info (ui, device)
+    elif (not device.get('printer-plugged') and device.get('hardware-info')):
+      # Printer was unplugged, clean hardware info
+      device['hardware-info'] = None
+      del device['hardware-info']
+      device['wireless-info'] = None
+      del device['wireless-info']
+      device['status'] = None
+      del device['status']
+  except socket.timeout, ValueError:
+    pass
+
+
+def device_unconnect (ui, device):
+  if (not device.get('connected')):
+    ui.error("trying to unconnect already unconnected device %s" % device.get('devicename'))
+  
+  # TODO: Unregister socket from server
+  # Close the USB/IP socket:
+  s = device.get ('socket-usbip')
+  if s:
+    s.close ()
+    del device['socket-usbip']
+
+  # and unlock the device:
+  request = SBSU_create_buffer (SBSU_UNLOCK)
+  ui.debug ("Unlocking device (TCP port 34447)")
+  s = device.get ('socket-commands');
+  try:
+    s.send(request) # , (device.get('ip'), port_command)
+    data = s.recv (8096)
+    # TODO: Check status response
+    update_connection_info (ui, device)
+  except socket.timeout, ValueError:
+    pass
+  s.close ()
+  del device['socket-commands']
+  
+  update_connection_info (ui, device)
+  device['connected'] = False
+
+
+def device_connect (ui, device):
+  # Create the socket for TCP port 34447
+  sock_cmd = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+  sock_cmd.connect((device.get('ip'), port_command))
+  sock_cmd.settimeout(1)
+  device['socket-commands'] = sock_cmd
+  # send the locking command, read the device status to check for success
+  local_ip = sock_cmd.getsockname()[0]
+  local_hostname = socket.gethostname()
+  unknown_data="\x7C\xF2\xF0\x00\xBE\xB0\x01\x10\x68\xF3" + \
+    "\xf0\x00\x20\xe9\x91\x7c\x60\x00\x92\x7c\xff\xff\xff\xff\x5d\x00" + \
+    "\x92\x7c\x67\xa4\x01\x10\x00\x00\xb6\x00\x00\x00\x00\x00\x86\xa4" + \
+    "\x01\x10\xf9\x85\xbe\x9b\x30\x2f\x3a\x00\x30\xf4\x00\x00\x00\x00" + \
+    "\x00\x00"
+
+  print local_ip
+  print local_hostname
+
+  # data is: 14 bytes IP, 0xf438 (UNKNOWN), 10 bytes hostname, 
+  bufferfmt = "<14sH10s"
+  request = SBSU_create_buffer (SBSU_LOCK, struct.pack (bufferfmt, local_ip, 0xf438, local_hostname) + unknown_data)
+  ui.debug ("Locking device (TCP port 34447)")
+  try:
+    s = device.get ('socket-commands');
+    s.send(request)#, (device.get('ip'), port_command))
+    data = s.recv (8096)
+    #found = SBSU_status_parse (ui, data)
+    #device.update (found)
+    update_connection_info (ui, device)
+    if (device.get('locked-ip')):
+      device['connected'] = True
+  except socket.timeout, ValueError:
+    pass
+
+  # Create the socket for TCP port 34448
+  sock_usbip = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+  sock_usbip.connect((device.get('ip'), port_usbnet))
+  sock_usbip.settimeout(1)
+  device['socket-usbip'] = sock_usbip
+
+
+
+###############################################################################
+##  MAIN OPERATIONS: ASK FOR OPERATION AND HANDLE IT
+###############################################################################
+
+
+def main ():
+  UI = ConsoleInterface (debug=True)
+  devs = device_detect (UI)
+  if (len(devs) == 0):
+    UI.progress ("No supported devices detected on the network. Supported devices are:")
+    for i in supported_devices:
+      UI.progress ("\t-) %s" % i.get('desc'))
+    UI.progress ("")
+    exit (0)
+  print devs
+  device_list (UI, devs)
+  
+  time.sleep (3)
+  print "=====\nConnecting now\n\n"
+  # Loop in detected devices
+  # update plugged-in status (
+  i = 0
+  while i<2:
+    i += 1
+    for d in devs:
+      device = devs[d]
+      update_connection_info (UI,device)
+      if (not device.get('locked-ip')):
+        device_connect (UI, device)
+    device_list (UI, devs)
+    print devs
+    time.sleep (3)
+    print "=====\n"
+
+  print "=====\nJust waiting now\n\n"
+  for d in devs:
+    device = devs[d]
+    #if (device.get('connected') or device.get('locked-ip')==device.get('socket-info').getsockname()[0]):
+    device_unconnect (UI, device)
+    update_connection_info (UI,device)
+
+  print devs
+  time.sleep (5)
+  print "=====\nUnconnecting now\n\n"
+  
+  for d in devs:
+    device = devs[d]
+    update_connection_info (UI,device)
+  device_list (UI, devs)
+
+
+
+###############################################################################
+##  MAIN FUNCTION
+###############################################################################
+
+main ()
diff --git a/appliance_setup/user_interface.py b/appliance_setup/user_interface.py
index 76fc90300fe22e5b528e49ebb81e6c3aafe9b2d5..b93a5dfebe9334f19ff833f1bf9686e32e3fe9ee 100644
--- a/appliance_setup/user_interface.py
+++ b/appliance_setup/user_interface.py
@@ -107,10 +107,9 @@ class ConsoleInterface (UserInterface):
   def __init__ (self, debug):
     UserInterface.__init__ (self, debug);
   def progress (self, str, newline=True):
+    sys.stdout.write(str)
     if newline:
-      print str
-    else:
-      print str,
+      sys.stdout.write("\n")
     sys.stdout.flush()
   def debug (self, str):
     if self.is_debug: