def addUser(self, login, name = None, last_name = None, email = None, passwd = None, sha_passwd = None, note = None): if not email: raise ScalakError("You have to supply user email.") # Some not really nice mailman hacks # Need to import Mailman code sys.path.insert(0, self._mailman_dir) sitedir = os.path.join(sys.prefix, 'lib', 'python'+sys.version[:3], 'site-packages') sys.path.append(sitedir) from Mailman import mm_cfg from Mailman import MailList from Mailman import Utils from Mailman import Errors from Mailman import Message from Mailman import i18n from email.Utils import parseaddr class UserDesc: pass if not Utils.list_exists(self.listname): raise ScalakError("No such mailing list") mlist = MailList.MailList(self.listname) usr = UserDesc() usr.fullname, usr.address = parseaddr(email) usr.digest = 0 try: mlist.ApprovedAddMember(usr, 0, 0) mlist.Save() finally: mlist.Unlock()
def errcheck (self, action): """Performs all error checks. Returns None is all's good. Otherwise returns a string with error message.""" if not can_create_lists(self.curr_user): return 'You are not authorized to creates lists on this server' if len(self.owner) <= 0: return 'Cannot create list without a owner.' if self.ln == '': return 'You forgot to enter the list name' if '@' in self.ln: return 'List name must not include "@": %s' % self.safeln if action == 'create' and Utils.list_exists(self.ln): return 'List already exists: %s' % self.safe_ln if mm_cfg.VIRTUAL_HOST_OVERVIEW and \ not mm_cfg.VIRTUAL_HOSTS.has_key(self.hn): safehostname = Utils.websafe(self.hn) return 'Unknown virtual host: %s' % safehostname return None
def remove(self): """Deletes mailing list First delete list reference from mailman, then delete aliases from MTA """ # Need to import Mailman code sys.path.insert(0, self._mailman_dir) from Mailman import mm_cfg from Mailman import MailList from Mailman import Utils from Mailman import Errors from Mailman import Message from Mailman import i18n stdoutOld = sys.stdout sys.stdout = open('/dev/null', 'w') # Part from Mailman code (rmlist script) REMOVABLES = [] if Utils.list_exists(self.listname): mlist = MailList.MailList(self.listname, lock=0) # Do the MTA-specific list deletion tasks if mm_cfg.MTA: modname = 'Mailman.MTA.' + mm_cfg.MTA __import__(modname) sys.modules[modname].remove(mlist) REMOVABLES = [ (os.path.join('lists', self.listname), ('list info')), ] # Remove any stale locks associated with the list for filename in os.listdir(mm_cfg.LOCK_DIR): fn_listname = filename.split('.')[0] if fn_listname == self.listname: REMOVABLES.append((os.path.join(mm_cfg.LOCK_DIR, filename), ('stale lock file'))) for dirtmpl, msg in REMOVABLES: dir = os.path.join(mm_cfg.VAR_PREFIX, dirtmpl) if os.path.islink(dir): os.unlink(dir) elif os.path.isdir(dir): shutil.rmtree(dir) elif os.path.isfile(dir): os.unlink(dir) with open(self._aliases_file, 'r') as tmp: file = tmp.readlines() with open(self._aliases_file, 'w') as tmp: for line in file: if(self.listname not in line): tmp.write(line) sys.stdout.close() sys.stdout = stdoutOld
def process_message(self, peer, mailfrom, rcpttos, data): from cStringIO import StringIO from Mailman import Utils from Mailman import Message from Mailman import MailList listnames = [] for rcpt in rcpttos: local = rcpt.lower().split('@')[0] parts = local.split('-') if len(parts) > 2: continue listname = parts[0] if len(parts) == 2: command = parts[1] else: command = '' if not Utils.list_exists(listname) or command not in ( '', 'admin', 'owner', 'request', 'join', 'leave'): continue listnames.append((rcpt, listname, command)) for rcpt, listname, command in listnames: rcpttos.remove(rcpt) print >> DEBUGSTREAM, 'forwarding recips:', ' '.join(rcpttos) if rcpttos: refused = self._deliver(mailfrom, rcpttos, data) print >> DEBUGSTREAM, 'we got refusals:', refused mlists = {} s = StringIO(data) msg = Message.Message(s) if not msg.getheader('from'): msg['From'] = mailfrom if not msg.getheader('date'): msg['Date'] = time.ctime(time.time()) for rcpt, listname, command in listnames: print >> DEBUGSTREAM, 'sending message to', rcpt mlist = mlists.get(listname) if not mlist: mlist = MailList.MailList(listname, lock=0) mlists[listname] = mlist if command == '': msg.Enqueue(mlist, tolist=1) elif command == 'admin': msg.Enqueue(mlist, toadmin=1) elif command == 'owner': msg.Enqueue(mlist, toowner=1) elif command == 'request': msg.Enqueue(mlist, torequest=1) elif command in ('join', 'leave'): if command == 'join': msg['Subject'] = 'subscribe' else: msg['Subject'] = 'unsubscribe' msg.Enqueue(mlist, torequest=1)
def process_message(self, peer, mailfrom, rcpttos, data): from cStringIO import StringIO from Mailman import Utils from Mailman import Message from Mailman import MailList listnames = [] for rcpt in rcpttos: local = rcpt.lower().split('@')[0] parts = local.split('-') if len(parts) > 2: continue listname = parts[0] if len(parts) == 2: command = parts[1] else: command = '' if not Utils.list_exists(listname) or command not in ('', 'admin', 'owner', 'request', 'join', 'leave'): continue listnames.append((rcpt, listname, command)) for rcpt, listname, command in listnames: rcpttos.remove(rcpt) print >> DEBUGSTREAM, 'forwarding recips:', ' '.join(rcpttos) if rcpttos: refused = self._deliver(mailfrom, rcpttos, data) print >> DEBUGSTREAM, 'we got refusals:', refused mlists = {} s = StringIO(data) msg = Message.Message(s) if not msg.getheader('from'): msg['From'] = mailfrom if not msg.getheader('date'): msg['Date'] = time.ctime(time.time()) for rcpt, listname, command in listnames: print >> DEBUGSTREAM, 'sending message to', rcpt mlist = mlists.get(listname) if not mlist: mlist = MailList.MailList(listname, lock=0) mlists[listname] = mlist if command == '': msg.Enqueue(mlist, tolist=1) elif command == 'admin': msg.Enqueue(mlist, toadmin=1) elif command == 'owner': msg.Enqueue(mlist, toowner=1) elif command == 'request': msg.Enqueue(mlist, torequest=1) elif command in ('join', 'leave'): if command == 'join': msg['Subject'] = 'subscribe' else: msg['Subject'] = 'unsubscribe' msg.Enqueue(mlist, torequest=1)
def validate_lists(): ''' Checks current data in the compsoc database corresponds to that in Mailman. Caveat: they have to be subscribed using the same email address they use for the compsoc website. This includes: Checking all lists in the MailingList model have a mailman equivalent Checking all signups to a list are subscribed to the mailman list ''' for list in MailingList.objects.all(): if not Utils.list_exists(list.list): print "%s doesn't exist on mailman" % list.list else: mailman_list = MailList.MailList(list.list, lock=False) members = mailman_list.getMemberCPAddresses(mailman_list.getRegularMemberKeys()+mailman_list.getDigestMemberKeys()) for user in list.users.all(): if not user.email in members: print "The website thinks %s is subscribed to %s but he/she isn't" % (user.member.all_name(),list.list)
def removeUser(self, id): con = openDB() c = con.cursor() res = c.execute('select email from users where login=%s limit 1', (id,)) if not res: raise ScalakError("Given user dosen't exists") email = c.fetchone()[0] con.commit() c.close() # Some not really nice mailman hacks # Need to import Mailman code sys.path.insert(0, self._mailman_dir) sitedir = os.path.join(sys.prefix, 'lib', 'python'+sys.version[:3], 'site-packages') sys.path.append(sitedir) from Mailman import mm_cfg from Mailman import MailList from Mailman import Utils from Mailman import Errors from Mailman import Message from Mailman import i18n from email.Utils import parseaddr class UserDesc: pass if not Utils.list_exists(self.listname): raise ScalakError("No such mailing list") mlist = MailList.MailList(self.listname) usr = UserDesc() usr.fullname, usr.address = parseaddr(email) usr.digest = 0 try: if mlist.isMember(email): mlist.ApprovedDeleteMember(email, 'bin/remove_members', 0, 0) mlist.Save() finally: mlist.Unlock()
def validate_lists(): ''' Checks current data in the compsoc database corresponds to that in Mailman. Caveat: they have to be subscribed using the same email address they use for the compsoc website. This includes: Checking all lists in the MailingList model have a mailman equivalent Checking all signups to a list are subscribed to the mailman list ''' for list in MailingList.objects.all(): if not Utils.list_exists(list.list): print "%s doesn't exist on mailman" % list.list else: mailman_list = MailList.MailList(list.list, lock=False) members = mailman_list.getMemberCPAddresses( mailman_list.getRegularMemberKeys() + mailman_list.getDigestMemberKeys()) for user in list.users.all(): if not user.email in members: print "The website thinks %s is subscribed to %s but he/she isn't" % ( user.member.all_name(), list.list)
def create_list(vhost, listname, desc, advertise, modlevel, inslevel, owners, members): name = vhost + '-' + listname if Utils.list_exists(name): return 0 mlist = MailList.MailList() try: oldmask = os.umask(002) pw = sha.new('foobar').hexdigest() try: mlist.Create(name, owners[0], pw) finally: os.umask(oldmask) mlist.real_name = listname mlist.host_name = vhost mlist.description = desc mlist.advertised = int(advertise) > 0 mlist.default_member_moderation = int(modlevel) is 2 mlist.generic_nonmember_action = int(modlevel) > 0 mlist.subscribe_policy = 2 * (int(inslevel) is 1) mlist.owner = owners mlist.subject_prefix = '[' + listname + '] ' mlist.max_message_size = 0 mlist.Save() mlist.Unlock() check_options(vhost, listname, True) mass_subscribe(vhost, listname, members) except: raise return 0 return 1
def create_list(vhost,listname,desc,advertise,modlevel,inslevel,owners,members): name = vhost+'-'+listname; if Utils.list_exists(name): return 0 mlist = MailList.MailList() try: oldmask = os.umask(002) pw = sha.new('foobar').hexdigest() try: mlist.Create(name, owners[0], pw) finally: os.umask(oldmask) mlist.real_name = listname mlist.host_name = vhost mlist.description = desc mlist.advertised = int(advertise) > 0 mlist.default_member_moderation = int(modlevel) is 2 mlist.generic_nonmember_action = int(modlevel) > 0 mlist.subscribe_policy = 2 * (int(inslevel) is 1) mlist.owner = owners mlist.subject_prefix = '['+listname+'] ' mlist.max_message_size = 0 mlist.Save() mlist.Unlock() check_options(vhost,listname,True) mass_subscribe(vhost,listname,members) except: raise return 0 return 1
#! /usr/bin/env python
def list_present(name): return Utils.list_exists(name.lower())
def deploy(self, project, config): """Creates and connect mailman instance with Scalak This part is kind of tricky because mailman provide minimal cli interface, that is definitely not sufficient. Parameters: project - Project instance (service would be added to it) config - ConfigParser.SafeconfigParser Complications: Mailman is using SHA-digested passwords, Scalak (mostly because of Apache) htpasswd. Most basic (and currently used) method to supply the SHA password is to keep it in db (they are generated with htpasswd) Steps: * Reading configuration for mailman bin directory, aliases, alias update command * Reading sha admin password (scalak keeps passwords in htpasswd mainly because of apache, so i add additional field with sha passwd) * Then is kind of black box - mailman internal callbacks, used code from Mailman:bin/newlist * Configuration part - adding and updating aliases """ super(Mailman, self).deploy(project, config) if self._config.has_section('mailman'): # Path to mailman install directory if config.has_option('mailman', 'mailman_dir'): self._mailman_dir = config.get('mailman', 'mailman_dir') # Path to mta aliases file if config.has_option('mailman', 'aliases_file'): self._aliases_file = config.get('mailman', 'aliases_file') # Command tu update aliases list if config.has_option('mailman', 'aliases_update'): self._aliases_update = config.get('mailman', 'aliases_update') # Text to add to aliases list file when creating new mailin list to # activate new list hanglind by mta # You can use $LIST_NAME it would be substituted by list name if config.has_option('mailman', 'aliases_config'): self._aliases_config = config.get('mailman', 'aliases_config') # Path to mailman administrator scripts self._bin_dir = os.path.join(self._mailman_dir, 'bin/') self.listname = '{0}-{1}'.format(self._project.id, self._name) # Need to import Mailman code sys.path.insert(0, self._mailman_dir) from Mailman import mm_cfg from Mailman import MailList from Mailman import Utils from Mailman import Errors from Mailman import Message from Mailman import i18n con = openDB() c = con.cursor() res = c.execute('select sha_password, email from users where login=%s limit 1', (project.admin,)) if not res: raise ScalakError("User given as admin don't exist in db") tmp = c.fetchone() adminPasswd = tmp[0] adminEmail = tmp[1] con.commit() c.close() # Mailman specific callbacks if Utils.list_exists(self.listname): raise ScalakError("Error: mailing list with given name {0} already " \ "exists".format(self.listname)) urlhost = mm_cfg.DEFAULT_URL_HOST host_name = mm_cfg.VIRTUAL_HOSTS.get(urlhost, mm_cfg.DEFAULT_EMAIL_HOST) web_page_url = mm_cfg.DEFAULT_URL_PATTERN % urlhost mlist = MailList.MailList() # Part of code from Mailman:bin/newlist oldmask = os.umask(002) lang = mm_cfg.DEFAULT_SERVER_LANGUAGE try: try: try: if lang == mm_cfg.DEFAULT_SERVER_LANGUAGE: langs = [lang] else: langs = [lang, mm_cfg.DEFAULT_SERVER_LANGUAGE] mlist.Create(self.listname, adminEmail, adminPasswd, langs=langs, emailhost=host_name) finally: os.umask(oldmask) except Errors.BadListNameError, s: raise ScalakError('Illegal list name: %(s)s') except Errors.EmailAddressError, s: raise ScalakError('Bad owner email address: %(s)s.' + 'Owner addresses need to be fully-qualified names, ' + 'like "*****@*****.**", not just "owner".')
def process_message(self, peer, mailfrom, rcpttos, data): from cStringIO import StringIO from Mailman import Utils from Mailman import Message from Mailman import MailList # If the message is to a Mailman mailing list, then we'll invoke the # Mailman script directly, without going through the real smtpd. # Otherwise we'll forward it to the local proxy for disposition. listnames = [] for rcpt in rcpttos: local = rcpt.lower().split('@')[0] # We allow the following variations on the theme # listname # listname-admin # listname-owner # listname-request # listname-join # listname-leave parts = local.split('-') if len(parts) > 2: continue listname = parts[0] if len(parts) == 2: command = parts[1] else: command = '' if not Utils.list_exists(listname) or command not in ( '', 'admin', 'owner', 'request', 'join', 'leave'): continue listnames.append((rcpt, listname, command)) # Remove all list recipients from rcpttos and forward what we're not # going to take care of ourselves. Linear removal should be fine # since we don't expect a large number of recipients. for rcpt, listname, command in listnames: rcpttos.remove(rcpt) # If there's any non-list destined recipients left, print >> DEBUGSTREAM, 'forwarding recips:', ' '.join(rcpttos) if rcpttos: refused = self._deliver(mailfrom, rcpttos, data) # TBD: what to do with refused addresses? print >> DEBUGSTREAM, 'we got refusals:', refused # Now deliver directly to the list commands mlists = {} s = StringIO(data) msg = Message.Message(s) # These headers are required for the proper execution of Mailman. All # MTAs in existence seem to add these if the original message doesn't # have them. if not msg.getheader('from'): msg['From'] = mailfrom if not msg.getheader('date'): msg['Date'] = time.ctime(time.time()) for rcpt, listname, command in listnames: print >> DEBUGSTREAM, 'sending message to', rcpt mlist = mlists.get(listname) if not mlist: mlist = MailList.MailList(listname, lock=0) mlists[listname] = mlist # dispatch on the type of command if command == '': # post msg.Enqueue(mlist, tolist=1) elif command == 'admin': msg.Enqueue(mlist, toadmin=1) elif command == 'owner': msg.Enqueue(mlist, toowner=1) elif command == 'request': msg.Enqueue(mlist, torequest=1) elif command in ('join', 'leave'): # TBD: this is a hack! if command == 'join': msg['Subject'] = 'subscribe' else: msg['Subject'] = 'unsubscribe' msg.Enqueue(mlist, torequest=1)
def create_list(userdesc, perms, vhost, listname, desc, advertise, modlevel, inslevel, owners, members): """ Create a new list. @root """ name = vhost.lower() + VHOST_SEP + listname.lower(); if Utils.list_exists(name): print >> sys.stderr, "List ", name, " already exists" return 0 owner = [] for o in owners: email = to_forlife(o) print >> sys.stderr, "owner in list", o, email email = email[0] if email is not None: owner.append(email) if len(owner) is 0: print >> sys.stderr, "No owner found in ", owners return 0 mlist = MailList.MailList() try: oldmask = os.umask(002) pw = sha.new('foobar').hexdigest() try: mlist.Create(name, owner[0], pw) finally: os.umask(oldmask) mlist.real_name = listname mlist.host_name = 'listes.polytechnique.org' mlist.description = desc mlist.advertised = int(advertise) is 0 mlist.default_member_moderation = int(modlevel) is 2 mlist.generic_nonmember_action = int(modlevel) > 0 mlist.subscribe_policy = 2 * (int(inslevel) is 1) mlist.admin_notify_mchanges = (mlist.subscribe_policy or mlist.generic_nonmember_action or mlist.default_member_moderation or not mlist.advertised) mlist.owner = owner mlist.subject_prefix = '['+listname+'] ' mlist.max_message_size = 0 inverted_listname = listname.lower() + '_' + vhost.lower() mlist.msg_footer = "_______________________________________________\n" \ + "Liste de diffusion %(real_name)s\n" \ + "http://listes.polytechnique.org/members/" + inverted_listname mlist.header_filter_rules = [] mlist.header_filter_rules.append(('X-Spam-Flag: Unsure, tests=bogofilter', mm_cfg.HOLD, False)) mlist.header_filter_rules.append(('X-Spam-Flag: Yes, tests=bogofilter', mm_cfg.HOLD, False)) if ON_CREATE_CMD != '': try: os.system(ON_CREATE_CMD + ' ' + name) except: pass check_options_runner(userdesc, perms, mlist, listname.lower(), True) mass_subscribe(userdesc, perms, mlist, members) mlist.Save() finally: mlist.Unlock() # avoid the "-1 mail to moderate" bug mlist = MailList.MailList(name) try: mlist._UpdateRecords() mlist.Save() finally: mlist.Unlock() return 1
for opt, arg in opts: if opt in ('-h', '--help'): usage(0) if opt in ('-v', '--verbose'): verbose = 1 if len(args) > 1: oldlistname = args[0].lower() newlistname = args[1].lower() else: print >> sys.stderr, 'No list names given' print >> sys.stderr, "Try '%s --help' for more information." % PROGRAM return if not Utils.list_exists(oldlistname): usage(1, "List '%s' not exists." % (oldlistname)) if Utils.list_exists(newlistname): usage(1, "List '%s' already exists." % (newlistname)) if verbose: print 'Renaming list %s to %s.' % (oldlistname, newlistname) oldmlist = MailList.MailList(oldlistname) if not oldmlist.Locked(): oldmlist.Lock() oldlistpath = Site.get_listpath(oldlistname) lists_path = os.path.dirname(oldlistpath) newlistpath = lists_path + '/' + newlistname
def exists(self): return Utils.list_exists(self.name)