1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 package com.sun.dhcpmgr.client;
  26 
  27 import java.awt.*;
  28 import java.awt.event.*;
  29 import java.util.*;
  30 import java.text.MessageFormat;
  31 import java.net.*;
  32 
  33 import javax.swing.*;
  34 import javax.swing.table.*;
  35 import javax.swing.event.*;
  36 import javax.swing.border.*;
  37 
  38 import com.sun.dhcpmgr.ui.*;
  39 import com.sun.dhcpmgr.data.*;
  40 import com.sun.dhcpmgr.server.*;
  41 import com.sun.dhcpmgr.bridge.BridgeException;
  42 import com.sun.dhcpmgr.bridge.ExistsException;
  43 
  44 /**
  45  * This wizard configures the DHCP service.  It also has a mode switch so
  46  * that it is also usable for just adding a single network, so that in
  47  * the tool it actually performs the Network Wizard function as well.
  48  */
  49 public class ConfigWizard extends DSWizard {
  50     private boolean fullConfig;
  51     private DhcpServiceMgr server;
  52     private int leaseLength = 3600*24;
  53     private boolean leaseNegotiable = true;
  54     private String dnsDomain;
  55     private Vector dnsServs;
  56     private Network network;
  57     private boolean isLan = true;
  58     private boolean routerDiscovery = true;
  59     private IPAddress router = null;
  60     private String nisDomain;
  61     private Vector nisServs;
  62     private static final String [] unitChoices = {
  63         ResourceStrings.getString("cfg_wiz_hours"),
  64         ResourceStrings.getString("cfg_wiz_days"),
  65         ResourceStrings.getString("cfg_wiz_weeks") };
  66     private static final int [] unitMultiples = { 60*60, 24*60*60, 7*24*60*60 };
  67 
  68     // This step specifies lease length and renewal policies for the server
  69     class LeaseStep implements WizardStep {
  70         private IntegerField length;
  71         private JComboBox units;
  72         private JCheckBox negotiable;
  73         private Box stepBox;
  74 
  75         public LeaseStep() {
  76             stepBox = Box.createVerticalBox();
  77 
  78             // Explanatory text
  79             stepBox.add(Wizard.createTextArea(
  80                 ResourceStrings.getString("cfg_wiz_lease_explain"), 3, 45));
  81 
  82             // Need to input a number together with units
  83             JPanel flowPanel = new JPanel();
  84 
  85             Mnemonic mnLease =
  86                 new Mnemonic(ResourceStrings.getString("cfg_wiz_lease_length"));
  87             JLabel lblLeaseLen = new JLabel(
  88                 mnLease.getString());
  89 
  90             flowPanel.add(lblLeaseLen);
  91 
  92             // Use a box for the value and units to keep together in layout
  93             Box leaseBox = Box.createHorizontalBox();
  94             length = new IntegerField();
  95             leaseBox.add(length);
  96             leaseBox.add(Box.createHorizontalStrut(5));
  97 
  98             lblLeaseLen.setLabelFor(length);
  99             lblLeaseLen.setToolTipText(mnLease.getString());
 100             lblLeaseLen.setDisplayedMnemonic(mnLease.getMnemonic());
 101 
 102             units = new JComboBox(unitChoices);
 103             leaseBox.add(units);
 104             flowPanel.add(leaseBox);
 105             stepBox.add(flowPanel);
 106             stepBox.add(Box.createVerticalStrut(10));
 107 
 108             // Explain negotiable, provide selection for it
 109             stepBox.add(Wizard.createTextArea(
 110                 ResourceStrings.getString("cfg_wiz_negotiable_explain"), 6,
 111                 45));
 112 
 113             negotiable = new JCheckBox(
 114                 ResourceStrings.getString("cfg_wiz_negotiable"), true);
 115             negotiable.setToolTipText(
 116                 ResourceStrings.getString("cfg_wiz_negotiable"));
 117             negotiable.setAlignmentX(Component.CENTER_ALIGNMENT);
 118             stepBox.add(negotiable);
 119             stepBox.add(Box.createVerticalGlue());
 120         }
 121 
 122         public String getDescription() {
 123             return ResourceStrings.getString("cfg_wiz_lease_desc");
 124         }
 125 
 126         public Component getComponent() {
 127             return stepBox;
 128         }
 129 
 130         public void setActive(int direction) {
 131             setForwardEnabled(true);
 132             // Set the units field to the maximum unit this value expresses
 133             int lengthVal = 0;
 134             int i;
 135             for (i = unitMultiples.length - 1; i >= 0; --i) {
 136                 lengthVal = leaseLength / unitMultiples[i];
 137                 if (lengthVal != 0) {
 138                     if (leaseLength % unitMultiples[i] == 0) {
 139                         break;
 140                     }
 141                 }
 142             }
 143             if (i == -1) {
 144                 i = 0;
 145             }
 146             units.setSelectedIndex(i);
 147             length.setValue(lengthVal);
 148             negotiable.setSelected(leaseNegotiable);
 149         }
 150 
 151         public boolean setInactive(int direction) {
 152             // Leases cannot be zero length
 153             long lease = (long)length.getValue();
 154             if (lease == 0) {
 155                 JOptionPane.showMessageDialog(ConfigWizard.this,
 156                     ResourceStrings.getString("cfg_wiz_zero_lease"),
 157                     ResourceStrings.getString("input_error"),
 158                     JOptionPane.ERROR_MESSAGE);
 159                 return false;
 160             }
 161             int multiplier = unitMultiples[units.getSelectedIndex()];
 162             lease *= multiplier;
 163             if (lease > Integer.MAX_VALUE) {
 164                 // Value is too large
 165                 MessageFormat form = new MessageFormat(
 166                     ResourceStrings.getString("cfg_wiz_lease_overflow"));
 167                 Object args = new Object[] {
 168                     new Integer(Integer.MAX_VALUE / multiplier),
 169                     units.getSelectedItem()
 170                 };
 171                 JOptionPane.showMessageDialog(ConfigWizard.this,
 172                     form.format(args), ResourceStrings.getString("input_error"),
 173                     JOptionPane.ERROR_MESSAGE);
 174                 return false;
 175             }
 176             leaseLength = (int)lease;
 177             leaseNegotiable = negotiable.isSelected();
 178             return true;
 179         }
 180     }
 181 
 182     // Step to configure DNS
 183     class DnsStep implements WizardStep {
 184         private NoSpaceField domain;
 185         private IPAddressList serverList;
 186         private Box stepBox;
 187         private boolean firstActive = true;
 188 
 189         public DnsStep() {
 190             stepBox = Box.createVerticalBox();
 191 
 192             // Explanatory text
 193             stepBox.add(Wizard.createTextArea(
 194                 ResourceStrings.getString("cfg_wiz_dns_explain"), 5, 45));
 195             stepBox.add(Box.createVerticalStrut(10));
 196 
 197             // Domain first
 198             JPanel fieldPanel = new JPanel(new FieldLayout());
 199 
 200             Mnemonic mnDNS =
 201                 new Mnemonic(ResourceStrings.getString("cfg_wiz_dns_domain"));
 202             JLabel jlDNSDomain = new JLabel(mnDNS.getString());
 203             fieldPanel.add(FieldLayout.LABEL, jlDNSDomain);
 204 
 205             domain = new NoSpaceField();
 206             jlDNSDomain.setLabelFor(domain);
 207             jlDNSDomain.setToolTipText(mnDNS.getString());
 208             jlDNSDomain.setDisplayedMnemonic(mnDNS.getMnemonic());
 209             fieldPanel.add(FieldLayout.FIELD, domain);
 210             stepBox.add(fieldPanel);
 211 
 212             serverList = new IPAddressList();
 213             Border tb = BorderFactory.createTitledBorder(
 214                 BorderFactory.createLineBorder(Color.black),
 215                 ResourceStrings.getString("cfg_wiz_dns_servers"));
 216             serverList.setBorder(BorderFactory.createCompoundBorder(tb,
 217                 BorderFactory.createEmptyBorder(5, 5, 5, 5)));
 218             stepBox.add(serverList);
 219         }
 220 
 221         public String getDescription() {
 222             return ResourceStrings.getString("cfg_wiz_dns_desc");
 223         }
 224 
 225         public Component getComponent() {
 226             return stepBox;
 227         }
 228 
 229         public void setActive(int direction) {
 230             setForwardEnabled(true);
 231 
 232             // First time through, ask the server for the defaults
 233             if (firstActive) {
 234                 firstActive = false;
 235                 try {
 236                     domain.setText(
 237                         server.getStringOption(StandardOptions.CD_DNSDOMAIN,
 238                         ""));
 239                     serverList.setAddressList(
 240                         server.getIPOption(StandardOptions.CD_DNSSERV, ""));
 241                 } catch (Throwable e) {
 242                     // Ignore errors, we're just supplying defaults
 243                 }
 244             }
 245         }
 246 
 247         public boolean setInactive(int direction) {
 248             if (direction == FORWARD) {
 249                 /*
 250                  * Either must supply both a domain and a list of servers, or
 251                  * neither
 252                  */
 253                 if ((domain.getText().length() == 0)
 254                         != (serverList.getListSize() == 0)) {
 255                     JOptionPane.showMessageDialog(ConfigWizard.this,
 256                         ResourceStrings.getString("cfg_wiz_dns_both"),
 257                         ResourceStrings.getString("input_error"),
 258                         JOptionPane.ERROR_MESSAGE);
 259                     return false;
 260                 }
 261             }
 262             dnsDomain = domain.getText();
 263             dnsServs = serverList.getAddressList();
 264             return true;
 265         }
 266     }
 267 
 268     // Select the network to configure
 269     class NetworkStep implements WizardStep {
 270         private JComboBox networkBox;
 271         private NetworkListModel networkListModel;
 272         private IPAddressField mask;
 273         private Box stepBox;
 274         private boolean firstActive = true;
 275         private Hashtable maskTable;
 276 
 277         // Model for the list of networks
 278         class NetworkListModel extends AbstractListModel
 279                 implements ComboBoxModel {
 280             private Object currentValue;
 281             private String [] data = null;
 282 
 283             public int getSize() {
 284                 if (data == null) {
 285                     return 0;
 286                 } else {
 287                     return data.length;
 288                 }
 289             }
 290 
 291             public Object getElementAt(int index) {
 292                 if (data == null) {
 293                     return null;
 294                 } else {
 295                     return data[index];
 296                 }
 297             }
 298 
 299             public void setSelectedItem(Object anItem) {
 300                 currentValue = anItem;
 301                 fireContentsChanged(this, -1, -1);
 302             }
 303 
 304             public Object getSelectedItem() {
 305                 return currentValue;
 306             }
 307 
 308             public void setData(Vector addrs) {
 309                 data = new String[addrs.size()];
 310                 addrs.copyInto(data);
 311                 fireContentsChanged(this, 0, data.length);
 312             }
 313         }
 314 
 315         /*
 316          * Editor for the Network combo box, ensures that a valid IP address
 317          * is entered. This implementation cribbed from Swing's
 318          * BasicComboBoxEditor in plaf/basic
 319          */
 320         class NetworkComboBoxEditor implements ComboBoxEditor, FocusListener {
 321             private IPAddressField editor;
 322 
 323             public NetworkComboBoxEditor() {
 324                 editor = new IPAddressField();
 325                 editor.addFocusListener(this);
 326             }
 327 
 328             public Component getEditorComponent() {
 329                 return editor;
 330             }
 331 
 332             public void setItem(Object obj) {
 333                 if (obj != null) {
 334                     editor.setText((String)obj);
 335                 } else {
 336                     editor.setText("");
 337                 }
 338             }
 339 
 340             public Object getItem() {
 341                 return editor.getText();
 342             }
 343 
 344             public void selectAll() {
 345                 editor.selectAll();
 346                 editor.requestFocus();
 347             }
 348 
 349             public void focusGained(FocusEvent e) {
 350             }
 351 
 352             public void focusLost(FocusEvent e) {
 353             }
 354 
 355             public void addActionListener(ActionListener l) {
 356                 editor.addActionListener(l);
 357             }
 358 
 359             public void removeActionListener(ActionListener l) {
 360                 editor.removeActionListener(l);
 361             }
 362         }
 363 
 364         public NetworkStep() {
 365             stepBox = Box.createVerticalBox();
 366 
 367             // Start with intro text, depending on mode.
 368             if (fullConfig) {
 369                 stepBox.add(Wizard.createTextArea(
 370                     ResourceStrings.getString("cfg_wiz_network_explain"), 4,
 371                     45));
 372             } else {
 373                 stepBox.add(Wizard.createTextArea(
 374                     ResourceStrings.getString("net_wiz_net_explain"), 6, 45));
 375             }
 376             stepBox.add(Box.createVerticalStrut(10));
 377 
 378             JPanel panel = new JPanel(new FieldLayout());
 379             Mnemonic mnAddr =
 380                 new Mnemonic(ResourceStrings.getString("cfg_wiz_network"));
 381             JLabel jlNetworkAddr = new JLabel(mnAddr.getString());
 382             panel.add(FieldLayout.LABEL, jlNetworkAddr);
 383             networkListModel = new NetworkListModel();
 384             networkBox = new JComboBox(networkListModel);
 385             networkBox.setEditable(true);
 386             networkBox.setEditor(new NetworkComboBoxEditor());
 387             panel.add(FieldLayout.FIELD, networkBox);
 388             jlNetworkAddr.setLabelFor(networkBox);
 389             jlNetworkAddr.setToolTipText(mnAddr.getString());
 390             jlNetworkAddr.setDisplayedMnemonic(mnAddr.getMnemonic());
 391 
 392             // Label and text field for subnet mask
 393             Mnemonic mnMask =
 394             new Mnemonic(ResourceStrings.getString("cfg_wiz_mask"));
 395             JLabel addrLbl =
 396                 new JLabel(mnMask.getString());
 397             addrLbl.setToolTipText(mnMask.getString());
 398             panel.add(FieldLayout.LABEL, addrLbl);
 399             mask = new IPAddressField();
 400             addrLbl.setLabelFor(mask);
 401             addrLbl.setDisplayedMnemonic(mnMask.getMnemonic());
 402 
 403             panel.add(FieldLayout.FIELD, mask);
 404             stepBox.add(panel);
 405 
 406             stepBox.add(Box.createVerticalStrut(10));
 407 
 408             if (fullConfig) {
 409                 stepBox.add(Wizard.createTextArea(
 410                     ResourceStrings.getString("cfg_wiz_network_explainmore"), 4,
 411                     45));
 412             }
 413             stepBox.add(Box.createVerticalGlue());
 414 
 415             /*
 416              * Listen to selection changes on the network box and change the
 417              * netmask accordingly.
 418              */
 419             networkBox.addItemListener(new ItemListener() {
 420                 public void itemStateChanged(ItemEvent e) {
 421                     if (e.getStateChange() == ItemEvent.SELECTED) {
 422                         String s = (String)e.getItem();
 423                         IPAddress a = (IPAddress)maskTable.get(s);
 424                         if (a != null) {
 425                             // We know the correct value, so set it
 426                             mask.setValue(a);
 427                         }
 428                     }
 429                 }
 430             });
 431         }
 432 
 433         public String getDescription() {
 434             return ResourceStrings.getString("cfg_wiz_network_desc");
 435         }
 436 
 437         public Component getComponent() {
 438             return stepBox;
 439         }
 440 
 441         public void setActive(int direction) {
 442             setForwardEnabled(true);
 443             if (firstActive) {
 444                 firstActive = false;
 445                 maskTable = new Hashtable();
 446                 try {
 447                     /*
 448                      * Initialize list to all networks directly attached to
 449                      * the server
 450                      */
 451                     IPInterface[] ifs = new IPInterface[0];
 452                     try {
 453                         ifs = server.getInterfaces();
 454                     } catch (BridgeException e) {
 455                         // we're not configured yet, apparently
 456                         ifs = null;
 457                     }
 458                     Vector addrs = new Vector();
 459 
 460                     // Get list of already-configured networks
 461                     Network [] nets = new Network[0];
 462                     try {
 463                         nets = DataManager.get().getNetworks(true);
 464                     } catch (BridgeException e) {
 465                         // Ignore; we're not configured yet, apparently
 466                     }
 467                     /*
 468                      * Now filter the list so only unconfigured networks
 469                      * show up in the selection list.
 470                      */
 471                     if (ifs != null) {
 472                     for (int i = 0; i < ifs.length; ++i) {
 473                         boolean alreadyConfigured = false;
 474                         for (int j = 0; j < nets.length; ++j) {
 475                             if (ifs[i].getNetwork().equals(nets[j])) {
 476                                 alreadyConfigured = true;
 477                                 break;
 478                             }
 479                         }
 480                         if (!alreadyConfigured) {
 481                             // Add to list
 482                             String s = ifs[i].getNetwork().
 483                                 getNetworkNumber().getHostAddress();
 484                             addrs.addElement(s);
 485                             // Save netmask for retrieval later
 486                             maskTable.put(s, ifs[i].getNetwork().getMask());
 487                         }
 488                     }
 489                     }
 490                     networkListModel.setData(addrs);
 491                     if (networkBox.getItemCount() > 0) {
 492                         networkBox.setSelectedIndex(0);
 493                     }
 494                 } catch (Throwable e) {
 495                     // Do nothing, we're just setting defaults
 496                     e.printStackTrace();
 497                 }
 498             }
 499         }
 500 
 501         public boolean setInactive(int direction) {
 502             if (direction == FORWARD) {
 503                 try {
 504                     network = new Network((String)networkBox.getSelectedItem());
 505                     if (mask.getValue() == null) {
 506                         /*
 507                          * Check for empty, in which case we just let the
 508                          * default happen
 509                          */
 510                         if (mask.getText().length() != 0) {
 511                             // Not a valid subnet mask
 512                             MessageFormat form = new MessageFormat(
 513                                 ResourceStrings.getString("cfg_wiz_bad_mask"));
 514                             Object [] args = new Object[1];
 515                             args[0] = mask.getText();
 516                             JOptionPane.showMessageDialog(ConfigWizard.this,
 517                                 form.format(args),
 518                                 ResourceStrings.getString("input_error"),
 519                                 JOptionPane.ERROR_MESSAGE);
 520                             return false;
 521                         }
 522                     } else {
 523                         network.setMask(mask.getValue());
 524                     }
 525 
 526                     // Check for network already configured, error if so
 527                     Network [] nets = new Network[0];
 528                     try {
 529                         nets = DataManager.get().getNetworks(false);
 530                     } catch (BridgeException e) {
 531                         // Ignore; must not be configured yet
 532                     }
 533                     for (int i = 0; i < nets.length; ++i) {
 534                         if (network.equals(nets[i])) {
 535                             MessageFormat form = new MessageFormat(
 536                                 ResourceStrings.getString(
 537                                 "cfg_wiz_network_configured"));
 538                             Object [] args = new Object[1];
 539                             args[0] = network.getAddress().getHostAddress();
 540                             JOptionPane.showMessageDialog(ConfigWizard.this,
 541                                 form.format(args),
 542                                 ResourceStrings.getString("input_error"),
 543                                 JOptionPane.ERROR_MESSAGE);
 544                             return false;
 545                         }
 546                     }
 547                 } catch (ValidationException e) {
 548                     // Not a valid IP address
 549                     MessageFormat form = new MessageFormat(
 550                         ResourceStrings.getString("cfg_wiz_bad_network"));
 551                     Object [] args = new Object[1];
 552                     args[0] = (String)networkBox.getSelectedItem();
 553                     if (args[0] == null) {
 554                         args[0] = "";
 555                     }
 556                     JOptionPane.showMessageDialog(ConfigWizard.this,
 557                         form.format(args),
 558                         ResourceStrings.getString("input_error"),
 559                         JOptionPane.ERROR_MESSAGE);
 560                     return false;
 561                 } catch (Throwable e) {
 562                     e.printStackTrace();
 563                     // Ignore other exceptions
 564                 }
 565             }
 566             return true;
 567         }
 568     }
 569 
 570     // Get the type of network and routing policy
 571     class NetTypeStep implements WizardStep {
 572         private JRadioButton lan, ptp;
 573         private ButtonGroup typeGroup, routingGroup;
 574         private JRadioButton discover, specify;
 575         private IPAddressField address;
 576         private Box stepBox;
 577         private boolean firstTime = true;
 578 
 579         public NetTypeStep() {
 580             stepBox = Box.createVerticalBox();
 581 
 582             // Explanatory text at the top
 583             stepBox.add(Wizard.createTextArea(
 584                 ResourceStrings.getString("cfg_wiz_nettype_explain"), 2, 45));
 585             stepBox.add(Box.createVerticalStrut(10));
 586 
 587             // Label and radio buttons for type of network
 588             JPanel panel = new JPanel(new GridLayout(2, 1));
 589             /*
 590              * Create a compound border with empty space on the outside and
 591              * a line border on the inside, then title it amd put a space
 592              * around the outside.
 593              */
 594             Border b = BorderFactory.createCompoundBorder(
 595                 BorderFactory.createEmptyBorder(0, 5, 0, 5),
 596                 BorderFactory.createLineBorder(Color.black));
 597             Border tb = BorderFactory.createTitledBorder(b,
 598                 ResourceStrings.getString("cfg_wiz_nettype_label"));
 599             panel.setBorder(BorderFactory.createCompoundBorder(tb,
 600                 BorderFactory.createEmptyBorder(0, 5, 0, 5)));
 601 
 602             lan = new JRadioButton(ResourceStrings.getString("cfg_wiz_lan"),
 603                 true);
 604             lan.setToolTipText(ResourceStrings.getString("cfg_wiz_lan"));
 605             typeGroup = new ButtonGroup();
 606             typeGroup.add(lan);
 607             panel.add(lan);
 608             ptp = new JRadioButton(ResourceStrings.getString("cfg_wiz_point"),
 609                 false);
 610             ptp.setToolTipText(ResourceStrings.getString("cfg_wiz_point"));
 611             typeGroup.add(ptp);
 612             panel.add(ptp);
 613             stepBox.add(panel);
 614             stepBox.add(Box.createVerticalStrut(20));
 615 
 616             // Routing policy
 617             panel = new JPanel(new GridLayout(2, 1));
 618             tb = BorderFactory.createTitledBorder(b,
 619                 ResourceStrings.getString("cfg_wiz_routing_label"));
 620             panel.setBorder(BorderFactory.createCompoundBorder(tb,
 621                 BorderFactory.createEmptyBorder(0, 5, 0, 5)));
 622 
 623             discover = new JRadioButton(
 624                 ResourceStrings.getString("cfg_wiz_router_discovery"), true);
 625             discover.setToolTipText(ResourceStrings.getString(
 626                 "cfg_wiz_router_discovery"));
 627             routingGroup = new ButtonGroup();
 628             routingGroup.add(discover);
 629             panel.add(discover);
 630 
 631             Box routerBox = Box.createHorizontalBox();
 632             specify = new JRadioButton(
 633                 ResourceStrings.getString("cfg_wiz_router_specify"), false);
 634             specify.setToolTipText(ResourceStrings.getString(
 635                 "cfg_wiz_router_specify"));
 636             routingGroup.add(specify);
 637             routerBox.add(specify);
 638             routerBox.add(Box.createHorizontalStrut(2));
 639             address = new IPAddressField();
 640             address.setEnabled(false); // Start off disabled
 641             address.setMaximumSize(address.getPreferredSize());
 642 
 643             // Box is sensitive to alignment, make sure they all agree
 644             address.setAlignmentY(specify.getAlignmentY());
 645 
 646             routerBox.add(address);
 647             panel.add(routerBox);
 648             stepBox.add(panel);
 649 
 650             stepBox.add(Box.createVerticalStrut(10));
 651             stepBox.add(Box.createVerticalGlue());
 652 
 653             /*
 654              * Enable forward if router discovery, or if specifying router and
 655              * address is not empty.
 656              */
 657             specify.addChangeListener(new ChangeListener() {
 658                 public void stateChanged(ChangeEvent e) {
 659                     address.setEnabled(specify.isSelected());
 660                     setForwardEnabled(!specify.isSelected()
 661                         || (address.getText().length() != 0));
 662                 }
 663             });
 664 
 665             // Enable forward when address is not empty.
 666             address.getDocument().addDocumentListener(new DocumentListener() {
 667                 public void insertUpdate(DocumentEvent e) {
 668                     setForwardEnabled(address.getText().length() != 0);
 669                 }
 670                 public void changedUpdate(DocumentEvent e) {
 671                     insertUpdate(e);
 672                 }
 673                 public void removeUpdate(DocumentEvent e) {
 674                     insertUpdate(e);
 675                 }
 676             });
 677         }
 678 
 679         public String getDescription() {
 680             return ResourceStrings.getString("cfg_wiz_nettype_desc");
 681         }
 682 
 683         public Component getComponent() {
 684             return stepBox;
 685         }
 686 
 687         public void setActive(int direction) {
 688             setForwardEnabled(true);
 689             lan.setSelected(isLan);
 690             discover.setSelected(routerDiscovery);
 691             address.setValue(router);
 692         }
 693 
 694         public boolean setInactive(int direction) {
 695             isLan = lan.isSelected();
 696             if (direction == FORWARD) {
 697                 routerDiscovery = discover.isSelected();
 698                 if (!routerDiscovery) {
 699                     IPAddress addr = address.getValue();
 700                     if (addr == null) {
 701                         // Invalid IP address
 702                         MessageFormat form = new MessageFormat(
 703                             ResourceStrings.getString(
 704                             "cfg_wiz_router_addr_err"));
 705                         Object [] args = new Object[1];
 706                         args[0] = address.getText();
 707                         JOptionPane.showMessageDialog(ConfigWizard.this,
 708                                 form.format(args),
 709                                 ResourceStrings.getString("input_error"),
 710                                 JOptionPane.ERROR_MESSAGE);
 711                         return false;
 712                     } else if (!network.containsAddress(addr)) {
 713                         // Router is not on the network we're configuring
 714                         MessageFormat form = new MessageFormat(
 715                             ResourceStrings.getString(
 716                             "cfg_wiz_router_net_err"));
 717                         Object [] args = new Object[2];
 718                         args[0] = address.getText();
 719                         args[1] = network.toString();
 720                         JOptionPane.showMessageDialog(ConfigWizard.this,
 721                             form.format(args),
 722                             ResourceStrings.getString("input_error"),
 723                             JOptionPane.ERROR_MESSAGE);
 724                         return false;
 725                     }
 726                     router = addr;
 727                 }
 728             }
 729             return true;
 730         }
 731     }
 732 
 733     // Get the NIS configuration
 734     class NisStep implements WizardStep {
 735         private NoSpaceField domain;
 736         private Box stepBox;
 737         private IPAddressField address;
 738         private JButton add, delete, moveUp, moveDown;
 739         private IPAddressList serverList;
 740         boolean firstActive = true;
 741 
 742         public NisStep() {
 743             stepBox = Box.createVerticalBox();
 744 
 745             stepBox.add(Wizard.createTextArea(
 746                 ResourceStrings.getString("cfg_wiz_nis_explain"), 6, 45));
 747             stepBox.add(Box.createVerticalStrut(10));
 748 
 749             JPanel fieldPanel = new JPanel(new FieldLayout());
 750             Mnemonic mnNis =
 751                 new Mnemonic(ResourceStrings.getString("cfg_wiz_nis_domain"));
 752             JLabel jlNISDomain =
 753                 new JLabel(mnNis.getString());
 754             fieldPanel.add(FieldLayout.LABEL, jlNISDomain);
 755             domain = new NoSpaceField();
 756             jlNISDomain.setLabelFor(domain);
 757             jlNISDomain.setToolTipText(mnNis.getString());
 758             jlNISDomain.setDisplayedMnemonic(mnNis.getMnemonic());
 759             fieldPanel.add(FieldLayout.FIELD, domain);
 760             stepBox.add(fieldPanel);
 761 
 762             serverList = new IPAddressList();
 763             Border tb = BorderFactory.createTitledBorder(
 764                 BorderFactory.createLineBorder(Color.black),
 765                 ResourceStrings.getString("cfg_wiz_nis_servers"));
 766             serverList.setBorder(BorderFactory.createCompoundBorder(tb,
 767                 BorderFactory.createEmptyBorder(5, 5, 5, 5)));
 768             stepBox.add(serverList);
 769         }
 770 
 771         public String getDescription() {
 772             return ResourceStrings.getString("cfg_wiz_nis_desc");
 773         }
 774 
 775         public Component getComponent() {
 776             return stepBox;
 777         }
 778 
 779         public void setActive(int direction) {
 780             setForwardEnabled(true);
 781             if (firstActive) {
 782                 firstActive = false;
 783                 try {
 784                     /*
 785                      * Order here is important; do the servers first because if
 786                      * there's an error, we don't retrieve a domain name, which
 787                      * appears to never fail.
 788                      */
 789                     serverList.setAddressList(
 790                         server.getIPOption(StandardOptions.CD_NIS_SERV, ""));
 791                     domain.setText(
 792                         server.getStringOption(StandardOptions.CD_NIS_DOMAIN,
 793                         ""));
 794                 } catch (Throwable e) {
 795                     // Do nothing, just setting defaults
 796                 }
 797             }
 798         }
 799 
 800         public boolean setInactive(int direction) {
 801             if (direction == FORWARD) {
 802                 /*
 803                  * Either must supply both a domain and a list of servers, or
 804                  * neither
 805                  */
 806                 if ((domain.getText().length() == 0)
 807                         != (serverList.getListSize() == 0)) {
 808                     JOptionPane.showMessageDialog(ConfigWizard.this,
 809                         ResourceStrings.getString("cfg_wiz_nis_both"),
 810                         ResourceStrings.getString("input_error"),
 811                         JOptionPane.ERROR_MESSAGE);
 812                     return false;
 813                 }
 814             }
 815             nisDomain = domain.getText();
 816             nisServs = serverList.getAddressList();
 817             return true;
 818         }
 819     }
 820 
 821     class ReviewStep implements WizardStep {
 822         private JLabel storeLabel;
 823         private JLabel leaseLabel;
 824         private JLabel networkLabel;
 825         private JLabel netTypeLabel;
 826         private JLabel netmaskLabel;
 827         private JLabel routerLabel;
 828         private JLabel dnsLabel;
 829         private JLabel dnsServLabel;
 830         private JLabel nisLabel;
 831         private JLabel nisServLabel;
 832         private JPanel panel;
 833         private JScrollPane scrollPane;
 834 
 835         public ReviewStep() {
 836             Box stepBox = Box.createVerticalBox();
 837             if (fullConfig) {
 838                 stepBox.add(Wizard.createTextArea(
 839                     ResourceStrings.getString("cfg_wiz_review_explain"), 3,
 840                     45));
 841             } else {
 842                 stepBox.add(Wizard.createTextArea(
 843                     ResourceStrings.getString("net_wiz_review_explain"), 3,
 844                     45));
 845             }
 846 
 847             panel = new JPanel(new FieldLayout());
 848             JLabel jlTmp;
 849 
 850             if (fullConfig) {
 851                 addLabel("cfg_wiz_datastore");
 852                 storeLabel = addField("uninitialized");
 853 
 854                 jlTmp = addLabelMnemonic("cfg_wiz_lease_length");
 855                 leaseLabel = addField("1 day");
 856 
 857                 jlTmp = addLabelMnemonic("cfg_wiz_dns_domain");
 858                 dnsLabel = addField("Bar.Sun.COM");
 859 
 860                 addLabel("cfg_wiz_dns_servers");
 861                 dnsServLabel = addField("109.151.1.15, 109.148.144.2");
 862             }
 863 
 864             jlTmp = addLabelMnemonic("cfg_wiz_network");
 865             networkLabel = addField("109.148.21.0");
 866             jlTmp.setLabelFor(networkLabel);
 867 
 868             jlTmp = addLabelMnemonic("cfg_wiz_mask");
 869             netmaskLabel = addField("255.255.255.0");
 870             jlTmp.setLabelFor(netmaskLabel);
 871 
 872             addLabel("cfg_wiz_nettype");
 873             netTypeLabel = addField(ResourceStrings.getString("cfg_wiz_lan"));
 874 
 875             addLabel("cfg_wiz_router");
 876             routerLabel = addField(
 877                 ResourceStrings.getString("cfg_wiz_router_discovery"));
 878 
 879             jlTmp = addLabelMnemonic("cfg_wiz_nis_domain");
 880             nisLabel = addField("Foo.Bar.Sun.COM");
 881             jlTmp.setLabelFor(nisLabel);
 882 
 883             addLabel("cfg_wiz_nis_servers");
 884             nisServLabel = addField("109.148.21.21, 109.148.21.44");
 885 
 886             stepBox.add(panel);
 887             stepBox.add(Box.createVerticalGlue());
 888 
 889             scrollPane = new JScrollPane(stepBox,
 890                 JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
 891                 JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
 892         }
 893 
 894         private void addLabel(String s) {
 895             JLabel jl;
 896             jl = new JLabel(ResourceStrings.getString(s));
 897             panel.add(FieldLayout.LABEL, jl);
 898             jl.setLabelFor(panel);
 899             jl.setToolTipText(ResourceStrings.getString(s));
 900         }
 901 
 902         private JLabel addLabelMnemonic(String s) {
 903             JLabel jl;
 904             Mnemonic mnStr =
 905                 new Mnemonic(ResourceStrings.getString(s));
 906             jl = new JLabel(mnStr.getString());
 907             panel.add(FieldLayout.LABEL, jl);
 908             jl.setToolTipText(mnStr.getString());
 909             return jl;
 910         }
 911 
 912         private JLabel addField(String s) {
 913             JLabel l = new JLabel(s);
 914             l.setForeground(Color.black);
 915             panel.add(FieldLayout.FIELD, l);
 916             l.setLabelFor(panel);
 917             l.setToolTipText(s);
 918             return l;
 919         }
 920 
 921         public String getDescription() {
 922             return ResourceStrings.getString("cfg_wiz_review_desc");
 923         }
 924 
 925         public Component getComponent() {
 926             return scrollPane;
 927         }
 928 
 929         public void setActive(int direction) {
 930             StringBuffer b = new StringBuffer();
 931             setFinishEnabled(true);
 932             if (fullConfig) {
 933                 storeLabel.setText(getDsconf().getModule().getDescription());
 934 
 935                 // Display lease length, reducing to largest units possible
 936                 int lengthVal = 0;
 937                 int i;
 938                 for (i = unitMultiples.length - 1; i >= 0; --i) {
 939                     lengthVal = leaseLength / unitMultiples[i];
 940                     if ((lengthVal != 0)
 941                             && (leaseLength % unitMultiples[i] == 0)) {
 942                         break;
 943                     }
 944                 }
 945                 if (i == -1) {
 946                     i = 0;
 947                 }
 948                 Object [] objs = new Object[3];
 949                 objs[0] = new Integer(lengthVal);
 950                 objs[1] = unitChoices[i];
 951                 if (leaseNegotiable) {
 952                     objs[2] = ResourceStrings.getString("cfg_wiz_renewable");
 953                 } else {
 954                     objs[2] = ResourceStrings.getString("cfg_wiz_nonrenewable");
 955                 }
 956                 leaseLabel.setText(MessageFormat.format(
 957                     ResourceStrings.getString("cfg_wiz_lease_fmt"), objs));
 958 
 959                 // Set DNS info
 960                 dnsLabel.setText(dnsDomain);
 961                 b.setLength(0);
 962                 Enumeration en = dnsServs.elements();
 963                 while (en.hasMoreElements()) {
 964                     IPAddress a = (IPAddress)en.nextElement();
 965                     if (b.length() != 0) {
 966                         b.append(", ");
 967                     }
 968                     b.append(a.getHostAddress());
 969                 }
 970                 dnsServLabel.setText(b.toString());
 971             }
 972 
 973             // Set network address
 974             networkLabel.setText(network.toString());
 975             // Set subnet mask
 976             netmaskLabel.setText(network.getMask().getHostAddress());
 977 
 978             // Set network type
 979             if (isLan) {
 980                 netTypeLabel.setText(ResourceStrings.getString("cfg_wiz_lan"));
 981             } else {
 982                 netTypeLabel.setText(
 983                     ResourceStrings.getString("cfg_wiz_point"));
 984             }
 985 
 986             // Set router
 987             if (routerDiscovery) {
 988                 routerLabel.setText(
 989                     ResourceStrings.getString("cfg_wiz_router_discovery"));
 990             } else {
 991                 routerLabel.setText(router.getHostAddress());
 992             }
 993 
 994             // Set NIS info
 995             nisLabel.setText(nisDomain);
 996             b.setLength(0);
 997             Enumeration en = nisServs.elements();
 998             while (en.hasMoreElements()) {
 999                 IPAddress a = (IPAddress)en.nextElement();
1000                 if (b.length() != 0) {
1001                     b.append(", ");
1002                 }
1003                 b.append(a.getHostAddress());
1004             }
1005             nisServLabel.setText(b.toString());
1006         }
1007 
1008         public boolean setInactive(int direction) {
1009             return true;
1010         }
1011     }
1012 
1013     public ConfigWizard(Frame owner, String title, boolean fullConfig) {
1014         super(owner, title);
1015 
1016         try {
1017             server = DataManager.get().getDhcpServiceMgr();
1018             if (fullConfig) {
1019                 dsconfList = new DSConfList();
1020                 dsconfList.init(server);
1021             }
1022         } catch (Throwable e) {
1023             e.printStackTrace(); // XXX Need to do something to handle this...
1024             return;
1025         }
1026 
1027         this.fullConfig = fullConfig;
1028 
1029         // If running as Config Wizard, put in the initial steps.
1030         if (fullConfig) {
1031             addStep(new DatastoreStep(
1032                 ResourceStrings.getString("cfg_wiz_explain"),
1033                 ResourceStrings.getString("cfg_wiz_store_explain")));
1034             addStep(new DatastoreModuleStep());
1035             addStep(new LeaseStep());
1036             addStep(new DnsStep());
1037         }
1038         // Now the steps that are common to both wizards.
1039         addStep(new NetworkStep());
1040         addStep(new NetTypeStep());
1041         addStep(new NisStep());
1042         addStep(new ReviewStep());
1043         showFirstStep();
1044     }
1045 
1046     public void doFinish() {
1047         /*
1048          * To activate the server, we have to do the following items:
1049          * 1. Create the location/path if necessary.
1050          * 2. Create the defaults file.
1051          * 3. Create the dhcptab; ignore errors if it already exists
1052          *    (as in NIS+ case)
1053          * 4. Create the Locale macro; ignore the error if it already exists
1054          * 5. Create the server macro; if it exists we just overwrite it
1055          * 6. Create the network macro;
1056          * 7. Create the network table
1057          * 8. Start the service
1058          */
1059         if (fullConfig) {
1060             getDsconf().setConfig();
1061             getDsconf().setLocation();
1062             // Create the location/path.
1063             try {
1064                 server.makeLocation(getDsconf().getDS());
1065             } catch (ExistsException e) {
1066                 // this is o.k.
1067             } catch (Throwable e) {
1068                 MessageFormat form = new MessageFormat(
1069                     ResourceStrings.getString("create_location_error"));
1070                 Object [] args = new Object[1];
1071                 args[0] = getDsconf().getDS().getLocation();
1072                 String msg = form.format(args);
1073                 JOptionPane.showMessageDialog(ConfigWizard.this,
1074                     msg,
1075                     ResourceStrings.getString("server_error_title"),
1076                     JOptionPane.ERROR_MESSAGE);
1077                 return;
1078             }
1079 
1080             // Create the defaults file.
1081             DhcpdOptions options = new DhcpdOptions();
1082             options.setDaemonEnabled(true);
1083             options.setDhcpDatastore(getDsconf().getDS());
1084             try {
1085                 server.writeDefaults(options);
1086             } catch (Throwable e) {
1087                 e.printStackTrace();
1088                 return;
1089             }
1090 
1091             // Create the dhcptab
1092             try {
1093                 DataManager.get().getDhcptabMgr().createDhcptab();
1094             } catch (Throwable e) {
1095                 // Not an error; some data stores are shared by multiple servers
1096             }
1097         }
1098 
1099         if (fullConfig) {
1100             try {
1101                 DataManager.get().getDhcptabMgr().createLocaleMacro();
1102             } catch (Throwable e) {
1103                 /*
1104                  * Ignore this error, if one's already there we'll assume
1105                  * it's correct
1106                  */
1107             }
1108 
1109             // Create the Server macro
1110             try {
1111                 String svrName =
1112                     DataManager.get().getDhcpServiceMgr().getShortServerName();
1113                 InetAddress svrAddress =
1114                     DataManager.get().getDhcpServiceMgr().getServerAddress();
1115                 DataManager.get().getDhcptabMgr().createServerMacro(svrName,
1116                     svrAddress, leaseLength, leaseNegotiable, dnsDomain,
1117                     dnsServs);
1118             } catch (Throwable e) {
1119                 // Couldn't create it; inform user because this is serious
1120                 Object [] args = new Object[2];
1121                 MessageFormat form = new MessageFormat(
1122                     ResourceStrings.getString("create_macro_error"));
1123                 args[0] = DataManager.get().getShortServerName();
1124                 args[1] = e.getMessage();
1125                 JOptionPane.showMessageDialog(this, form.format(args),
1126                     ResourceStrings.getString("server_error_title"),
1127                     JOptionPane.ERROR_MESSAGE);
1128                 return;
1129             }
1130         }
1131 
1132         // Create the network macro
1133         IPAddress [] routers = null;
1134         if (router != null) {
1135             routers = new IPAddress[] { router };
1136         }
1137         try {
1138             DataManager.get().getDhcptabMgr().createNetworkMacro(network,
1139                 routers, isLan, nisDomain, nisServs);
1140         } catch (Throwable e) {
1141             // Ignore this error? dhcpconfig gives a merge option
1142         }
1143 
1144         // Create the network table
1145         try {
1146             DataManager.get().getDhcpNetMgr().createNetwork(network.toString());
1147         } catch (BridgeException e) {
1148             // This indicates table existed; no error
1149         } catch (Throwable e) {
1150             Object [] args = new Object[2];
1151             MessageFormat form = new MessageFormat(
1152                 ResourceStrings.getString("create_network_table_error"));
1153             args[0] = network.toString();
1154             args[1] = e.getMessage();
1155             JOptionPane.showMessageDialog(this, form.format(args),
1156                 ResourceStrings.getString("server_error_title"),
1157                 JOptionPane.ERROR_MESSAGE);
1158             return;
1159         }
1160 
1161         // Start the server in the initial configuration case
1162         if (fullConfig) {
1163             try {
1164                 DataManager.get().getDhcpServiceMgr().startup();
1165             } catch (Throwable e) {
1166                 // Just warn user; this isn't disastrous
1167                 Object [] args = new Object[1];
1168                 MessageFormat form = new MessageFormat(
1169                     ResourceStrings.getString("startup_server_error"));
1170                 args[0] = e.getMessage();
1171                 JOptionPane.showMessageDialog(this, form.format(args),
1172                     ResourceStrings.getString("server_error_title"),
1173                     JOptionPane.WARNING_MESSAGE);
1174             }
1175         }
1176 
1177         super.doFinish();
1178     }
1179 
1180     public void doHelp() {
1181         if (fullConfig) {
1182             DhcpmgrApplet.showHelp("config_wizard");
1183         } else {
1184             DhcpmgrApplet.showHelp("network_wizard");
1185         }
1186     }
1187 }