comparison roundup/mailgw.py @ 905:502a5ae11cc5

Very close now. The cgi and mailgw now use the new security API. The two templates have been migrated to that setup. Lots of unit tests. Still some issue in the web form for editing Roles assigned to users.
author Richard Jones <richard@users.sourceforge.net>
date Fri, 26 Jul 2002 08:27:00 +0000
parents b0d3d3535998
children 23c9d4f86380
comparison
equal deleted inserted replaced
904:02763530b9e8 905:502a5ae11cc5
71 set() method to add the message to the item's spool; in the second case we 71 set() method to add the message to the item's spool; in the second case we
72 are calling the create() method to create a new node). If an auditor raises 72 are calling the create() method to create a new node). If an auditor raises
73 an exception, the original message is bounced back to the sender with the 73 an exception, the original message is bounced back to the sender with the
74 explanatory message given in the exception. 74 explanatory message given in the exception.
75 75
76 $Id: mailgw.py,v 1.78 2002-07-25 07:14:06 richard Exp $ 76 $Id: mailgw.py,v 1.79 2002-07-26 08:26:59 richard Exp $
77 ''' 77 '''
78 78
79 79
80 import string, re, os, mimetools, cStringIO, smtplib, socket, binascii, quopri 80 import string, re, os, mimetools, cStringIO, smtplib, socket, binascii, quopri
81 import time, random 81 import time, random
91 pass 91 pass
92 92
93 class MailUsageHelp(Exception): 93 class MailUsageHelp(Exception):
94 pass 94 pass
95 95
96 class UnAuthorized(Exception): 96 class Unauthorized(Exception):
97 """ Access denied """ 97 """ Access denied """
98 98
99 def initialiseSecurity(security): 99 def initialiseSecurity(security):
100 ''' Create some Permissions and Roles on the security object 100 ''' Create some Permissions and Roles on the security object
101 101
102 This function is directly invoked by security.Security.__init__() 102 This function is directly invoked by security.Security.__init__()
103 as a part of the Security object instantiation. 103 as a part of the Security object instantiation.
104 ''' 104 '''
105 newid = security.addPermission(name="Email Registration", 105 newid = security.addPermission(name="Email Registration",
106 description="Anonymous may register through e-mail") 106 description="Anonymous may register through e-mail")
107 security.addPermissionToRole('Anonymous', newid)
108 107
109 class Message(mimetools.Message): 108 class Message(mimetools.Message):
110 ''' subclass mimetools.Message so we can retrieve the parts of the 109 ''' subclass mimetools.Message so we can retrieve the parts of the
111 message... 110 message...
112 ''' 111 '''
180 m = [''] 179 m = ['']
181 m.append(str(value)) 180 m.append(str(value))
182 m.append('\n\nMail Gateway Help\n=================') 181 m.append('\n\nMail Gateway Help\n=================')
183 m.append(fulldoc) 182 m.append(fulldoc)
184 m = self.bounce_message(message, sendto, m) 183 m = self.bounce_message(message, sendto, m)
185 except UnAuthorized, value: 184 except Unauthorized, value:
186 # just inform the user that he is not authorized 185 # just inform the user that he is not authorized
187 sendto = [sendto[0][1]] 186 sendto = [sendto[0][1]]
188 m = [''] 187 m = ['']
189 m.append(str(value)) 188 m.append(str(value))
190 m = self.bounce_message(message, sendto, m) 189 m = self.bounce_message(message, sendto, m)
520 519
521 # 520 #
522 # handle the users 521 # handle the users
523 # 522 #
524 523
525 # Don't create users if ANONYMOUS_REGISTER_MAIL is denied 524 # Don't create users if anonymous isn't allowed to register
526 # ... fall back on ANONYMOUS_REGISTER if the other doesn't exist
527 create = 1 525 create = 1
528 if hasattr(self.instance, 'ANONYMOUS_REGISTER_MAIL'): 526 anonid = self.db.user.lookup('anonymous')
529 if self.instance.ANONYMOUS_REGISTER_MAIL == 'deny': 527 if not self.db.security.hasPermission('Email Registration', anonid):
530 create = 0
531 elif self.instance.ANONYMOUS_REGISTER == 'deny':
532 create = 0 528 create = 0
533 529
534 author = self.db.uidFromAddress(message.getaddrlist('from')[0], 530 author = uidFromAddress(self.db, message.getaddrlist('from')[0],
535 create=create) 531 create=create)
536 if not author: 532 if not author:
537 raise UnAuthorized, ''' 533 raise Unauthorized, '''
538 You are not a registered user. 534 You are not a registered user.
539 535
540 Unknown address: %s 536 Unknown address: %s
541 '''%message.getaddrlist('from')[0][1] 537 '''%message.getaddrlist('from')[0][1]
542 538
559 if r == tracker_email or not r: 555 if r == tracker_email or not r:
560 continue 556 continue
561 557
562 # look up the recipient - create if necessary (and we're 558 # look up the recipient - create if necessary (and we're
563 # allowed to) 559 # allowed to)
564 recipient = self.db.uidFromAddress(recipient, create) 560 recipient = uidFromAddress(self.db, recipient, create)
565 561
566 # if all's well, add the recipient to the list 562 # if all's well, add the recipient to the list
567 if recipient: 563 if recipient:
568 recipients.append(recipient) 564 recipients.append(recipient)
569 565
729 # commit the changes to the DB 725 # commit the changes to the DB
730 self.db.commit() 726 self.db.commit()
731 727
732 return nodeid 728 return nodeid
733 729
730 def extractUserFromList(userClass, users):
731 '''Given a list of users, try to extract the first non-anonymous user
732 and return that user, otherwise return None
733 '''
734 if len(users) > 1:
735 for user in users:
736 # make sure we don't match the anonymous or admin user
737 if userClass.get(user, 'username') in ('admin', 'anonymous'):
738 continue
739 # first valid match will do
740 return user
741 # well, I guess we have no choice
742 return user[0]
743 elif users:
744 return users[0]
745 return None
746
747 def uidFromAddress(db, address, create=1):
748 ''' address is from the rfc822 module, and therefore is (name, addr)
749
750 user is created if they don't exist in the db already
751 '''
752 (realname, address) = address
753
754 # try a straight match of the address
755 user = extractUserFromList(db.user, db.user.stringFind(address=address))
756 if user is not None: return user
757
758 # try the user alternate addresses if possible
759 props = db.user.getprops()
760 if props.has_key('alternate_addresses'):
761 users = db.user.filter(None, {'alternate_addresses': address},
762 [], [])
763 user = extractUserFromList(db.user, users)
764 if user is not None: return user
765
766 # try to match the username to the address (for local
767 # submissions where the address is empty)
768 user = extractUserFromList(db.user, db.user.stringFind(username=address))
769
770 # couldn't match address or username, so create a new user
771 if create:
772 return db.user.create(username=address, address=address,
773 realname=realname, roles=db.config.NEW_EMAIL_USER_ROLES)
774 else:
775 return 0
776
734 def parseContent(content, keep_citations, keep_body, 777 def parseContent(content, keep_citations, keep_body,
735 blank_line=re.compile(r'[\r\n]+\s*[\r\n]+'), 778 blank_line=re.compile(r'[\r\n]+\s*[\r\n]+'),
736 eol=re.compile(r'[\r\n]+'), 779 eol=re.compile(r'[\r\n]+'),
737 signature=re.compile(r'^[>|\s]*[-_]+\s*$'), 780 signature=re.compile(r'^[>|\s]*[-_]+\s*$'),
738 original_message=re.compile(r'^[>|\s]*-----Original Message-----$')): 781 original_message=re.compile(r'^[>|\s]*-----Original Message-----$')):
798 content = '\n\n'.join(l) 841 content = '\n\n'.join(l)
799 return summary, content 842 return summary, content
800 843
801 # 844 #
802 # $Log: not supported by cvs2svn $ 845 # $Log: not supported by cvs2svn $
846 # Revision 1.78 2002/07/25 07:14:06 richard
847 # Bugger it. Here's the current shape of the new security implementation.
848 # Still to do:
849 # . call the security funcs from cgi and mailgw
850 # . change shipped templates to include correct initialisation and remove
851 # the old config vars
852 # ... that seems like a lot. The bulk of the work has been done though. Honest :)
853 #
803 # Revision 1.77 2002/07/18 11:17:31 gmcm 854 # Revision 1.77 2002/07/18 11:17:31 gmcm
804 # Add Number and Boolean types to hyperdb. 855 # Add Number and Boolean types to hyperdb.
805 # Add conversion cases to web, mail & admin interfaces. 856 # Add conversion cases to web, mail & admin interfaces.
806 # Add storage/serialization cases to back_anydbm & back_metakit. 857 # Add storage/serialization cases to back_anydbm & back_metakit.
807 # 858 #

Roundup Issue Tracker: http://roundup-tracker.org/