Did more integration of Lukes code ready for the first release.
[kai/samba.git] / source3 / param / loadparm.c
1 /* 
2    Unix SMB/Netbios implementation.
3    Version 1.9.
4    Parameter loading functions
5    Copyright (C) Karl Auer 1993,1994
6
7    Largely re-written by Andrew Tridgell, September 1994
8    
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 2 of the License, or
12    (at your option) any later version.
13    
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18    
19    You should have received a copy of the GNU General Public License
20    along with this program; if not, write to the Free Software
21    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 */
23
24 /*
25  *  Load parameters.
26  *
27  *  This module provides suitable callback functions for the params
28  *  module. It builds the internal table of service details which is
29  *  then used by the rest of the server.
30  *
31  * To add a parameter:
32  *
33  * 1) add it to the global or service structure definition
34  * 2) add it to the parm_table
35  * 3) add it to the list of available functions (eg: using FN_GLOBAL_STRING())
36  * 4) If it's a global then initialise it in init_globals. If a local
37  *    (ie. service) parameter then initialise it in the sDefault structure
38  *  
39  *
40  * Notes:
41  *   The configuration file is processed sequentially for speed. It is NOT
42  *   accessed randomly as happens in 'real' Windows. For this reason, there
43  *   is a fair bit of sequence-dependent code here - ie., code which assumes
44  *   that certain things happen before others. In particular, the code which
45  *   happens at the boundary between sections is delicately poised, so be
46  *   careful!
47  *
48  */
49
50 #include "includes.h"
51
52 #include "params.h"
53 #include "loadparm.h"
54 #include "pcap.h"
55
56 BOOL bLoaded = False;
57
58 extern int DEBUGLEVEL;
59 extern int ReadSize;
60 extern pstring user_socket_options;
61
62 #ifndef GLOBAL_NAME
63 #define GLOBAL_NAME "global"
64 #endif
65
66 #ifndef PRINTCAP_NAME
67 #ifdef AIX
68 #define PRINTCAP_NAME "/etc/qconfig"
69 #else
70 #define PRINTCAP_NAME "/etc/printcap"
71 #endif
72 #endif
73
74 #ifndef PRINTERS_NAME
75 #define PRINTERS_NAME "printers"
76 #endif
77
78 #ifndef HOMES_NAME
79 #define HOMES_NAME "homes"
80 #endif
81
82 /* some helpful bits */
83 #define pSERVICE(i) ServicePtrs[i]
84 #define iSERVICE(i) (*pSERVICE(i))
85 #define LP_SNUM_OK(iService) (((iService) >= 0) && ((iService) < iNumServices) && iSERVICE(iService).valid)
86 #define VALID(i) iSERVICE(i).valid
87
88 /* these are the types of parameter we have */
89 typedef enum
90 {
91   P_BOOL,P_BOOLREV,P_CHAR,P_INTEGER,P_OCTAL,P_STRING,P_GSTRING
92 } parm_type;
93
94 typedef enum
95 {
96   P_LOCAL,P_GLOBAL,P_NONE
97 } parm_class;
98
99 int keepalive=0;
100 extern BOOL use_getwd_cache;
101
102 extern int extra_time_offset;
103 #ifdef KANJI
104 extern int coding_system;
105 #endif
106
107 /* 
108  * This structure describes global (ie., server-wide) parameters.
109  */
110 typedef struct
111 {
112    char *szPrintcapname;
113    char *szLockDir;
114    char *szRootdir;
115    char *szDefaultService;
116    char *szDfree;
117    char *szMsgCommand;
118    char *szHostsEquiv;
119    char *szServerString;
120    char *szAutoServices;
121    char *szPasswdProgram;
122    char *szPasswdChat;
123    char *szLogFile;
124    char *szConfigFile;
125    char *szSMBPasswdFile;
126    char *szPasswordServer;
127    char *szSocketOptions;
128    char *szValidChars;
129    char *szWorkGroup;
130    char *szDomainController;
131    char *szUsernameMap;
132    char *szCharacterSet;
133    char *szLogonScript;
134    char *szSmbrun;
135    char *szWINSserver;
136    int max_log_size;
137    int mangled_stack;
138    int max_xmit;
139    int max_mux;
140    int max_packet;
141    int pwordlevel;
142    int deadtime;
143    int maxprotocol;
144    int security;
145    int printing;
146    int maxdisksize;
147    int lpqcachetime;
148    int syslog;
149    int os_level;
150    int max_ttl;
151    BOOL bWINSsupport;
152    BOOL bWINSproxy;
153    BOOL bPreferredMaster;
154    BOOL bDomainMaster;
155    BOOL bDomainLogons;
156    BOOL bEncryptPasswords;
157    BOOL bStripDot;
158    BOOL bNullPasswords;
159    BOOL bLoadPrinters;
160    BOOL bUseRhosts;
161    BOOL bReadRaw;
162    BOOL bWriteRaw;
163    BOOL bReadPrediction;
164    BOOL bReadbmpx;
165    BOOL bSyslogOnly;
166    BOOL bBrowseList;
167 } global;
168
169 static global Globals;
170
171
172
173 /* 
174  * This structure describes a single service. 
175  */
176 typedef struct
177 {
178   BOOL valid;
179   char *szService;
180   char *szPath;
181   char *szUsername;
182   char *szGuestaccount;
183   char *szInvalidUsers;
184   char *szValidUsers;
185   char *szAdminUsers;
186   char *szCopy;
187   char *szInclude;
188   char *szPreExec;
189   char *szPostExec;
190   char *szRootPreExec;
191   char *szRootPostExec;
192   char *szPrintcommand;
193   char *szLpqcommand;
194   char *szLprmcommand;
195   char *szLppausecommand;
196   char *szLpresumecommand;
197   char *szPrintername;
198   char *szDontdescend;
199   char *szHostsallow;
200   char *szHostsdeny;
201   char *szMagicScript;
202   char *szMagicOutput;
203   char *szMangledMap;
204   char *comment;
205   char *force_user;
206   char *force_group;
207   char *readlist;
208   char *writelist;
209   char *volume;
210   int  iMinPrintSpace;
211   int  iCreate_mode;
212   int  iMaxConnections;
213   int  iDefaultCase;
214   BOOL bAlternatePerm;
215   BOOL bRevalidate;
216   BOOL bCaseSensitive;
217   BOOL bCasePreserve;
218   BOOL bShortCasePreserve;
219   BOOL bCaseMangle;
220   BOOL status;
221   BOOL bHideDotFiles;
222   BOOL bBrowseable;
223   BOOL bAvailable;
224   BOOL bRead_only;
225   BOOL bNo_set_dir;
226   BOOL bGuest_only;
227   BOOL bGuest_ok;
228   BOOL bPrint_ok;
229   BOOL bPostscript;
230   BOOL bMap_system;
231   BOOL bMap_hidden;
232   BOOL bMap_archive;
233   BOOL bLocking;
234   BOOL bStrictLocking;
235   BOOL bShareModes;
236   BOOL bOnlyUser;
237   BOOL bMangledNames;
238   BOOL bWidelinks;
239   BOOL bSyncAlways;
240   char magic_char;
241   BOOL *copymap;
242   BOOL bDeleteReadonly;
243   char dummy[3]; /* for alignment */
244 } service;
245
246
247 /* This is a default service used to prime a services structure */
248 static service sDefault = 
249 {
250   True,   /* valid */
251   NULL,    /* szService */
252   NULL,    /* szPath */
253   NULL,    /* szUsername */
254   NULL,    /* szGuestAccount */
255   NULL,    /* szInvalidUsers */
256   NULL,    /* szValidUsers */
257   NULL,    /* szAdminUsers */
258   NULL,    /* szCopy */
259   NULL,    /* szInclude */
260   NULL,    /* szPreExec */
261   NULL,    /* szPostExec */
262   NULL,    /* szRootPreExec */
263   NULL,    /* szRootPostExec */
264   NULL,    /* szPrintcommand */
265   NULL,    /* szLpqcommand */
266   NULL,    /* szLprmcommand */
267   NULL,    /* szLppausecommand */
268   NULL,    /* szLpresumecommand */
269   NULL,    /* szPrintername */
270   NULL,    /* szDontdescend */
271   NULL,    /* szHostsallow */
272   NULL,    /* szHostsdeny */
273   NULL,    /* szMagicScript */
274   NULL,    /* szMagicOutput */
275   NULL,    /* szMangledMap */
276   NULL,    /* comment */
277   NULL,    /* force user */
278   NULL,    /* force group */
279   NULL,    /* readlist */
280   NULL,    /* writelist */
281   NULL,    /* volume */
282   0,       /* iMinPrintSpace */
283   0755,    /* iCreate_mode */
284   0,       /* iMaxConnections */
285   CASE_LOWER, /* iDefaultCase */
286   False,   /* bAlternatePerm */
287   False,   /* revalidate */
288   False,   /* case sensitive */
289   False,   /* case preserve */
290   False,   /* short case preserve */
291   False,  /* case mangle */
292   True,  /* status */
293   True,  /* bHideDotFiles */
294   True,  /* bBrowseable */
295   True,  /* bAvailable */
296   True,  /* bRead_only */
297   True,  /* bNo_set_dir */
298   False, /* bGuest_only */
299   False, /* bGuest_ok */
300   False, /* bPrint_ok */
301   False, /* bPostscript */
302   False, /* bMap_system */
303   False, /* bMap_hidden */
304   True,  /* bMap_archive */
305   True,  /* bLocking */
306   False,  /* bStrictLocking */
307   True,  /* bShareModes */
308   False, /* bOnlyUser */
309   True,  /* bMangledNames */
310   True,  /* bWidelinks */
311   False, /* bSyncAlways */
312   '~',   /* magic char */
313   NULL,  /* copymap */
314   False, /* bDeleteReadonly */
315   ""     /* dummy */
316 };
317
318
319
320 /* local variables */
321 static service **ServicePtrs = NULL;
322 static int iNumServices = 0;
323 static int iServiceIndex = 0;
324 static BOOL bInGlobalSection = True;
325 static BOOL bGlobalOnly = False;
326
327
328 #define NUMPARAMETERS (sizeof(parm_table) / sizeof(struct parm_struct))
329
330 /* prototypes for the special type handlers */
331 static BOOL handle_valid_chars(char *pszParmValue, char **ptr);
332 static BOOL handle_include(char *pszParmValue, char **ptr);
333 static BOOL handle_copy(char *pszParmValue, char **ptr);
334 static BOOL handle_protocol(char *pszParmValue,int *val);
335 static BOOL handle_security(char *pszParmValue,int *val);
336 static BOOL handle_case(char *pszParmValue,int *val);
337 static BOOL handle_printing(char *pszParmValue,int *val);
338 static BOOL handle_character_set(char *pszParmValue,int *val);
339 #ifdef KANJI
340 static BOOL handle_coding_system(char *pszParmValue,int *val);
341 #endif /* KANJI */
342
343 struct parm_struct
344 {
345   char *label;
346   parm_type type;
347   parm_class class;
348   void *ptr;
349   BOOL (*special)();
350 } parm_table[] =
351 {
352   {"debuglevel",       P_INTEGER, P_GLOBAL, &DEBUGLEVEL,                NULL},
353   {"log level",        P_INTEGER, P_GLOBAL, &DEBUGLEVEL,                NULL},
354   {"syslog",           P_INTEGER, P_GLOBAL, &Globals.syslog,            NULL},
355   {"syslog only",      P_BOOL,    P_GLOBAL, &Globals.bSyslogOnly,       NULL},
356   {"protocol",         P_INTEGER, P_GLOBAL, &Globals.maxprotocol,handle_protocol},
357   {"security",         P_INTEGER, P_GLOBAL, &Globals.security,handle_security},
358   {"printing",         P_INTEGER, P_GLOBAL, &Globals.printing,handle_printing},
359   {"max disk size",    P_INTEGER, P_GLOBAL, &Globals.maxdisksize,       NULL},
360   {"lpq cache time",   P_INTEGER, P_GLOBAL, &Globals.lpqcachetime,      NULL},
361   {"encrypt passwords",P_BOOL,    P_GLOBAL, &Globals.bEncryptPasswords, NULL},
362   {"getwd cache",      P_BOOL,    P_GLOBAL, &use_getwd_cache,           NULL},
363   {"read prediction",  P_BOOL,    P_GLOBAL, &Globals.bReadPrediction,   NULL},
364   {"read bmpx",        P_BOOL,    P_GLOBAL, &Globals.bReadbmpx,         NULL},
365   {"read raw",         P_BOOL,    P_GLOBAL, &Globals.bReadRaw,          NULL},
366   {"write raw",        P_BOOL,    P_GLOBAL, &Globals.bWriteRaw,         NULL},
367   {"use rhosts",       P_BOOL,    P_GLOBAL, &Globals.bUseRhosts,        NULL},
368   {"load printers",    P_BOOL,    P_GLOBAL, &Globals.bLoadPrinters,     NULL},
369   {"null passwords",   P_BOOL,    P_GLOBAL, &Globals.bNullPasswords,    NULL},
370   {"strip dot",        P_BOOL,    P_GLOBAL, &Globals.bStripDot,         NULL},
371   {"password server",  P_STRING,  P_GLOBAL, &Globals.szPasswordServer,  NULL},
372   {"socket options",   P_GSTRING, P_GLOBAL, user_socket_options,        NULL},
373   {"smbrun",           P_STRING,  P_GLOBAL, &Globals.szSmbrun,          NULL},
374   {"log file",         P_STRING,  P_GLOBAL, &Globals.szLogFile,         NULL},
375   {"config file",      P_STRING,  P_GLOBAL, &Globals.szConfigFile,      NULL},
376   {"smb passwd file",  P_STRING,  P_GLOBAL, &Globals.szSMBPasswdFile,   NULL},
377   {"hosts equiv",      P_STRING,  P_GLOBAL, &Globals.szHostsEquiv,      NULL},
378   {"preload",          P_STRING,  P_GLOBAL, &Globals.szAutoServices,    NULL},
379   {"auto services",    P_STRING,  P_GLOBAL, &Globals.szAutoServices,    NULL},
380   {"server string",    P_STRING,  P_GLOBAL, &Globals.szServerString,    NULL},
381   {"printcap name",    P_STRING,  P_GLOBAL, &Globals.szPrintcapname,    NULL},
382   {"printcap",         P_STRING,  P_GLOBAL, &Globals.szPrintcapname,    NULL},
383   {"lock dir",         P_STRING,  P_GLOBAL, &Globals.szLockDir,         NULL},
384   {"lock directory",   P_STRING,  P_GLOBAL, &Globals.szLockDir,         NULL},
385   {"root directory",   P_STRING,  P_GLOBAL, &Globals.szRootdir,         NULL},
386   {"root dir",         P_STRING,  P_GLOBAL, &Globals.szRootdir,         NULL},
387   {"root",             P_STRING,  P_GLOBAL, &Globals.szRootdir,         NULL},
388   {"default service",  P_STRING,  P_GLOBAL, &Globals.szDefaultService,  NULL},
389   {"default",          P_STRING,  P_GLOBAL, &Globals.szDefaultService,  NULL},
390   {"message command",  P_STRING,  P_GLOBAL, &Globals.szMsgCommand,      NULL},
391   {"dfree command",    P_STRING,  P_GLOBAL, &Globals.szDfree,           NULL},
392   {"passwd program",   P_STRING,  P_GLOBAL, &Globals.szPasswdProgram,   NULL},
393   {"passwd chat",      P_STRING,  P_GLOBAL, &Globals.szPasswdChat,      NULL},
394   {"valid chars",      P_STRING,  P_GLOBAL, &Globals.szValidChars,      handle_valid_chars},
395   {"workgroup",        P_STRING,  P_GLOBAL, &Globals.szWorkGroup,       NULL},
396   {"domain controller",P_STRING,  P_GLOBAL, &Globals.szDomainController,NULL},
397   {"username map",     P_STRING,  P_GLOBAL, &Globals.szUsernameMap,     NULL},
398   {"character set",    P_STRING,  P_GLOBAL, &Globals.szCharacterSet,    handle_character_set},
399   {"logon script",     P_STRING,  P_GLOBAL, &Globals.szLogonScript,     NULL},
400   {"max log size",     P_INTEGER, P_GLOBAL, &Globals.max_log_size,      NULL},
401   {"mangled stack",    P_INTEGER, P_GLOBAL, &Globals.mangled_stack,     NULL},
402   {"max mux",          P_INTEGER, P_GLOBAL, &Globals.max_mux,           NULL},
403   {"max xmit",         P_INTEGER, P_GLOBAL, &Globals.max_xmit,          NULL},
404   {"max packet",       P_INTEGER, P_GLOBAL, &Globals.max_packet,        NULL},
405   {"packet size",      P_INTEGER, P_GLOBAL, &Globals.max_packet,        NULL},
406   {"password level",   P_INTEGER, P_GLOBAL, &Globals.pwordlevel,        NULL},
407   {"keepalive",        P_INTEGER, P_GLOBAL, &keepalive,                 NULL},
408   {"deadtime",         P_INTEGER, P_GLOBAL, &Globals.deadtime,          NULL},
409   {"time offset",      P_INTEGER, P_GLOBAL, &extra_time_offset,         NULL},
410   {"read size",        P_INTEGER, P_GLOBAL, &ReadSize,                  NULL},
411 #ifdef KANJI
412   {"coding system",    P_INTEGER, P_GLOBAL, &coding_system, handle_coding_system},
413 #endif /* KANJI */
414   {"os level",         P_INTEGER, P_GLOBAL, &Globals.os_level,          NULL},
415   {"max ttl",          P_INTEGER, P_GLOBAL, &Globals.max_ttl,           NULL},
416   {"wins support",     P_BOOL,    P_GLOBAL, &Globals.bWINSsupport,      NULL},
417   {"wins proxy",       P_BOOL,    P_GLOBAL, &Globals.bWINSproxy,        NULL},
418   {"wins server",      P_STRING,  P_GLOBAL, &Globals.szWINSserver,      NULL},
419   {"preferred master", P_BOOL,    P_GLOBAL, &Globals.bPreferredMaster,  NULL},
420   {"prefered master",  P_BOOL,    P_GLOBAL, &Globals.bPreferredMaster,  NULL},
421   {"domain master",    P_BOOL,    P_GLOBAL, &Globals.bDomainMaster,     NULL},
422   {"domain logons",    P_BOOL,    P_GLOBAL, &Globals.bDomainLogons,     NULL},
423   {"browse list",      P_BOOL,    P_GLOBAL, &Globals.bBrowseList,       NULL},
424
425   {"-valid",           P_BOOL,    P_LOCAL,  &sDefault.valid,            NULL},
426   {"comment",          P_STRING,  P_LOCAL,  &sDefault.comment,          NULL},
427   {"copy",             P_STRING,  P_LOCAL,  &sDefault.szCopy,    handle_copy},
428   {"include",          P_STRING,  P_LOCAL,  &sDefault.szInclude, handle_include},
429   {"exec",             P_STRING,  P_LOCAL,  &sDefault.szPreExec,        NULL},
430   {"preexec",          P_STRING,  P_LOCAL,  &sDefault.szPreExec,        NULL},
431   {"postexec",         P_STRING,  P_LOCAL,  &sDefault.szPostExec,       NULL},
432   {"root preexec",     P_STRING,  P_LOCAL,  &sDefault.szRootPreExec,    NULL},
433   {"root postexec",    P_STRING,  P_LOCAL,  &sDefault.szRootPostExec,   NULL},
434   {"alternate permissions",P_BOOL,P_LOCAL,  &sDefault.bAlternatePerm,   NULL},
435   {"revalidate",       P_BOOL,    P_LOCAL,  &sDefault.bRevalidate,      NULL},
436   {"default case",     P_INTEGER, P_LOCAL,  &sDefault.iDefaultCase,   handle_case},
437   {"case sensitive",   P_BOOL,    P_LOCAL,  &sDefault.bCaseSensitive,   NULL},
438   {"casesignames",     P_BOOL,    P_LOCAL,  &sDefault.bCaseSensitive,   NULL},
439   {"preserve case",    P_BOOL,    P_LOCAL,  &sDefault.bCasePreserve,    NULL},
440   {"short preserve case",P_BOOL,  P_LOCAL,  &sDefault.bShortCasePreserve,NULL},
441   {"mangle case",      P_BOOL,    P_LOCAL,  &sDefault.bCaseMangle,      NULL},
442   {"mangling char",    P_CHAR,    P_LOCAL,  &sDefault.magic_char,       NULL},
443   {"browseable",       P_BOOL,    P_LOCAL,  &sDefault.bBrowseable,      NULL},
444   {"browsable",        P_BOOL,    P_LOCAL,  &sDefault.bBrowseable,      NULL},
445   {"available",        P_BOOL,    P_LOCAL,  &sDefault.bAvailable,       NULL},
446   {"path",             P_STRING,  P_LOCAL,  &sDefault.szPath,           NULL},
447   {"directory",        P_STRING,  P_LOCAL,  &sDefault.szPath,           NULL},
448   {"username",         P_STRING,  P_LOCAL,  &sDefault.szUsername,       NULL},
449   {"user",             P_STRING,  P_LOCAL,  &sDefault.szUsername,       NULL},
450   {"users",            P_STRING,  P_LOCAL,  &sDefault.szUsername,       NULL},
451   {"guest account",    P_STRING,  P_LOCAL,  &sDefault.szGuestaccount,   NULL},
452   {"invalid users",    P_STRING,  P_LOCAL,  &sDefault.szInvalidUsers,   NULL},
453   {"valid users",      P_STRING,  P_LOCAL,  &sDefault.szValidUsers,     NULL},
454   {"admin users",      P_STRING,  P_LOCAL,  &sDefault.szAdminUsers,     NULL},
455   {"read list",        P_STRING,  P_LOCAL,  &sDefault.readlist,         NULL},
456   {"write list",       P_STRING,  P_LOCAL,  &sDefault.writelist,        NULL},
457   {"volume",           P_STRING,  P_LOCAL,  &sDefault.volume,           NULL},
458   {"force user",       P_STRING,  P_LOCAL,  &sDefault.force_user,       NULL},
459   {"force group",      P_STRING,  P_LOCAL,  &sDefault.force_group,      NULL},
460   {"group",            P_STRING,  P_LOCAL,  &sDefault.force_group,      NULL},
461   {"read only",        P_BOOL,    P_LOCAL,  &sDefault.bRead_only,       NULL},
462   {"write ok",         P_BOOLREV, P_LOCAL,  &sDefault.bRead_only,       NULL},
463   {"writeable",        P_BOOLREV, P_LOCAL,  &sDefault.bRead_only,       NULL},
464   {"writable",         P_BOOLREV, P_LOCAL,  &sDefault.bRead_only,       NULL},
465   {"max connections",  P_INTEGER, P_LOCAL,  &sDefault.iMaxConnections,  NULL},
466   {"min print space",  P_INTEGER, P_LOCAL,  &sDefault.iMinPrintSpace,   NULL},
467   {"create mask",      P_OCTAL,   P_LOCAL,  &sDefault.iCreate_mode,     NULL},
468   {"create mode",      P_OCTAL,   P_LOCAL,  &sDefault.iCreate_mode,     NULL},
469   {"set directory",    P_BOOLREV, P_LOCAL,  &sDefault.bNo_set_dir,      NULL},
470   {"status",           P_BOOL,    P_LOCAL,  &sDefault.status,           NULL},
471   {"hide dot files",   P_BOOL,    P_LOCAL,  &sDefault.bHideDotFiles,    NULL},
472   {"guest only",       P_BOOL,    P_LOCAL,  &sDefault.bGuest_only,      NULL},
473   {"only guest",       P_BOOL,    P_LOCAL,  &sDefault.bGuest_only,      NULL},
474   {"guest ok",         P_BOOL,    P_LOCAL,  &sDefault.bGuest_ok,        NULL},
475   {"public",           P_BOOL,    P_LOCAL,  &sDefault.bGuest_ok,        NULL},
476   {"print ok",         P_BOOL,    P_LOCAL,  &sDefault.bPrint_ok,        NULL},
477   {"printable",        P_BOOL,    P_LOCAL,  &sDefault.bPrint_ok,        NULL},
478   {"postscript",       P_BOOL,    P_LOCAL,  &sDefault.bPostscript,      NULL},
479   {"map system",       P_BOOL,    P_LOCAL,  &sDefault.bMap_system,      NULL},
480   {"map hidden",       P_BOOL,    P_LOCAL,  &sDefault.bMap_hidden,      NULL},
481   {"map archive",      P_BOOL,    P_LOCAL,  &sDefault.bMap_archive,     NULL},
482   {"locking",          P_BOOL,    P_LOCAL,  &sDefault.bLocking,         NULL},
483   {"strict locking",   P_BOOL,    P_LOCAL,  &sDefault.bStrictLocking,   NULL},
484   {"share modes",      P_BOOL,    P_LOCAL,  &sDefault.bShareModes,      NULL},
485   {"only user",        P_BOOL,    P_LOCAL,  &sDefault.bOnlyUser,        NULL},
486   {"wide links",       P_BOOL,    P_LOCAL,  &sDefault.bWidelinks,       NULL},
487   {"sync always",      P_BOOL,    P_LOCAL,  &sDefault.bSyncAlways,      NULL},
488   {"mangled names",    P_BOOL,    P_LOCAL,  &sDefault.bMangledNames,    NULL},
489   {"print command",    P_STRING,  P_LOCAL,  &sDefault.szPrintcommand,   NULL},
490   {"lpq command",      P_STRING,  P_LOCAL,  &sDefault.szLpqcommand,     NULL},
491   {"lprm command",     P_STRING,  P_LOCAL,  &sDefault.szLprmcommand,    NULL},
492   {"lppause command",  P_STRING,  P_LOCAL,  &sDefault.szLppausecommand, NULL},
493   {"lpresume command", P_STRING,  P_LOCAL,  &sDefault.szLpresumecommand,NULL},
494   {"printer",          P_STRING,  P_LOCAL,  &sDefault.szPrintername,    NULL},
495   {"printer name",     P_STRING,  P_LOCAL,  &sDefault.szPrintername,    NULL},
496   {"hosts allow",      P_STRING,  P_LOCAL,  &sDefault.szHostsallow,     NULL},
497   {"allow hosts",      P_STRING,  P_LOCAL,  &sDefault.szHostsallow,     NULL},
498   {"hosts deny",       P_STRING,  P_LOCAL,  &sDefault.szHostsdeny,      NULL},
499   {"deny hosts",       P_STRING,  P_LOCAL,  &sDefault.szHostsdeny,      NULL},
500   {"dont descend",     P_STRING,  P_LOCAL,  &sDefault.szDontdescend,    NULL},
501   {"magic script",     P_STRING,  P_LOCAL,  &sDefault.szMagicScript,    NULL},
502   {"magic output",     P_STRING,  P_LOCAL,  &sDefault.szMagicOutput,    NULL},
503   {"mangled map",      P_STRING,  P_LOCAL,  &sDefault.szMangledMap,     NULL},
504   {"delete readonly",  P_BOOL,    P_LOCAL,  &sDefault.bDeleteReadonly,  NULL},
505
506   {NULL,               P_BOOL,    P_NONE,   NULL,                       NULL}
507 };
508
509
510
511 /***************************************************************************
512 Initialise the global parameter structure.
513 ***************************************************************************/
514 static void init_globals(void)
515 {
516   static BOOL done_init = False;
517   pstring s;
518
519   if (!done_init)
520     {
521       int i;
522       bzero((void *)&Globals,sizeof(Globals));
523
524       for (i = 0; parm_table[i].label; i++) 
525         if (parm_table[i].type == P_STRING && 
526             parm_table[i].ptr)
527           string_init(parm_table[i].ptr,"");
528
529       string_set(&sDefault.szGuestaccount, GUEST_ACCOUNT);
530
531       done_init = True;
532     }
533
534
535   DEBUG(3,("Initialising global parameters\n"));
536
537 #ifdef SMB_PASSWD_FILE
538   string_set(&Globals.szSMBPasswdFile, SMB_PASSWD_FILE);
539 #endif
540   string_set(&Globals.szPasswdChat,"*old*password* %o\\n *new*password* %n\\n *new*password* %n\\n *changed*");
541   string_set(&Globals.szWorkGroup, WORKGROUP);
542 #ifdef SMB_PASSWD
543   string_set(&Globals.szPasswdProgram, SMB_PASSWD);
544 #else
545   string_set(&Globals.szPasswdProgram, "/bin/passwd");
546 #endif
547   string_set(&Globals.szPrintcapname, PRINTCAP_NAME);
548   string_set(&Globals.szLockDir, LOCKDIR);
549   string_set(&Globals.szRootdir, "/");
550   string_set(&Globals.szSmbrun, SMBRUN);
551   sprintf(s,"Samba %s",VERSION);
552   string_set(&Globals.szServerString,s);
553   Globals.bLoadPrinters = True;
554   Globals.bUseRhosts = False;
555   Globals.max_packet = 65535;
556   Globals.mangled_stack = 50;
557   Globals.max_xmit = Globals.max_packet;
558   Globals.max_mux = 2;
559   Globals.lpqcachetime = 10;
560   Globals.pwordlevel = 0;
561   Globals.deadtime = 0;
562   Globals.max_log_size = 5000;
563   Globals.maxprotocol = PROTOCOL_NT1;
564   Globals.security = SEC_SHARE;
565   Globals.bEncryptPasswords = False;
566   Globals.printing = DEFAULT_PRINTING;
567   Globals.bReadRaw = True;
568   Globals.bWriteRaw = True;
569   Globals.bReadPrediction = False;
570   Globals.bReadbmpx = True;
571   Globals.bNullPasswords = False;
572   Globals.bStripDot = False;
573   Globals.syslog = 1;
574   Globals.bSyslogOnly = False;
575   Globals.os_level = 0;
576   Globals.max_ttl = 60*60*4; /* 2 hours default */
577   Globals.bPreferredMaster = True;
578   Globals.bDomainMaster = False;
579   Globals.bDomainLogons = False;
580   Globals.bBrowseList = True;
581   Globals.bWINSsupport = True;
582   Globals.bWINSproxy = False;
583
584 #ifdef KANJI
585   coding_system = interpret_coding_system (KANJI, SJIS_CODE);
586 #endif /* KANJI */
587
588 }
589
590 /***************************************************************************
591 check if a string is initialised and if not then initialise it
592 ***************************************************************************/
593 static void string_initial(char **s,char *v)
594 {
595   if (!*s || !**s)
596     string_init(s,v);
597 }
598
599
600 /***************************************************************************
601 Initialise the sDefault parameter structure.
602 ***************************************************************************/
603 static void init_locals(void)
604 {
605   /* choose defaults depending on the type of printing */
606   switch (Globals.printing)
607     {
608     case PRINT_BSD:
609     case PRINT_AIX:
610     case PRINT_PLP:
611       string_initial(&sDefault.szLpqcommand,"lpq -P%p");
612       string_initial(&sDefault.szLprmcommand,"lprm -P%p %j");
613       string_initial(&sDefault.szPrintcommand,"lpr -r -P%p %s");
614       break;
615
616     case PRINT_SYSV:
617     case PRINT_HPUX:
618       string_initial(&sDefault.szLpqcommand,"lpstat -o%p");
619       string_initial(&sDefault.szLprmcommand,"cancel %p-%j");
620       string_initial(&sDefault.szPrintcommand,"lp -c -d%p %s; rm %s");
621 #ifdef SVR4
622       string_initial(&sDefault.szLppausecommand,"lp -i %p-%j -H hold");
623       string_initial(&sDefault.szLpresumecommand,"lp -i %p-%j -H resume");
624 #endif
625       break;
626
627     case PRINT_QNX:
628       string_initial(&sDefault.szLpqcommand,"lpq -P%p");
629       string_initial(&sDefault.szLprmcommand,"lprm -P%p %j");
630       string_initial(&sDefault.szPrintcommand,"lp -r -P%p %s");
631       break;
632
633       
634     }
635 }
636
637
638 /*******************************************************************
639 a convenience rooutine to grab string parameters into a rotating
640 static buffer, and run standard_sub_basic on them. The buffers
641 can be written to by callers
642 ********************************************************************/
643 char *lp_string(char *s)
644 {
645   static pstring bufs[10];
646   static int next=0;
647   char *ret;
648   
649   ret = &bufs[next][0];
650   next = (next+1)%10;
651
652   if (!s) 
653     *ret = 0;
654   else
655     StrnCpy(ret,s,sizeof(pstring)-1);
656
657   standard_sub_basic(ret);
658   return(ret);
659 }
660
661
662 /*
663    In this section all the functions that are used to access the 
664    parameters from the rest of the program are defined 
665 */
666
667 #define FN_GLOBAL_STRING(fn_name,ptr) \
668  char *fn_name(void) {return(lp_string(*(char **)(ptr) ? *(char **)(ptr) : ""));}
669 #define FN_GLOBAL_BOOL(fn_name,ptr) \
670  BOOL fn_name(void) {return(*(BOOL *)(ptr));}
671 #define FN_GLOBAL_CHAR(fn_name,ptr) \
672  char fn_name(void) {return(*(char *)(ptr));}
673 #define FN_GLOBAL_INTEGER(fn_name,ptr) \
674  int fn_name(void) {return(*(int *)(ptr));}
675
676 #define FN_LOCAL_STRING(fn_name,val) \
677  char *fn_name(int i) {return(lp_string((LP_SNUM_OK(i)&&pSERVICE(i)->val)?pSERVICE(i)->val : sDefault.val));}
678 #define FN_LOCAL_BOOL(fn_name,val) \
679  BOOL fn_name(int i) {return(LP_SNUM_OK(i)? pSERVICE(i)->val : sDefault.val);}
680 #define FN_LOCAL_CHAR(fn_name,val) \
681  char fn_name(int i) {return(LP_SNUM_OK(i)? pSERVICE(i)->val : sDefault.val);}
682 #define FN_LOCAL_INTEGER(fn_name,val) \
683  int fn_name(int i) {return(LP_SNUM_OK(i)? pSERVICE(i)->val : sDefault.val);}
684
685 FN_GLOBAL_STRING(lp_logfile,&Globals.szLogFile)
686 FN_GLOBAL_STRING(lp_smbrun,&Globals.szSmbrun)
687 FN_GLOBAL_STRING(lp_configfile,&Globals.szConfigFile)
688 FN_GLOBAL_STRING(lp_smb_passwd_file,&Globals.szSMBPasswdFile)
689 FN_GLOBAL_STRING(lp_serverstring,&Globals.szServerString)
690 FN_GLOBAL_STRING(lp_printcapname,&Globals.szPrintcapname)
691 FN_GLOBAL_STRING(lp_lockdir,&Globals.szLockDir)
692 FN_GLOBAL_STRING(lp_rootdir,&Globals.szRootdir)
693 FN_GLOBAL_STRING(lp_defaultservice,&Globals.szDefaultService)
694 FN_GLOBAL_STRING(lp_msg_command,&Globals.szMsgCommand)
695 FN_GLOBAL_STRING(lp_dfree_command,&Globals.szDfree)
696 FN_GLOBAL_STRING(lp_hosts_equiv,&Globals.szHostsEquiv)
697 FN_GLOBAL_STRING(lp_auto_services,&Globals.szAutoServices)
698 FN_GLOBAL_STRING(lp_passwd_program,&Globals.szPasswdProgram)
699 FN_GLOBAL_STRING(lp_passwd_chat,&Globals.szPasswdChat)
700 FN_GLOBAL_STRING(lp_passwordserver,&Globals.szPasswordServer)
701 FN_GLOBAL_STRING(lp_workgroup,&Globals.szWorkGroup)
702 FN_GLOBAL_STRING(lp_domain_controller,&Globals.szDomainController)
703 FN_GLOBAL_STRING(lp_username_map,&Globals.szUsernameMap)
704 FN_GLOBAL_STRING(lp_character_set,&Globals.szCharacterSet) 
705 FN_GLOBAL_STRING(lp_logon_script,&Globals.szLogonScript) 
706 FN_GLOBAL_STRING(lp_wins_server,&Globals.szWINSserver)
707
708 FN_GLOBAL_BOOL(lp_wins_support,&Globals.bWINSsupport)
709 FN_GLOBAL_BOOL(lp_wins_proxy,&Globals.bWINSproxy)
710 FN_GLOBAL_BOOL(lp_domain_master,&Globals.bDomainMaster)
711 FN_GLOBAL_BOOL(lp_domain_logons,&Globals.bDomainLogons)
712 FN_GLOBAL_BOOL(lp_preferred_master,&Globals.bPreferredMaster)
713 FN_GLOBAL_BOOL(lp_load_printers,&Globals.bLoadPrinters)
714 FN_GLOBAL_BOOL(lp_use_rhosts,&Globals.bUseRhosts)
715 FN_GLOBAL_BOOL(lp_getwdcache,&use_getwd_cache)
716 FN_GLOBAL_BOOL(lp_readprediction,&Globals.bReadPrediction)
717 FN_GLOBAL_BOOL(lp_readbmpx,&Globals.bReadbmpx)
718 FN_GLOBAL_BOOL(lp_readraw,&Globals.bReadRaw)
719 FN_GLOBAL_BOOL(lp_writeraw,&Globals.bWriteRaw)
720 FN_GLOBAL_BOOL(lp_null_passwords,&Globals.bNullPasswords)
721 FN_GLOBAL_BOOL(lp_strip_dot,&Globals.bStripDot)
722 FN_GLOBAL_BOOL(lp_encrypted_passwords,&Globals.bEncryptPasswords)
723 FN_GLOBAL_BOOL(lp_syslog_only,&Globals.bSyslogOnly)
724 FN_GLOBAL_BOOL(lp_browse_list,&Globals.bBrowseList)
725
726 FN_GLOBAL_INTEGER(lp_os_level,&Globals.os_level)
727 FN_GLOBAL_INTEGER(lp_max_ttl,&Globals.max_ttl)
728 FN_GLOBAL_INTEGER(lp_max_log_size,&Globals.max_log_size)
729 FN_GLOBAL_INTEGER(lp_mangledstack,&Globals.mangled_stack)
730 FN_GLOBAL_INTEGER(lp_maxxmit,&Globals.max_xmit)
731 FN_GLOBAL_INTEGER(lp_maxmux,&Globals.max_mux)
732 FN_GLOBAL_INTEGER(lp_maxpacket,&Globals.max_packet)
733 FN_GLOBAL_INTEGER(lp_keepalive,&keepalive)
734 FN_GLOBAL_INTEGER(lp_passwordlevel,&Globals.pwordlevel)
735 FN_GLOBAL_INTEGER(lp_deadtime,&Globals.deadtime)
736 FN_GLOBAL_INTEGER(lp_maxprotocol,&Globals.maxprotocol)
737 FN_GLOBAL_INTEGER(lp_security,&Globals.security)
738 FN_GLOBAL_INTEGER(lp_printing,&Globals.printing)
739 FN_GLOBAL_INTEGER(lp_maxdisksize,&Globals.maxdisksize)
740 FN_GLOBAL_INTEGER(lp_lpqcachetime,&Globals.lpqcachetime)
741 FN_GLOBAL_INTEGER(lp_syslog,&Globals.syslog)
742
743 FN_LOCAL_STRING(lp_preexec,szPreExec)
744 FN_LOCAL_STRING(lp_postexec,szPostExec)
745 FN_LOCAL_STRING(lp_rootpreexec,szRootPreExec)
746 FN_LOCAL_STRING(lp_rootpostexec,szRootPostExec)
747 FN_LOCAL_STRING(lp_servicename,szService)
748 FN_LOCAL_STRING(lp_pathname,szPath)
749 FN_LOCAL_STRING(lp_dontdescend,szDontdescend)
750 FN_LOCAL_STRING(lp_username,szUsername)
751 FN_LOCAL_STRING(lp_guestaccount,szGuestaccount)
752 FN_LOCAL_STRING(lp_invalid_users,szInvalidUsers)
753 FN_LOCAL_STRING(lp_valid_users,szValidUsers)
754 FN_LOCAL_STRING(lp_admin_users,szAdminUsers)
755 FN_LOCAL_STRING(lp_printcommand,szPrintcommand)
756 FN_LOCAL_STRING(lp_lpqcommand,szLpqcommand)
757 FN_LOCAL_STRING(lp_lprmcommand,szLprmcommand)
758 FN_LOCAL_STRING(lp_lppausecommand,szLppausecommand)
759 FN_LOCAL_STRING(lp_lpresumecommand,szLpresumecommand)
760 FN_LOCAL_STRING(lp_printername,szPrintername)
761 FN_LOCAL_STRING(lp_hostsallow,szHostsallow)
762 FN_LOCAL_STRING(lp_hostsdeny,szHostsdeny)
763 FN_LOCAL_STRING(lp_magicscript,szMagicScript)
764 FN_LOCAL_STRING(lp_magicoutput,szMagicOutput)
765 FN_LOCAL_STRING(lp_comment,comment)
766 FN_LOCAL_STRING(lp_force_user,force_user)
767 FN_LOCAL_STRING(lp_force_group,force_group)
768 FN_LOCAL_STRING(lp_readlist,readlist)
769 FN_LOCAL_STRING(lp_writelist,writelist)
770 FN_LOCAL_STRING(lp_volume,volume)
771 FN_LOCAL_STRING(lp_mangled_map,szMangledMap)
772
773 FN_LOCAL_BOOL(lp_alternate_permissions,bAlternatePerm)
774 FN_LOCAL_BOOL(lp_revalidate,bRevalidate)
775 FN_LOCAL_BOOL(lp_casesensitive,bCaseSensitive)
776 FN_LOCAL_BOOL(lp_preservecase,bCasePreserve)
777 FN_LOCAL_BOOL(lp_shortpreservecase,bShortCasePreserve)
778 FN_LOCAL_BOOL(lp_casemangle,bCaseMangle)
779 FN_LOCAL_BOOL(lp_status,status)
780 FN_LOCAL_BOOL(lp_hide_dot_files,bHideDotFiles)
781 FN_LOCAL_BOOL(lp_browseable,bBrowseable)
782 FN_LOCAL_BOOL(lp_readonly,bRead_only)
783 FN_LOCAL_BOOL(lp_no_set_dir,bNo_set_dir)
784 FN_LOCAL_BOOL(lp_guest_ok,bGuest_ok)
785 FN_LOCAL_BOOL(lp_guest_only,bGuest_only)
786 FN_LOCAL_BOOL(lp_print_ok,bPrint_ok)
787 FN_LOCAL_BOOL(lp_postscript,bPostscript)
788 FN_LOCAL_BOOL(lp_map_hidden,bMap_hidden)
789 FN_LOCAL_BOOL(lp_map_archive,bMap_archive)
790 FN_LOCAL_BOOL(lp_locking,bLocking)
791 FN_LOCAL_BOOL(lp_strict_locking,bStrictLocking)
792 FN_LOCAL_BOOL(lp_share_modes,bShareModes)
793 FN_LOCAL_BOOL(lp_onlyuser,bOnlyUser)
794 FN_LOCAL_BOOL(lp_manglednames,bMangledNames)
795 FN_LOCAL_BOOL(lp_widelinks,bWidelinks)
796 FN_LOCAL_BOOL(lp_syncalways,bSyncAlways)
797 FN_LOCAL_BOOL(lp_map_system,bMap_system)
798 FN_LOCAL_BOOL(lp_delete_readonly,bDeleteReadonly)
799
800 FN_LOCAL_INTEGER(lp_create_mode,iCreate_mode)
801 FN_LOCAL_INTEGER(lp_max_connections,iMaxConnections)
802 FN_LOCAL_INTEGER(lp_defaultcase,iDefaultCase)
803 FN_LOCAL_INTEGER(lp_minprintspace,iMinPrintSpace)
804
805 FN_LOCAL_CHAR(lp_magicchar,magic_char)
806
807
808
809 /* local prototypes */
810 static int    strwicmp( char *psz1, char *psz2 );
811 static int    map_parameter( char *pszParmName);
812 static BOOL   set_boolean( BOOL *pb, char *pszParmValue );
813 static int    getservicebyname(char *pszServiceName, service *pserviceDest);
814 static void   copy_service( service *pserviceDest, 
815                             service *pserviceSource,
816                             BOOL *pcopymapDest );
817 static BOOL   service_ok(int iService);
818 static BOOL   do_parameter(char *pszParmName, char *pszParmValue);
819 static BOOL   do_section(char *pszSectionName);
820 static void   dump_globals(void);
821 static void   dump_a_service(service *pService);
822 static void init_copymap(service *pservice);
823
824
825 /***************************************************************************
826 initialise a service to the defaults
827 ***************************************************************************/
828 static void init_service(service *pservice)
829 {
830   bzero((char *)pservice,sizeof(service));
831   copy_service(pservice,&sDefault,NULL);
832 }
833
834
835 /***************************************************************************
836 free the dynamically allocated parts of a service struct
837 ***************************************************************************/
838 static void free_service(service *pservice)
839 {
840   int i;
841   if (!pservice)
842      return;
843
844   for (i=0;parm_table[i].label;i++)
845     if (parm_table[i].type == P_STRING && parm_table[i].class == P_LOCAL)
846       string_free((char **)(((char *)pservice) + PTR_DIFF(parm_table[i].ptr,&sDefault)));
847 }
848
849 /***************************************************************************
850 add a new service to the services array initialising it with the given 
851 service
852 ***************************************************************************/
853 static int add_a_service(service *pservice, char *name)
854 {
855   int i;
856   service tservice;
857   int num_to_alloc = iNumServices+1;
858
859   tservice = *pservice;
860
861   /* it might already exist */
862   if (name) 
863     {
864       i = getservicebyname(name,NULL);
865       if (i >= 0)
866         return(i);
867     }
868
869   /* find an invalid one */
870   for (i=0;i<iNumServices;i++)
871     if (!pSERVICE(i)->valid)
872       break;
873
874   /* if not, then create one */
875   if (i == iNumServices)
876     {
877       ServicePtrs = (service **)Realloc(ServicePtrs,sizeof(service *)*num_to_alloc);
878       if (ServicePtrs)
879         pSERVICE(iNumServices) = (service *)malloc(sizeof(service));
880
881       if (!ServicePtrs || !pSERVICE(iNumServices))
882         return(-1);
883
884       iNumServices++;
885     }
886   else
887     free_service(pSERVICE(i));
888
889   pSERVICE(i)->valid = True;
890
891   init_service(pSERVICE(i));
892   copy_service(pSERVICE(i),&tservice,NULL);
893   if (name)
894     string_set(&iSERVICE(i).szService,name);  
895
896   return(i);
897 }
898
899 /***************************************************************************
900 add a new home service, with the specified home directory, defaults coming 
901 from service ifrom
902 ***************************************************************************/
903 BOOL lp_add_home(char *pszHomename, int iDefaultService, char *pszHomedir)
904 {
905   int i = add_a_service(pSERVICE(iDefaultService),pszHomename);
906
907   if (i < 0)
908     return(False);
909
910   if (!(*(iSERVICE(i).szPath)) || strequal(iSERVICE(i).szPath,lp_pathname(-1)))
911     string_set(&iSERVICE(i).szPath,pszHomedir);
912   if (!(*(iSERVICE(i).comment)))
913     {
914       pstring comment;
915       sprintf(comment,"Home directory of %s",pszHomename);
916       string_set(&iSERVICE(i).comment,comment);
917     }
918   iSERVICE(i).bAvailable = sDefault.bAvailable;
919   iSERVICE(i).bBrowseable = sDefault.bBrowseable;
920
921   DEBUG(3,("adding home directory %s at %s\n", pszHomename, pszHomedir));
922
923   return(True);
924 }
925
926 /***************************************************************************
927 add a new service, based on an old one
928 ***************************************************************************/
929 int lp_add_service(char *pszService, int iDefaultService)
930 {
931   return(add_a_service(pSERVICE(iDefaultService),pszService));
932 }
933
934
935 /***************************************************************************
936 add the IPC service
937 ***************************************************************************/
938 static BOOL lp_add_ipc(void)
939 {
940   pstring comment;
941   int i = add_a_service(&sDefault,"IPC$");
942
943   if (i < 0)
944     return(False);
945
946   sprintf(comment,"IPC Service (%s)",lp_serverstring());
947
948   string_set(&iSERVICE(i).szPath,"/tmp");
949   string_set(&iSERVICE(i).szUsername,"");
950   string_set(&iSERVICE(i).comment,comment);
951   iSERVICE(i).status = False;
952   iSERVICE(i).iMaxConnections = 0;
953   iSERVICE(i).bAvailable = True;
954   iSERVICE(i).bRead_only = True;
955   iSERVICE(i).bGuest_only = False;
956   iSERVICE(i).bGuest_ok = True;
957   iSERVICE(i).bPrint_ok = False;
958   iSERVICE(i).bBrowseable = sDefault.bBrowseable;
959
960   DEBUG(3,("adding IPC service\n"));
961
962   return(True);
963 }
964
965
966 /***************************************************************************
967 add a new printer service, with defaults coming from service iFrom
968 ***************************************************************************/
969 BOOL lp_add_printer(char *pszPrintername, int iDefaultService)
970 {
971   char *comment = "From Printcap";
972   int i = add_a_service(pSERVICE(iDefaultService),pszPrintername);
973   
974   if (i < 0)
975     return(False);
976   
977   /* note that we do NOT default the availability flag to True - */
978   /* we take it from the default service passed. This allows all */
979   /* dynamic printers to be disabled by disabling the [printers] */
980   /* entry (if/when the 'available' keyword is implemented!).    */
981   
982   /* the printer name is set to the service name. */
983   string_set(&iSERVICE(i).szPrintername,pszPrintername);
984   string_set(&iSERVICE(i).comment,comment);
985   iSERVICE(i).bBrowseable = sDefault.bBrowseable;
986   
987   DEBUG(3,("adding printer service %s\n",pszPrintername));
988   
989   return(True);
990 }
991
992
993 /***************************************************************************
994 Do a case-insensitive, whitespace-ignoring string compare.
995 ***************************************************************************/
996 static int strwicmp(char *psz1, char *psz2)
997 {
998    /* if BOTH strings are NULL, return TRUE, if ONE is NULL return */
999    /* appropriate value. */
1000    if (psz1 == psz2)
1001       return (0);
1002    else
1003       if (psz1 == NULL)
1004          return (-1);
1005       else
1006           if (psz2 == NULL)
1007               return (1);
1008
1009    /* sync the strings on first non-whitespace */
1010    while (1)
1011    {
1012       while (isspace(*psz1))
1013          psz1++;
1014       while (isspace(*psz2))
1015          psz2++;
1016       if (toupper(*psz1) != toupper(*psz2) || *psz1 == '\0' || *psz2 == '\0')
1017          break;
1018       psz1++;
1019       psz2++;
1020    }
1021    return (*psz1 - *psz2);
1022 }
1023
1024 /***************************************************************************
1025 Map a parameter's string representation to something we can use. 
1026 Returns False if the parameter string is not recognised, else TRUE.
1027 ***************************************************************************/
1028 static int map_parameter(char *pszParmName)
1029 {
1030    int iIndex;
1031
1032    if (*pszParmName == '-')
1033      return(-1);
1034
1035    for (iIndex = 0; parm_table[iIndex].label; iIndex++) 
1036       if (strwicmp(parm_table[iIndex].label, pszParmName) == 0)
1037          return(iIndex);
1038
1039    DEBUG(0,( "Unknown parameter encountered: \"%s\"\n", pszParmName));
1040    return(-1);
1041 }
1042
1043
1044 /***************************************************************************
1045 Set a boolean variable from the text value stored in the passed string.
1046 Returns True in success, False if the passed string does not correctly 
1047 represent a boolean.
1048 ***************************************************************************/
1049 static BOOL set_boolean(BOOL *pb, char *pszParmValue)
1050 {
1051    BOOL bRetval;
1052
1053    bRetval = True;
1054    if (strwicmp(pszParmValue, "yes") == 0 ||
1055        strwicmp(pszParmValue, "true") == 0 ||
1056        strwicmp(pszParmValue, "1") == 0)
1057       *pb = True;
1058    else
1059       if (strwicmp(pszParmValue, "no") == 0 ||
1060           strwicmp(pszParmValue, "False") == 0 ||
1061           strwicmp(pszParmValue, "0") == 0)
1062          *pb = False;
1063       else
1064       {
1065          DEBUG(0,( "Badly formed boolean in configuration file: \"%s\".\n",
1066                pszParmValue));
1067          bRetval = False;
1068       }
1069    return (bRetval);
1070 }
1071
1072 /***************************************************************************
1073 Find a service by name. Otherwise works like get_service.
1074 ***************************************************************************/
1075 static int getservicebyname(char *pszServiceName, service *pserviceDest)
1076 {
1077    int iService;
1078
1079    for (iService = iNumServices - 1; iService >= 0; iService--)
1080       if (VALID(iService) &&
1081           strwicmp(iSERVICE(iService).szService, pszServiceName) == 0) 
1082       {
1083          if (pserviceDest != NULL)
1084            copy_service(pserviceDest, pSERVICE(iService), NULL);
1085          break;
1086       }
1087
1088    return (iService);
1089 }
1090
1091
1092
1093 /***************************************************************************
1094 Copy a service structure to another
1095
1096 If pcopymapDest is NULL then copy all fields
1097 ***************************************************************************/
1098 static void copy_service(service *pserviceDest, 
1099                          service *pserviceSource,
1100                          BOOL *pcopymapDest)
1101 {
1102   int i;
1103   BOOL bcopyall = (pcopymapDest == NULL);
1104
1105   for (i=0;parm_table[i].label;i++)
1106     if (parm_table[i].ptr && parm_table[i].class == P_LOCAL && 
1107         (bcopyall || pcopymapDest[i]))
1108       {
1109         void *def_ptr = parm_table[i].ptr;
1110         void *src_ptr = 
1111           ((char *)pserviceSource) + PTR_DIFF(def_ptr,&sDefault);
1112         void *dest_ptr = 
1113           ((char *)pserviceDest) + PTR_DIFF(def_ptr,&sDefault);
1114
1115         switch (parm_table[i].type)
1116           {
1117           case P_BOOL:
1118           case P_BOOLREV:
1119             *(BOOL *)dest_ptr = *(BOOL *)src_ptr;
1120             break;
1121
1122           case P_INTEGER:
1123           case P_OCTAL:
1124             *(int *)dest_ptr = *(int *)src_ptr;
1125             break;
1126
1127           case P_CHAR:
1128             *(char *)dest_ptr = *(char *)src_ptr;
1129             break;
1130
1131           case P_STRING:
1132             string_set(dest_ptr,*(char **)src_ptr);
1133             break;
1134           default:
1135             break;
1136           }
1137       }
1138
1139   if (bcopyall)
1140     {
1141       init_copymap(pserviceDest);
1142       if (pserviceSource->copymap)
1143         memcpy((void *)pserviceDest->copymap,
1144                (void *)pserviceSource->copymap,sizeof(BOOL)*NUMPARAMETERS);
1145     }
1146 }
1147
1148 /***************************************************************************
1149 Check a service for consistency. Return False if the service is in any way
1150 incomplete or faulty, else True.
1151 ***************************************************************************/
1152 static BOOL service_ok(int iService)
1153 {
1154    BOOL bRetval;
1155
1156    bRetval = True;
1157    if (iSERVICE(iService).szService[0] == '\0')
1158    {
1159       DEBUG(0,( "The following message indicates an internal error:\n"));
1160       DEBUG(0,( "No service name in service entry.\n"));
1161       bRetval = False;
1162    }
1163
1164    /* The [printers] entry MUST be printable. I'm all for flexibility, but */
1165    /* I can't see why you'd want a non-printable printer service...        */
1166    if (strwicmp(iSERVICE(iService).szService,PRINTERS_NAME) == 0)
1167       if (!iSERVICE(iService).bPrint_ok)
1168       {
1169          DEBUG(0,( "WARNING: [%s] service MUST be printable!\n",
1170                iSERVICE(iService).szService));
1171          iSERVICE(iService).bPrint_ok = True;
1172       }
1173
1174    if (iSERVICE(iService).szPath[0] == '\0' &&
1175        strwicmp(iSERVICE(iService).szService,HOMES_NAME) != 0)
1176    {
1177       DEBUG(0,("No path in service %s - using /tmp\n",iSERVICE(iService).szService));
1178       string_set(&iSERVICE(iService).szPath,"/tmp");      
1179    }
1180
1181    /* If a service is flagged unavailable, log the fact at level 0. */
1182    if (!iSERVICE(iService).bAvailable) 
1183       DEBUG(1,( "NOTE: Service %s is flagged unavailable.\n",
1184             iSERVICE(iService).szService));
1185
1186    return (bRetval);
1187 }
1188
1189 static struct file_lists {
1190   struct file_lists *next;
1191   char *name;
1192   time_t modtime;
1193 } *file_lists = NULL;
1194
1195 /*******************************************************************
1196 keep a linked list of all config files so we know when one has changed 
1197 it's date and needs to be reloaded
1198 ********************************************************************/
1199 static void add_to_file_list(char *fname)
1200 {
1201   struct file_lists *f=file_lists;
1202
1203   while (f) {
1204     if (f->name && !strcmp(f->name,fname)) break;
1205     f = f->next;
1206   }
1207
1208   if (!f) {
1209     f = (struct file_lists *)malloc(sizeof(file_lists[0]));
1210     if (!f) return;
1211     f->next = file_lists;
1212     f->name = strdup(fname);
1213     if (!f->name) {
1214       free(f);
1215       return;
1216     }
1217     file_lists = f;
1218   }
1219
1220   {
1221     pstring n2;
1222     strcpy(n2,fname);
1223     standard_sub_basic(n2);
1224     f->modtime = file_modtime(n2);
1225   }
1226
1227 }
1228
1229 /*******************************************************************
1230 check if a config file has changed date
1231 ********************************************************************/
1232 BOOL lp_file_list_changed(void)
1233 {
1234   struct file_lists *f = file_lists;
1235   while (f) {
1236     pstring n2;
1237     strcpy(n2,f->name);
1238     standard_sub_basic(n2);
1239     if (f->modtime != file_modtime(n2)) return(True);
1240     f = f->next;   
1241   }
1242   return(False);
1243 }
1244
1245 #ifdef KANJI
1246 /***************************************************************************
1247   handle the interpretation of the coding system parameter
1248   *************************************************************************/
1249 static BOOL handle_coding_system(char *pszParmValue,int *val)
1250 {
1251   *val = interpret_coding_system(pszParmValue,*val);
1252   return(True);
1253 }
1254 #endif /* KANJI */
1255
1256 /***************************************************************************
1257 handle the interpretation of the character set system parameter
1258 ***************************************************************************/
1259 static BOOL handle_character_set(char *pszParmValue,int *val)
1260 {
1261   string_set(&Globals.szCharacterSet,pszParmValue);
1262   *val = interpret_character_set(pszParmValue,*val);
1263   return(True);
1264 }
1265
1266
1267 /***************************************************************************
1268 handle the interpretation of the protocol parameter
1269 ***************************************************************************/
1270 static BOOL handle_protocol(char *pszParmValue,int *val)
1271 {
1272   *val = interpret_protocol(pszParmValue,*val);
1273   return(True);
1274 }
1275
1276 /***************************************************************************
1277 handle the interpretation of the security parameter
1278 ***************************************************************************/
1279 static BOOL handle_security(char *pszParmValue,int *val)
1280 {
1281   *val = interpret_security(pszParmValue,*val);
1282   return(True);
1283 }
1284
1285 /***************************************************************************
1286 handle the interpretation of the default case
1287 ***************************************************************************/
1288 static BOOL handle_case(char *pszParmValue,int *val)
1289 {
1290   if (strequal(pszParmValue,"LOWER"))
1291     *val = CASE_LOWER;
1292   else if (strequal(pszParmValue,"UPPER"))
1293     *val = CASE_UPPER;
1294   return(True);
1295 }
1296
1297 /***************************************************************************
1298 handle the interpretation of the printing system
1299 ***************************************************************************/
1300 static BOOL handle_printing(char *pszParmValue,int *val)
1301 {
1302   if (strequal(pszParmValue,"sysv"))
1303     *val = PRINT_SYSV;
1304   else if (strequal(pszParmValue,"aix"))
1305     *val = PRINT_AIX;
1306   else if (strequal(pszParmValue,"hpux"))
1307     *val = PRINT_HPUX;
1308   else if (strequal(pszParmValue,"bsd"))
1309     *val = PRINT_BSD;
1310   else if (strequal(pszParmValue,"qnx"))
1311     *val = PRINT_QNX;
1312   else if (strequal(pszParmValue,"plp"))
1313     *val = PRINT_PLP;
1314   return(True);
1315 }
1316
1317 /***************************************************************************
1318 handle the valid chars lines
1319 ***************************************************************************/
1320 static BOOL handle_valid_chars(char *pszParmValue,char **ptr)
1321
1322   string_set(ptr,pszParmValue);
1323
1324   add_char_string(pszParmValue);
1325   return(True);
1326 }
1327
1328
1329 /***************************************************************************
1330 handle the include operation
1331 ***************************************************************************/
1332 static BOOL handle_include(char *pszParmValue,char **ptr)
1333
1334   pstring fname;
1335   strcpy(fname,pszParmValue);
1336
1337   add_to_file_list(fname);
1338
1339   standard_sub_basic(fname);
1340
1341   string_set(ptr,fname);
1342
1343   if (file_exist(fname,NULL))
1344     return(pm_process(fname, do_section, do_parameter));      
1345
1346   DEBUG(2,("Can't find include file %s\n",fname));
1347
1348   return(False);
1349 }
1350
1351
1352 /***************************************************************************
1353 handle the interpretation of the copy parameter
1354 ***************************************************************************/
1355 static BOOL handle_copy(char *pszParmValue,char **ptr)
1356 {
1357    BOOL bRetval;
1358    int iTemp;
1359    service serviceTemp;
1360
1361    string_set(ptr,pszParmValue);
1362
1363    init_service(&serviceTemp);
1364
1365    bRetval = False;
1366    
1367    DEBUG(3,("Copying service from service %s\n",pszParmValue));
1368
1369    if ((iTemp = getservicebyname(pszParmValue, &serviceTemp)) >= 0)
1370      {
1371        if (iTemp == iServiceIndex)
1372          {
1373            DEBUG(0,("Can't copy service %s - unable to copy self!\n",
1374                     pszParmValue));
1375          }
1376        else
1377          {
1378            copy_service(pSERVICE(iServiceIndex), 
1379                         &serviceTemp,
1380                         iSERVICE(iServiceIndex).copymap);
1381            bRetval = True;
1382          }
1383      }
1384    else
1385      {
1386        DEBUG(0,( "Unable to copy service - source not found: %s\n",
1387                 pszParmValue));
1388        bRetval = False;
1389      }
1390
1391    free_service(&serviceTemp);
1392    return (bRetval);
1393 }
1394
1395
1396 /***************************************************************************
1397 initialise a copymap
1398 ***************************************************************************/
1399 static void init_copymap(service *pservice)
1400 {
1401   int i;
1402   if (pservice->copymap) free(pservice->copymap);
1403   pservice->copymap = (BOOL *)malloc(sizeof(BOOL)*NUMPARAMETERS);
1404   if (!pservice->copymap)
1405     DEBUG(0,("Couldn't allocate copymap!! (size %d)\n",NUMPARAMETERS));
1406
1407   for (i=0;i<NUMPARAMETERS;i++)
1408     pservice->copymap[i] = True;
1409 }
1410
1411
1412 /***************************************************************************
1413 Process a parameter.
1414 ***************************************************************************/
1415 static BOOL do_parameter(char *pszParmName, char *pszParmValue)
1416 {
1417    int parmnum;
1418    void *parm_ptr=NULL; /* where we are going to store the result */
1419    void *def_ptr=NULL;
1420
1421    if (!bInGlobalSection && bGlobalOnly) return(True);
1422
1423    DEBUG(3,("doing parameter %s = %s\n",pszParmName,pszParmValue));
1424    
1425    parmnum = map_parameter(pszParmName);
1426
1427    if (parmnum < 0)
1428      {
1429        DEBUG(0,( "Ignoring unknown parameter \"%s\"\n", pszParmName));
1430        return(True);
1431      }
1432
1433    def_ptr = parm_table[parmnum].ptr;
1434
1435    /* we might point at a service, the default service or a global */
1436    if (bInGlobalSection)
1437      parm_ptr = def_ptr;
1438    else
1439      {
1440        if (parm_table[parmnum].class == P_GLOBAL)
1441          {
1442            DEBUG(0,( "Global parameter %s found in service section!\n",pszParmName));
1443            return(True);
1444          }
1445        parm_ptr = ((char *)pSERVICE(iServiceIndex)) + PTR_DIFF(def_ptr,&sDefault);
1446      }
1447
1448    if (!bInGlobalSection)
1449      {
1450        int i;
1451        if (!iSERVICE(iServiceIndex).copymap)
1452          init_copymap(pSERVICE(iServiceIndex));
1453        
1454        /* this handles the aliases - set the copymap for other entries with
1455           the same data pointer */
1456        for (i=0;parm_table[i].label;i++)
1457          if (parm_table[i].ptr == parm_table[parmnum].ptr)
1458            iSERVICE(iServiceIndex).copymap[i] = False;
1459      }
1460
1461    /* if it is a special case then go ahead */
1462    if (parm_table[parmnum].special)
1463      {
1464        parm_table[parmnum].special(pszParmValue,parm_ptr);
1465        return(True);
1466      }
1467
1468    /* now switch on the type of variable it is */
1469    switch (parm_table[parmnum].type)
1470      {
1471      case P_BOOL:
1472        set_boolean(parm_ptr,pszParmValue);
1473        break;
1474
1475      case P_BOOLREV:
1476        set_boolean(parm_ptr,pszParmValue);
1477        *(BOOL *)parm_ptr = ! *(BOOL *)parm_ptr;
1478        break;
1479
1480      case P_INTEGER:
1481        *(int *)parm_ptr = atoi(pszParmValue);
1482        break;
1483
1484      case P_CHAR:
1485        *(char *)parm_ptr = *pszParmValue;
1486        break;
1487
1488      case P_OCTAL:
1489        sscanf(pszParmValue,"%o",(int *)parm_ptr);
1490        break;
1491
1492      case P_STRING:
1493        string_set(parm_ptr,pszParmValue);
1494        break;
1495
1496      case P_GSTRING:
1497        strcpy((char *)parm_ptr,pszParmValue);
1498        break;
1499      }
1500
1501    return(True);
1502 }
1503
1504 /***************************************************************************
1505 print a parameter of the specified type
1506 ***************************************************************************/
1507 static void print_parameter(parm_type type,void *ptr)
1508 {
1509   switch (type)
1510     {
1511     case P_BOOL:
1512       printf("%s",BOOLSTR(*(BOOL *)ptr));
1513       break;
1514       
1515     case P_BOOLREV:
1516       printf("%s",BOOLSTR(! *(BOOL *)ptr));
1517       break;
1518       
1519     case P_INTEGER:
1520       printf("%d",*(int *)ptr);
1521       break;
1522       
1523     case P_CHAR:
1524       printf("%c",*(char *)ptr);
1525       break;
1526       
1527     case P_OCTAL:
1528       printf("0%o",*(int *)ptr);
1529       break;
1530       
1531     case P_GSTRING:
1532       if ((char *)ptr)
1533         printf("%s",(char *)ptr);
1534       break;
1535
1536     case P_STRING:
1537       if (*(char **)ptr)
1538         printf("%s",*(char **)ptr);
1539       break;
1540     }
1541 }
1542
1543
1544 /***************************************************************************
1545 check if two parameters are equal
1546 ***************************************************************************/
1547 static BOOL equal_parameter(parm_type type,void *ptr1,void *ptr2)
1548 {
1549   switch (type)
1550     {
1551     case P_BOOL:
1552     case P_BOOLREV:
1553       return(*((BOOL *)ptr1) == *((BOOL *)ptr2));
1554
1555     case P_INTEGER:
1556     case P_OCTAL:
1557       return(*((int *)ptr1) == *((int *)ptr2));
1558       
1559     case P_CHAR:
1560       return(*((char *)ptr1) == *((char *)ptr2));
1561
1562     case P_GSTRING:
1563       {
1564         char *p1 = (char *)ptr1, *p2 = (char *)ptr2;
1565         if (p1 && !*p1) p1 = NULL;
1566         if (p2 && !*p2) p2 = NULL;
1567         return(p1==p2 || strequal(p1,p2));
1568       }
1569     case P_STRING:
1570       {
1571         char *p1 = *(char **)ptr1, *p2 = *(char **)ptr2;
1572         if (p1 && !*p1) p1 = NULL;
1573         if (p2 && !*p2) p2 = NULL;
1574         return(p1==p2 || strequal(p1,p2));
1575       }
1576     }
1577   return(False);
1578 }
1579
1580 /***************************************************************************
1581 Process a new section (service). At this stage all sections are services.
1582 Later we'll have special sections that permit server parameters to be set.
1583 Returns True on success, False on failure.
1584 ***************************************************************************/
1585 static BOOL do_section(char *pszSectionName)
1586 {
1587    BOOL bRetval;
1588    BOOL isglobal = ((strwicmp(pszSectionName, GLOBAL_NAME) == 0) || 
1589                     (strwicmp(pszSectionName, GLOBAL_NAME2) == 0));
1590    bRetval = False;
1591
1592    /* if we were in a global section then do the local inits */
1593    if (bInGlobalSection && !isglobal)
1594      init_locals();
1595
1596    /* if we've just struck a global section, note the fact. */
1597    bInGlobalSection = isglobal;   
1598
1599    /* check for multiple global sections */
1600    if (bInGlobalSection)
1601    {
1602      DEBUG(3,( "Processing section \"[%s]\"\n", pszSectionName));
1603      return(True);
1604    }
1605
1606    if (!bInGlobalSection && bGlobalOnly) return(True);
1607
1608    /* if we have a current service, tidy it up before moving on */
1609    bRetval = True;
1610
1611    if (iServiceIndex >= 0)
1612      bRetval = service_ok(iServiceIndex);
1613
1614    /* if all is still well, move to the next record in the services array */
1615    if (bRetval)
1616      {
1617        /* We put this here to avoid an odd message order if messages are */
1618        /* issued by the post-processing of a previous section. */
1619        DEBUG(2,( "Processing section \"[%s]\"\n", pszSectionName));
1620
1621        if ((iServiceIndex=add_a_service(&sDefault,pszSectionName)) < 0)
1622          {
1623            DEBUG(0,("Failed to add a new service\n"));
1624            return(False);
1625          }
1626      }
1627
1628    return (bRetval);
1629 }
1630
1631 /***************************************************************************
1632 Display the contents of the global structure.
1633 ***************************************************************************/
1634 static void dump_globals(void)
1635 {
1636   int i;
1637   printf("Global parameters:\n");
1638
1639   for (i=0;parm_table[i].label;i++)
1640     if (parm_table[i].class == P_GLOBAL &&
1641         parm_table[i].ptr &&
1642         (i == 0 || (parm_table[i].ptr != parm_table[i-1].ptr)))
1643       {
1644         printf("\t%s: ",parm_table[i].label);
1645         print_parameter(parm_table[i].type,parm_table[i].ptr);
1646         printf("\n");
1647       }
1648 }
1649
1650 /***************************************************************************
1651 Display the contents of a single services record.
1652 ***************************************************************************/
1653 static void dump_a_service(service *pService)
1654 {
1655   int i;
1656   if (pService == &sDefault)
1657     printf("\nDefault service parameters:\n");
1658   else
1659     printf("\nService parameters [%s]:\n",pService->szService);
1660
1661   for (i=0;parm_table[i].label;i++)
1662     if (parm_table[i].class == P_LOCAL &&
1663         parm_table[i].ptr && 
1664         (*parm_table[i].label != '-') &&
1665         (i == 0 || (parm_table[i].ptr != parm_table[i-1].ptr)))
1666       {
1667         int pdiff = PTR_DIFF(parm_table[i].ptr,&sDefault);
1668
1669         if (pService == &sDefault || !equal_parameter(parm_table[i].type,
1670                                                       ((char *)pService) + pdiff,
1671                                                       ((char *)&sDefault) + pdiff))
1672           {
1673             printf("\t%s: ",parm_table[i].label);
1674             print_parameter(parm_table[i].type,
1675                             ((char *)pService) + pdiff);
1676             printf("\n");
1677           }
1678       }
1679 }
1680
1681 #if 0
1682 /***************************************************************************
1683 Display the contents of a single copy structure.
1684 ***************************************************************************/
1685 static void dump_copy_map(BOOL *pcopymap)
1686 {
1687   int i;
1688   if (!pcopymap) return;
1689
1690   printf("\n\tNon-Copied parameters:\n");
1691
1692   for (i=0;parm_table[i].label;i++)
1693     if (parm_table[i].class == P_LOCAL &&
1694         parm_table[i].ptr && !pcopymap[i] &&
1695         (i == 0 || (parm_table[i].ptr != parm_table[i-1].ptr)))
1696       {
1697         printf("\t\t%s\n",parm_table[i].label);
1698       }
1699 }
1700 #endif
1701
1702 /***************************************************************************
1703 Return TRUE if the passed service number is within range.
1704 ***************************************************************************/
1705 BOOL lp_snum_ok(int iService)
1706 {
1707    return (LP_SNUM_OK(iService) && iSERVICE(iService).bAvailable);
1708 }
1709
1710
1711 /***************************************************************************
1712 auto-load some homes and printer services
1713 ***************************************************************************/
1714 static void lp_add_auto_services(char *str)
1715 {
1716   char *s;
1717   char *p;
1718   int homes = lp_servicenumber(HOMES_NAME);
1719   int printers = lp_servicenumber(PRINTERS_NAME);
1720
1721   if (!str)
1722     return;
1723
1724   s = strdup(str);
1725   if (!s) return;
1726
1727   for (p=strtok(s,LIST_SEP);p;p=strtok(NULL,LIST_SEP))
1728     {
1729       char *home = get_home_dir(p);
1730
1731       if (lp_servicenumber(p) >= 0) continue;
1732
1733       if (home && homes >= 0)
1734         {
1735           lp_add_home(p,homes,home);
1736           continue;
1737         }
1738
1739       if (printers >= 0 && pcap_printername_ok(p,NULL))
1740         lp_add_printer(p,printers);
1741     }
1742   free(s);
1743 }
1744
1745 /***************************************************************************
1746 auto-load one printer
1747 ***************************************************************************/
1748 static void lp_add_one_printer(char *name,char *comment)
1749 {
1750   int printers = lp_servicenumber(PRINTERS_NAME);
1751   int i;
1752
1753   if (lp_servicenumber(name) < 0)
1754     {
1755       lp_add_printer(name,printers);
1756       if ((i=lp_servicenumber(name)) >= 0)
1757         string_set(&iSERVICE(i).comment,comment);
1758     }      
1759 }
1760
1761
1762 /***************************************************************************
1763 auto-load printer services
1764 ***************************************************************************/
1765 static void lp_add_all_printers(void)
1766 {
1767   int printers = lp_servicenumber(PRINTERS_NAME);
1768
1769   if (printers < 0) return;
1770
1771   pcap_printer_fn(lp_add_one_printer);
1772 }
1773
1774 /***************************************************************************
1775 have we loaded a services file yet?
1776 ***************************************************************************/
1777 BOOL lp_loaded(void)
1778 {
1779   return(bLoaded);
1780 }
1781
1782 /***************************************************************************
1783 unload unused services
1784 ***************************************************************************/
1785 void lp_killunused(BOOL (*snumused)(int ))
1786 {
1787   int i;
1788   for (i=0;i<iNumServices;i++)
1789     if (VALID(i) && !snumused(i))
1790       {
1791         iSERVICE(i).valid = False;
1792         free_service(pSERVICE(i));
1793       }
1794 }
1795
1796 /***************************************************************************
1797 Load the services array from the services file. Return True on success, 
1798 False on failure.
1799 ***************************************************************************/
1800 BOOL lp_load(char *pszFname,BOOL global_only)
1801 {
1802   pstring n2;
1803   BOOL bRetval;
1804   
1805   add_to_file_list(pszFname);
1806
1807   bRetval = False;
1808
1809   bInGlobalSection = True;
1810   bGlobalOnly = global_only;
1811   
1812   init_globals();
1813   
1814   strcpy(n2,pszFname);
1815   standard_sub_basic(n2);
1816
1817   /* We get sections first, so have to start 'behind' to make up */
1818   iServiceIndex = -1;
1819   bRetval = pm_process(n2, do_section, do_parameter);
1820   
1821   /* finish up the last section */
1822   DEBUG(3,("pm_process() returned %s\n", BOOLSTR(bRetval)));
1823   if (bRetval)
1824     if (iServiceIndex >= 0)
1825       bRetval = service_ok(iServiceIndex);         
1826
1827   lp_add_auto_services(lp_auto_services());
1828   if (lp_load_printers())
1829     lp_add_all_printers();
1830
1831   lp_add_ipc();
1832
1833   bLoaded = True;
1834
1835   return (bRetval);
1836 }
1837
1838
1839 /***************************************************************************
1840 return the max number of services
1841 ***************************************************************************/
1842 int lp_numservices(void)
1843 {
1844   return(iNumServices);
1845 }
1846
1847 /***************************************************************************
1848 Display the contents of the services array in human-readable form.
1849 ***************************************************************************/
1850 void lp_dump(void)
1851 {
1852    int iService;
1853
1854    dump_globals();
1855    
1856    dump_a_service(&sDefault);
1857
1858    for (iService = 0; iService < iNumServices; iService++)
1859    {
1860      if (VALID(iService))
1861        {
1862          if (iSERVICE(iService).szService[0] == '\0')
1863            break;
1864          dump_a_service(pSERVICE(iService));
1865        }
1866    }
1867 }
1868
1869 /***************************************************************************
1870 Return the number of the service with the given name, or -1 if it doesn't
1871 exist. Note that this is a DIFFERENT ANIMAL from the internal function
1872 getservicebyname()! This works ONLY if all services have been loaded, and
1873 does not copy the found service.
1874 ***************************************************************************/
1875 int lp_servicenumber(char *pszServiceName)
1876 {
1877    int iService;
1878
1879    for (iService = iNumServices - 1; iService >= 0; iService--)
1880       if (VALID(iService) &&
1881           strwicmp(iSERVICE(iService).szService, pszServiceName) == 0) 
1882          break;
1883
1884    if (iService < 0)
1885      DEBUG(7,("lp_servicenumber: couldn't find %s\n",pszServiceName));
1886    
1887    return (iService);
1888 }
1889
1890
1891
1892
1893 /*******************************************************************
1894   get a workgroup - but map to standalone if '*'
1895   ******************************************************************/
1896 char *my_workgroup(void)
1897 {
1898   char *res = lp_workgroup();
1899   if (*res == '*') return("STANDALONE");
1900   return(res);
1901 }
1902
1903 /*******************************************************************
1904   a useful volume label function
1905   ******************************************************************/
1906 char *volume_label(int snum)
1907 {
1908   char *ret = lp_volume(snum);
1909   if (!*ret) return(lp_servicename(snum));
1910   return(ret);
1911 }