home *** CD-ROM | disk | FTP | other *** search
/ Big Green CD 8 / BGCD_8_Dev.iso / NEXTSTEP / Networking / SambaManager / Services.m < prev    next >
Encoding:
Text File  |  1998-04-01  |  30.7 KB  |  913 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 "Services.h"
  23. #import "Controller.h"
  24. #import "NIDirectory.h"
  25. #import "NIProperty.h"
  26. #import "Panels.h"
  27. #import "SMBKeys.h"
  28. #import "NetInfoKeys.h"
  29.  
  30. #define ALERT_STATUS(a,m,b1,b2,b3,arg1,status) \
  31.                             NXRunAlertPanel(getString(a), getString(m), \
  32.                                                             getString(b1), \
  33.                                                             b2?getString(b2):NULL, \
  34.                                                             b3?getString(b3):NULL, \
  35.                                                             arg1, ni_error(status))
  36.  
  37. // The special sections (as spelled in smb.config):
  38. char    *sectionNames[] = {
  39.   NULL,    // This is just a place holder for any service!
  40.     "homes",
  41.     "global",
  42.     "printers"
  43. };
  44.     
  45. // An intermediate object for the dual text field (form):
  46. @interface BiText:Object
  47. {
  48.     id        form;
  49.     id        textDelegate;
  50.     char     sep, pre, post, *strng;
  51. }
  52. - init:(char)s form:f pre:(char)b post:(char)e;
  53. - free;
  54. - setTextDelegate:sender;
  55. - selectText:sender;
  56. - nextText;
  57. - setNextText:sender;
  58. - setStringValue:(const char *)s;
  59. - (const char *)stringValue;
  60. @end
  61.  
  62. @implementation BiText
  63. - init:(char)s form:f pre:(char)b post:(char)e
  64. {
  65.         [super init];
  66.         textDelegate = nil;
  67.         form = f;
  68.         sep = s;
  69.         pre = b;
  70.         post = e;
  71.         strng = NULL;
  72.         return self;
  73. }
  74.  
  75. - free
  76. {
  77.     if (strng)
  78.         NXZoneFree([self zone], strng);
  79.     return [super free];
  80. }
  81.  
  82. - textDidEnd:textObject endChar:(unsigned short)whyEnd
  83. {
  84.         if (whyEnd == NX_RETURN)
  85.             if ([form selectedRow] == 1)
  86.                 [textDelegate textDidEnd:textObject endChar:whyEnd];
  87.         return self;
  88. }
  89.  
  90. - setTextDelegate:sender
  91. {
  92.         textDelegate = sender;
  93.         return [form setTextDelegate:self];
  94. }
  95.  
  96. - selectText:sender
  97. {
  98.         return [form selectTextAt:0];
  99. }
  100.  
  101. - nextText
  102. {
  103.         return nil;
  104. }
  105.  
  106. - setNextText:sender
  107. {
  108.         return self;
  109. }
  110.  
  111. - setStringValue:(const char *)s
  112. {
  113. char    *p = NULL, *d, *str = NULL;
  114.  
  115.         if (!s) {
  116.             [form setStringValue:"" at:0];
  117.             [form setStringValue:"" at:1];
  118.             return self;
  119.         } else {
  120.             p = str = NXCopyStringBufferFromZone(s, [self zone]);
  121.             if (pre && (*p == pre))
  122.                 p++;
  123.             if (post && (str[strlen(str)-1] == post))
  124.                 str[strlen(str)-1] = '\0';
  125.         }
  126.  
  127.         if (d = strchr(p, sep)) {
  128.             [form setStringValue:d+1 at:1];
  129.             *d = '\0';
  130.             [form setStringValue:p at:0];
  131.         } else {
  132.             [form setStringValue:p at:0];
  133.             [form setStringValue:"" at:1];
  134.         }
  135.         
  136.         NXZoneFree([self zone], str);
  137.         return self;
  138. }
  139.  
  140. - (const char *)stringValue
  141. {
  142. int        l1 = strlen([form stringValueAt:0]),
  143.             l2 = strlen([form stringValueAt:1]);
  144. char    *p;
  145.  
  146.         p = strng = NXZoneRealloc([self zone], strng, l1 + l2 + 3);
  147.         if (pre)
  148.             *p++ = pre;
  149.         strcpy(p, [form stringValueAt:0]);
  150.         p+= l1;
  151.         *p++ = sep;
  152.         strcpy(p, [form stringValueAt:1]);
  153.         p+= l2;
  154.         if (post)
  155.             *p++ = post;
  156.         *p = '\0';
  157.         return strng;
  158. }
  159. @end
  160.  
  161. // An intermediate object for the file modes:
  162. @interface FileModes:Object
  163. {
  164.     id        window;
  165.     id        radio;
  166.     id        check1, check2, check3;
  167.     id        netinfoDir;
  168.     id        prop;
  169.     
  170.     int        mask;
  171. }
  172. - init:w radio:r check1:c1 check2:c2 check3:c3 niDir:d label:(const char *)l;
  173. - display:sender;
  174. @end
  175.  
  176. @implementation FileModes
  177. - show:(int)value
  178. {
  179.         [check1 setState:value&0400 at:0 :0];
  180.         [check1 setState:value&0200 at:0 :1];
  181.         [check1 setState:value&0100 at:0 :2];
  182.  
  183.  
  184.         [check2 setState:value&0040 at:0 :0];
  185.         [check2 setState:value&0020 at:0 :1];
  186.         [check2 setState:value&0010 at:0 :2];
  187.  
  188.         [check3 setState:value&0004 at:0 :0];
  189.         [check3 setState:value&0002 at:0 :1];
  190.         [check3 setState:value&0001 at:0 :2];
  191.  
  192.         return self;
  193. }
  194.  
  195. - changed:sender
  196. {
  197. char    buf[4];
  198. int        col = [radio selectedCol];
  199.  
  200.         [window setDocEdited:YES];
  201.         if (sender == radio) {
  202.             if (col) {
  203.                 sprintf(buf, "%03o", mask&0777);
  204.                 [prop updateValue:buf at:0];
  205.                 [self show:mask];
  206.             } else {
  207.                 [prop removeValues];
  208.                 [self show:0];
  209.             }
  210.         } else {
  211.             [radio selectCellAt:0 :1];
  212.             
  213.             mask = 0;
  214.             mask|= [[check1 cellAt:0 :0] state]?0400:0;
  215.             mask|= [[check1 cellAt:0 :1] state]?0200:0;
  216.             mask|= [[check1 cellAt:0 :2] state]?0100:0;
  217.  
  218.             mask|= [[check2 cellAt:0 :0] state]?0040:0;
  219.             mask|= [[check2 cellAt:0 :1] state]?0020:0;
  220.             mask|= [[check2 cellAt:0 :2] state]?0010:0;
  221.  
  222.             mask|= [[check3 cellAt:0 :0] state]?0004:0;
  223.             mask|= [[check3 cellAt:0 :1] state]?0002:0;
  224.             mask|= [[check3 cellAt:0 :2] state]?0001:0;
  225.             
  226.             sprintf(buf, "%03o", mask);
  227.             [prop updateValue:buf at:0];
  228.         }
  229.         
  230.         return self;
  231. }
  232.  
  233. - init:w radio:r check1:c1 check2:c2 check3:c3 niDir:d label:(const char *)l
  234. {
  235.         window =w;
  236.         radio = r;
  237.         check1 = c1;
  238.         check2 = c2;
  239.         check3 = c3;
  240.         netinfoDir = d;
  241.         mask = 0;
  242.         [radio setTarget:self];
  243.         [radio setAction:@selector(changed:)];
  244.         [check1 setTarget:self];
  245.         [check1 setAction:@selector(changed:)];
  246.         [check2 setTarget:self];
  247.         [check2 setAction:@selector(changed:)];
  248.         [check3 setTarget:self];
  249.         [check3 setAction:@selector(changed:)];
  250.         prop = [netinfoDir addCall:l displayAction:@selector(display:)];
  251.         [prop setDelegate:self];
  252.         return self;
  253. }
  254.  
  255. - display:sender
  256. {
  257.         mask = 0;    // Isn't set if the string has no number!
  258.         sscanf([sender valueAt:0], "%o", &mask);
  259.         [radio selectCellAt:0 :mask?1:0];
  260.         [self show:mask];
  261.         return self;
  262. }
  263. @end
  264.  
  265. // Class variable with the string for the open/save panel's title.
  266. static const char *hostTitle, *groupTitle, *userTitle, *servicesTitle;
  267.  
  268. @implementation Services
  269. // ************************************************************************
  270. // Class methods:
  271. + initialize
  272. // Called once by the run time system
  273. {
  274.         hostTitle = getString("Title:Hosts");
  275.         groupTitle = getString("Title:Groups");
  276.         userTitle = getString("Title:Users");
  277.         servicesTitle = getString("Title:Services");
  278.         return self;
  279. }
  280.  
  281. + new:sender at:(NXCoord *)offset
  282. {
  283. NIDirectory    *NIDir;
  284. Services        *service = [Services alloc];
  285.  
  286.         if ((service->serviceType = [[Panels new] selectService]) < 0)
  287.             return [service free];
  288.  
  289.         if ((NIDir = [NIDirectory new:sender root:SMNI_SAMBA directory:NULL])) {
  290.             [NIDir setDelegate:service];
  291.             if ([service init:sender dirObj:NIDir delta:offset service:NULL]) {
  292.                 [NIDir setSaveTitle:servicesTitle];
  293.                 return service;
  294.             }
  295.             [NIDir close];
  296.         }
  297.         return [service free];
  298. }
  299.  
  300. + open:sender at:(NXCoord *)offset
  301. {
  302. NIDirectory    *NIDir;
  303. Services        *service = [Services alloc];
  304. const char     *sName;
  305.  
  306.         if ((NIDir = [NIDirectory open:sender root:SMNI_SAMBA withTitle:servicesTitle])) {        
  307.             [NIDir setDelegate:service];
  308.             sName = [NIDir baseName];
  309.             for (service->serviceType = 3; service->serviceType; service->serviceType--)
  310.                 if (!strcmp(sectionNames[service->serviceType], sName))
  311.                     break;
  312.             if ([service init:sender dirObj:NIDir delta:offset service:sName])
  313.                 return service;
  314.  
  315.             [NIDir close];
  316.         }
  317.         return [service free];
  318. }
  319.  
  320. // ************************************************************************
  321. // Local methods:
  322.  
  323. - free
  324. {
  325.         [remAnnounce free];
  326.         [mangleMap free];
  327.         [interfaces free];
  328.         [objCreateMask free];
  329.         [objDirMask free];
  330.         [objForceCreateMask free];
  331.         [objForceDirMask free];
  332.  
  333.         return [super free];
  334. }
  335.  
  336. // Set which page of options to display
  337. - selectPage:sender
  338. {
  339. int    number = [[matrixPages selectedCell] tag];
  340.  
  341.         if (number != lastPage) {
  342.             [[boxChoices contentView] replaceSubview:lastPageID with:boxes[number]];
  343.             lastPageID = boxes[number];
  344.             lastPage = number;
  345.             [window display];
  346.         }
  347.         
  348.         return self;
  349. }
  350.  
  351. // Display the socket options
  352. - getSocketOpts:sender
  353. {
  354. const char     *p;
  355. int                    i, count = [sender values];
  356.         
  357.         for (i=0; i < count; i++) {
  358.             p = [sender valueAt:i];
  359.             if (!strcmp(p, S_SO_KEEPALIVE))
  360.                     [formSOChecks selectCellAt:0 :0];
  361.             else if (!strcmp(p, S_SO_REUSEADDR))
  362.                 [formSOChecks selectCellAt:1 :0];
  363.             else if (!strcmp(p, S_SO_BROADCAST))
  364.                 [formSOChecks selectCellAt:0 :1];
  365.             else if (!strcmp(p, S_SO_TCP_NODEL))
  366.                 [formSOChecks selectCellAt:1 :1];
  367.             else if (!strncmp(p, S_SO_SNDBUF, strlen(S_SO_SNDBUF))) {
  368.                 p = strchr(p, '=') + 1;
  369.                 [formSOBufSizes setStringValue:p at:0];
  370.             } else if (!strncmp(p, S_SO_RCVBUF, strlen(S_SO_RCVBUF))) {
  371.                 p = strchr(p, '=') + 1;
  372.                 [formSOBufSizes setStringValue:p at:1];
  373.             } else if (!strncmp(p, S_SO_SNDLOWAT, strlen(S_SO_SNDLOWAT))) {
  374.                 p = strchr(p, '=') + 1;
  375.                 [formSOLowWatMark setStringValue:p at:0];
  376.             } else if (!strncmp(p, S_SO_RCVLOWAT, strlen(S_SO_RCVLOWAT))) {
  377.                 p = strchr(p, '=') + 1;
  378.                 [formSOLowWatMark setStringValue:p at:1];
  379.             }
  380.         }
  381.         return self;
  382. }
  383.  
  384. - setSocketOpts:sender
  385. {
  386.         [window setDocEdited:YES];
  387.         return self;
  388. }
  389.  
  390.  
  391. // ************************************************************************
  392. //    Methods:
  393. - (BOOL)minimumOK
  394. {
  395. const char    *value = [[ni_dirObj property:S_PATH] valueAt:0];
  396. char                *pathEnd = strrchr(value, '/');
  397.  
  398.         if (serviceType > 0)
  399.             return [super minimumOK];
  400.         else if (*value) {
  401.             if (!*[[ni_dirObj property:S_NAME] valueAt:0]) {
  402.                 [[ni_dirObj property:S_NAME] updateValue:pathEnd?pathEnd+1:value at:0];
  403.                 [ni_dirObj setAllowChangName:YES];
  404.             }
  405.         } else {
  406.             NXRunAlertPanel(getString("Alert:Alert"),
  407.                                             getString("Message:No path set!"),
  408.                                             getString("Button:OK"),
  409.                                             NULL, NULL);
  410.             return NO;
  411.         }
  412.         return YES;
  413. }
  414.  
  415. - setGlobService
  416. {        
  417.         // GLOBALS
  418.  
  419.         // access password security name mangling
  420.         [ni_dirObj addBool:S_ENCRYPT_PASS outlet:radioEncryptPasswd];
  421.         [ni_dirObj addBool:S_NULL_PASSWDS outlet:radioNullPasswd];
  422.         [ni_dirObj addBool:S_UNIX_REALNAME outlet:radioUnixRealName];
  423.         [ni_dirObj addInt:S_PASSWD_LEVEL text:textPasswdLevel slider:sliderPasswdLevel zero:NULL];
  424.         [ni_dirObj addPopup:S_SECURITY outlet:popupSecurity];
  425.         [ni_dirObj addString:S_HOSTS_EQUIV text:textHostsEquiv
  426.                              button:[formSetPassSec cellAt:0 :0] mode:NIPT_FILE path:NULL title:NULL];
  427.         [ni_dirObj addString:S_PASSWD_CHAT outlet:textPasswdChat];
  428.         [ni_dirObj addString:S_PASSWD_PROG text:textPasswdProgram
  429.                              button:[formSetPassSec cellAt:2 :0] mode:NIPT_FILE path:NULL title:NULL];
  430.         [ni_dirObj addString:S_ROOT_DIR text:textRootDirectory
  431.                              button:[formSetPassSec cellAt:3 :0]  mode:NIPT_DIR path:NULL title:NULL];
  432.         [ni_dirObj addString:S_SMB_PASSWD_FL text:textSMBPasswdFile
  433.                              button:[formSetPassSec cellAt:4 :0] mode:NIPT_FILE path:NULL title:NULL];
  434.         [ni_dirObj addBrowser:S_PASSWD_SERVER browser:browserPasswdServer text:textPasswdServer
  435.                              add:buttonAddPasswdServer remove:buttonRemPasswdServer];
  436.         [ni_dirObj addBool:S_CASE_SENSITIV outlet:radioCaseSensitive];
  437.         [ni_dirObj addBool:S_STRIP_DOT outlet:radioStripDot];
  438.         [ni_dirObj addInt:S_MANGLED_STACK text:textMangleStack slider:sliderMangleStack zero:NULL];
  439.         [ni_dirObj addPopup:S_CHAR_SET outlet:popupCharSet];
  440.         [ni_dirObj addPopup:S_CLNT_CODE_PG outlet:popupCodePage];
  441.  
  442.         // Logon locking logging
  443.         [ni_dirObj addBool:S_DOMAIN_LOGONS outlet:radioDomainLogons];
  444.         [ni_dirObj addString:S_LOGON_PATH outlet:textLogonPath];
  445.         [ni_dirObj addString:S_LOGON_SCRIPT text:textLogonScript
  446.                              button:[formGSetLogon cellAt:1 :0] mode:NIPT_FILE path:NULL title:NULL];
  447.         [ni_dirObj addString:S_MESSAGE outlet:textMessageCommand];
  448.         [ni_dirObj addString:S_SMB_RUN text:textSMBRun
  449.                              button:[formGSetLogon cellAt:3 :0] mode:NIPT_FILE path:NULL title:NULL];
  450.         [ni_dirObj addString:S_USERNAME_MAP text:textUserNameMap
  451.                              button:[formGSetLogon cellAt:4 :0] mode:NIPT_FILE path:NULL title:NULL];
  452.         [ni_dirObj addBool:S_STATUS outlet:radioStatus];
  453.         [ni_dirObj addBool:S_SYSLOG_ONLY outlet:radioSyslogOnly];
  454.         [ni_dirObj addString:S_LOCK_DIR text:textLockDir
  455.                              button:buttonSetLockDir mode:NIPT_DIR path:NULL title:NULL];
  456. //!!! suffix = log.%m
  457.         propLogFile = [ni_dirObj addString:S_LOG_FILE text:textLogFile
  458.                                                          button:buttonSetLogFile mode:NIPT_DIR path:NULL title:NULL];
  459.         [ni_dirObj addInt:S_MAX_LOG_SIZE text:textLogSize slider:sliderLogSize
  460.                              zero:getString("string:unlimited")];
  461.         [ni_dirObj addInt:S_LOG_LEVEL text:textLogLevel slider:sliderLogLevel zero:NULL];
  462.         
  463.         // nmbd
  464.         [ni_dirObj addBool:S_DNS_PROXY outlet:radioDNSProxy];
  465.         [ni_dirObj addBool:S_LOCAL_MASTER outlet:radioLocalMaster];
  466.         [ni_dirObj addBool:S_TIME_SERVER outlet:radioTimeServer];
  467.         [ni_dirObj addBool:S_WINS_PROXY outlet:radioWINSProxy];
  468.         remAnnounce = [[BiText alloc] init:'/' form:formRemAnnounce pre:'\0' post:'\0'];
  469.         [ni_dirObj addBrowser:S_REM_ANNOUNCE browser:browserRemAnnounce text:remAnnounce
  470.                              add:buttonAddRemAnnounce remove:buttonRemRemAnnounce];
  471.         [ni_dirObj addBrowser:S_NB_ALIASES browser:browserNBAliases text:textNBAliases
  472.                              add:buttonAddNBAliases remove:buttonRemNBAliases];
  473.  
  474.         // Startup
  475.         [ni_dirObj addBool:S_DOMAIN_MASTER outlet:radioDomainMaster];
  476.         [ni_dirObj addBool:S_LOAD_PRNTRS outlet:radioLoadPrinters];
  477.         [ni_dirObj addBool:S_PREF_MASTER outlet:radioPrefMaster];
  478.         [ni_dirObj addBool:S_WINS_SUPPORT outlet:radioWINSSupport];
  479.         [ni_dirObj addInt:S_OS_LEVEL text:textOSLevel slider:sliderOSLevel zero:NULL];
  480.         [ni_dirObj addPopup:S_ANNOUNCE_AS outlet:popupAnnounceAs];
  481.         [ni_dirObj addPopup:S_PRINTING outlet:popupPrinting];
  482.         [ni_dirObj addPopup:S_PROTOCOL outlet:popupProtocol];
  483.         propAnnounceVersion = [ni_dirObj addString:S_ANNOUNCE_VER outlet:textAnnounceVersion];
  484.         [ni_dirObj addString:S_CONF_FILE text:textConfigFile
  485.                              button:[formSetStartup cellAt:1 :0]  mode:NIPT_FILE path:NULL title:NULL];
  486.         [ni_dirObj addString:S_DEFAULT_SERV text:textDefaultService
  487.                              button:[formSetStartup cellAt:2 :0]  mode:NIPT_NETINFO
  488.                              path:SMNI_SAMBA title:servicesTitle];
  489.         [ni_dirObj addString:S_NB_NAME outlet:textNetBIOSName];
  490.         [ni_dirObj addString:S_PRNTCAP_NAME text:textPrintcapName
  491.                              button:[formSetStartup cellAt:4 :0]  mode:NIPT_FILE path:NULL title:NULL];
  492.         [ni_dirObj addString:S_SERVER_STRNG outlet:textServerString];
  493.         [ni_dirObj addString:S_SOCK_ADDR outlet:textSocketAddress];
  494.         [ni_dirObj addString:S_WINS_SERVER text:textWINSServer
  495.                              button:[formSetStartup cellAt:7 :0] mode:NIPT_NETINFO
  496.                              path:SMNI_SAMBA title:hostTitle];
  497.         [ni_dirObj addString:S_WORKGROUP outlet:textWorkGroup];
  498.         interfaces = [[BiText alloc] init:'/' form:formInterfaces pre:'\0' post:'\0'];
  499.         [ni_dirObj addBrowser:S_INTERFACES browser:browserInterfaces text:interfaces
  500.                               add:buttonAddInterfaces remove:buttonRemInterfaces];
  501.         [ni_dirObj addBrowser:S_AUTO_SERVICES browser:browserAutoServices
  502.                              add:buttonAddAutoServices remove:buttonRemAutoServices
  503.                              mode:NIPT_NETINFO path:SMNI_SAMBA title:servicesTitle];
  504.  
  505.         // Tuning
  506.         [ni_dirObj addBool:S_GETWD_CACHE outlet:radioGetwdCache];
  507.         [ni_dirObj addBool:S_READ_PRED outlet:radioReadPrediction];
  508.         [ni_dirObj addBool:S_READ_RAW outlet:radioReadRaw];
  509.         [ni_dirObj addBool:S_SYNC_ALWAYS outlet:radioSyncAlways];
  510.         [ni_dirObj addBool:S_WRITE_RAW outlet:radioWriteRaw];
  511.         [ni_dirObj addInt:S_DEAD_TIME text:textDeadTime slider:sliderDeadTime
  512.                      zero:getString("string:no timeout")];
  513.         [ni_dirObj addInt:S_KEEP_ALIVE text:textKeepAlive slider:sliderKeepAlive
  514.                      zero:getString("string:no packets")];
  515.         [ni_dirObj addInt:S_LPQ_CACHE_TM text:textlpqCache slider:sliderlpqCache
  516.                      zero:getString("string:no caching")];
  517.         [ni_dirObj addInt:S_READ_SIZE text:textReadSize slider:sliderReadSize zero:NULL];
  518.         [formSOBufSizes setTextDelegate:self];
  519.         [formSOLowWatMark setTextDelegate:self];
  520.         [formSOChecks setTarget:self];
  521.         [formSOChecks setAction:@selector(setSocketOpts:)];
  522.         [ni_dirObj addCall:S_SOCK_OPTS displayAction:@selector(getSocketOpts:)];
  523.         
  524.         return self;
  525. }
  526.  
  527. - setService
  528. {    
  529.         // SERVICES
  530.         
  531.         // access
  532.         [ni_dirObj addBool:S_BROWSEABLE outlet:radioBrowseable];
  533.         [ni_dirObj addBool:S_GUEST_ONLY outlet:radioGuestOnly];
  534.         [ni_dirObj addBool:S_ONLY_USER outlet:radioOnlyUser];
  535.         [ni_dirObj addBool:S_PRNTABLE outlet:radioPrintable];
  536.         [ni_dirObj addBool:S_PUBLIC outlet:radioPublic];
  537.         [ni_dirObj addBool:S_READ_ONLY outlet:radioReadOnly];
  538.         propAllowHosts = [ni_dirObj addBrowser:S_ALLOWHOSTS browser:browserAllowHosts
  539.                                                                 add:buttonAddAllowHosts remove:buttonRemAllowHosts
  540.                                                                 mode:NIPT_NETINFO path:SMNI_HOSTS title:hostTitle];
  541.         propDenyHosts = [ni_dirObj addBrowser:S_DENY_HOSTS browser:browserDenyHosts
  542.                                                              add:buttonAddDenyHosts remove:buttonRemDenyHosts
  543.                                                              mode:NIPT_NETINFO path:SMNI_HOSTS title:hostTitle];
  544.         propReadList = [ni_dirObj addBrowser:S_READ_LIST browser:browserReadList
  545.                                                              add:buttonAddReadList remove:buttonRemReadList
  546.                                                              mode:NIPT_NETINFO path:SMNI_USERS title:userTitle];
  547.         propWriteList = [ni_dirObj addBrowser:S_WRITE_LIST browser:browserWriteList
  548.                                                              add:buttonAddWriteList remove:buttonRemWriteList
  549.                                                              mode:NIPT_NETINFO path:SMNI_USERS title:userTitle];
  550.         propValidUsers = [ni_dirObj addBrowser:S_VALID_USERS browser:browserValidUsers
  551.                                                                 add:buttonAddValidUsers remove:buttonRemValidUsers
  552.                                                                 mode:NIPT_NETINFO path:SMNI_USERS title:userTitle];
  553.         propInvalidUsers = [ni_dirObj addBrowser:S_INVALID_USERS browser:browserInvalidUsers
  554.                                                                     add:buttonAddInvalidUsers remove:buttonRemInvalidUsers
  555.                                                                     mode:NIPT_NETINFO path:SMNI_USERS title:userTitle];
  556.         [ni_dirObj addInt:S_MAX_CONNS text:textMaxCons slider:sliderMaxCons
  557.                              zero:getString("string:unlimited")];
  558.         [ni_dirObj addString:S_VOLUME outlet:textVolume];
  559.  
  560.         // File visibility name mangling
  561.         [ni_dirObj addBool:S_HIDE_DOT_FILE outlet:radioHideDots];
  562.         [ni_dirObj addBool:S_SET_DIR outlet:radioSetDir];
  563.         [ni_dirObj addBool:S_FOLLOW_SYMLNK outlet:radioFollowSymLinks];
  564.         [ni_dirObj addBool:S_WIDE_LINKS outlet:radioWideLinks];
  565.         [ni_dirObj addBrowser:S_DONT_DESCEND browser:browserDescend
  566.                               add:buttonAddDescend remove:buttonRemDescend
  567.                              mode:NIPT_DIR path:NULL title:NULL];
  568. // seperator = '/'
  569.         propHideFiles = [ni_dirObj addBrowser:S_HIDE_FILES browser:browserHideFiles text:textHideFiles
  570.                                                               add:buttonAddHideFiles remove:buttonRemHideFiles];
  571.         propHideFilesSeparator = [ni_dirObj addProperty:S_HIDE_FILES_S];
  572. // seperator = '/'
  573.         propVetoFiles = [ni_dirObj addBrowser:S_VETO_FILES browser:browserVetoFiles text:textVetoFiles
  574.                                                              add:buttonAddVetoFiles remove:buttonRemVetoFiles];
  575.         propVetoFilesSeparator = [ni_dirObj addProperty:S_VETO_FILES_S];
  576.         [ni_dirObj addBool:S_MANGLE_CASE outlet:radioMangleCase];
  577.         [ni_dirObj addBool:S_MANGLED_NAMES outlet:radioMangledName];
  578.         [ni_dirObj addBool:S_PRESERVE_CASE outlet:radioPreserveCase];
  579.         [ni_dirObj addBool:S_SHRT_PRS_CASE outlet:radioShortPresCase];
  580.         [ni_dirObj addBool:S_DEFAULT_CASE outlet:radioDefaultCase];
  581.         [ni_dirObj addBrowser:S_VALID_CHARS browser:browserValidChars text:textValidChars
  582.                               add:buttonAddValidChars remove:buttonRemValidChars];
  583.         mangleMap = [[BiText alloc] init:' ' form:formMangleMap pre:'(' post:')'];
  584.         [ni_dirObj addBrowser:S_MANGLED_MAP browser:browserMangledMap text:mangleMap
  585.                               add:buttonAddMangledMap remove:buttonRemMangledMap];
  586.         [ni_dirObj addChar:S_MANGLING_CHAR outlet:textMangleChar];
  587.  
  588.         // File permissions locking logging
  589.         [ni_dirObj addBool:S_ALTPERM outlet:radioAlternate];
  590.         [ni_dirObj addBool:S_DEL_READ_ONLY outlet:radioDelReadOnly];
  591.         [ni_dirObj addBool:S_DOS_FILETIMES outlet:radioDOSFileTimes];
  592.         [ni_dirObj addBool:S_MAP_ARCHIVE outlet:radioMapArchive];
  593.         [ni_dirObj addBool:S_MAP_HIDDEN outlet:radioMapHidden];
  594.         [ni_dirObj addBool:S_MAP_SYSTEM outlet:radioMapSystem];
  595.         [ni_dirObj addString:S_FRCE_USER text:textForceUser
  596.                              button:buttonSetForceUser mode:NIPT_NETINFO
  597.                              path:SMNI_USERS title:userTitle];
  598.         [ni_dirObj addString:S_FRCE_GROUP text:textForceGroup
  599.                              button:buttonSetForceGroup mode:NIPT_NETINFO 
  600.                              path:SMNI_GROUPS title:groupTitle];
  601.         objCreateMask = [[FileModes alloc] init:window radio:radioCreateMask
  602.                                                                              check1:check1CreateMask
  603.                                                                              check2:check2CreateMask
  604.                                                                              check3:check3CreateMask
  605.                                                                              niDir:ni_dirObj
  606.                                                                              label:S_CREATE_MASK];
  607.         objDirMask = [[FileModes alloc] init:window radio:radioDirMask
  608.                                                                              check1:check1DirMask
  609.                                                                              check2:check2DirMask
  610.                                                                              check3:check3DirMask
  611.                                                                              niDir:ni_dirObj
  612.                                                                              label:S_DIR_MASK];
  613.         objForceCreateMask = [[FileModes alloc] init:window radio:radioForceCreateMask
  614.                                                                              check1:check1ForceCreateMask
  615.                                                                              check2:check2ForceCreateMask
  616.                                                                              check3:check3ForceCreateMask
  617.                                                                              niDir:ni_dirObj
  618.                                                                              label:S_FRCE_CREAT_MD];
  619.         objForceDirMask = [[FileModes alloc] init:window radio:radioForceDirMask
  620.                                                                              check1:check1ForceDirMask
  621.                                                                              check2:check2ForceDirMask
  622.                                                                              check3:check3ForceDirMask
  623.                                                                              niDir:ni_dirObj
  624.                                                                              label:S_FRCE_DIR_MODE];
  625.         [ni_dirObj addBool:S_FAKE_OPLOCKS outlet:radioFakeOpLocks];
  626.         [ni_dirObj addBool:S_LOCKING outlet:radioLocking];
  627.         [ni_dirObj addBool:S_SHARE_MODES outlet:radioShareModes];
  628.         [ni_dirObj addBool:S_STRCT_LOCKING outlet:radioStrictLocking];
  629.  
  630.         // Passwords and Security logon and execution startup
  631.         [ni_dirObj addBool:S_REVALIDATE outlet:radioRevalidate];
  632.         [ni_dirObj addString:S_GUEST_ACCOUNT text:textGuestAccount
  633.                              button:buttonSetGuestAccount mode:NIPT_NETINFO 
  634.                              path:SMNI_USERS title:userTitle];
  635.         [ni_dirObj addBrowser:S_ADMINUSERS browser:browserAdminUsers
  636.                               add:buttonAddAdminUsers remove:buttonRemAdminUsers
  637.                              mode:NIPT_NETINFO path:SMNI_USERS title:userTitle];
  638.         propUserNames = [ni_dirObj addBrowser:S_USERNAME browser:browserUserNames
  639.                                           add:buttonAddUserNames remove:buttonRemUserNames
  640.                                          mode:NIPT_NETINFO path:SMNI_USERS title:userTitle];
  641.         propMagicOutput= [ni_dirObj addString:S_MAGIC_OUTPUT text:textMagicOutput
  642.                                                                 button:[formSetLogon cellAt:0 :0] mode:NIPT_DIR path:NULL title:NULL];
  643.         [ni_dirObj addString:S_MAGIC_SCRIPT text:textMagicScript
  644.                              button:[formSetLogon cellAt:1 :0]  mode:NIPT_FILE path:NULL title:NULL];
  645.         [ni_dirObj addString:S_PATH text:textPath
  646.                              button:[formSetLogon cellAt:2 :0] mode:NIPT_DIR path:NULL title:NULL];
  647.         [ni_dirObj addString:S_PRE_EXEC text:textPreExecution
  648.                              button:[formSetLogon cellAt:3 :0]  mode:NIPT_FILE path:NULL title:NULL];
  649.         [ni_dirObj addString:S_POST_EXEC text:textPostExecution
  650.                              button:[formSetLogon cellAt:4 :0] mode:NIPT_FILE path:NULL title:NULL];
  651.         [ni_dirObj addString:S_ROOT_PRE_EX text:textRootPreExecution
  652.                              button:[formSetLogon cellAt:5 :0] mode:NIPT_FILE path:NULL title:NULL];
  653.         [ni_dirObj addString:S_ROOT_POST_EX text:textRootPostExecution
  654.                              button:[formSetLogon cellAt:6 :0] mode:NIPT_FILE path:NULL title: NULL];
  655.         [ni_dirObj addString:S_INCLUDE text:textInclude
  656.                              button:buttonSetInclude mode:NIPT_FILE path:NULL title: NULL];
  657.  
  658.         return self;
  659. }
  660.  
  661. - setPrinters
  662. {
  663.         // PRINTERS
  664.         [[ni_dirObj addProperty:S_COMMENT] updateValue:"Template for all Samba Printers" at:0];
  665.         [[ni_dirObj addProperty:S_SHARE_MODES] updateValue:"no" at:0];
  666.         [[ni_dirObj addProperty:S_READ_ONLY] updateValue:"no" at:0];
  667.  
  668.         [ni_dirObj addInt:S_MIN_PRNT_SPC text:textMinPrntSpace slider:sliderMinPrntSpace
  669.                      zero:getString("string:no caching")];
  670.         [ni_dirObj addBool:S_AVAILABLE outlet:checkPAvailable];
  671.         [ni_dirObj addBool:S_BROWSEABLE outlet:radioPBrowseable];
  672.         [ni_dirObj addBool:S_POSTSCRIPT outlet:radioPostscript];
  673.         [ni_dirObj addBool:S_PUBLIC outlet:radioPPublic];
  674.         [ni_dirObj addBool:S_GUEST_ONLY outlet:radioPGuestOnly];
  675.         [ni_dirObj addBool:S_WRITEABLE outlet:radioPWriteable];
  676.         [[ni_dirObj addProperty:S_PRNTABLE] updateValue:"yes" at:0];
  677.         [ni_dirObj addString:S_PRNT_DRIVER outlet:textPrinterDriver];
  678.         [ni_dirObj addString:S_PATH text:textSpoolDirectory
  679.                              button:buttonSetSpoolDir mode:NIPT_DIR path:NULL title: NULL];
  680.         [ni_dirObj addString:S_PRNT_COMM outlet:textUnixPrint];
  681.         [ni_dirObj addString:S_LPRM outlet:textUnixDelete];
  682.         [ni_dirObj addString:S_LPQ outlet:textUnixShowQueue];
  683.         [ni_dirObj addString:S_LPPAUSE outlet:textUnixPause];
  684.         [ni_dirObj addString:S_LPRESUME outlet:textUnixResume];
  685.  
  686.         return self;
  687. }
  688.  
  689.  
  690. - setupAndLoad
  691. {
  692. NXRect    bframe;
  693. id            nameProp;
  694.  
  695.         // Set the target and action of the page pop up list.
  696.         popupPages = [buttonPages target];
  697.         [popupPages setTarget:self];
  698.         [popupPages setAction:@selector(selectPage:)];
  699.         matrixPages = [popupPages itemList];
  700.  
  701.         // Set the users or group panel
  702.         panels = [Panels new];
  703.  
  704.         locked = NO;
  705.         
  706.         // Set the name field. If this was a +new, set the name for homes, 
  707.         // globals, and printers (serviceType > 0)
  708.         nameProp = [ni_dirObj addProperty:S_NAME];
  709.         if (![ni_dirObj domainName] && (serviceType > 0))
  710.             [nameProp insertValue:sectionNames[serviceType]];
  711.  
  712. #define setOrigin(n) [n getFrame:&bframe]; bframe.origin.x = 5.0; bframe.origin.y = 5.0; [n setFrame:&bframe]
  713.  
  714.         if (serviceType < 3) {
  715.  
  716.             boxes[0] = boxSAccess; setOrigin(boxSAccess);
  717.             boxes[1] = boxSVisMangle; setOrigin(boxSVisMangle);
  718.             boxes[2] = boxSPermLock; setOrigin(boxSPermLock);
  719.             boxes[3] = boxSPwSecLogExecStart; setOrigin(boxSPwSecLogExecStart);
  720.             [self setService];
  721.             
  722.             if (serviceType < 2) {
  723.                 boxes[8] = nil; [popupPages removeItemAt:9];
  724.                 boxes[7] = nil; [popupPages removeItemAt:8];
  725.                 boxes[6] = nil; [popupPages removeItemAt:7];
  726.                 boxes[5] = nil; [popupPages removeItemAt:6];
  727.                 boxes[4] = nil; [popupPages removeItemAt:5];
  728.             } else {
  729.                 // Put the box ids into a list:
  730.                 boxes[4] = boxGAccPwSecNM; setOrigin(boxGAccPwSecNM);
  731.                 boxes[5] = boxGLockLog; setOrigin(boxGLockLog);
  732.                 boxes[6] = boxGBinder; setOrigin(boxGBinder);
  733.                 boxes[7] = boxGStartup; setOrigin(boxGStartup);
  734.                 boxes[8] = boxGTunig; setOrigin(boxGTunig);
  735.                 [self setGlobService];
  736.             }
  737.  
  738.             [[boxChoices contentView] replaceSubview:lastPageID with:boxes[0]];
  739.             lastPageID = boxSAccess;
  740.             lastPage = 0;
  741.         } else {
  742.             setOrigin(boxPrinters);
  743.             [[window contentView] replaceSubview:boxChoices with:boxPrinters];
  744.             [self setPrinters];
  745.         }
  746.         
  747.         [ni_dirObj scan];
  748.         return self;
  749. }
  750.  
  751.  
  752. // ************************************************************************
  753. // Delegates:
  754. - (int)willSelect:sender what:(int)kind path:(char **)ni_path title:(char **)ni_panel_title state:(int *)mode
  755. {
  756.         if ((sender == propReadList) || (sender == propWriteList) ||
  757.                 (sender == propValidUsers) || (sender == propInvalidUsers) ||
  758.                 (sender == propUserNames)) {
  759.             if ((*mode = [panels userOrGroup]) == PS_NONE)
  760.                 return NIPT_NONE;
  761.             if (*mode == PS_GROUP) {
  762.                 *ni_path = SMNI_GROUPS;
  763.                 *ni_panel_title = (char *)groupTitle;
  764.             }
  765.         } else if ((sender == propAllowHosts) || (sender == propDenyHosts)) {
  766.             if ((*mode = [panels netgroupOrHost]) == PS_NONE)
  767.                 return NIPT_NONE;
  768.         }
  769.         return kind;
  770. }
  771.  
  772. - (int)didSelect:sender what:(int)kind value:(char **)selection domain:(const char *)niDomain state:(int)mode
  773. {
  774. ni_id                tempDir;
  775. ni_name            tempFullDir;
  776. ni_namelist    netgroupList;
  777. void                *tempHandle = NULL;
  778. NIDomain        *tempDomain;
  779. char                *p;
  780. int                    status;
  781.  
  782.         if (!*selection || !**selection)
  783.             return 0;
  784.     
  785.         if ((sender == propLogFile) || (sender == propMagicOutput)) {
  786.             if (!strrchr(*selection, '.')) {
  787.                 p = NXZoneRealloc([NXApp zone], *selection, strlen(*selection)+8);
  788.                 if (p[strlen(p)-1] != '/')
  789.                     (void)strcat(p,"/");
  790.                 if (sender == propMagicOutput)
  791.                     (void)strcat(p, "%U.out");
  792.                 else
  793.                     (void)strcat(p, "log.%m");
  794.                 *selection = p;
  795.             }
  796.         } else if ((sender == propReadList) || (sender == propWriteList) ||
  797.                              (sender == propValidUsers) || (sender == propInvalidUsers) ||
  798.                              (sender == propUserNames)) {
  799.             if (mode == PS_GROUP) {
  800.                 p = NXZoneRealloc([NXApp zone], *selection, strlen(*selection)+1);
  801.                 bcopy(p, p+1, strlen(p)+1);
  802.                 *p = '@';
  803.                 *selection = p;
  804.             }
  805.         } else if ((sender == propAllowHosts) || (sender == propDenyHosts)) {
  806.             if (mode == PS_GROUP) {
  807.                 // Present a browser with all possible choices.
  808.                 // Allocate and connect a NetInfo handle.
  809.                 tempDomain = [[NIDomain alloc] init];
  810.                 status = [tempDomain setConnection:niDomain readTimeout:5 writeTimeout:10 canAbort:YES mustWrite:NO];
  811.                 if (status == NI_OK) {
  812.                     tempHandle = [tempDomain getDomainHandle];
  813.                     if (tempHandle == NULL) {
  814.                         status = [tempDomain lastError];
  815.                     }
  816.                 }
  817.                 if (status == NI_OK) {
  818.                     tempFullDir = NXZoneMalloc([self zone], sizeof(char)*(strlen(SMNI_HOSTS)+strlen(*selection)+2));
  819.                     (void)strcpy(tempFullDir, SMNI_HOSTS);
  820.                     (void)strcat(tempFullDir, "/");
  821.                     (void)strcat(tempFullDir, *selection);
  822.                     // Locate the directory.
  823.                     status = ni_pathsearch(tempHandle, &tempDir, tempFullDir);
  824.                     ni_name_free(&tempFullDir);
  825.                     if (status == NI_OK)
  826.                         status = ni_lookupprop(tempHandle, &tempDir, SMNIP_NETGROUP, &netgroupList);
  827.                 }
  828.                 [tempDomain free];
  829.                 if (status != NI_OK) {
  830.                     ALERT_STATUS("Alert:NetInfo Error", "Message:Connecting to",
  831.                                              "Button:OK", NULL, NULL, niDomain, status);
  832.                     return -1;
  833.                 }
  834.                 if (netgroupList.ni_namelist_len <= 0) {
  835.                     status = NXRunAlertPanel(getString("Alert:Alert"),
  836.                                                             getString("Message:No Netgroups"),
  837.                                                             getString("Button:Try Again"),
  838.                                                             getString("Button:Cancel"), NULL);
  839.                     if (status ==  NX_ALERTALTERNATE)
  840.                         return -1;
  841.                     return 1;
  842.                 }
  843.                 p = (char *)[panels showNetgroups:&netgroupList];
  844.                 if (!p) {
  845.                     ni_namelist_free(&netgroupList);
  846.                     return -1;
  847.                 }
  848.                 
  849.                 // Prepend the '@'
  850.                 *selection = NXZoneRealloc([NXApp zone], *selection, strlen(p)+1);
  851.                 strcpy(*selection+1, p);
  852.                 **selection = '@';
  853.                 ni_namelist_free(&netgroupList);
  854.             }
  855.         }
  856.         return 0;
  857. }
  858.  
  859. - (BOOL)propertyWillChange:sender value:(char **)string default:(BOOL *)remove index:(int)anInt
  860. {
  861. char    *p = *string;
  862. int        alert = 0;
  863.  
  864.         if (*string && ((sender == propHideFiles) || (sender == propVetoFiles))) {
  865.             if (strchr(*string, '/')) {
  866.                 NXRunAlertPanel(getString("Alert:Alert"),
  867.                                                 getString("Message:No '/' in names allowed!"),
  868.                                                 getString("Button:OK"),
  869.                                                 NULL, NULL);
  870.                 return YES;
  871.             }
  872.         } else if (*string && (sender == propAnnounceVersion)) {
  873.             alert = 1;
  874.             if (atoi(*string) > 0) {
  875.                 if (p = strchr(*string, '.')) {
  876.                     if (atoi(p+1) > 0)
  877.                         alert = 0;
  878.                 }
  879.             }
  880.             if (alert) {
  881.                 NXRunAlertPanel(getString("Alert:Alert"),
  882.                                                 getString("Message:Illegal version number in Anounce Version"),
  883.                                                 getString("Button:OK"),
  884.                                                 NULL, NULL);
  885.                 return YES;
  886.             }
  887.         }
  888.         
  889.         return NO;
  890. }
  891.  
  892. - propertyDidChange:sender value:(const char *)string
  893. {
  894.         if (locked)
  895.             return self;
  896.         
  897.         [window setDocEdited:YES];
  898.          if (sender == propHideFiles) {
  899.             if (string)
  900.                 [propHideFilesSeparator updateValue:"/" at:0];
  901.             else
  902.                 [propHideFilesSeparator removeValues];
  903.         } else if (sender == propVetoFiles) {
  904.             if (string)
  905.                 [propVetoFilesSeparator updateValue:"/" at:0];
  906.             else
  907.                 [propVetoFilesSeparator removeValues];
  908.         }
  909.         return self;
  910. }
  911.  
  912. @end
  913.