Advertisement
Guest User

pyffle_data.py

a guest
Jun 10th, 2017
96
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 47.53 KB | None | 0 0
  1. #!/usr/bin/env python
  2. ###
  3. ###    This file is part of Pyffle BBS.
  4. ###
  5. ###    Pyffle BBS is free software: you can redistribute it and/or modify
  6. ###    it under the terms of the GNU General Public License as published by
  7. ###    the Free Software Foundation, either version 3 of the License, or
  8. ###    (at your option) any later version.
  9. ###
  10. ###    Pyffle BBS is distributed in the hope that it will be useful,
  11. ###    but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ###    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13. ###    GNU General Public License for more details.
  14. ###
  15. ###    You should have received a copy of the GNU General Public License
  16. ###    along with Foobar.  If not, see <http://www.gnu.org/licenses/>.
  17. ###
  18. ###
  19.  
  20.  
  21.  
  22. ## Models for SqlAlchemy version 6
  23. from sqlalchemy.ext.declarative import declarative_base
  24. from sqlalchemy.orm import relation, backref
  25. from sqlalchemy import *
  26. from sqlalchemy.dialects.postgresql import *
  27. from sqlalchemy.orm import sessionmaker
  28. from pyffle_tables import *
  29. from datetime import datetime
  30. from pyffle_dispatch import PyffleDispatch
  31. import os
  32. import psutil
  33. from threading import Lock
  34. ### This is the central class for Pyffle - it deals with:
  35. ###
  36. ###  - Message creation/updating/deleting/querying
  37. ###  - Logging
  38. ###  - Security / ACL/ACE ops
  39. ###  - Various housekeeping tasks
  40. ###
  41. ###  Almost everything in the system has a pointer to an
  42. ###  instance of this class and it is the central "switchboard"
  43. ###  of the system.
  44. ###  
  45. ###  Additionally there are calls to and from the Utility class
  46. ###  which provides string formatting and I/O etc, that are typically
  47. ###  accessed through the data.util. handle.
  48. ###  
  49. ###  On start up, Pyffle (and stand alone tools), create an instance
  50. ###  of PyffleData once a DB session has been set up, and connect it with
  51. ###  an instance of PyffleUtility
  52. ###  
  53. ###  PS: I know this should be refactored :)
  54. ###  
  55. ###  sampsa
  56.  
  57. class PyffleData:
  58.     currentUser = None          ## The currently logged in user, set by PyffleMain typically
  59.     currentBoard = None         ## The currently selected message board
  60.  
  61.  
  62.     buddyListHasBeenShown = False       ## FIXME - module loading issue...Hard to fix.
  63.     session = None              ## Database sesson
  64.     util = None                 ## Instance of PyffleUtility, set by PyffleMain typically
  65.     static = None               ## Loaded configuration from STATIC file, dictionary
  66.  
  67.     toolMode = False            ## This is set to true when running as a standalone tool to bypass the SRM
  68.  
  69.     mtaModules = {}             ## Modules for MTAs that handle external mail
  70.     mtas = []                   ## mta entry = [mta module name to be loaded, mta name, mta description]
  71.  
  72.     loggedIn = False
  73.     sessionRef = None           ## id into currentlyon table
  74.    
  75.     staticCookies = None
  76.     loggingOff = False
  77.     sessionLock = None
  78.     sessionLocked = False
  79.     himclient = None ## ugly hack until  we get the instantiation thing ironed out
  80.     instances = {}
  81.     def __init__ (self):
  82.         ## self.sessionLock = Lock()
  83.         pass
  84.    
  85.  
  86.     #####VERSION STRINGS####    - fixme, should be pulled from git or something
  87.     def getPyffleVersionString(self):
  88.         return 'Pyffle v1.37.42 "Creaky Elevator"'
  89.        
  90.     ## Returns a short form of the version string
  91.     def getPyffleVersionShortString(self):
  92.         return "1.37.42"
  93.  
  94.     def getStaticCookies(self):
  95.         rv = []
  96.         if self.staticCookies == None:
  97.             self.staticCookies = self.util.texts["SYSTEM"]["cookies"].split("|")
  98.         rv = self.staticCookies
  99.         return rv
  100.     ## easiest way to do multithreading - grab a local copy of the DB session...
  101.     def getLocalSession(self):
  102.         Session = sessionmaker()
  103.        
  104.         ##      engine = create_engine('postgresql://postgres:f00btron@localhost/pyffledev', echo=False)
  105.         engine = create_engine(self.static.options['pyffle.dburl'], echo = False)
  106.         Session.configure(bind=engine)
  107.        
  108.         localSession = Session()       
  109.         return localSession
  110.        
  111.     def getSession(self):
  112.         return self.session
  113.    
  114.     def lockSession(self):
  115.         ##self.sessionLock.acquire()
  116.         ##self.sessionLocked = True
  117.         pass
  118.        
  119.     def releaseSession(self):
  120.         ##if self.sessionLocked:
  121.         ##  self.sessionLock.release()
  122.         ##  self.sessionLocked = False 
  123.         pass
  124.        
  125.  
  126.     def pluginDeleteSystem(self,key):
  127.         if not self.currentUser == None:
  128.             username = self.currentUser.username
  129.         else:
  130.             username = "<none>"
  131.         self.lockSession()
  132.         for object in self.getSession().query(Pluginsystem).filter(Pluginsystem.key == key):
  133.             self.getSession().delete(object)
  134.             self.getSession().commit()
  135.             self.logEntry(self.LOGINFO,"DELETE/PLUGIN/SYSTEM",str(username),"Deleted |%s|=|%s|" % (str(key),str(object.value)))
  136.         self.releaseSession()
  137.            
  138.     def pluginDeleteUser(self,username,key):
  139.         self.lockSession()
  140.         for object in self.getSession().query(Pluginuser).filter(Pluginuser.key == key).filter(Pluginuser.username == username):
  141.             self.getSession().delete(object)
  142.             self.getSession().commit()
  143.             self.logEntry(self.LOGINFO,"DELETE/PLUGIN/USER",str(username),"Deleted %s's |%s|=|%s|" % (str(username),str(key),str(object.value)))
  144.         self.releaseSession()
  145.            
  146.     def pluginWriteSystem(self,key,value):
  147.         if not self.currentUser == None:
  148.             username = self.currentUser.username
  149.         else:
  150.             username = "<none>"
  151.  
  152.         self.pluginDeleteSystem(key)
  153.         object = Pluginsystem()
  154.         object.key=key
  155.         object.value=value
  156.         self.lockSession()
  157.         self.getSession().add(object)
  158.         self.getSession().commit()
  159.         self.releaseSession()
  160.         self.logEntry(self.LOGINFO,"CREATE/PLUGIN/SYSTEM",str(username),"Stored |%s|=|%s|" % (str(key),str(value)))
  161.        
  162.     def pluginWriteUser(self,username,key,value):
  163.         self.pluginDeleteUser(username,key)
  164.         object = Pluginuser()
  165.         object.username=username
  166.         object.key=key
  167.         object.value=value
  168.         self.lockSession()
  169.         self.getSession().add(object)
  170.         self.getSession().commit()
  171.         self.releaseSession()
  172.         self.logEntry(self.LOGINFO,"CREATE/PLUGIN/USER",str(username),"Stored %s's |%s|=|%s|" % (str(username),str(key),str(value)))
  173.  
  174.     def pluginReadSystem(self,key):
  175.         if not self.currentUser == None:
  176.             username = self.currentUser.username
  177.         else:
  178.             username = "<none>"
  179.  
  180.         rv = None
  181.         self.lockSession()
  182.         for object in self.getSession().query(Pluginsystem).filter(Pluginsystem.key == key):
  183.             rv = object.value
  184.             self.logEntry(self.LOGINFO,"READ/PLUGIN/SYSTEM",str(username),"Read |%s|=|%s|" % (str(key),str(rv)))
  185.             break
  186.         self.releaseSession()
  187.  
  188.         return rv
  189.        
  190.                    
  191.     def pluginReadUser(self,username,key):
  192.         rv = None
  193.         for object in self.getSession().query(Pluginuser).filter(Pluginuser.key == key).filter(Pluginuser.username == username):
  194.             rv = object.value
  195.             self.logEntry(self.LOGINFO,"READ/PLUGIN/USER",str(username),"Read %s's |%s|=|%s|" % (str(username),str(key),str(rv)))
  196.             break
  197.         return rv
  198.        
  199. ## Logging functions start
  200.  
  201. ###
  202. ### Logging criticality levels
  203. ###
  204.     LOGCRIT = 5
  205.     LOGWARN = 4
  206.     LOGNORMAL = 3
  207.     LOGINFO = 2
  208.     LOGDEBUG = 1
  209.    
  210.     LOGLEVEL=3
  211.     ## Post an entry to the log
  212.     def logEntry(self,level,code,subject,description):
  213.         #print "LOG ENTRY CALLED"
  214.         if self.loggingOff == True:
  215.             return
  216.         else:
  217.             # HACK
  218.             if level >= self.LOGLEVEL:
  219.                 entry = Logentry()
  220.                 entry.level = level
  221.                 entry.code = code
  222.                 entry.subject = subject
  223.                 entry.description = description
  224.                 entry.date = datetime.now()
  225.                 self.getSession().add(entry)
  226.                 self.getSession().commit()
  227.        
  228.     ## Returns the name of the previous caller from the system log
  229.     def getLastUser(self)
  230.         ## since our call has already been logged, grab the one before us
  231.         ## FIXME - check for None
  232.         lastUsers = self.getLastUsers(2)
  233.         if lastUsers == None or len(lastUsers) < 2:
  234.             return "  "
  235.         else:
  236.             return lastUsers[1]
  237.    
  238.     ## Log a loginfailure
  239.     def logLoginFail(self,username,reason="Bad credentials."):
  240.         self.logEntry(self.LOGWARN,"LOGIN/FAILURE",str(username),"%s failed to log in, %s" % (str(username),str(reason)))
  241.  
  242.  
  243.     def setCurrentlyonActivity(self, activity):
  244.         entries = self.getSession().query(Currentlyon).filter(Currentlyon.id == self.sessionRef)
  245.         entry = entries.first()
  246.  
  247.         if not entry == None:
  248.             entry.activity  = activity
  249.            
  250.             self.getSession().add(entry)
  251.             self.getSession().commit()
  252.             return entry.id
  253.         else:
  254.             return None
  255.    
  256.     def addToCurrentlyon(self):
  257.         entry = Currentlyon()
  258.         entry.activity  = ""
  259.         entry.origin        = ""        ## FIXME - add origin here
  260.         entry.username  = self.currentUser.username
  261.         entry.dateon        = datetime.now()
  262.         entry.pid           = os.getpid()
  263.         self.getSession().add(entry)
  264.         self.getSession().commit()
  265.         self.sessionRef = entry.id
  266.    
  267.     def resetCurrentlyOn(self):
  268.         for entry in    self.getSession().query(Currentlyon):
  269.             self.getSession().delete(entry)
  270.             self.getSession().commit()
  271.             self.sessionRef = None
  272.            
  273.  
  274.     def purgeLogentries(self, maxEntries):
  275.         entries = self.getSession().query(Logentry).order_by(desc(Logentry.date))
  276.         count = 0
  277.         for entry in entries:
  278.             count = count + 1
  279.             if count > maxEntries:
  280.                 self.getSession().delete(entry)
  281.         self.getSession().commit()
  282.            
  283.     def removeFromCurrentlyon(self):
  284.         for entry in    self.getSession().query(Currentlyon).filter(Currentlyon.id == self.sessionRef):
  285.             self.getSession().delete(entry)
  286.             self.getSession().commit()
  287.             self.sessionRef = None
  288.        
  289.     def getCurrentlyonEntries(self):
  290.         rv = []
  291.         entries =   self.getSession().query(Currentlyon)
  292.         for entry in entries:
  293.             ## check that the entry is still valid (i.e. the process is still running)
  294.             if psutil.pid_exists(entry.pid):
  295.                 ## print "%s is still valid" % (entry.pid)
  296.                 rv.append(entry)
  297.             else:
  298.                 ## print "%s is a stale PID, deleting" % (entry.pid)
  299.                 ## it's not, remove from the table
  300.                 self.getSession().delete(entry)
  301.                 self.getSession().commit()
  302.         return rv
  303.        
  304.        
  305.     ## Log a succesful start to session
  306.     def logCall(self):
  307.         loggedIn = True
  308.         self.addToCurrentlyon()
  309.         if self.currentUser.timescalled == None:
  310.             self.currentUser.timescalled = 0
  311.         self.currentUser.timescalled = int(self.currentUser.timescalled) + 1
  312.         self.getSession().add(self.currentUser)
  313.         self.getSession().commit()
  314.         self.logEntry(self.LOGNORMAL,"LOGIN/SUCCESS",self.currentUser.username,"%s logged in normally" % (self.currentUser.username))
  315.  
  316.     ## Log a succesful logout
  317.     def logLogout(self):
  318.         self.removeFromCurrentlyon()
  319.         loggedIn = False
  320.         self.currentUser.datefastlogin = datetime.now()
  321.         if self.currentUser.datefirstlogin == None:
  322.             self.currentUser.datefirstlogin = self.currentUser.datefastlogin
  323.         self.getSession().add(self.currentUser)
  324.         self.getSession().commit()
  325.         self.logEntry(self.LOGNORMAL,"LOGOUT/SUCCESS",self.currentUser.username,"%s logged out normally" % (self.currentUser.username))
  326.    
  327.     ## Return a list of num x log entries, each entry being a list:
  328.     ## [entry.level,entry.code,entry.subject,entry.date,entry.description]
  329.     def getLog(self,num = 22, level = -1):
  330.         rv = []
  331.         i = 0
  332.         for entry in self.getSession().query(Logentry).filter(Logentry.level >= level).order_by(Logentry.date.desc()):
  333.             rv.append([entry.level,entry.code,entry.subject,entry.date,entry.description,entry.id])
  334.             i = i + 1
  335.             if i == num:
  336.                 break
  337.         return rv
  338.    
  339.     def _getLog(self,num = 22, level = -1):
  340.         rv = []
  341.         i = 0
  342.         for entry in self.getSession().query(Logentry).filter(Logentry.level >= level).order_by(Logentry.id.asc()):
  343.             rv.append([entry.level,entry.code,entry.subject,entry.date,entry.description,entry.id])
  344.             i = i + 1
  345.             if i == num:
  346.                 break
  347.         return rv
  348.  
  349.     ## Returns the amount of calls to the system from the system log
  350.     def getSystemCalls(self):
  351.         rv = self.getSession().query(Logentry).filter(Logentry.code == "LOGIN/SUCCESS").count()
  352.         return rv
  353.    
  354.     ## Returns a list of num last callers, each entry being a list of:
  355.     ## [subject == caller username, date]
  356.     def getLastUsers(self,num = 20):
  357.         rv = []
  358.         i = 0
  359.         for entry in self.getSession().query(Logentry).filter(Logentry.code == "LOGIN/SUCCESS").order_by(Logentry.date.desc()):
  360.             rv.append([entry.subject,entry.date])
  361.             i = i + 1
  362.             if i > num:
  363.                 break
  364.         return rv
  365.        
  366.    
  367. ### MTA functions start
  368.    
  369.     ## Imports the modules for the mtas given  
  370.     def loadMtaList(self,mtas):
  371.         ### single mta = [module.py, mta name, mta description]
  372.         self.mtas = mtas
  373.         for mta in mtas:
  374.             self.mtaModules[mta[1]] = (__import__(mta[0]))
  375.  
  376.  
  377.     ## Loops through out MTAs and tries to parse an external addres
  378.     ## to match an internal user. Returns a string if the parsing was succesful,
  379.     ## None if not
  380.     def parseIncomingAddress(self,toname):
  381.         toname = toname.strip()
  382.         self.util.debugln("TONAME=" + toname)
  383.         if self.userExists(toname):
  384.             ## Got a local user, great, this will be simple
  385.             return toname;
  386.         else:
  387.             ## OK, the user is remote - let's see if anybody will accept delivery
  388.             self.util.debugln("Address not local, checking MTAs")
  389.             for mtaName in self.mtaModules.keys():
  390.                 ## Loop through our MTAs, instantiating each one until
  391.                 ## we get one that accepts the address
  392.                 mta = self.mtaModules[mtaName]
  393.                 mtaInstance = mta.PyffleMta()
  394.                 mtaInstance.data = self
  395.                 mtaInstance.currentUser = self.currentUser
  396.                 if mtaInstance.matchIncomingAddress(toname):
  397.                     username,system = mtaInstance.parseIncomingAddress(toname)
  398.                     ## FIXME: check destination system name here too
  399.                     if (not username == None) and (not username == ""):
  400.                         ## Cool, this MTA likes the address, let's jump out of this
  401.                         self.util.debugln("MTA " + mtaName + " thinks this is for " + username)
  402.                         return username                
  403.             ## Address doesn't appear to be valid - bork, return without sending or storing anything
  404.             self.util.debugln("Destination address invalid, no MTA will accept destination")
  405.             return None
  406.            
  407.  
  408. ### Event dispatcher
  409.     dispatcher = None
  410.     def setDispatcher(self,d):
  411.         self.dispatcher = d
  412.  
  413.     def stateChange(self,s,params=None):
  414.         self.dispatcher.stateChange(s,args=params)
  415.  
  416. ### Housekeeping / misc functions start
  417.  
  418.     ## Returns a string describing the amount of time the user has left.
  419.     ## Not implemented.
  420.     def getTimeLeft(self):
  421.         return "59 mins"
  422.        
  423.                
  424.     ## Returns the username of the system operator
  425.     def getSysopId(self):
  426.         return "system"         ## FIXME Static?
  427.  
  428.  
  429.     def getNodename(self):
  430.         return self.static.options["node"] 
  431.  
  432. ### JOIN functions start...
  433.     def unjoinByBoardid(self, boardid, username = None):
  434.         if username == None:
  435.             username = self.currentUser.username
  436.  
  437.         for join in self.getSession().query(Joinedboard).filter(Joinedboard.boardid == boardid).filter(Joinedboard.username == username):
  438.             self.getSession().delete(join)
  439.             self.getSession().commit()
  440.         self.logEntry(self.LOGNORMAL,"UNJOIN/BOARD","BOARDID:" + str(boardid),"%s UNJOINed %s " % (username,str(boardid)))
  441.  
  442.     def joinAll(self,username = None):
  443.  
  444.         if username == None:
  445.             username = self.currentUser.username
  446.         for boardid in self.getBoardids():
  447.             self.joinByBoardid(boardid,username)
  448.  
  449.        
  450.     def unjoinAll(self,username = None):
  451.  
  452.         if username == None:
  453.             username = self.currentUser.username
  454.  
  455.         for boardid in self.getJoinedBoardids():
  456.             self.unjoinByBoardid(boardid,username)
  457.            
  458.     def joinByBoardid(self, boardid, username = None):
  459.  
  460.         if username == None:
  461.             username = self.currentUser.username
  462.  
  463.         if self.isJoinedByBoardid(boardid,username):
  464.             return ## Already joined
  465.         join  = Joinedboard()
  466.         join.username = username
  467.         join.boardid = boardid
  468.         self.getSession().add(join)
  469.         self.getSession().commit()
  470.        
  471.         self.logEntry(self.LOGNORMAL,"JOIN/BOARD","BOARDID:" + str(boardid),"%s JOINed %s " % (username,str(boardid)))
  472.  
  473.         return join.id
  474.        
  475.     def isJoinedByBoardid(self, boardid, username = None):
  476.  
  477.         if username == None:
  478.             username = self.currentUser.username
  479.  
  480.         rv = False;
  481.         for joins in self.getSession().query(Joinedboard).filter(Joinedboard.boardid == boardid).filter(Joinedboard.username == username):
  482.             rv = True
  483.             break
  484.         return rv
  485.  
  486.     def getJoinedBoardids(self, username = None):
  487.  
  488.         if username == None:
  489.             username = self.currentUser.username
  490.  
  491.         rv = []
  492.         for boardid in self.getBoardids():
  493.             if self.isJoinedByBoardid(boardid,username):
  494.                 rv.append(boardid)
  495.         return rv
  496.        
  497.        
  498.     def joinBoardToggle(self, boardid, username = None):
  499.  
  500.         print "Toggling %s" % (str(boardid))
  501.         if username == None:
  502.             username = self.currentUser.username
  503.  
  504.  
  505.         if self.isJoinedByBoardid(boardid,username):
  506.             print "It's on, turning off %s" % (str(boardid))       
  507.             self.unjoinByBoardid(boardid,username)
  508.         else:
  509.             print "It's off, turning on %s" % (str(boardid))       
  510.             self.joinByBoardid(boardid,username)
  511.    
  512.    
  513. #### Group membership functions
  514.  
  515.     def addGroupMember(self,groupname,member):
  516.         rv = False
  517.         group = self.getGroup(groupname)
  518.         if not group == None:
  519.             if not self.getUser(member) == None:
  520.                 membership = Groupmember()
  521.                 membership.groupname = group.groupname
  522.                 membership.username = member
  523.                 self.session.add(membership)
  524.                 self.session.commit()
  525.                 rv = True
  526.         return rv
  527.    
  528.     def getGroupMemberships(self,member):
  529.         rv = []
  530.         for theMembership in self.getSession().query(Groupmember).filter(Groupmember.username == member):
  531.             rv.append(theMembership.groupname)
  532.         return rv
  533.     def getGroupMembership(self,group,member):
  534.         rv = None
  535.         for theMembership in self.getSession().query(Groupmember).filter(Groupmember.groupname == group.groupname).filter(Groupmember.username == member):
  536.             rv = theMembership
  537.             break
  538.         return rv
  539.    
  540.     def getGroupMembers(self,groupname):
  541.         rv = []
  542.         for theMembership in self.getSession().query(Groupmember).filter(Groupmember.groupname == groupname):
  543.             rv.append(theMembership.username)
  544.         return rv
  545.     def isGroupMember(self,groupname,member):
  546.         rv = False
  547.         members = self.getGroupMembers(groupname)
  548.         if member in members:
  549.             rv = True
  550.         return rv
  551.    
  552.     def dropGroupMember(self,groupname,member):
  553.         rv = False
  554.         group = self.getGroup(groupname)
  555.         if not group == None:
  556.             if self.isGroupMember(group,member):
  557.                 membership = self.getGroupMembership(group,member)
  558.                 self.session.delete(membership)
  559.                 self.session.commit()
  560.                 rv = True
  561.         return rv
  562.    
  563.  
  564. #### Group functions
  565.  
  566.     def deleteGroupByGroupname(self,name):
  567.         ## Get the board
  568.         group = self.getGroup(name)
  569.         if not group == None:
  570.             ## remove any members
  571.             members = self.getGroupMembers(name)
  572.             for member in members:
  573.                 self.dropGroupMember(name,member)
  574.             ## remove ourselves
  575.             ## but first lets remember our acl id so we can kill it after
  576.             aclid = group.aclid
  577.             self.getSession().delete(group)
  578.             self.getSession().commit()     
  579.             self.deleteAcl(aclid)
  580.            
  581.    
  582.    
  583.     def createGroup(self,name,description,aclid = None):
  584.         #### creates a group
  585.         myGroup = Usergroup()
  586.         myGroup.groupname = name
  587.         myGroup.description = description
  588.         if aclid == None:
  589.             myAcl = self.createAcl()
  590.             myAcl.description="GROUP: "+name
  591.             self.getSession().add(myAcl)
  592.             self.getSession().commit()                 
  593.             aclid = myAcl.id
  594.         myGroup.aclid = aclid
  595.         self.getSession().add(myGroup)
  596.         self.getSession().commit()
  597.         self.logEntry(self.LOGNORMAL,"CREATE/GROUP","GROUPNAME:" + str(myGroup.groupname),"Group created: %s " % (str(myGroup.groupname)))
  598.  
  599.         return myGroup.groupname
  600.        
  601.    
  602.     def getGroups(self):
  603.         rv = []
  604.         for theGroup in self.getSession().query(Usergroup).filter(Usergroup.groupname != "MONKEYBUSINESS!!"):
  605.             rv.append( theGroup)
  606.         return rv
  607.     def getGroup(self, name):
  608.         for theGroup in self.getSession().query(Usergroup).filter(Usergroup.groupname == name):
  609.             return theGroup
  610.         return None
  611.        
  612. ### Board functions start
  613.     ## Returns a descriptive string of the currently selected board
  614.     def getCurrentBoardString(self):
  615.         boardname = self.getCurrentBoard()
  616.         description = ""
  617.         if not boardname == None:
  618.             board = self.getBoardByName(boardname)
  619.             if not board == None:
  620.                 description = str(self.getBoardByName(boardname).description)
  621.            
  622.         return "[" + boardname + ": " + description +"]"
  623.  
  624.     def getCurrentBoard(self):
  625.         return str(self.currentBoard)
  626.        
  627.     def setCurrentBoard(self,boardname):
  628.         rv = False
  629.         board = self.getBoard(self.getBoardid(boardname))
  630.         if self.srmcheck(board.aclid,self.currentUser.username,"READ",minlevel=board.minreadlevel):
  631.             self.currentBoard = boardname
  632.             rv = True
  633.         return rv
  634.  
  635.  
  636.     def getBoardids(self):
  637.         ##
  638.         rv = []
  639.         for theBoard in self.getBoards():
  640.             rv.append(theBoard.id)
  641.         return rv
  642.  
  643.     def getBoards(self):
  644.         ##
  645.         rv = []
  646.         for theBoard in self.getSession().query(Board).order_by(Board.id):
  647.             rv.append(theBoard)
  648.         return rv
  649.  
  650.     def getBoardNames(self):
  651.         rv = []
  652.         boards = self.getBoards()
  653.         for board in boards:
  654.             rv.append(board.name)
  655.         return rv
  656.        
  657.     def getBoardByExternalname(self,name):
  658.         for theBoard in self.getSession().query(Board).filter(Board.externalname == name):
  659.             return theBoard
  660.         return None
  661.  
  662.  
  663.     def getBoardByName(self,name):
  664.         ##
  665.         for theBoard in self.getSession().query(Board).filter(Board.name == name):
  666.             return theBoard
  667.         return None
  668.        
  669.     def getMessageIdsOlderThan(self, date, boardname = "__pyffle_email"):
  670.         board = self.getBoardByName(boardname)
  671.         boardid = board.id
  672.         rv = []
  673.         for theMsg in self.getSession().query(Message).filter(Message.boardid == boardid).filter(Message.sentdate <= date):
  674.             rv.append(theMsg.id)
  675.         return rv
  676.    
  677.     def getOldMessagesOver(self, boardname, maxmsgs):
  678.         print "Got Boardname: " + boardname
  679.         msgs = self.getMessagesByBoardname(boardname,checkSrm=False)
  680.         count = 0
  681.         rv = []
  682.         for id in msgs:
  683.             count = count + 1
  684.             if count > maxmsgs:
  685.                 rv.append(id)
  686.         return rv
  687.    
  688.     def getBoard(self,boardid):
  689.         ##
  690.         for theBoard in self.getSession().query(Board).filter(Board.id == boardid):
  691.             return theBoard
  692.         return None
  693.        
  694.     def deleteBoardByBoardid(self, boardid):
  695.         ## Delete messages first
  696.         msgids = self.getMessagesByBoardid(boardid)
  697.         for msgid in msgids:
  698.             self.deleteMessage(msgid)
  699.        
  700.         ## Get the board
  701.         board = self.getBoard(boardid)
  702.         if not board == None:
  703.             boardname = board.name
  704.    
  705.            
  706.             ## remove ourselves
  707.             self.getSession().delete(board)
  708.             self.getSession().commit()     
  709.    
  710.             ## Finally delete the ACL
  711.             self.deleteAcl(board.aclid)
  712.    
  713.        
  714.             self.logEntry(self.LOGNORMAL,"DELETE/BOARD","BOARDID:" + str(boardid),"Board deleted: %s " % (str(boardname)))
  715.        
  716.     def deleteBoardByBoardname(self,    name):
  717.         return self.deleteBoardByBoardid(self.getBoardid(name))
  718.        
  719.        
  720.     def createBoard(self,   name,
  721.                             description,
  722.                             owner,
  723.                             externalname,
  724.                             minreadlevel,
  725.                             minpostlevel,
  726.                             minoplevel,
  727.                             network = "usenet",
  728.                             aclid = None):
  729.         #### creates a board
  730.         myBoard = Board()
  731.         myBoard.name = name
  732.         myBoard.description = description
  733.         myBoard.owner = owner
  734.         myBoard.externalname = externalname
  735.         myBoard.minreadlevel = minreadlevel
  736.         myBoard.minpostlevel = minpostlevel
  737.         myBoard.minoplevel = minoplevel
  738.         myBoard.network = network
  739.  
  740.         myAcl = self.createAcl()
  741.         myAcl.description="BOARD: "+name
  742.         self.getSession().add(myAcl)
  743.         self.getSession().commit()                 
  744.         aclid = myAcl.id
  745.         myBoard.aclid = aclid
  746.         self.getSession().add(myBoard)
  747.         self.getSession().commit()
  748.         self.logEntry(self.LOGNORMAL,"CREATE/BOARD","BOARDID:" + str(myBoard.id),"Board created: %s " % (str(myBoard.name)))
  749.  
  750.         return myBoard.id
  751.    
  752.    
  753.     def getBoardid(self,name):
  754.         for instance in self.getSession().query(Board).filter(Board.name == name):
  755.             return instance.id
  756.         return None
  757.  
  758. ### User functions start
  759.  
  760.     def updateUserPosts(self):
  761.         if self.currentUser.messagesposted == None:
  762.             self.currentUser.messagesposted = 0
  763.         self.currentUser.messagesposted = self.currentUser.messagesposted + 1
  764.        
  765.         self.getSession().add(self.currentUser)
  766.         self.getSession().commit()
  767.  
  768.  
  769.     def registerUser(self,answers):
  770.         ## FIXME chck for existing users #CRITICAL
  771.         theUser = Users()
  772.         theUser.fullidentity = answers["*IDENTITY"].strip()
  773.         theUser.username = answers["*NAME"].strip()
  774.         theAcl = self.createAcl(description="ACL for user " + theUser.username)
  775.         theUser.aclid = theAcl.id
  776.         theUser.password = answers["*PASSWORD"].strip()
  777.         theUser.realname = answers["*FIRST"].strip()
  778.         theUser.comment  = answers["*ASK BACKGROUND"].strip()
  779.         theUser.timescalled = 0
  780.         theUser.datefirstlogin = datetime.now()
  781.         theUser.datefastlogin = datetime.now()
  782.         theUser.messagesposted = 0
  783.         theUser.accesslevel = 10 ## FIXME grab from static
  784.         theUser.fakelevel = "10"
  785.         theUser.transferprotocol = "K"
  786.         theUser.kbuploaded = 0
  787.         theUser.kbdownloaded = 0
  788.         theUser.datelastnewscan = None
  789.         theUser.externaleditor = "pico"
  790.         theUser.consoleeditor = "pico"
  791.         theUser.terminal = "vt100"
  792.         theUser.pagelength = 23
  793.         theUser.disablepagedmsgs = False
  794.         theUser.minutesontoday = -1
  795.         theUser.splashfile = None
  796.  
  797.        
  798.         self.storeUser(theUser)
  799.         self.currentUser = theUser
  800.         self.util.currentUser = theUser
  801.         self.logEntry(self.LOGNORMAL,"CREATE/USER",str(theUser.username),"Registered new user %s" % (str(theUser.username)))
  802.  
  803.         return None
  804.  
  805.  
  806.     def storeUser(self,theUser):
  807.         theUser.username = theUser.username.lower()
  808.         self.getSession().add(theUser)
  809.         self.getSession().commit()
  810.         self.logEntry(self.LOGINFO,"STORE/USER",str(theUser.username),"Stored user record %s" % (str(theUser.username)))
  811.        
  812.    
  813.     def setPassword(self,password,user = None):
  814.         if user == None:
  815.             user = self.currentUser
  816.         user.password = password
  817.         self.logEntry(self.LOGNORMAL,"ALTER/USER/PASSWORD",str(user.username),"%s changed password" % (str(user.username)))
  818.         self.storeUser(user)
  819.  
  820.     def setRealName(self,name,user = None):
  821.         if user == None:
  822.             user = self.currentUser
  823.         user.realname = name
  824.         self.logEntry(self.LOGNORMAL,"ALTER/USER/REALNAME",str(user.username),"%s changed real name" % (str(user.username)))
  825.         self.storeUser(user)
  826.  
  827.     def setProtocol(self,p):
  828.         user = self.currentUser
  829.         user.transferprotocol = p
  830.         self.logEntry(self.LOGNORMAL,"ALTER/USER/PROTO",str(user.username),"%s changed page protocol " % (str(user.username)))
  831.         self.storeUser(user)
  832.  
  833.        
  834.     def setPageLength(self,i):
  835.         user = self.currentUser
  836.         user.pagelength = i
  837.         self.logEntry(self.LOGNORMAL,"ALTER/USER/ROWS",str(user.username),"%s changed page length " % (str(user.username)))
  838.         self.storeUser(user)
  839.  
  840.     def setEditor(self,editor,user = None):
  841.         if user == None:
  842.             user = self.currentUser
  843.         user.externaleditor = editor
  844.         self.logEntry(self.LOGNORMAL,"ALTER/USER/EDITOR",str(user.username),"%s changed editor" % (str(user.username)))
  845.         self.storeUser(user)
  846.  
  847.  
  848.     def getUsers(self):
  849.         ## There will always be at least the system user, hopefully
  850.         return self.getSession().query(Users)
  851.        
  852.     def getUser(self,username):
  853.         ##
  854.         rv = None
  855.         for theUser in self.getSession().query(Users).filter(Users.username == username.lower()):
  856.             rv = theUser
  857.         return rv
  858.    
  859.     def userExists(self,name):
  860.         ##
  861.    
  862.         found = False
  863.  
  864.         for myUser in self.getSession().query(Users).filter(Users.username == name):
  865.             found = True
  866. #       for myUser in self.getSession().query(Users).filter(func.lower(Users.realname) == func.lower(name)):
  867. #           found = True
  868.         return found
  869.        
  870.     def _getname(self,name): ## TODO
  871.         rv = None
  872.         for myUser in self.getSession().query(Users).filter(func.lower(Users.realname) == func.lower(name)):
  873.             rv = myUser.username
  874.             break
  875.         return rv
  876.    
  877.  
  878.     def getUsersOlderThan(self, date):
  879.         rv = []
  880.         for user in self.getSession().query(Users).filter(Users.datefastlogin <= date):
  881.             rv.append(user.username)
  882.         return rv
  883.  
  884.  
  885.     ## Deletes a message
  886.     ## Security is checked 
  887.     def deleteUser(self,username):
  888.         ##
  889.         ## let's get the message first so that we can delete it's components
  890.         user = self.getUser(username)
  891.         if not user == None:       
  892.             ## remember the acl id for the step after this
  893.             aclid = user.aclid
  894.             self.deleteAces(aclid)
  895.             ## delete the user itself
  896.             self.getSession().delete(user)
  897.            
  898.             ## finally we delete the ACL
  899.             self.deleteAcl(aclid)
  900.             self.logEntry(self.LOGINFO,"DELETE/USER",str(username),"Deleted user: %s" % (str(username)))
  901.            
  902.             self.deleteAcl(aclid)
  903.             self.getSession().commit()
  904.  
  905.             return True
  906.  
  907.  
  908.  
  909. ### ACL functions start
  910.     def getAcl(self,aclid):
  911.         ##
  912.         theAcl = self.getSession().query(Acl).filter(Acl.id == aclid)[0]
  913.         return theAcl
  914.        
  915.  
  916.        
  917.     def deleteAcl(self,aclid):
  918.         ## delete any ACEs under this id
  919.         self.deleteAces(aclid)
  920.        
  921.         ## delete the ACL
  922.         for theAcl in self.getSession().query(Acl).filter(Acl.id == aclid):
  923.             self.getSession().delete(theAcl)
  924.             self.getSession().commit()
  925.             self.logEntry(self.LOGINFO,"DELETE/ACL","ACLID:" + str(aclid),"Deleted ACL: %s" % (str(aclid)))
  926.  
  927.  
  928.     def createAcl(self,description=""):
  929.         acl = Acl()
  930.         acl.description = description
  931.         self.getSession().add(acl)
  932.         self.getSession().commit()
  933.         self.logEntry(self.LOGINFO,"CREATE/ACL","ACLID:" + str(acl.id),"Created ACL: %s" % (str(acl.id)))
  934.         return acl
  935.    
  936.     def getGroupAces(self,username,grantordeny):
  937.         memberships = self.getGroupMemberships(username)
  938.         rv = []
  939.         for membership in memberships:
  940.             group = self.getGroup(membership)
  941.             aclid = group.aclid
  942.             aces =  self.getSession().query(Ace).filter(Ace.aclid==aclid).filter(Ace.grantordeny == grantordeny)
  943.             if not aces == None:
  944.                 for myAce in aces:
  945.                     rv.append([myAce.permission,username])
  946.         return rv
  947.    
  948.     def getAces(self,aclid,grantordeny):
  949.         rv = []
  950.         aces =  self.getSession().query(Ace).filter(Ace.aclid==aclid).filter(Ace.grantordeny == grantordeny)
  951.  
  952.         if not aces == None:
  953.             for myAce in aces:
  954.                 rv.append([myAce.permission,myAce.subjectid])
  955.         return rv
  956.    
  957.     def getAclGrants(self,aclid):
  958.         return self.getAces(aclid,"GRANT")
  959.        
  960.     def getAclDenies(self,aclid):
  961.         return self.getAces(aclid,"DENY")
  962.    
  963. ### ACE functions start
  964.  
  965.     def deleteAces(self,aclid):
  966.         ##
  967.         for ace in self.getSession().query(Ace).filter(Ace.aclid == aclid):
  968.             aceid = ace.id
  969.             self.getSession().delete(ace)
  970.             self.getSession().commit()
  971.             self.logEntry(self.LOGINFO,"DELETE/ACE","ACEID:" + str(aceid),"Deleted ACE: %s" % (str(aceid)))
  972.        
  973.  
  974.  
  975.     def dropGrant(self,acl, subject, object):
  976.         if self.isGranted(acl,subject,object):
  977.             for myAce in self.getSession().query(Ace).filter(Ace.aclid==acl.id).filter(Ace.subjectid==subject).filter(Ace.permission == object).filter(Ace.grantordeny == "GRANT"):
  978.                 self.getSession().delete(myAce)
  979.                 self.getSession().commit()
  980.             self.logEntry(self.LOGINFO,"ACE/DROPGRANT",str(subject),"Dropped grant %s to %s" % (str(object),str(subject)))
  981.  
  982.  
  983.     def dropDeny(self,acl, subject, object):
  984.         if self.isDenied(acl,subject,object):
  985.             for myAce in self.getSession().query(Ace).filter(Ace.aclid==acl.id).filter(Ace.subjectid==subject).filter(Ace.permission == object).filter(Ace.grantordeny == "DENY")
  986.                 self.getSession().delete(myAce)
  987.                 self.getSession().commit()
  988.             self.logEntry(self.LOGINFO,"ACE/DROPDENY",str(subject),"Dropped deny %s to %s" % (str(object),str(subject)))
  989.  
  990.        
  991.     def grant(self,acl, subject, object):
  992.  
  993.         ## FIXME: add checking of pre-existing ACE
  994.         ##
  995.         if self.isGranted(acl,subject,object):
  996.             return;     ## This ACE already exists, we don't need to do anything
  997.         myAce = Ace()
  998.         myAce.aclid = acl.id
  999.         myAce.subjectid = subject
  1000.         myAce.permission = object
  1001.         myAce.grantordeny = "GRANT"
  1002.         self.getSession().add(myAce)
  1003.         self.getSession().commit()
  1004.         self.logEntry(self.LOGINFO,"ACE/GRANT",str(subject),"Granted %s to %s" % (str(object),str(subject)))
  1005.  
  1006.  
  1007.  
  1008.        
  1009.     def deny(self,acl, subject, object):
  1010.         ##
  1011.         if self.isDenied(acl,subject,object):
  1012.             return;     ## This ACE already exists, we don't need to do anything
  1013.         myAce = Ace()
  1014.         myAce.aclid = acl.id
  1015.         myAce.subjectid = subject
  1016.         myAce.permission = object
  1017.         myAce.grantordeny = "DENY"
  1018.         self.getSession().add(myAce)
  1019.         self.getSession().commit()
  1020.         self.logEntry(self.LOGINFO,"ACE/DENY",str(subject),"Denied %s to %s" % (str(object),str(subject)))
  1021.    
  1022.    
  1023.    
  1024.    
  1025.     def isDenied(self,acl, subject, object, inherited=True):
  1026.         ## we check the given ACL as well as any group ACLs if inherited is set to true
  1027.         denied = False
  1028.         myAces = self.getAces(acl.id,"DENY")
  1029.         if inherited:
  1030.             groupAces = self.getGroupAces(subject,"DENY")
  1031.             for groupAce in groupAces:
  1032.                 myAces.append(groupAce)
  1033.         for myAce in myAces:
  1034.             if myAce[0] == object and myAce[1] == subject:
  1035.                 denied = True
  1036.                 break
  1037.         return denied
  1038.        
  1039.        
  1040.        
  1041.        
  1042.        
  1043.     def isGranted(self,acl, subject, object, inherited=True):
  1044.         ##
  1045.         granted = False
  1046.         myAces = self.getAces(acl.id,"GRANT")
  1047.         if inherited:
  1048.             groupAces = self.getGroupAces(subject,"GRANT")
  1049.             for groupAce in groupAces:
  1050.                 myAces.append(groupAce)
  1051.  
  1052.         for myAce in myAces:
  1053.             if myAce[0] == object and myAce[1] == subject:
  1054.                 granted = True
  1055.                 break
  1056.         return granted
  1057.    
  1058.    
  1059.    
  1060.  
  1061. ### SRM    
  1062.     def srmcheck(self,aclid,subject,object,minlevel=-1):
  1063.         passed = False;
  1064.        
  1065.         ## Are we running in tool mode? If so, don't check security
  1066.         if self.toolMode:
  1067.             return True
  1068.            
  1069.         ## If we're a sysop, we automatically get pass
  1070.         ## Let's load the user's own ACL to check
  1071.         user = self.getUser(subject)
  1072.         usersAcl = self.getAcl(user.aclid)
  1073.         ## The ACE is subject=user, object=SYSOP
  1074.         if self.isGranted(usersAcl,subject,"SYSOP"):
  1075.             ## User has sysop privs, let him pass
  1076.     #       self.logEntry(self.LOGINFO,"SRM/SYSOP/PASS",str(subject),"SYSOP: %s for %s" % (str(object),str(subject)))
  1077.             return True
  1078.            
  1079.         ## Non-sysop users go by the following:
  1080.         ## 1. If level is higher than minlevel then pass, otherwise...
  1081.         ## 2. If GRANT exists, then pass even if we don't meet the level (+VE override)
  1082.         ## 3. Unless a DENY exists, in which case you don't pass, even if 1&2 hold (-VE override)
  1083.         ##
  1084.         ## Should we look at the level (-1 = ignore)
  1085.         if minlevel > -1:
  1086.             ## Yes we should
  1087.             if self.currentUser.accesslevel >= minlevel:
  1088.                 ## We're higher than the level, so we're good so far
  1089.                 passed = True
  1090.                
  1091.         acl = self.getAcl(aclid)
  1092.         if not acl == None:
  1093.             ## Check for any overriding grants?
  1094.             if self.isGranted(acl,subject,object):
  1095.                 passed = True
  1096.             ## Check for any overriding deny's?
  1097.             if self.isDenied(acl,subject,object):
  1098.                 passed = False
  1099.     #   if passed:
  1100.     #       self.logEntry(self.LOGINFO,"SRM/PASS",str(subject),"PASS: %s for %s" % (str(object),str(subject)))
  1101.     #   else:
  1102.     #       self.logEntry(self.LOGINFO,"SRM/FAIL",str(subject),"FAIL: %s for %s" % (str(object),str(subject)))
  1103.         return passed
  1104.    
  1105.    
  1106.  
  1107.  
  1108. ### MessageText handling
  1109.        
  1110.     def getMessagetexts(self, msgid):
  1111.         rv = []
  1112.         for msgtext in self.getSession().query(Messagetext).filter(Messagetext.messageid == msgid).order_by(Messagetext.id):   
  1113.             rv.append(msgtext.msgtext)
  1114.         return rv
  1115.  
  1116.  
  1117.  
  1118.        
  1119.     def deleteMessagetexts(self,msgid):
  1120.         for msgText in self.getSession().query(Messagetext).filter(Messagetext.messageid == msgid):
  1121.             self.getSession().delete(msgText)
  1122.             self.getSession().commit()
  1123.    
  1124.     def searchMessagetexts(self,text,boardname=None,searchSpecial = False):
  1125.         rv = []
  1126.         query = self.getSession().query(Messagetext).filter(Messagetext.msgtext.like('%' + text + '%'))
  1127.         for msgtext in query:
  1128.             msg = self.getMessage(msgtext.messageid)
  1129.        
  1130.             boardOK = False
  1131.             if not boardname == None:
  1132.                 board = self.getBoardByName(boardname)
  1133.                 if (msg.boardid == board.id):
  1134.                     boardOK = True
  1135.             else:
  1136.                 board = self.getBoard(msg.boardid)
  1137.                 if not board == None:
  1138.                     if not searchSpecial:
  1139.                         if not board.name.startswith('__'):
  1140.                             boardOK = True
  1141.                     else:
  1142.                         boardOK = True                     
  1143.             if boardOK:
  1144.                 rv.append(msg.id)
  1145.         return rv
  1146.          
  1147.            
  1148. ### Message functions
  1149.  
  1150.  
  1151.  
  1152.     def getTotalMessageCount(self):
  1153.         rv = self.getSession().query(Message).count()
  1154.         return rv
  1155.  
  1156.     def getBoardMessageCount(self,boardname):
  1157.         theboard = self.getBoardByName(boardname)
  1158.         rv = self.getSession().query(Message).filter(Message.boardid == theboard.id).count()
  1159.         return rv
  1160.  
  1161.     ## Returns the message object specified by msgid
  1162.     def getMessage(self,msgid,callback=None):
  1163.         ##
  1164.         if not callback == None:
  1165.             if not self.util == None:
  1166.                 self.util.printn(".")
  1167.         theMessage = self.getSession().query(Message).filter(Message.id == msgid)[0]
  1168.         return theMessage
  1169.  
  1170.        
  1171.  
  1172.     ## Returns message ids for the board id that have been psoted since date
  1173.     ## Checks security against current user if specified
  1174.     def getMessagesSince(self,board,date,checkSrm=True,callback=None):
  1175.         rv = []
  1176.         for msg in self.getSession().query(Message).filter(Message.boardid == board.id).filter(Message.sentdate > date).order_by(Message.sentdate):
  1177.             if not callback == None:
  1178.                         if not self.util == None:
  1179.                             self.util.printn("|")
  1180.        
  1181.             if checkSrm:
  1182.                 if self.srmcheck(msg.aclid,self.currentUser.username,"READ",minlevel=board.minreadlevel):
  1183.                     rv.append(msg.id)
  1184.             else:
  1185.                 rv.append(msg.id)  
  1186.         return rv
  1187.  
  1188.  
  1189.     def getMessagesSinceCount(self,board,date):
  1190.         rv = self.getSession().query(Message).filter(Message.boardid == board.id).filter(Message.sentdate > date).count()
  1191.         return rv
  1192.            
  1193.  
  1194.     def getMessagesByBoardByToUsername(self,board,username,checkSrm = True):   
  1195.         rv = []
  1196.         for msg in self.getSession().query(Message).filter(Message.boardid == board.id).filter(Message.toname == username):
  1197.             if checkSrm:
  1198.                 if self.srmcheck(msg.aclid,self.currentUser.username,"READ",minlevel=board.minreadlevel):
  1199.                     rv.append(msg.id)
  1200.             else:
  1201.                 rv.append(msg.id)  
  1202.         return rv
  1203.  
  1204.     ## Returns message ids for the board id that have been posted by the given user
  1205.     ## Checks security against current user if specified
  1206.     def getMessagesByBoardByUsername(self,board,username,checkSrm = True)
  1207.         rv = []
  1208.         for msg in self.getSession().query(Message).filter(Message.boardid == board.id).filter(Message.fromname == username):
  1209.             if checkSrm:
  1210.                 if self.srmcheck(msg.aclid,self.currentUser.username,"READ",minlevel=board.minreadlevel):
  1211.                     rv.append(msg.id)
  1212.             else:
  1213.                 rv.append(msg.id)  
  1214.         return rv
  1215.    
  1216.        
  1217.  
  1218.  
  1219.     ## Returns all message ids for the board id
  1220.     ## Does NOT check security (why? FIXME?)
  1221.     def getMessagesByBoardid(self,boardid):
  1222.         ##
  1223.         rv = []
  1224.         for instance in self.getSession().query(Message).filter(Message.boardid == boardid).order_by(Message.sentdate):
  1225.             rv.append(instance.id)
  1226.         return rv
  1227.  
  1228.  
  1229.     ## Returns all message ids for the board NAME
  1230.     ## Checks security against current user if specified
  1231.     def getMessagesByBoardname(self,name,checkSrm=True):
  1232.         ##
  1233.         board = self.getBoardByName(name)
  1234.         boardid = board.id
  1235.         rv = []
  1236.         for msg in self.getSession().query(Message).filter(Message.boardid == board.id).order_by(Message.sentdate):
  1237.             if checkSrm:
  1238.                 if self.srmcheck(msg.aclid,self.currentUser.username,"READ",minlevel=board.minreadlevel):
  1239.                     rv.append(msg.id)
  1240.             else:
  1241.                 rv.append(msg.id)  
  1242.         return rv
  1243.  
  1244.  
  1245.                    
  1246.     ## Returns all message ids with to=username
  1247.     ## Checks security against username if specified
  1248.     def getMessagesByUser(self,username,checkSrm=True):
  1249.         ##
  1250.         rv = []
  1251.        
  1252.         for instance in self.getSession().query(Message).filter(func.lower(Message.toname) == func.lower(username)).order_by(Message.sentdate):
  1253.             if not self.toolMode:
  1254.                 if checkSrm:
  1255.                     if instance:
  1256.                         if self.srmcheck(instance.aclid,username,"READ"):
  1257.                             rv.append(instance.id)
  1258.             else:
  1259.                 rv.append(instance.id) 
  1260.         return rv
  1261.  
  1262.  
  1263.     def getMailMessagesByUser(self,username,checkSrm=True):
  1264.         ##
  1265.         rv = []
  1266.         board = self.getBoardByName("__pyffle_email")
  1267.         for instance in self.getSession().query(Message).filter(Message.boardid == board.id).filter(func.lower(Message.toname) == func.lower(username)).order_by(Message.sentdate):
  1268.             if not self.toolMode:
  1269.                 if checkSrm:
  1270.                     if instance:
  1271.                         if self.srmcheck(instance.aclid,username,"READ"):
  1272.                             rv.append(instance.id)
  1273.             else:
  1274.                 rv.append(instance.id) 
  1275.         return rv
  1276.  
  1277.  
  1278.  
  1279.  
  1280.     def getMessagesAuthoredByUser(self,username,checkSrm=True):
  1281.         ##
  1282.         rv = []
  1283.         for instance in self.getSession().query(Message).filter(Message.fromname == username).order_by(Message.sentdate):
  1284.             if checkSrm:
  1285.                 if self.srmcheck(instance.aclid,username,"READ"):
  1286.                     rv.append(instance.id)
  1287.             else:
  1288.                 rv.append(instance.id) 
  1289.         return rv
  1290.  
  1291.  
  1292.  
  1293.     def searchMessageSubjects(self,text,boardname=None,searchSpecial=False):
  1294.         rv = []
  1295.         query = self.getSession().query(Message).filter(Message.subject.like('%' + text + '%'))
  1296.         for msg in query:
  1297.             boardOK = False
  1298.             if not boardname == None:
  1299.                 board = self.getBoardByName(boardname)
  1300.                 if (msg.boardid == board.id):
  1301.                     boardOK = True
  1302.             else:
  1303.                 board = self.getBoard(msg.boardid)
  1304.                 if not board == None:
  1305.                     if not searchSpecial:
  1306.                         if not board.name.startswith('__'):
  1307.                             boardOK = True
  1308.                     else:
  1309.                         boardOK = True
  1310.             if boardOK:
  1311.                 rv.append(msg.id)
  1312.         return rv
  1313.  
  1314.    
  1315.     def getNewMessagesAllUsers(self,boardname='__pyffle_email'):
  1316.         rv = []
  1317.         board = self.getBoardByName(boardname)     
  1318.         for msg in self.getSession().query(Message).filter(Message.boardid == board.id).filter(Message.readbyrecipient == False):
  1319.             rv.append(msg.id)
  1320.         return rv
  1321.        
  1322.     ## Returns all unread message ids with to=user (object)
  1323.     ## Checks security against user if specified
  1324.     def getNewMessages(self,user=None,boardname='__pyffle_email',checkSrm=False):
  1325.         if user == None:
  1326.             user = self.currentUser
  1327.         rv = []
  1328.         board = self.getBoardByName(boardname)
  1329.         msgids = []
  1330.         msgids1 = self.getSession().query(Message).filter(Message.boardid == board.id).filter(func.lower(Message.toname) == func.lower(user.username)).filter(Message.readbyrecipient == False).all()
  1331.         msgids2 = self.getSession().query(Message).filter(Message.boardid == board.id).filter(func.lower(Message.toname) == func.lower(user.realname)).filter(Message.readbyrecipient == False).all()
  1332.         msgids = msgids1 + msgids2
  1333.         for msg in msgids:
  1334.             if checkSrm:
  1335.                 if self.srmcheck(msg.aclid,user.username,"READ"):
  1336.                     rv.append(msg.id)
  1337.             else:
  1338.                 rv.append(msg.id)
  1339.         return rv
  1340.    
  1341.  
  1342.  
  1343.     ## Marks the message read
  1344.     ## Security is not checked
  1345.     def setMessageRead(self,msgid):
  1346.         theMessage = self.getMessage(msgid)
  1347.         ## FIXME read receipt
  1348.         theMessage.readbyrecipient = True
  1349.         self.getSession().add(theMessage)
  1350.         self.getSession().commit()
  1351.         self.logEntry(self.LOGINFO,"READ/MESSAGE","MSGID:" + str(msgid),"Recipient read msg: %s" % (str(msgid)))
  1352.  
  1353.  
  1354.  
  1355.  
  1356.    
  1357.     ## Deletes a message
  1358.     ## Security is checked 
  1359.     def deleteMessage(self,msgid):
  1360.         ##
  1361.         ## let's get the message first so that we can delete it's components
  1362.         msg = self.getMessage(msgid)
  1363.         if not msg == None:
  1364.             ## are we allowd to delete this message? if not, error out
  1365.             ## first check if it's a forum posting
  1366.             minlevel = -1
  1367.             board = self.getBoard(msg.boardid)
  1368.            
  1369.             if not board == None:
  1370.                 if not board.name.startswith('__'):
  1371.                     ## it's a forum post, get the minimum operator level for the board
  1372.                     minlevel = board.minoplevel
  1373.            
  1374.             if not self.toolMode:
  1375.                 if not self.srmcheck(msg.aclid,self.currentUser.username,"DELETE",minlevel):
  1376.                     self.util.println("You are not allowed to delete this message")
  1377.                     return False
  1378.                
  1379.             ## now delete any text
  1380.             self.deleteMessagetexts(msgid)
  1381.            
  1382.             ## remember the acl id for the step after this
  1383.             aclid = msg.aclid
  1384.            
  1385.             ## delete the message itself
  1386.             self.getSession().delete(msg)
  1387.             self.getSession().commit()
  1388.            
  1389.             ## finally we delete the ACL
  1390.             self.deleteAcl(aclid)
  1391.             self.logEntry(self.LOGINFO,"DELETE/MESSAGE","MSGID:" + str(msgid),"Deleted Message: %s" % (str(msgid)))
  1392.            
  1393.             return True
  1394.  
  1395.  
  1396.  
  1397.     ## Deletes ALL messages in the system
  1398.     ## Security is not checked
  1399.     def clearMessages(self):
  1400.         ##
  1401.         for instance in self.getSession().query(Message).order_by(Message.id):
  1402.             self.util.debugln("Deleting MsgID: " + str(instance.id) + " received at " + str(instance.sentdate))
  1403.             self.deleteMessage(instance.id)
  1404.  
  1405.  
  1406.  
  1407.  
  1408.    
  1409.     ## Debug function              
  1410.     def _dumpMessages(self):
  1411.    
  1412.         if True: ##self.util.DEBUG:
  1413.             for instance in self.getSession().query(Message).order_by(Message.id):
  1414.                 self.util.debugln("MsgID: " + str(instance.id) + " received at " + str(instance.sentdate))
  1415.                 self.util.debugln("From: " + str(instance.fromname).strip())
  1416.                 self.util.debugln("To: " + str(instance.toname).strip())
  1417.                 self.util.debugln("Subj: " + str(instance.subject))
  1418.                 self.util.debugln("--------------------------------------------------------------")
  1419.                 for msgtext in self.getSession().query(Messagetext).filter(Messagetext.messageid == instance.id).order_by(Messagetext.id):
  1420.                     self.util.debugln(msgtext.msgtext)
  1421.                 self.util.debugln(" ")
  1422.        
  1423.  
  1424.                
  1425.    
  1426.    
  1427.    
  1428.     ## Creates a  message (if board == __pyffle_email), with standard ACLs
  1429.     ## i.e. if recipient exists locally, grant him R+D. If remote, passes to MTAs
  1430.     ##
  1431.     ## If board != __pyffle_email, we just post the message with an empty ACL on
  1432.     ## the relevant board
  1433.     ##
  1434.     ## Security is not checked prior to creating - callers should establish posting/mailing
  1435.     ## privs
  1436.     def createMessage(self,fromname,toname,subject,text,board='__pyffle_email'):
  1437.         ## FIXME - should support unicode, but for now we clean it
  1438.         import unicodedata
  1439.         text = unicodedata.normalize('NFKD', unicode(text)).encode('ascii','ignore')
  1440.         subject = unicodedata.normalize('NFKD', unicode(subject)).encode('ascii','ignore')
  1441.        
  1442.         ## Find the board id for the requested board
  1443.         for emailBoard in self.getSession().query(Board).filter(Board.name==board).order_by(Board.id):
  1444.             pass       
  1445.         emailId = emailBoard.id
  1446.         msgAcl = None
  1447.         ## If the recipient is local, setup the permissions for this message
  1448.         foundMTA = False
  1449.         mtaInstance = None
  1450.         if board == '__pyffle_email':
  1451.             ### This is an email, let's have a look at the address
  1452.             if self.userExists(toname):
  1453.                 ## Got a local user, great, this will be simple
  1454.                 ## Create an ACL for the message now, we know the recipient is good
  1455.                 msgAcl = self.createAcl()
  1456.                 ## Ensure the recipient can read and delete this message   
  1457.                 self.grant(msgAcl,toname,"READ")
  1458.                 self.grant(msgAcl,toname,"DELETE")
  1459.                 self.util.debugln("Recipient can R/D: " + str(self.isGranted(msgAcl,toname,"READ")) + str(self.isGranted(msgAcl,toname,"DELETE")))
  1460.             else:
  1461.                 ## OK, the user is remote - let's see if anybody will accept delivery
  1462.                 self.util.debugln("User not local, checking MTAs")
  1463.                 for mtaName in self.mtaModules.keys():
  1464.                     ## Loop through our MTAs, instantiating each one until
  1465.                     ## we get one that accepts the address
  1466.                     mta = self.mtaModules[mtaName]
  1467.                     mtaInstance = mta.PyffleMta()
  1468.                     mtaInstance.data = self
  1469.                     mtaInstance.currentUser = self.currentUser
  1470.                     if (mtaInstance.matchAddress(toname)):
  1471.                         ## Cool, this MTA likes the address, let's jump out of this
  1472.                         self.util.debugln("Sending using " + mtaName)
  1473.                         foundMTA = True
  1474.                         break
  1475.                        
  1476.                 if foundMTA:
  1477.                     ## We need to create an ACL for the message's local copy
  1478.                     msgAcl = self.createAcl()
  1479.                 else:
  1480.                     ## Address doesn't appear to be valid - bork, return without sending or storing anything
  1481.                     self.util.debugln("Destination address invalid, no MTA will accept destination")
  1482.                     return None
  1483.         else:
  1484.             ## Not an email, no need to deal with the addressing bruhaha above...
  1485.             ## Still need an ACL though
  1486.             ## So we grab the board's acl and use it for the message
  1487.             ## FIXME - make a COPY of the board's ACL
  1488.             msgAcl = self.createAcl()
  1489.    
  1490.         ## Finally build the message itself.
  1491.         ##  
  1492.         msg = Message()
  1493.         msg.fromname = fromname
  1494.         msg.toname = toname
  1495.         msg.subject = subject
  1496.         msg.aclid = msgAcl.id
  1497.         msg.boardid = emailId
  1498.         msg.sentdate = datetime.now()
  1499.         msg.readbyrecipient = False
  1500.         self.getSession().add(msg)
  1501.         self.getSession().commit()
  1502.         self.logEntry(self.LOGNORMAL,"CREATE/MESSAGE","MSGID:"+str(msg.id),"Created Message: %s" % (str(msg.id)))
  1503.            
  1504.         ## Now the message text    
  1505.         msgtext = Messagetext()
  1506.         msgtext.messageid = msg.id
  1507.         msgtext.aclid = msgAcl.id
  1508.         msgtext.msgtext = text
  1509.         self.getSession().add(msgtext)
  1510.         self.getSession().commit()
  1511.         self.logEntry(self.LOGNORMAL,"CREATE/MESSAGETEXT","MSGTEXTID:"+str(msgtext.id),"Created Messagetext: %s" % (str(msgtext.id)))
  1512.        
  1513.         ## Finally if this is an external message, pass it to the MTA
  1514.         if foundMTA:
  1515.             mtaInstance.sendMessage(msg)
  1516.             self.logEntry(self.LOGNORMAL,"SEND/MESSAGE","MSGID:"+str(msg.id),"Sent Message: %s using %s"  % (str(msg.id),str(mtaInstance.getName())))
  1517.            
  1518.         return msg.id
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement