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