home *** CD-ROM | disk | FTP | other *** search
/ Big Green CD 8 / BGCD_8_Dev.iso / NEXTSTEP / Networking / SambaManager / Hosts.m < prev    next >
Encoding:
Text File  |  1998-03-28  |  12.6 KB  |  456 lines

  1. /*
  2.     SambaManger. A graphical frontend to configure the NetInfo enhanced samba.
  3.     Copyright (C) 1998  Robert Frank
  4.  
  5.     This program is free software; you can redistribute it and/or modify
  6.     it under the terms of the GNU General Public License as published by
  7.     the Free Software Foundation; either version 2 of the License, or
  8.     (at your option) any later version.
  9.  
  10.     This program is distributed in the hope that it will be useful,
  11.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.     GNU General Public License for more details.
  14.  
  15.     You should have received a copy of the GNU General Public License
  16.     along with this program; if not, write to the Free Software
  17.     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  18.         
  19.         Robert Frank, frank@ifi.unibas.ch
  20. */
  21.  
  22. #import "Hosts.h"
  23. #import "Controller.h"
  24. #import "NIDirectory.h"
  25. #import "NIProperty.h"
  26. #import "NetInfoKeys.h"
  27.  
  28. // The property names of a host's directory:
  29. #define H_NAME                "name"
  30. #define H_NETBIOSNAME    "netbios name"
  31. #define H_IPADDRESS        "ip_address"
  32. #define H_ETHERNET        "en_address"
  33. #define H_NETGROUPS        "netgroups"
  34. #define H_SYSTEM            "system_type"
  35. #define H_OWNER                "owner"
  36. #define H_BOOTFILE        "bootfile"
  37. #define H_BOOTPARAMS    "bootparams"
  38.  
  39. // Class variable with the string for the open/save panel's title.
  40. static const char         *title;
  41. static unsigned char  hexOk[128] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  42.                                     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  43.                                     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  44.                                     1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,
  45.                                     0,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,
  46.                                     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  47.                                     0,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,
  48.                                                                         0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
  49.  
  50. @implementation Hosts
  51.  
  52. // ************************************************************************
  53. // ************************************************************************
  54. // Class methods:
  55. + initialize
  56. // Called once by the run time system
  57. {
  58.         title = [Service stringFor:"Title:Hosts"];
  59.         return self;
  60. }
  61.  
  62. + new:sender at:(NXCoord *)offset
  63. {
  64. NIDirectory    *NIDir;
  65. Hosts                *host = [Hosts alloc];
  66.  
  67.         if ((NIDir = [NIDirectory new:sender root:SMNI_HOSTS directory:NULL])) {
  68.             [NIDir setDelegate:host];
  69.             if ([host init:sender dirObj:NIDir delta:offset service:NULL]) {
  70.                 [NIDir setSaveTitle:title];
  71.                 return host;
  72.             }
  73.             [NIDir close];
  74.         }
  75.         return [host free];
  76. }
  77.  
  78. + open:sender at:(NXCoord *)offset
  79. {
  80. NIDirectory    *NIDir;
  81. Hosts                *host = [Hosts alloc];
  82.  
  83.         if ((NIDir = [NIDirectory open:sender root:SMNI_HOSTS withTitle:title])) {        
  84.             [NIDir setDelegate:host];
  85.             if ([host init:sender dirObj:NIDir delta:offset service:[NIDir baseName]])
  86.                 return host;
  87.  
  88.             [NIDir close];
  89.         }
  90.         return [host free];
  91. }
  92.  
  93.  
  94. - getBootParms:parameter
  95. {
  96. int                                i;
  97. NIProperty                *prop;
  98. const ni_namelist    *values;
  99.  
  100.         if (!(prop = [ni_dirObj property:H_BOOTPARAMS]))
  101.             return self;
  102.         values = [prop valueList];
  103.         [textRootDirectory setStringValue:""];
  104.         [textPrivateDirectory setStringValue:""];
  105.         
  106.         for (i = 0; i < values->ni_namelist_len; i++)
  107.             if (!strncasecmp(values->ni_namelist_val[i], "root", 4))
  108.                 [textRootDirectory setStringValue:values->ni_namelist_val[i]+5];
  109.             else if (!strncasecmp(values->ni_namelist_val[i], "private", 7))
  110.                 [textPrivateDirectory setStringValue:values->ni_namelist_val[i]+8];
  111.  
  112.         return self;
  113. }
  114.  
  115. - setBootParms
  116. {
  117. char                            *root = NULL, *private = NULL;
  118. const char                *s = NULL;
  119. NIProperty                *prop;
  120.  
  121.         if (!(prop = [ni_dirObj property:H_BOOTPARAMS]))
  122.             return nil;
  123.         
  124.         s = [textRootDirectory stringValue];
  125.         if (s && *s) {
  126.             root = (char *)NXZoneMalloc([self zone], strlen(s) + 6);
  127.             strcpy(root, "root=");
  128.             strcat(root, s);
  129.         }
  130.         s = [textPrivateDirectory stringValue];
  131.         if (s && *s) {
  132.             private = (char *)NXZoneMalloc([self zone], strlen(s) + 9);
  133.             strcpy(private, "private=");
  134.             strcat(private, s);
  135.         }
  136.         
  137.         // Search. If inexistant, create! If exists and root/private non-null,
  138.         // update, otherwise delete
  139.         [prop updateValue:root at:[prop findValue:"^root.*" how:NI_FIND_REGEX]];
  140.         [prop updateValue:private at:[prop findValue:"^private.*" how:NI_FIND_REGEX]];
  141.         if (root)
  142.             NXZoneFree([self zone], root);
  143.         if (private)
  144.             NXZoneFree([self zone], private);
  145.  
  146.         return self;
  147. }
  148.  
  149. - selectAlias:sender
  150. {
  151.         [textAliases setStringValue:[[sender selectedCell] stringValue]];
  152.         [textAliases selectText:self];
  153.         return self;
  154. }
  155.  
  156. - (BOOL)minimumOK
  157. {
  158. char    value[32], *c = value;
  159. int        l, ival;
  160.  
  161.         if (!*[textHostname stringValue] || !*[textInternetAddress stringValue]) {
  162.             NXRunAlertPanel(getString("Alert:Alert"),
  163.                                             getString("Message:Must have a name and address"),
  164.                                             getString("Button:OK"),NULL,NULL);
  165.             return NO;
  166.         }
  167.         
  168.         // Let's check a few values for correctnes:
  169.         // The Netbios name may be atmost 15 characters
  170.         if (strlen([textNetbiosname stringValue]) > 15 ) {
  171.             NXRunAlertPanel(getString("Alert:Alert"),
  172.                                             getString("Message:Netbios Name may have atmost 15 characters."),
  173.                                             getString("Button:OK"),NULL,NULL);
  174.             return NO;
  175.         }
  176.  
  177.         // The IP address must be four values with three dots:
  178.         // nnn.nnn.nnn.nnn
  179.         bzero(value, 32);
  180.         if (*strncpy(value, [textInternetAddress stringValue], 30)) {
  181.             value[strlen(value)] = '.';
  182.             for (l = 4; l && c; l--) {
  183.                 ival = atoi(c);
  184.                 if ((ival > 0) && (ival < 256)) {
  185.                     if (c = strchr(c, '.'))
  186.                         c++;
  187.                 } else
  188.                     c = NULL;
  189.             }
  190.             if (!c) {
  191.                 NXRunAlertPanel(getString("Alert:Alert"),
  192.                                                 getString("Message:Invalid IP address.\nMust be of the form: `nnn.nnn.nnn.nnn'."),
  193.                                                 getString("Button:OK"),NULL,NULL);
  194.                 return NO;
  195.             }
  196.         }
  197.         
  198.         // The Ethernet address must be six hex values with five colons,
  199.         // no leading zeros: 0:0:f:0:81:f9
  200.         bzero(value, 32);
  201.         c = value;
  202.         if (*strncpy(value, [textEthernetAddress stringValue], 30)) {
  203.             value[strlen(value)] = ':';
  204.             for (l = 6; l && c; l--) {
  205.                 if (!hexOk[*c++&0x7f]) {
  206.                     c = NULL;
  207.                     break;
  208.                 }
  209.                 if (*c != ':')
  210.                     if (!((*(c-1) != '0') && hexOk[*c++&0x7f])) {
  211.                         c = NULL;
  212.                         break;
  213.                     }
  214.                 if (*c != ':')
  215.                     c = NULL;
  216.                 else
  217.                     c++;
  218.             }
  219.             if (!c) {
  220.                 NXRunAlertPanel(getString("Alert:Alert"),
  221.                                                 getString("Message:Invalid Ethernet address.\nMust be: `hh:hh:hh:hh:hh:hh' with no leading zeros."),
  222.                                                 getString("Button:OK"),NULL,NULL);
  223.                 return NO;
  224.             }
  225.         }
  226.  
  227.         return YES;
  228. }
  229.  
  230. // ************************************************************************
  231. //    Methods:
  232. - revert:sender
  233. {
  234.         [super revert:sender];
  235.     [browserAliases loadColumnZero];
  236.         return self;
  237. }
  238.  
  239. - delete:sender
  240. {
  241.         if (!strcmp([ni_dirObj baseName], "localhost") ||
  242.                 !strcmp([ni_dirObj baseName], "broadcasthost")) {
  243.             NXRunAlertPanel(getString("Alert:Alert"),
  244.                                             getString("Message:Cannot delete localhost or broadcasthost!"),
  245.                                             getString("Button:OK"), NULL, NULL);
  246.             return self;
  247.         }
  248.  
  249.         return [super delete:self];
  250. }
  251.  
  252. - setupAndLoad
  253. {
  254. NIProperty    *nbname, *name;
  255. char                *NBName, *p;
  256.  
  257.         // Initialize the parameter list
  258.         name = [ni_dirObj addString:H_NAME outlet:textHostname];
  259.         nbname = [ni_dirObj addString:H_NETBIOSNAME outlet:textNetbiosname];
  260.         [ni_dirObj addString:H_IPADDRESS outlet:textInternetAddress];
  261.         [ni_dirObj addString:H_ETHERNET outlet:textEthernetAddress];
  262.         [ni_dirObj addString:H_OWNER outlet:textSystemOwner];
  263.         [ni_dirObj addPopup:H_SYSTEM outlet:popupSystemType default:"Unknown"];
  264.         [ni_dirObj addBrowser:H_NETGROUPS browser:browserNetGroups text:textNetgroups
  265.                              add:buttonAddNetGroup remove:buttonDelNetGroup];
  266.         [ni_dirObj addString:H_BOOTFILE outlet:textKernel];
  267.         [ni_dirObj addCall:H_BOOTPARAMS displayAction:@selector(getBootParms:)];
  268.  
  269.         // Scan the loaded NetInfo values and update the GUI.
  270.         [ni_dirObj scan];
  271.  
  272.         // Check for a netbios name. If none exists, uppercase the hostname.
  273.         if (([nbname index] == NI_VALUE_NOT_FOUND) && (*[name valueAt:0])) {
  274.             NBName = NXCopyStringBufferFromZone([name valueAt:0],[self zone]);
  275.             for (p = NBName; *p; p++)
  276.                 *p = NXToUpper(*p);
  277.             [nbname insertValue:NBName];
  278.             [textNetbiosname setStringValue:NBName];
  279.             NXZoneFree([self zone], NBName);
  280.         }
  281.         
  282.         // Set up the alias browser and text.
  283.         [browserAliases setDelegate:self];
  284.         [browserAliases setAction:@selector(selectAlias:)];
  285.     [browserAliases loadColumnZero];
  286.         [textAliases setTextDelegate:self];
  287.         [textRootDirectory setTextDelegate:self];
  288.         [textPrivateDirectory setTextDelegate:self];
  289.         
  290.         // Select the top field.
  291.         [textHostname selectText:self];
  292.         return self;
  293. }
  294.  
  295. // ************************************************************************
  296. // Actions:
  297.  
  298. - addAlias:sender
  299. {
  300. const char                 *v;
  301. int                                i;
  302. NIProperty                *prop;
  303. const ni_namelist    *values;
  304.  
  305.         if (!(prop = [ni_dirObj property:H_NAME]))
  306.             return 0;
  307.         values = [prop valueList];
  308.         v = [textAliases stringValue];
  309.         
  310.         if (values->ni_namelist_len) {
  311.             for (i = 1; i < values->ni_namelist_len; i++)
  312.                 if (!strcasecmp(values->ni_namelist_val[i], v)) {
  313.                     [[browserAliases matrixInColumn:0] selectCellAt:i-1 :0];
  314.                     return self;
  315.                 } else if (strcasecmp(values->ni_namelist_val[i], v) > 0)
  316.                     break;
  317.             [prop insertValue:v at:i--];
  318.             [window setDocEdited:YES];
  319.             [browserAliases reloadColumn:0];
  320.             [[browserAliases matrixInColumn:0] selectCellAt:i :0];
  321.             [textAliases selectText:self];
  322.         }
  323.  
  324.     return self;
  325. }
  326.  
  327. - removeAlias:sender
  328. {
  329. int                                    i;
  330. NIProperty                *prop;
  331. const ni_namelist    *values;
  332. id                                cell = [browserAliases selectedCell];
  333.  
  334.         if (!cell || !(prop = [ni_dirObj property:H_NAME]))
  335.             return self;
  336.         values = [prop valueList];
  337.  
  338.         i = ni_namelist_match(*values, [[browserAliases selectedCell] stringValue]);
  339.     if ((i != NI_INDEX_NULL) && (i > 0)) { // Must not delete the name!
  340.             [prop deleteValue:i];
  341.             [window setDocEdited:YES];
  342.             [browserAliases reloadColumn:0];
  343.             i-= 2; // The browser starts with value index 1!
  344.             if (i > 0)
  345.                 [[browserAliases matrixInColumn:0] selectCellAt:i :0];
  346.             else if (values->ni_namelist_len)
  347.                 [[browserAliases matrixInColumn:0] selectCellAt:0 :0];
  348.         }
  349.     return self;
  350. }
  351.  
  352. - setNetBoot:sender
  353. {
  354. BOOL    edited = [window isDocEdited];
  355. int        signal;
  356. char    *bootFile = NXCopyStringBufferFromZone([textKernel stringValue],[self zone]),
  357.             *bootParms1 = NXCopyStringBufferFromZone([textRootDirectory stringValue],[self zone]),
  358.             *bootParms2 = NXCopyStringBufferFromZone([textPrivateDirectory stringValue],[self zone]);
  359.  
  360.         [textKernel selectText:self];
  361.  
  362.         // Run a modal for the panel.
  363.         signal = [NXApp runModalFor:panel];
  364.         [panel close];
  365.         
  366.         switch (signal) {
  367.             case NX_RUNABORTED:
  368.                 // Restore to previos values
  369.                 [[ni_dirObj property:H_BOOTFILE] updateProperty:bootFile default:(!bootFile || !*bootFile)];
  370.                 [textKernel setStringValue:bootFile];
  371.                 [textRootDirectory setStringValue:bootParms1];
  372.                 [textPrivateDirectory setStringValue:bootParms2];
  373.                 [window setDocEdited:edited];
  374.                 break;
  375.             case NX_RUNSTOPPED: 
  376.             default: ;
  377.         }
  378.         
  379.         NXZoneFree([self zone], bootFile);
  380.         NXZoneFree([self zone], bootParms1);
  381.         NXZoneFree([self zone], bootParms2);
  382.     return self;
  383. }
  384.  
  385. // Actions from the Net Boot configuration panel
  386. - configOK:sender
  387. {
  388.         [NXApp stopModal];
  389.         [self setBootParms];
  390.         return self;
  391. }
  392.  
  393. - configCancel:sender
  394. {
  395.         [NXApp abortModal];
  396.         return self;
  397. }
  398.  
  399. // ************************************************************************
  400. // Delegates:
  401.  
  402. - (BOOL)textWillEnd:textObject
  403. {
  404. const char    *alert = NULL,
  405.                         *path = [[textObject superview] stringValue],
  406.                         *p = strchr(path,':');
  407.  
  408.         if ([textObject superview] == textRootDirectory)
  409.             alert = getString("Alert:Invalid root directory.");
  410.         else if ([textObject superview] == textPrivateDirectory)
  411.             alert = getString("Alert:Invalid private directory.");
  412.  
  413.         // Accept the empty input and check for ':/'.
  414.         if (alert && path && *path && ((p && (*(p+1) != '/')) || !p)) {
  415.             NXRunAlertPanel(getString("Alert:Alert"), alert, getString("Button:OK"), NULL, NULL);
  416.             return YES;
  417.         }
  418.         return NO;
  419. }
  420.  
  421. - textDidEnd:textObject endChar:(unsigned short)whyEnd
  422. {
  423.         if (([textObject superview] == textAliases) && (whyEnd == NX_RETURN))
  424.             [self addAlias:self];
  425.  
  426.         return self;
  427. }
  428.  
  429. - (int) browser:sender fillMatrix:matrix inColumn:(int) column
  430. {
  431. NIProperty                *prop;
  432. const ni_namelist    *values;
  433. int                                rows = 0, i = 0;
  434. id                                cell;
  435.  
  436.         if (!(prop = [ni_dirObj property:H_NAME]))  // Can be called before ni_dirObj is set.
  437.             return 0;
  438.         if ([prop index] == NI_INDEX_NULL)
  439.             return 0;
  440.         
  441.         values = [prop valueList];
  442.  
  443.         for (i = 1; i < values->ni_namelist_len; i++) {
  444.             [matrix addRow];
  445.             cell = [matrix cellAt:rows :0];
  446.             [cell setStringValue:values->ni_namelist_val[i]];
  447.             [cell setLoaded:YES];
  448.             [cell setLeaf:YES];
  449.             rows++;
  450.         }
  451.  
  452.         return rows;
  453. }
  454.  
  455. @end
  456.