Index: /pykota/trunk/CREDITS
===================================================================
--- /pykota/trunk/CREDITS (revision 1015)
+++ /pykota/trunk/CREDITS (revision 1017)
@@ -44,4 +44,5 @@
     - John Flynn - University of Belize : LDAP support
     - Wayne Godoy - University of Belize : LDAP support
+    - Leif Johansson - LDAP support
 
 ============================================================
Index: /pykota/trunk/pykota/storages/ldapstorage.py
===================================================================
--- /pykota/trunk/pykota/storages/ldapstorage.py (revision 1016)
+++ /pykota/trunk/pykota/storages/ldapstorage.py (revision 1017)
@@ -21,4 +21,8 @@
 #
 # $Log$
+# Revision 1.2  2003/06/06 14:21:08  jalet
+# New LDAP schema.
+# Small bug fixes.
+#
 # Revision 1.1  2003/06/05 11:19:13  jalet
 # More good work on LDAP storage.
@@ -64,9 +68,9 @@
             self.closed = 1
         
-    def doSearch(self, key, fields, base="") :
+    def doSearch(self, key, fields, base="", scope=ldap.SCOPE_SUBTREE) :
         """Does an LDAP search query."""
         try :
             # prepends something more restrictive at the beginning of the base dn
-            result = self.database.search_s(base or self.basedn, ldap.SCOPE_SUBTREE, key, fields)
+            result = self.database.search_s(base or self.basedn, scope, key, fields)
         except ldap.NO_SUCH_OBJECT :    
             return
@@ -79,6 +83,4 @@
         if result :
             return [(printerid, printer["pykotaPrinterName"][0]) for (printerid, printer) in result if fnmatch.fnmatchcase(printer["pykotaPrinterName"][0], printerpattern)]
-        else :    
-            return
             
     def getPrinterId(self, printername) :        
@@ -87,6 +89,4 @@
         if result :
             return result[0][0]
-        else :    
-            return
             
     def getPrinterPrices(self, printerid) :        
@@ -95,6 +95,4 @@
         if result :
             return (float(result[0][1]["pykotaPricePerPage"][0]), float(result[0][1]["pykotaPricePerJob"][0]))
-        else :
-            return 
             
     def setPrinterPrices(self, printerid, perpage, perjob) :
@@ -104,13 +102,11 @@
     def getUserId(self, username) :
         """Returns a userid given a username."""
-        result = self.doSearch("(&(objectClass=pykotaUser)(uid=%s))" % username, ["uid"])
+        result = self.doSearch("(&(objectClass=pykotaAccount)(pykotaUserName=%s))" % username, ["uid"])
         if result :
             return result[0][0]
-        else :    
-            return
             
     def getGroupId(self, groupname) :
         """Returns a groupid given a grupname."""
-        result = self.doSearch("(&(objectClass=pykotaGroup)(cn=%s))" % groupname, ["cn"])
+        result = self.doSearch("(&(objectClass=pykotaGroup)(pykotaGroupName=%s))" % groupname, ["cn"])
         if result is not None :
             (groupid, dummy) = result[0]
@@ -123,25 +119,27 @@
     def getPrinterUsers(self, printerid) :        
         """Returns the list of userids and usernames which uses a given printer."""
-        result = self.doSearch("(&(objectClass=pykotaUserPQuota)(uid=*))", ["uid"], base=printerid) 
-        if result :
-            return [(pquotauserid, fields["uid"][0]) for (pquotauserid, fields) in result]
-        else :
-            return
+        # first get the printer's name from the id
+        result = self.doSearch("objectClass=pykotaPrinter", ["pykotaPrinterName"], base=printerid, scope=ldap.SCOPE_BASE)
+        if result :
+            printername = result[0][1]["pykotaPrinterName"][0]
+            result = self.doSearch("(&(objectClass=pykotaUserPQuota)(pykotaPrinterName=%s))" % printername, ["pykotaUserName"]) 
+            if result :
+                return [(pquotauserid, fields["pykotaUserName"][0]) for (pquotauserid, fields) in result]
         
     def getPrinterGroups(self, printerid) :        
         """Returns the list of groups which uses a given printer."""
-        result = self.doSearch("(&(objectClass=pykotaGroupPQuota)(cn=*))", ["cn"], base=printerid) 
-        if result :
-            return [(pquotagroupid, fields["cn"][0]) for (pquotagroupid, fields) in result]
-        else :
-            return
+        # first get the printer's name from the id
+        result = self.doSearch("objectClass=pykotaPrinter", ["pykotaPrinterName"], base=printerid, scope=ldap.SCOPE_BASE)
+        if result :
+            printername = result[0][1]["pykotaPrinterName"][0]
+            result = self.doSearch("(&(objectClass=pykotaGroupPQuota)(pykotaPrinterName=%s))" % printername, ["pykotaGroupName"]) 
+            if result :
+                return [(pquotagroupid, fields["pykotaGroupName"][0]) for (pquotagroupid, fields) in result]
         
     def getGroupMembersNames(self, groupname) :        
         """Returns the list of user's names which are member of this group."""
-        result = self.doSearch("(&(objectClass=pykotaGroup)(cn=%s))" % groupname, ["memberUid"])
+        result = self.doSearch("(&(objectClass=pykotaGroup)(pykotaGroupName=%s))" % groupname, ["memberUid"])
         if result :
             return result[0][1]["memberUid"]
-        else :
-            return
         
     def getUserGroupsNames(self, userid) :        
@@ -173,46 +171,59 @@
         pass
         
-    def getUserBalance(self, userid) :    
-        """Returns the current account balance for a given user."""
-        shortuid = userid.split(",")[0]
-        result = self.doSearch("(&(objectClass=pykotaUser)(%s))" % shortuid, ["pykotaBalance", "pykotaLifeTimePaid"])
-        if result :
-            fields = result[0][1]
-            return (float(fields["pykotaBalance"][0]), float(fields["pykotaLifeTimePaid"][0]))
-        else :    
-            return
-        
-    def getGroupBalance(self, groupid) :    
+    def getUserBalance(self, userquotaid) :    
+        """Returns the current account balance for a given user quota identifier."""
+        # first get the user's name from the user quota id
+        result = self.doSearch("objectClass=pykotaUserPQuota", ["pykotaUserName"], base=userquotaid, scope=ldap.SCOPE_BASE)
+        if result :
+            username = result[0][1]["pykotaUserName"][0]
+            result = self.doSearch("(&(objectClass=pykotaAccountBalance)(pykotaUserName=%s))" % username, ["pykotaBalance", "pykotaLifeTimePaid"])
+            if result :
+                fields = result[0][1]
+                return (float(fields["pykotaBalance"][0]), float(fields["pykotaLifeTimePaid"][0]))
+        
+    def getUserBalanceFromUserId(self, userid) :    
+        """Returns the current account balance for a given user id."""
+        # first get the user's name from the user id
+        result = self.doSearch("objectClass=pykotaAccount", ["pykotaUserName"], base=userid, scope=ldap.SCOPE_BASE)
+        if result :
+            username = result[0][1]["pykotaUserName"][0]
+            result = self.doSearch("(&(objectClass=pykotaAccountBalance)(pykotaUserName=%s))" % username, ["pykotaBalance", "pykotaLifeTimePaid"])
+            if result :
+                fields = result[0][1]
+                return (float(fields["pykotaBalance"][0]), float(fields["pykotaLifeTimePaid"][0]))
+        
+    def getGroupBalance(self, groupquotaid) :    
         """Returns the current account balance for a given group, as the sum of each of its users' account balance."""
-        groupname = groupid.split(",")[0].split("=")[1]
-        members = self.getGroupMembersNames(groupname)
-        balance = lifetimepaid = 0.0
-        for member in members :
-            userid = self.getUserId(member)
-            if userid :
-                userbal = self.getUserBalance(userid)
-                if userbal :
-                    (bal, paid) = userbal
-                    balance += bal
-                    lifetimepaid += paid
-        return (balance, lifetimepaid)            
+        # first get the group's name from the group quota id
+        result = self.doSearch("objectClass=pykotaGroupPQuota", ["pykotaGroupName"], base=groupquotaid, scope=ldap.SCOPE_BASE)
+        if result :
+            groupname = result[0][1]["pykotaGroupName"][0]
+            members = self.getGroupMembersNames(groupname)
+            balance = lifetimepaid = 0.0
+            for member in members :
+                userid = self.getUserId(member)
+                if userid :
+                    userbal = self.getUserBalanceFromUserId(userid)
+                    if userbal :
+                        (bal, paid) = userbal
+                        balance += bal
+                        lifetimepaid += paid
+            return (balance, lifetimepaid)            
         
     def getUserLimitBy(self, userid) :    
         """Returns the way in which user printing is limited."""
-        shortuid = userid.split(",")[0]
-        result = self.doSearch("(&(objectClass=pykotaUser)(%s))" % shortuid, ["pykotaLimitBy"])
+        result = self.doSearch("objectClass=pykotaAccount", ["pykotaLimitBy"], base=userid, scope=ldap.SCOPE_BASE)
         if result :
             return result[0][1]["pykotaLimitBy"][0]
-        else :    
-            return
-        
-    def getGroupLimitBy(self, groupid) :    
+        
+    def getGroupLimitBy(self, groupquotaid) :    
         """Returns the way in which group printing is limited."""
-        shortgid = groupid.split(",")[0]
-        result = self.doSearch("(&(objectClass=pykotaGroup)(%s))" % shortgid, ["pykotaLimitBy"])
-        if result :
-            return result[0][1]["pykotaLimitBy"][0]
-        else :    
-            return
+        # first get the group's name from the group quota id
+        result = self.doSearch("objectClass=pykotaGroupPQuota", ["pykotaGroupName"], base=groupquotaid, scope=ldap.SCOPE_BASE)
+        if result :
+            groupname = result[0][1]["pykotaGroupName"][0]
+            result = self.doSearch("(&(objectClass=pykotaGroup)(pykotaGroupName=%s))" % groupname, ["pykotaLimitBy"])
+            if result :
+                return result[0][1]["pykotaLimitBy"][0]
         
     def setUserBalance(self, userid, balance) :    
@@ -248,7 +259,8 @@
         pass
         
-    def getUserPQuota(self, userid, printerid) :
-        """Returns the Print Quota information for a given (userid, printerid)."""
-        result = self.doSearch("(&(objectClass=pykotaUserPQuota)(uid=*))", ["uid", "pykotaPageCounter", "pykotaLifePageCounter", "pykotaSoftLimit", "pykotaHardLimit", "pykotaDateLimit"], base=userid)
+    def getUserPQuota(self, userquotaid, printerid) :
+        """Returns the Print Quota information for a given (userquotaid, printerid)."""
+        # first get the user's name from the id
+        result = self.doSearch("objectClass=pykotaUserPQuota", ["pykotaUserName", "pykotaPageCounter", "pykotaLifePageCounter", "pykotaSoftLimit", "pykotaHardLimit", "pykotaDateLimit"], base=userquotaid, scope=ldap.SCOPE_BASE)
         if result :
             fields = result[0][1]
@@ -262,12 +274,11 @@
                      "datelimit" : datelimit
                    }
-        else :
-            return
-        
-    def getGroupPQuota(self, groupid, printerid) :
-        """Returns the Print Quota information for a given (groupid, printerid)."""
-        result = self.doSearch("(&(objectClass=pykotaGroupPQuota)(cn=*))", ["pykotaSoftLimit", "pykotaHardLimit", "pykotaDateLimit"], base=groupid)
+        
+    def getGroupPQuota(self, grouppquotaid, printerid) :
+        """Returns the Print Quota information for a given (grouppquotaid, printerid)."""
+        result = self.doSearch("objectClass=pykotaGroupPQuota", ["pykotaGroupName", "pykotaSoftLimit", "pykotaHardLimit", "pykotaDateLimit"], base=grouppquotaid, scope=ldap.SCOPE_BASE)
         if result :
             fields = result[0][1]
+            groupname = fields["pykotaGroupName"][0]
             datelimit = fields["pykotaDateLimit"][0].strip()
             if (not datelimit) or (datelimit.upper() == "NONE") : 
@@ -278,5 +289,4 @@
                       "datelimit" : datelimit
                     }
-            groupname = groupid.split(",")[0].split("=")[1]
             members = self.getGroupMembersNames(groupname)
             pagecounter = lifepagecounter = 0
@@ -291,6 +301,4 @@
             quota.update({"pagecounter": pagecounter, "lifepagecounter": lifepagecounter})                
             return quota
-        else :
-            return
         
     def setUserDateLimit(self, userid, printerid, datelimit) :
@@ -316,6 +324,4 @@
         if result :
             pass # TODO
-        else :
-            return 
         
     def addUserToGroup(self, userid, groupid) :    
Index: /pykota/trunk/pykota/version.py
===================================================================
--- /pykota/trunk/pykota/version.py (revision 1016)
+++ /pykota/trunk/pykota/version.py (revision 1017)
@@ -21,5 +21,5 @@
 #
 
-__version__ = "1.08alpha5_unofficial"
+__version__ = "1.08alpha6_unofficial"
 
 __doc__ = """PyKota : a complete Printing Quota Solution for CUPS and LPRng."""
Index: /pykota/trunk/bin/repykota
===================================================================
--- /pykota/trunk/bin/repykota (revision 1005)
+++ /pykota/trunk/bin/repykota (revision 1017)
@@ -23,4 +23,8 @@
 #
 # $Log$
+# Revision 1.36  2003/06/06 14:21:08  jalet
+# New LDAP schema.
+# Small bug fixes.
+#
 # Revision 1.35  2003/05/28 13:56:24  jalet
 # Unneeded code.
@@ -256,5 +260,5 @@
                 (balance, lifetimepaid) = balance
             else :    
-                (balance, lifetimepaid) = 0.0
+                (balance, lifetimepaid) = (0.0, 0.0)
             if datelimit is not None :
                 now = DateTime.now()
@@ -274,4 +278,6 @@
             print "%-9.9s %s %7i %7s %7s %10s %-10.10s %8i %10s" % (name, reached, pagecounter, str(softlimit), str(hardlimit), strbalance, str(datelimit)[:10], lifepagecounter, strlifetimepaid)
             return (lifepagecounter, lifetimepaid)
+        else :    
+            return (0, 0)
         
                     
Index: /pykota/trunk/initscripts/ldap/pykota-sample.ldif
===================================================================
--- /pykota/trunk/initscripts/ldap/pykota-sample.ldif (revision 1015)
+++ /pykota/trunk/initscripts/ldap/pykota-sample.ldif (revision 1017)
@@ -4,5 +4,5 @@
 # $Id$
 #
-# 
+ 
 dn: ou=People,dc=librelogiciel,dc=com
 ou: People
@@ -13,6 +13,26 @@
 objectClass: organizationalUnit
 
-dn: ou=Printers,dc=librelogiciel,dc=com
+dn: ou=PyKota,dc=librelogiciel,dc=com
+ou: PyKota
+objectClass: organizationalUnit
+
+dn: ou=Printers,ou=PyKota,dc=librelogiciel,dc=com
 ou: Printers
+objectClass: organizationalUnit
+
+dn: ou=UQuotas,ou=PyKota,dc=librelogiciel,dc=com
+ou: UQuotas
+objectClass: organizationalUnit
+
+dn: ou=GQuotas,ou=PyKota,dc=librelogiciel,dc=com
+ou: GQuotas
+objectClass: organizationalUnit
+
+dn: ou=Jobs,ou=PyKota,dc=librelogiciel,dc=com
+ou: Jobs
+objectClass: organizationalUnit
+
+dn: ou=LastJobs,ou=PyKota,dc=librelogiciel,dc=com
+ou: LastJobs
 objectClass: organizationalUnit
 
@@ -24,5 +44,6 @@
 objectClass: top
 objectClass: shadowAccount
-objectClass: pykotaUser
+objectClass: pykotaAccount
+objectClass: pykotaAccountBalance
 userPassword: {crypt}PvuIT4Mz8.lCM
 shadowLastChange: 12093
@@ -34,7 +55,8 @@
 homeDirectory: /home/jerome
 gecos: Jerome Alet,,,
+pykotaUserName: jerome
 pykotaLimitBy: quota
-pykotaBalance: 0
-pykotaLifeTimePaid: 0
+pykotaBalance: 9.25
+pykotaLifeTimePaid: 10
 
 dn: cn=devel,ou=Groups,dc=librelogiciel,dc=com
@@ -46,47 +68,52 @@
 gidNumber: 500
 memberUid: jerome
+pykotaGroupName: devel
 pykotaLimitBy: quota
 
-dn: pykotaPrinterName=apple,ou=Printers,dc=librelogiciel,dc=com
+dn: cn=apple,ou=Printers,ou=PyKota,dc=librelogiciel,dc=com
+objectClass: pykotaNamed
 objectClass: pykotaPrinter
+cn: apple
 pykotaPrinterName: apple
 pykotaPricePerPage: 0.1
 pykotaPricePerJob: 0.25
 
-dn: ou=userPQuotas,pykotaPrinterName=apple,ou=Printers,dc=librelogiciel,dc=com
-ou: userPQuotas
-objectClass: organizationalUnit
-
-dn: ou=groupPQuotas,pykotaPrinterName=apple,ou=Printers,dc=librelogiciel,dc=com
-ou: groupPQuotas
-objectClass: organizationalUnit
-
-dn: ou=Jobs,pykotaPrinterName=apple,ou=Printers,dc=librelogiciel,dc=com
-ou: Jobs
-objectClass: organizationalUnit
-
-dn: uid=jerome,ou=userPQuotas,pykotaPrinterName=apple,ou=Printers,dc=librelogiciel,dc=com
+dn: cn=uniqueidentifier01,ou=UQuotas,ou=PyKota,dc=librelogiciel,dc=com
+objectClass: pykotaNamed
 objectClass: pykotaUserPQuota
-uid: jerome
-pykotaPageCounter: 0
-pykotaLifePageCounter: 0
+cn: uniqueidentifier01
+pykotaUserName: jerome
+pykotaPrinterName: apple
+pykotaPageCounter: 5
+pykotaLifePageCounter: 5
 pykotaSoftLimit: 100
 pykotaHardLimit: 110
 pykotaDateLimit: None
 
-dn: cn=devel,ou=groupPQuotas,pykotaPrinterName=apple,ou=Printers,dc=librelogiciel,dc=com
+dn: cn=uniqueidentifier02,ou=GQuotas,ou=PyKota,dc=librelogiciel,dc=com
+objectClass: pykotaNamed
 objectClass: pykotaGroupPQuota
-cn: devel
+cn: uniqueidentifier02
+pykotaGroupName: devel
+pykotaPrinterName: apple
 pykotaSoftLimit: 400
 pykotaHardLimit: 450
 pykotaDateLimit: None
 
-dn: pykotaJobHistoryId=1,ou=Jobs,pykotaPrinterName=apple,ou=Printers,dc=librelogiciel,dc=com
-objectClass: pykotaPrinterJob
-pykotaJobHistoryId: 1
+dn: cn=uniqueidentifier03,ou=Jobs,ou=PyKota,dc=librelogiciel,dc=com
+objectClass: pykotaNamed
+objectClass: pykotaJob
+cn: uniqueidentifier03
+pykotaUserName: jerome
+pykotaPrinterName: apple
 pykotaJobId: 15
-uid: jerome
 pykotaPrinterPageCounter: 1533
 pykotaJobSize: 5
 pykotaAction: ALLOW
-pykotaJobDate: 2003-06-04 16:12
+
+dn: cn=uniqueidentifier04,ou=LastJobs,ou=PyKota,dc=librelogiciel,dc=com
+objectClass: pykotaNamed
+objectClass: pykotaLastJob
+cn: uniqueidentifier04
+pykotaPrinterName: apple
+pykotaLastJobUUID: uniqueidentifier03
Index: /pykota/trunk/initscripts/ldap/pykota.schema
===================================================================
--- /pykota/trunk/initscripts/ldap/pykota.schema (revision 1015)
+++ /pykota/trunk/initscripts/ldap/pykota.schema (revision 1017)
@@ -16,4 +16,6 @@
 #
 #
+# Contributors : Leif Johansson
+#
 # THIS IS WORK UNDER HEAVY DEVELOPPMENT !
 #
@@ -24,6 +26,9 @@
 #
 
-## Pykota related LDAP attributes
+#        
+# PyKota Attributes Types
+#
 
+# pykotaLimitBy
 attributetype ( 1.3.6.1.4.1.16868.1.1.1 NAME 'pykotaLimitBy'
         DESC 'How to limit the user/group : quota or balance'
@@ -31,4 +36,5 @@
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
 
+# pykotaBalance
 attributetype ( 1.3.6.1.4.1.16868.1.1.2 NAME 'pykotaBalance'
         DESC 'Current account balance for the user, float'
@@ -36,4 +42,5 @@
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
 
+# pykotaLifeTimePaid
 attributetype ( 1.3.6.1.4.1.16868.1.1.3 NAME 'pykotaLifeTimePaid'
         DESC 'Total money paid by the user to fill his account balance, float'
@@ -41,4 +48,5 @@
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
 
+# pykotaPricePerPage
 attributetype ( 1.3.6.1.4.1.16868.1.1.4 NAME 'pykotaPricePerPage'
         DESC 'Price per page for a printer, float'
@@ -46,4 +54,5 @@
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
 
+# pykotaPricePerJob
 attributetype ( 1.3.6.1.4.1.16868.1.1.5 NAME 'pykotaPricePerJob'
         DESC 'Price per job for a printer, float'
@@ -51,99 +60,137 @@
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
 
-attributetype ( 1.3.6.1.4.1.16868.1.1.6 NAME 'pykotaPrinterName'
-        DESC 'Printer name as defined in the printing environment, e.g. lp'
-        EQUALITY caseIgnoreIA5Match
-        SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
-
-attributetype ( 1.3.6.1.4.1.16868.1.1.7 NAME 'pykotaSoftLimit'
+# pykotaSoftLimit
+attributetype ( 1.3.6.1.4.1.16868.1.1.6 NAME 'pykotaSoftLimit'
         DESC 'Soft limit in maximal number of pages'
         EQUALITY integerMatch
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
         
-attributetype ( 1.3.6.1.4.1.16868.1.1.8 NAME 'pykotaHardLimit'
+# pykotaHardLimit        
+attributetype ( 1.3.6.1.4.1.16868.1.1.7 NAME 'pykotaHardLimit'
         DESC 'Hard limit in maximal number of pages'
         EQUALITY integerMatch
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
 
-attributetype ( 1.3.6.1.4.1.16868.1.1.9 NAME 'pykotaDateLimit'
+# pykotaDateLimit
+attributetype ( 1.3.6.1.4.1.16868.1.1.8 NAME 'pykotaDateLimit'
         DESC 'Date at which the soft limit becomes a hard one'
         EQUALITY caseIgnoreIA5Match
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
 
-attributetype ( 1.3.6.1.4.1.16868.1.1.10 NAME 'pykotaPageCounter'
+# pykotaPageCounter
+attributetype ( 1.3.6.1.4.1.16868.1.1.9 NAME 'pykotaPageCounter'
         DESC 'Current page counter for the user on a particular printer'
         EQUALITY integerMatch
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
 
-attributetype ( 1.3.6.1.4.1.16868.1.1.11 NAME 'pykotaLifePageCounter'
+# pykotaLifePageCounter
+attributetype ( 1.3.6.1.4.1.16868.1.1.10 NAME 'pykotaLifePageCounter'
         DESC 'Total page counter for the user on a particular printer'
         EQUALITY integerMatch
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
 
-attributetype ( 1.3.6.1.4.1.16868.1.1.12 NAME 'pykotaJobHistoryId'
-        DESC 'Id of an entry in a printer history of jobs'
-        EQUALITY integerMatch
-        SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+# pykotaJobId
+attributetype ( 1.3.6.1.4.1.16868.1.1.11 NAME 'pykotaJobId'
+        DESC 'Id of a job in a printer history of jobs'
+        EQUALITY caseExactIA5Match
+        SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
 
-attributetype ( 1.3.6.1.4.1.16868.1.1.13 NAME 'pykotaJobId'
-        DESC 'Id of a job in a printer history of jobs'
-        EQUALITY integerMatch
-        SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
-
-attributetype ( 1.3.6.1.4.1.16868.1.1.14 NAME 'pykotaPrinterPageCounter'
+# pykotaPrinterPageCounter
+attributetype ( 1.3.6.1.4.1.16868.1.1.12 NAME 'pykotaPrinterPageCounter'
         DESC 'Life time page counter of a printer when the job began'
         EQUALITY integerMatch
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
 
-attributetype ( 1.3.6.1.4.1.16868.1.1.15 NAME 'pykotaJobSize'
+# pykotaJobSize
+attributetype ( 1.3.6.1.4.1.16868.1.1.13 NAME 'pykotaJobSize'
         DESC 'Current job size in number of pages in the history'
         EQUALITY integerMatch
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
 
-attributetype ( 1.3.6.1.4.1.16868.1.1.16 NAME 'pykotaAction'
+# pykotaAction
+attributetype ( 1.3.6.1.4.1.16868.1.1.14 NAME 'pykotaAction'
         DESC 'Was the job allowed, or denied'
         EQUALITY caseIgnoreIA5Match
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
         
-attributetype ( 1.3.6.1.4.1.16868.1.1.17 NAME 'pykotaJobDate'
-        DESC 'Date of when the job began'
+# pykotaPrinterName        
+attributetype ( 1.3.6.1.4.1.16868.1.1.15 NAME 'pykotaPrinterName'
+        DESC 'PyKota printer name as received from the printing subsystem'
         EQUALITY caseIgnoreIA5Match
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
+        
+# pykotaUserName        
+attributetype ( 1.3.6.1.4.1.16868.1.1.16 NAME 'pykotaUserName'
+        DESC 'PyKota user name'
+        EQUALITY caseExactIA5Match
+        SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
+        
+# pykotaGroupName        
+attributetype ( 1.3.6.1.4.1.16868.1.1.17 NAME 'pykotaGroupName'
+        DESC 'PyKota group name'
+        EQUALITY caseExactIA5Match
+        SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
+        
+# pykotaLastJobUUID        
+attributetype ( 1.3.6.1.4.1.16868.1.1.18 NAME 'pykotaLastJobUUID'
+        DESC 'Last job uuid in the history'
+        EQUALITY caseExactIA5Match
+        SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
+        
+#        
+# PyKota Object Classes
+#
 
-
-## New Pykota User object type
-objectclass ( 1.3.6.1.4.1.16868.1.2.1 NAME 'pykotaUser' SUP top AUXILIARY
+# pykotaUser
+objectclass ( 1.3.6.1.4.1.16868.1.2.1 NAME 'pykotaAccount' SUP top AUXILIARY
         DESC 'PyKota Auxiliary User Account'
-        MUST ( uid )
-        MAY  ( pykotaLimitBy $ pykotaBalance $ pykotaLifeTimePaid ) )
+        MUST ( uid $ pykotaUserName )
+        MAY  ( pykotaLimitBy ) )
         
-## New Pykota Group object type
+# pykotaGroup        
 objectclass ( 1.3.6.1.4.1.16868.1.2.2 NAME 'pykotaGroup' SUP top AUXILIARY
         DESC 'PyKota Auxiliary Group'
-        MUST ( cn )
-        MAY  ( pykotaLimitBy ) )
+        MUST ( cn $ pykotaGroupName )
+        MAY  ( pykotaLimitBy $ memberUid ) )
         
-## New Pykota Printer object type
-objectclass ( 1.3.6.1.4.1.16868.1.2.3 NAME 'pykotaPrinter' SUP top STRUCTURAL
+# pykotaPrinter        
+objectclass ( 1.3.6.1.4.1.16868.1.2.3 NAME 'pykotaPrinter' SUP top AUXILIARY
         DESC 'PyKota Printer'
-        MUST ( pykotaPrinterName )
+        MUST ( cn $ pykotaPrinterName )
         MAY  ( pykotaPricePerPage $ pykotaPricePerJob ) )
         
-## New PyKota User Print Quota on a Printer        
-objectclass ( 1.3.6.1.4.1.16868.1.2.4 NAME 'pykotaUserPQuota' SUP top STRUCTURAL
+# pykotaUserPQuota        
+objectclass ( 1.3.6.1.4.1.16868.1.2.4 NAME 'pykotaUserPQuota' SUP top AUXILIARY
         DESC 'PyKota User Quota on a Printer'
-        MUST ( uid )
+        MUST ( cn $ pykotaUserName $ pykotaPrinterName )
         MAY  ( pykotaPageCounter $ pykotaLifePageCounter $ pykotaSoftLimit $ pykotaHardLimit $ pykotaDateLimit ) )
         
-## New PyKota Group Print Quota on a Printer        
-objectclass ( 1.3.6.1.4.1.16868.1.2.5 NAME 'pykotaGroupPQuota' SUP top STRUCTURAL
+# pykotaGroupPQuota        
+objectclass ( 1.3.6.1.4.1.16868.1.2.5 NAME 'pykotaGroupPQuota' SUP top AUXILIARY
         DESC 'PyKota Group Quota on a Printer'
-        MUST ( cn )
+        MUST ( cn $ pykotaGroupName $ pykotaPrinterName )
         MAY  ( pykotaSoftLimit $ pykotaHardLimit $ pykotaDateLimit ) )
         
-## New PyKota Job entry in a Printer's history        
-objectclass ( 1.3.6.1.4.1.16868.1.2.6 NAME 'pykotaPrinterJob' SUP top STRUCTURAL
+# pykotaJob        
+objectclass ( 1.3.6.1.4.1.16868.1.2.6 NAME 'pykotaJob' SUP top AUXILIARY
         DESC 'An entry in the job history for a printer'
-        MUST ( pykotaJobHistoryId $ uid $ pykotaJobId )
-        MAY  ( pykotaPrinterPageCounter $ pykotaJobSize $ pykotaAction $ pykotaJobDate ) )
+        MUST ( cn $ pykotaUserName $ pykotaPrinterName $ pykotaJobId )
+        MAY  ( pykotaPrinterPageCounter $ pykotaJobSize $ pykotaAction ) )
         
+# pykotaAccountBalance
+objectclass ( 1.3.6.1.4.1.16868.1.2.7 NAME 'pykotaAccountBalance' SUP top AUXILIARY
+        DESC 'PyKota User account balance'
+        MUST ( pykotaUserName )
+        MAY  ( pykotaBalance $ pykotaLifeTimePaid ) )
+        
+# pykotaLastJob        
+objectclass ( 1.3.6.1.4.1.16868.1.2.8 NAME 'pykotaLastJob' SUP top AUXILIARY
+        DESC 'Last job information for a printer'
+        MUST ( pykotaPrinterName $ pykotaLastJobUUID ) )
+        
+# pykotaNamed - Use it if you have to 
+objectclass ( 1.3.6.1.4.1.16868.1.2.9 NAME 'pykotaNamed' SUP top STRUCTURAL
+        DESC 'PyKota Named Object'
+        MUST ( cn ) )
+        
+        
Index: /pykota/trunk/NEWS
===================================================================
--- /pykota/trunk/NEWS (revision 1016)
+++ /pykota/trunk/NEWS (revision 1017)
@@ -22,8 +22,13 @@
 PyKota NEWS :
 
+    - 1.08alpha6 : 
+    
+        - Minor bug corrections
+        - More work on LDAP : new schema
+        
     - 1.08alpha5 :
     
-        More good work on LDAP storage.
-        repykota now works reasonably well with the sample LDAP directory.
+        - More good work on LDAP storage.
+          repykota now works reasonably well with the sample LDAP directory.
         
     - 1.08alpha4 :
