import nis, re, UserList
class UserDataEntry:
'''
UserDataEntry - provide a simple interface for user data
(userid, (full) name, mailname). For convenience, there is a
method lastname() which trys to guess the lastname from name
by using the last whitespace separated part.
'''
def __init__( self, userid='', name='', mailname='' ):
'Usage: data = UserDataEntry( userid, name, mailname )'
self.userid = userid.strip()
self.name = name.strip()
self.mailname = mailname.strip()
def __str__( self ):
return ' '.join( [
self.userid.ljust(8),
self.name.ljust(30),
self.mailname ] )
def lastname( self ):
'''
Guess a last name by using the last word of the name field.
If there is only whitespace return an empty string.
Usage: data.lastname()
'''
parts = self.name.split()
if parts:
return parts[-1]
else:
return ''
class UserDataList( UserList.UserList ):
'''
UserDataList - provide operations for handling of user data
from NIS and a sendmail user database (userdb)
Usage:
user_list = user_data_list.UserDataList( source='NIS' )
user_list.filter_by( 'lastname', 'Schwarzer' )
user_list.update_mailnames( '/path/to/userdb' )
# synonymous:
# user_list.userdb = '/path/to/userdb'
# user_list.update_mailnames()
user_list.sort_by( 'userid' )
print user_list
'''
def __init__( self, source=None ):
'''
Inititialize the UserDataEntry's, possibly from NIS
Usage: data = UserDataList( source='NIS' )
'''
UserList.UserList.__init__( self )
# turn data into _list, a private attribute (by convention)
self._list = self.data
del self.data
self.userdb = ''
if source == 'NIS':
self._init_from_NIS()
def _init_from_NIS( self ):
'Initialize object from NIS password data'
passwd_lines = nis.cat( 'passwd.byname' ).values()
for line in passwd_lines:
line_parts = line.split( ':' )
try:
userid, name = line_parts[0], line_parts[4]
self._list.append( UserDataEntry(userid, name) )
except IndexError:
# ignore invalidly formed lines
pass
def __str__( self ):
'Return a list of passwd entries, one per line'
formatted_entries = [ str(entry) for entry in self._list ]
return '\n'.join( formatted_entries )
def _sort_function( self, fieldname ):
'Return a sort function appropriate for the specified field'
sort_function_dict = {
'userid' : lambda a, b: cmp( a.userid, b.userid ),
'name' : lambda a, b: cmp( a.name, b.name ),
'lastname': lambda a, b: cmp( a.lastname(), b.lastname() ),
'mailname': lambda a, b: cmp( a.mailname, b.mailname )
}
if sort_function_dict.has_key( fieldname ):
return sort_function_dict[fieldname]
else:
raise( ValueError('unsupported sort field "%s"' % fieldname) )
def sort_by( self, fieldname ):
'''
Sort entry list by the specified fieldname
Usage: data.sort_by( 'lastname' )
'''
self._list.sort( self._sort_function(fieldname) )
def _filter_function( self, fieldname ):
'''
Return a filter function appropriate for the specified field
A match occurs for fieldname
userid if the userid EQUALS the value,
name if the name CONTAINS the value,
lastname if the lastname CONTAINS the value,
mailname if the mailname CONTAINS the value,
nomail if the mailname EQUALS '', the value is ignored
'''
filter_function_dict = {
'userid' : lambda entry, value: entry.userid == value,
'name' : lambda entry, value: entry.name.find(value) != -1,
'lastname': lambda entry, value: entry.lastname().find(value) != -1,
'mailname': lambda entry, value: entry.mailname.find(value) != -1,
'nomail' : lambda entry, value='': entry.mailname == ''
}
if filter_function_dict.has_key( fieldname ):
return filter_function_dict[fieldname]
else:
raise( ValueError('unsupported filter field "%s"' % fieldname) )
def filter_by( self, fieldname, value ):
'''
Extract all entries where the fieldname matches the given value.
A match occurs for fieldname
userid if the userid EQUALS the value,
name if the name CONTAINS the value,
lastname if the lastname CONTAINS the value,
mailname if the mailname CONTAINS the value,
nomail if the mailname EQUALS '', the value is ignored
Usage: data.filter_by( 'name', 'Schwarzer' )
'''
self._list = [ entry
for entry in self._list
if self._filter_function(fieldname)(entry, value) ]
def update_mailnames( self, filename=None ):
'''
Update mailnames in passwd entries by using the userdb file
Usage: data.update_mailnames( userdb ) or
data.userdb= userdb; data.update_mailnames()
'''
# get the userdb file contents,
# raising an implicit exception on IO error
if filename is None:
file = open( self.userdb, 'r' )
else:
file = open( filename, 'r' )
contents = file.readlines()
file.close()
# generate a dictionary with key userid -> value mailname
mailname_dict = {}
for line in contents:
pattern = re.compile( r'^(\w+):mailname\s+(\S+)' )
matchobj = pattern.search( line )
if matchobj:
userid, mailname = matchobj.groups()
mailname_dict[userid] = mailname
# iterate over the UserDataList contents (entries) and update them
for entry in self._list:
if mailname_dict.has_key( entry.userid ):
entry.mailname = mailname_dict[entry.userid]