import sys, string, SambaParm
from smbparm import parm_table
######################################################################
##
##  smb.conf parser class
##
##  Copyright (C) Gerald Carter		       2004.
##
##  This program is free software; you can redistribute it and/or modify
##  it under the terms of the GNU General Public License as published by
##  the Free Software Foundation; either version 3 of the License, or
##  (at your option) any later version.
##
##  This program is distributed in the hope that it will be useful,
##  but WITHOUT ANY WARRANTY; without even the implied warranty of
##  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
##  GNU General Public License for more details.
##
##  You should have received a copy of the GNU General Public License
##  along with this program; if not, see .
##
######################################################################
#####################################################################
## multi line Samba comment
class SambaComment:
	def __init__( self, comment ):
		self.comment = comment
		
	def Dump( self, stream, whitespace=None ):
		if not self.comment:
			return
		for line in self.comment:
			if whitespace:
				stream.write( whitespace )
			stream.write( line )
			stream.write( "\n" )
		
	
#####################################################################
## string smb.conf parms
class SambaParameter :
	## indexs into the parm table tuples
	DisplayName  = 0
	ObjectType   = 1
	DefaultValue = 2
	Scope        = 3
	## Stores a key into the parm_table and creates an
	## SambaParmXXX object to store the value
	def __init__( self, name, value, comment=None ):
		self.key = string.upper(string.strip(name))
		self.comment = None
		assert parm_table.has_key( self.key ), "Bad parameter name! [%s]" % name
		self.parm = parm_table[self.key][self.ObjectType]( value )
		if comment :
			self.comment = SambaComment( comment )
			
		#if not self.parm.valid:
		#	self.parm.SetValue( parm_table[self.key][self.DefaultValue] )
	## simple test for global or service parameter scope
	def isGlobalParm( self ) :
		return parm_table[self.key][Scope]
	## dump  1` character so setup the result
			if not result: 
				result = ""
			
			## Check for comments -- terminated by \n -- no continuation
			
			if input_str[0] == '#' or input_str[0] == ';' :
				result = input_str
				break
			
			## check for line continuation			
			
			if input_str[-1] == "\\" :
				result += input_str[0:-1]
				contine
			## otherwise we have a complete line
			result += input_str
			break
		return result
		
	## convert the parameter name to a form suitable as a dictionary key	
	def NormalizeParamName( self, param ):
		return string.upper( string.join(string.split(param), "") )
		
	## Open the file and parse it into a services dictionary
	## if possible
	def ReadConfig( self, filename ):
		self.filename = filename
		try:
			fconfig = open( filename, "r" )
		except IOError:
			self.valid = False
			return
		section_name = None
		
		## the most recent seen comment is stored as an array
		current_comment = []
		
		while True:
		
			str = self.ReadLine( fconfig )
			if not str:
				break
			## Check for comments
			if str[0] == '#' or str[0] == ';' :
				current_comment.append( str )
				continue
			## look for a next section name
			if str[0]=='[' and str[-1]==']' :
				section_name = str[1:-1]
				self.AddService( section_name, current_comment )
				current_comment = []
				continue
			str_list = string.split( str, "=" )
			if len(str_list) != 2 :
				continue
			if not section_name :
				print "parameter given without section name!"
				break
			param = self.NormalizeParamName( str_list[0] )
			value = string.strip(str_list[1])
			self.SetServiceOption( section_name, param, value, current_comment )
			self.dirty = False
			
			## reset the comment strinf if we have one
			current_comment = []
			
		fconfig.close()
	## Add a parameter to the global section
	def SetGlobalOption( self, param, value, comment=None ) :
		self.SetServiceOption( "GLOBAL", param, value, comment )
	## Add a parameter to a specific service
	def SetServiceOption( self, servicename, param, value, comment=None ) :
		service = string.upper(servicename)
		parm = self.NormalizeParamName(param)
		self.services[service]['_order_'].append( parm )
		self.services[service][parm] = SambaParameter( parm, value, comment )
		self.dirty = True
	## remove a service from the config file
	def DelService( self, servicename ) :
		service = string.upper(servicename)
		self.services[service] = None
		self.dirty = True
		
	## remove a service from the config file
	def AddService( self, servicename, comment=None ) :
		service = string.upper(servicename)
		self.services[service] = {}
		self.services[service]['_order_'] = []
		if ( comment ):
			self.services[service]['_comment_'] = SambaComment( comment )
		self.services_order.append( service )
		self.dirty = True
		
	def isService( self, servicename ):
		service = string.upper(servicename)
		return self.services.has_key( service )
		
	## dump a single service to stream
	def DumpService( self, stream, servicename ):
	
		## comments first 
		if self.services[servicename].has_key( '_comment_' ):
			self.services[servicename]['_comment_'].Dump( stream )
			
		## section header
		stream.write( "[%s]\n" % (servicename) )
		
		## parameter = value
		for parm in self.services[servicename]['_order_']:
			self.services[servicename][parm].Dump(stream)
	
	## dump the config to stream
	def Dump( self, stream ):
		self.DumpService( stream, "GLOBAL" )
		stream.write("\n")
		
		for section in self.services_order:
			## already handled the global section
			if section == "GLOBAL": 
				continue
				
			## check for deleted sections ##
			if not self.services[section]:
				continue
				
			self.DumpService( stream, section )
			stream.write( "\n" )
			
	## write out any changes to disk
	def Flush( self ):
		if not self.dirty: 
			return
			
		try:
			fconfig = open( self.filename, "w" )
		except IOError:
			sys.stderr.write( "ERROR!\n" ) 
			return 1
			
		self.Dump( fconfig )
		fconfig.close()
		return 0
		
	def Services( self ):
		service_list = []
		for section in self.services.keys():
			service_list.append( section )
			
		return service_list
		
	def NumServices( self ):
		return len(self.Services())
		
	def Write( self, filename ):
		self.filename = filename
		self.valid = True
		if not self.dirty:
			return
		
		self.Flush()
			
		
######################################################################
## Unit tests
######################################################################
if __name__ == "__main__" :
	x = SambaConf( )
	x.ReadConfig( sys.argv[1] )
	if not x.valid :
		print "Bad file!"
		sys.exit(1)
	x.Dump( sys.stdout )
	
	
	
## end of SambaConfig.py ######################################################
###############################################################################