def update_maillist(mail, form, conn=None): """Update mailing list account. Parameters stored in backend: @name """ mail = str(mail).lower() (_, domain) = mail.split('@', 1) if not utils.is_email(mail): return (False, 'INVALID_EMAIL') mod_attrs = [] name = form.get('name') if name: mod_attrs += [(ldap.MOD_REPLACE, 'cn', [name.encode('utf-8')])] else: mod_attrs += [(ldap.MOD_REPLACE, 'cn', None)] if 'only_moderator_can_post' in form: mod_attrs += [(ldap.MOD_REPLACE, 'accessPolicy', ['moderatorsonly'])] elif 'only_subscriber_can_post' in form: mod_attrs += [(ldap.MOD_REPLACE, 'accessPolicy', ['membersonly'])] if 'max_message_size' in form: max_mail_size = form_utils.get_max_message_size(form) if max_mail_size: mod_attrs += [(ldap.MOD_REPLACE, 'maxMessageSize', [str(max_mail_size)])] else: mod_attrs += [(ldap.MOD_REPLACE, 'maxMessageSize', None)] if 'moderators' in form: moderators = form.get('moderators', '').split(',') moderators = [ str(i).strip().lower() for i in moderators if utils.is_email(i) ] if moderators: mod_attrs += [(ldap.MOD_REPLACE, 'listAllowedUser', moderators)] else: mod_attrs += [(ldap.MOD_REPLACE, 'listAllowedUser', None)] if mod_attrs: if not conn: _wrap = LDAPWrap() conn = _wrap.conn try: dn = 'mail=%s,ou=Groups,domainName=%s,%s' % ( mail, domain, settings.iredmail_ldap_basedn) conn.modify_s(dn, mod_attrs) return (True, ) except ldap.NO_SUCH_OBJECT: return (False, 'ACCOUNT_NOT_EXIST') except Exception as e: return (False, repr(e)) else: return (True, )
def POST(self, mail): """ Add multiple subscribers to given subscription version. :param mail: email address of the mailing list account Available form parameters: `subscribers`: subscribers' email addresses. Multiple subscribers must be separated by comma. `subscription`: subscription version. either `normal`, `digest` or `nomail`. """ form = web.input() if 'add_subscribers' in form: subscribers = form.get('add_subscribers', '').replace(' ', '').split(',') subscribers = [ str(i).lower() for i in subscribers if utils.is_email(i) ] require_confirm = True if form.get('require_confirm') != 'yes': require_confirm = False subscription = form.get('subscription', 'normal') if subscription not in ['normal', 'digest', 'nomail']: subscription = 'normal' qr = mlmmj.add_subscribers(mail=mail, subscribers=subscribers, subscription=subscription, require_confirm=require_confirm) if not qr[0]: return api_render(qr) if 'remove_subscribers' in form: if form.get('remove_subscribers') == 'ALL': qr = mlmmj.remove_all_subscribers(mail=mail) else: subscribers = form.get('remove_subscribers', '').replace(' ', '').split(',') subscribers = [ str(i).lower() for i in subscribers if utils.is_email(i) ] qr = mlmmj.remove_subscribers(mail=mail, subscribers=subscribers) if not qr[0]: return api_render(qr) return api_render(True)
def is_maillist_exists(mail, conn=None): """Return True if mailing list account is invalid or exist.""" mail = str(mail).lower() if not utils.is_email(mail): return True if not conn: _wrap = SQLWrap() conn = _wrap.conn try: # Check `maillists` qr = conn.select('maillists', vars={'mail': mail}, what='address', where='address=$mail', limit=1) if qr: return True return False except Exception as e: logger.error("SQL error: {0}".format(e)) return True
def subscribe_to_lists(subscriber, lists, subscription='normal', require_confirm=True): """Add one subscriber to multiple mailing lists. @subscriber -- mail address of subscriber @lists -- a list/tuple/set of mailing lists @subscription -- subscription version: normal, nomail, digest. @require_confirm -- subscription version: normal, nomail, digest. """ subscriber = subscriber.lower() lists = [str(i).lower() for i in lists if utils.is_email(i)] if not lists: return (True, ) for l in lists: qr = add_subscribers(mail=l, subscribers=[subscriber], subscription=subscription, require_confirm=require_confirm) if not qr[0]: return qr return (True, )
def __reset_moderators(mail, form, conn): # Get moderators, store in SQL table `vmail.moderators` if 'moderators' in form: domain = mail.split('@', 1)[-1] moderators = [i.strip() for i in form.get('moderators', '').split(',')] moderators = [i.lower() for i in moderators if utils.is_email(i)] try: conn.delete('moderators', vars={'address': mail}, where='address=$address') except Exception as e: return (False, repr(e)) if moderators: _moderators = __exclude_non_existing_addresses(domain=domain, addresses=moderators, conn=conn) records = [] for _addr in _moderators: params = { 'address': mail, 'domain': domain, 'moderator': _addr, 'dest_domain': _addr.split('@', 1)[-1], } records.append(params) try: conn.multiple_insert('moderators', records) except Exception as e: return (False, repr(e)) return (True, )
def __reset_owners(mail, form, conn): if 'owner' in form: # Reset all owners. try: conn.delete("maillist_owners", vars={'mail': mail}, where="address=$mail") except Exception as e: return (False, repr(e)) owners = [i.strip().lower() for i in form.get('owner', '').split(',') if utils.is_email(i)] domain = mail.split("@", 1)[-1] owners = __exclude_non_existing_addresses(domain=domain, addresses=owners, conn=conn) if owners: records = [] for _addr in owners: params = { 'address': mail, 'domain': mail.split('@', 1)[-1], 'owner': _addr, 'dest_domain': _addr.split('@', 1)[-1], } records.append(params) try: conn.multiple_insert('maillist_owners', records) except Exception as e: return (False, repr(e)) return (True, )
def add_maillist(mail, form, conn=None): """Add required SQL records to add a mailing list account.""" mail = str(mail).lower() (listname, domain) = mail.split('@', 1) if not utils.is_email(mail): return (False, 'INVALID_EMAIL') if not conn: _wrap = SQLWrap() conn = _wrap.conn if not is_domain_exists(domain=domain): return (False, 'NO_SUCH_DOMAIN') if is_email_exists(mail=mail): return (False, 'ALREADY_EXISTS') params = { 'active': 1, 'address': mail, 'domain': domain, 'name': form.get('name', ''), 'transport': '%s:%s/%s' % (settings.MTA_TRANSPORT_NAME, domain, listname), 'mlid': __get_new_mlid(conn=conn), 'maxmsgsize': form_utils.get_max_message_size(form), } if 'only_moderator_can_post' in form: params['accesspolicy'] = 'moderatorsonly' elif 'only_subscriber_can_post' in form: params['accesspolicy'] = 'membersonly' try: conn.insert('maillists', **params) params = { 'active': 1, 'address': mail, 'domain': domain, 'forwarding': mail, 'dest_domain': domain, } conn.insert('forwardings', **params) # Get moderators, store in SQL table `vmail.moderators` if 'moderators' in form: qr = __reset_moderators(mail=mail, form=form, conn=conn) if 'owner' in form: qr = __reset_owners(mail=mail, form=form, conn=conn) if not qr[0]: return qr logger.info('Created: {0}.'.format(mail)) return (True,) except Exception as e: logger.error('Error while creating {0}: {1}'.format(mail, e)) return (False, repr(e))
def is_maillist_exists(mail, conn=None): """Check whether mailing list account exists.""" mail = str(mail).lower() if not utils.is_email(mail): return True # Filter used to search mail accounts. query_filter = '(&' query_filter += '(|(objectClass=mailUser)(objectClass=mailList)(objectClass=mailAlias))' query_filter += '(|(mail=%s)(shadowAddress=%s))' % (mail, mail) query_filter += ')' try: if not conn: _wrap = LDAPWrap() conn = _wrap.conn qr = conn.search_s(settings.iredmail_ldap_basedn, ldap.SCOPE_SUBTREE, query_filter, ['dn']) if qr: return True else: # Account not exist. return False except: return False
def is_email_exists(mail, conn=None): mail = str(mail).lower() mail = utils.strip_mail_ext_address(mail) if not utils.is_email(mail): return True # Filter used to search mail accounts. query_filter = '(&' query_filter += '(|(objectClass=mailUser)(objectClass=mailList)(objectClass=mailingList)(objectClass=mailAlias))' query_filter += '(|(mail=%s)(shadowAddress=%s))' % (mail, mail) query_filter += ')' try: if not conn: _wrap = LDAPWrap() conn = _wrap.conn qr = conn.search_s(settings.iredmail_ldap_basedn, ldap.SCOPE_SUBTREE, query_filter, ['dn']) if qr: return True else: # Account not exist. return False except: # Account 'EXISTS' (fake) if lookup failed. return True
def remove_subscribers(mail, subscribers, conn=None): """Remove subscribers from mailing list.""" mail = str(mail).lower() if not utils.is_email(mail): return (False, 'INVALID_EMAIL') if not subscribers: return (False, 'NO_SUBSCRIBERS') if not isinstance(subscribers, (list, tuple, set)): return (False, 'NO_SUBSCRIBERS') if not conn: _wrap = SQLWrap() conn = _wrap.conn try: conn.delete('maillist_members', vars={'mail': mail, 'subscribers': subscribers}, where='address=$mail AND member IN $subscribers') return (True,) except Exception as e: logger.error("SQL error: {0}".format(e)) return (False, repr(e))
def found_terminator(self): if self.buffer: line = self.buffer.pop().decode() logger.debug("{} input: {}".format(self.log_prefix, line)) if line.startswith('get '): addr = line.strip().split(' ', 1)[-1] if utils.is_email(addr): domain = addr.split('@', 1)[-1] if self.rewrite_address_type == 'sender': reply = self.srs_forward(addr=addr, domain=domain) logger.debug("{} {}".format(self.log_prefix, reply)) self.push(reply) else: reply = self.srs_reverse(addr=addr) logger.debug("{} {}".format(self.log_prefix, reply)) self.push(reply) else: logger.debug("{} Not a valid email address, bypassed.".format(self.log_prefix)) self.push(TCP_REPLIES['not_exist'] + 'Not a valid email address, bypassed.') else: logger.debug("{} Unexpected input: {}".format(self.log_prefix, line)) self.push(TCP_REPLIES['not_exist'] + 'Unexpected input: {}'.format(line))
def is_email_exists(mail, conn=None): # Return True if account is invalid or exist. mail = str(mail).lower() if not utils.is_email(mail): return True if not conn: _wrap = SQLWrap() conn = _wrap.conn try: # `forwardings` table has email addr of mail user account and alias account. qr = conn.select('forwardings', vars={'mail': mail}, what='address', where='address=$mail', limit=1) if qr: return True # Check `alias` for alias account which doesn't have any member. qr = conn.select('alias', vars={'mail': mail}, what='address', where='address=$mail', limit=1) if qr: return True return False except Exception as e: logger.error("SQL error: {0}".format(e)) return True
def remove_subscribers(mail, subscribers): """Remove multiple subscribers from given mailing list. :param mail: mail address of mailing list account :param subscribers: a list/tuple/set of subscribers' mail addresses. """ mail = mail.lower() subscribers = [str(i).lower() for i in subscribers if utils.is_email(i)] if not subscribers: return (True, ) grouped_subscribers = {} for i in subscribers: letter = i[0] if letter in grouped_subscribers: grouped_subscribers[letter].append(i) else: grouped_subscribers[letter] = [i] for subscription in ['normal', 'digest', 'nomail']: _dir = __get_ml_subscribers_dir(mail=mail, subscription=subscription) for letter in grouped_subscribers: # Get file stores the subscriber. path = os.path.join(_dir, letter) qr = __remove_lines_in_file(path=path, lines=grouped_subscribers[letter]) if not qr[0]: return qr return (True, )
def __get_ml_dir(mail): """Get absolute path of the root directory of mailing list account.""" if not utils.is_email(mail): return None mail = str(mail).lower() (_username, _domain) = mail.split('@', 1) return os.path.join(settings.MLMMJ_SPOOL_DIR, _domain, _username)
def __ldif_ml(mail, mlid, name=None, access_policy=None, max_message_size=None, alias_domains=None, domain_status=None, moderators=None): """Generate LDIF (a dict) for a new (mlmmj) mailing list account. :param mail: mail address of new (mlmmj) mailing list account :param mlid: a server-wide unique id for each (mlmmj) mailing list :param name: short description of mailing list :param access_policy: access policy of mailing list :param alias_domains: a list/tuple/set of alias domains :param domain_status: status of primary domain: active, disabled :param moderators: a list/tuple/set of moderator email addresses """ mail = str(mail).lower() listname, domain = mail.split('@', 1) transport = '%s:%s/%s' % (settings.MTA_TRANSPORT_NAME, domain, listname) ldif = __attrs_ldif({ 'objectClass': 'mailList', 'mail': mail, 'mtaTransport': transport, 'mailingListID': mlid, 'accountStatus': 'active', 'enabledService': ['mail', 'deliver', 'mlmmj'], }) if name: ldif += __attr_ldif('cn', name) if access_policy: p = str(access_policy).lower() ldif += __attr_ldif('accessPolicy', p) if max_message_size and isinstance(max_message_size, int): ldif += __attr_ldif('maxMessageSize', max_message_size) if alias_domains: alias_domains = [str(d).lower() for d in alias_domains if utils.is_domain(d)] shadow_addresses = [listname + '@' + d for d in alias_domains] if shadow_addresses: ldif += __attr_ldif('shadowAddress', shadow_addresses) if domain_status != 'active': ldif += __attr_ldif('domainStatus', 'disabled') if moderators: _addresses = [str(i).strip().lower() for i in moderators if utils.is_email(i)] if _addresses: ldif += __attr_ldif('listAllowedUser', _addresses) return ldif
def __convert_web_param_value_to_list(value, is_email=False): try: # Split by ',' and remove empty values v = [i for i in value.replace(' ', '').split(',') if i] except: v = [] if v and is_email: v = [str(i).lower() for i in v if utils.is_email(i)] return v
def add_subscribers(mail, subscribers, subscription='normal', require_confirm=True): """Add subscribers to given subscription version of mailing list. :param mail: mail address of mailing list account :param subscribers: a list/tuple/set of subscribers' email addresses :param subscription: subscription version: normal, nomail, digest. :param require_confirm: subscription version: normal, nomail, digest. """ mail = mail.lower() subscribers = [str(i).lower() for i in subscribers if utils.is_email(i)] if not subscribers: return (True, ) if require_confirm: qr = __add_subscribers_with_confirm(mail=mail, subscribers=subscribers, subscription=subscription) if not qr[0]: logger.error('[{0}] {1} Failed to add subscribers (require ' 'confirm): error={2}'.format(web.ctx.ip, mail, qr[1])) return qr else: grouped_subscribers = {} for i in subscribers: letter = i[0] if letter in grouped_subscribers: grouped_subscribers[letter].append(i) else: grouped_subscribers[letter] = [i] _dir = __get_ml_subscribers_dir(mail=mail, subscription=subscription) for letter in grouped_subscribers: # Get file stores the subscriber. path = os.path.join(_dir, letter) qr = __add_lines_in_file(f=path, lines=grouped_subscribers[letter]) if not qr[0]: logger.error('[{0}] {1} Failed to add subscribers to file: ' 'error={2}'.format(web.ctx.ip, mail, qr[1])) return qr logger.info( '[{0}] {1}, added subscribers without confirming: {2}.'.format( web.ctx.ip, mail, ', '.join(subscribers))) return (True, )
def update_maillist(mail, form, conn=None): """ Update mailing list account. Parameters stored in backend: - name - moderators - owner - only_moderator_can_post - only_subscriber_can_post """ mail = str(mail).lower() if not utils.is_email(mail): return (False, 'INVALID_EMAIL') if not conn: _wrap = SQLWrap() conn = _wrap.conn params = { 'name': form.get('name', ''), } if 'max_message_size' in form: params['maxmsgsize'] = form_utils.get_max_message_size(form) if 'only_moderator_can_post' in form: params['accesspolicy'] = 'moderatorsonly' elif 'only_subscriber_can_post' in form: params['accesspolicy'] = 'membersonly' try: conn.update('maillists', vars={'mail': mail}, where='address=$mail', **params) # Get moderators, store in SQL table `vmail.moderators` if 'moderators' in form: qr = __reset_moderators(mail=mail, form=form, conn=conn) if not qr[0]: return qr if 'owner' in form: qr = __reset_owners(mail=mail, form=form, conn=conn) if not qr[0]: return qr return (True,) except Exception as e: return (False, repr(e))
def __get_param_file(mail, param): """Get path to the file used to control parameter setting. Sample value: /var/spool/mlmmj/<domain>/<username>/control/<param> """ if not utils.is_email(mail): return None (_username, _domain) = mail.split('@', 1) return os.path.join(settings.MLMMJ_SPOOL_DIR, _domain, _username, 'control', param)
def add_subscribers(mail, subscribers, conn=None): """Add subscribers to mailing list.""" mail = str(mail).lower() (listname, domain) = mail.split('@', 1) if not utils.is_email(mail): return (False, 'INVALID_EMAIL') if not conn: _wrap = SQLWrap() conn = _wrap.conn if not is_domain_exists(domain=domain): return (False, 'NO_SUCH_DOMAIN') if not is_email_exists(mail=mail): return (False, 'MAILLIST_NOT_EXIST') if not subscribers: return (False, 'NO_SUBSCRIBERS') if not isinstance(subscribers, (list, tuple, set)): return (False, 'NO_SUBSCRIBERS') try: # Delete existing members first, then add them with one SQL statement. # To avoid inserting rows one by one, and have to handle duplicate # record error. conn.delete('maillist_members', vars={'address': mail, 'members': subscribers}, where='address=$address AND member IN $members') subscribers = __exclude_non_existing_addresses(domain=domain, addresses=subscribers, conn=conn) if subscribers: records = [] for _addr in subscribers: params = { 'address': mail, 'domain': domain, 'member': _addr, 'dest_domain': _addr.split('@', 1)[-1], } records.append(params) conn.multiple_insert('maillist_members', records) logger.info('Added subscribers: {0}.'.format(mail)) return (True,) except Exception as e: logger.error('Error while adding members {0}: {1}'.format(mail, e)) return (False, repr(e))
def __update_normal_param(mail, param, value, param_file=None, is_email=False): # Although we write all given value, but only first line is used by mlmmj. if not param_file: param_file = __get_param_file(mail=mail, param=param) if param == 'maxmailsize': try: value = int(value) except: value = 0 if not value: # Remove param file. qr = __remove_file(path=param_file) return qr if value: if is_email: value = str(value).lower() if not utils.is_email(value): return (False, 'INVALID_EMAIL') try: if isinstance(value, int): value = str(value) value = value.encode('utf-8') with open(param_file, 'w') as f: f.write(value + '\n') except Exception as e: logger.error( "[{0}] {1}, error while updating (normal) parameter: {2} -> {3}, {4}" .format(web.ctx.ip, mail, param, value, e)) return (False, repr(e)) else: qr = __remove_file(path=param_file) if not qr[0]: return qr logger.info("[{0}] {1}, updated (normal) parameter: {2} -> {3}".format( web.ctx.ip, mail, param, value)) return (True, )
def add_subscribers(mail, subscribers, subscription='normal', require_confirm=True): """Add subscribers to given subscription version of mailing list. :param mail: mail address of mailing list account :param subscribers: a list/tuple/set of subscribers' email addresses :param subscription: subscription version: normal, nomail, digest. :param require_confirm: subscription version: normal, nomail, digest. """ mail = mail.lower() subscribers = [str(i).lower() for i in subscribers if utils.is_email(i)] if not subscribers: return (True, ) if require_confirm: qr = __add_subscribers_with_confirm(mail=mail, subscribers=subscribers, subscription=subscription) if not qr[0]: return qr else: grouped_subscribers = {} for i in subscribers: letter = i[0] if letter in grouped_subscribers: grouped_subscribers[letter].append(i) else: grouped_subscribers[letter] = [i] _dir = __get_ml_subscribers_dir(mail=mail, subscription=subscription) for letter in grouped_subscribers: # Get file stores the subscriber. path = os.path.join(_dir, letter) qr = __add_lines_in_file(f=path, lines=grouped_subscribers[letter]) if not qr[0]: return qr return (True, )
def remove_maillist(mail, conn=None): """Remove required SQL records to remove a mailing list account.""" mail = str(mail).lower() if not utils.is_email(mail): return (False, 'INVALID_EMAIL') if not conn: _wrap = SQLWrap() conn = _wrap.conn try: conn.delete('maillists', vars={'mail': mail}, where='address=$mail') conn.delete('forwardings', vars={'mail': mail}, where='address=$mail') return (True, ) except Exception as e: logger.error("SQL error: {0}".format(e)) return (False, repr(e))
def remove_maillist(mail, conn=None): """Remove LDAP object to remove a mailing list account.""" mail = str(mail).lower() (_, domain) = mail.split('@', 1) if not utils.is_email(mail): return (False, 'INVALID_EMAIL') if not conn: _wrap = LDAPWrap() conn = _wrap.conn try: dn = 'mail=%s,ou=Groups,domainName=%s,%s' % (mail, domain, settings.iredmail_ldap_basedn) conn.delete_s(dn) return (True,) except ldap.NO_SUCH_OBJECT: return (False, 'ACCOUNT_NOT_EXIST') except Exception as e: logger.error("Error: {0}".format(e)) return (False, repr(e))
def create_ml(mail, **kwargs): """Create required directories/files for a new mailing list on file system. WARNING: it doesn't check whether account already exists in backend. @mail - full email address of new mailing list you're going to create @kwargs - dict of parameter/value pairs used to set account profile """ if not utils.is_email(mail): return (False, 'INVALID_EMAIL') mail = str(mail).lower() _ml_dir = __get_ml_dir(mail=mail) if not os.path.exists(_ml_dir): try: os.makedirs(_ml_dir, mode=settings.MLMMJ_FILE_PERMISSION) except Exception, e: _msg = "error while creating base directory ({0}), {1}".format( _ml_dir, repr(e)) logger.error("[{0}] {1}, {2}".format(web.ctx.ip, mail, _msg)) return (False, _msg)
def POST(self, subscriber): """ Add one subscriber to multiple mailing lists. :param subscriber: email address of the subscriber Available form parameters: `lists`: mailing lists. Multilple mailing lists must be separated by comma. `require_confirm`: [yes|no]. If set to `no`, will not send subscription confirm to subscriber. Defaults to `yes`. `subscription`: possible subscription versions: normal, digest, nomail. """ subscriber = str(subscriber).lower() form = web.input() subscription = form.get('subscription', 'normal') if subscription not in mlmmj.subscription_versions: subscription = 'normal' # Get mailing lists lists = form.get('lists', '').replace(' ', '').split(',') lists = [str(i).lower() for i in lists if utils.is_email(i)] require_confirm = True if form.get('require_confirm') == 'no': require_confirm = False qr = mlmmj.subscribe_to_lists(subscriber=subscriber, lists=lists, subscription=subscription, require_confirm=require_confirm) return api_render(qr)
run_backend_cli = False backend = None if settings.backend_api == 'bk_none': run_backend_cli = True backend = __import__(settings.backend_cli) action = sys.argv[1] if action not in ['info', 'create', 'update', 'delete', 'has_subscriber', 'subscribers', 'subscribed', 'add_subscribers', 'remove_subscribers']: print("<ERROR> Invalid action: {0}. Usage:\n\n{1}".format(action, usage)) sys.exit() mail = sys.argv[2] if not is_email(mail): sys.exit('Invalid email address: {0}'.format(mail)) args = sys.argv[3:] # Convert args to a dict arg_kvs = {} for arg in args: if '=' in arg: (k, v) = arg.split('=', 1) arg_kvs[k] = v api_url = api_base_url + '/' + mail api_subscriber_url = api_base_url + '/subscriber/' + mail if action == 'info':
def __sync_addresses(mail, addresses, address_type): msg = "" if address_type not in ["owner", "moderator"]: msg = "Unsupported address type: {}.".format(address_type) return (False, msg) addresses = [i.lower() for i in addresses if is_email(i)] if backend == "sql": _map = { "owner": { "table": "maillist_owners", "column": "owner", }, "moderator": { "table": "moderators", "column": "moderator", }, } sql_table = _map[address_type]["table"] sql_column = _map[address_type]["column"] conn.delete(sql_table, vars={"mail": mail}, where="address=$mail") if addresses: rows = [] for i in addresses: row = { "address": mail, sql_column: i, "domain": mail.split("@", 1)[-1], "dest_domain": i.split("@", 1)[-1], } rows.append(row) try: conn.multiple_insert(sql_table, rows) except Exception as e: msg = "Error while updating {}: {}".format(sql_table, repr(e)) return (False, msg) elif backend == "ldap": _domain = mail.split("@", 1)[-1] ldn = "mail={},ou=Groups,domainName={},{}".format( mail, _domain, settings.iredmail_ldap_basedn) if not addresses: # Remove attribute. addresses = None if address_type == "owner": mod_attr = [(ldap.MOD_REPLACE, "listOwner", str2bytes(addresses))] elif address_type == "moderator": mod_attr = [(ldap.MOD_REPLACE, "listModerator", str2bytes(addresses))] try: conn.modify_s(ldn, mod_attr) except ldap.OBJECT_CLASS_VIOLATION: print("<<< ERROR >>> Seems your OpenLDAP server doesn't support " "`listOwner` and `listModerator` attributes which were " "introduced in iRedMail-1.4.0, please follow iRedMail " "upgrade tutorial to update LDAP schema file " "`iredmail.schema` first: " "https://docs.iredmail.org/iredmail.releases.html") sys.exit() except Exception as e: msg = "Error while updating {} of mailing list {}: {}".format( address_type, mail, repr(e)) return (False, msg) return (True, )
_filter = "(&(objectClass=mailList)(accountStatus=active)(enabledService=mlmmj))" try: qr = conn.search_s(settings.iredmail_ldap_basedn, ldap.SCOPE_SUBTREE, _filter, ["mail"]) for (_dn, _ldif) in qr: mls += [bytes2str(i).lower() for i in _ldif["mail"]] except Exception as e: print("Error while querying: {}".format(repr(e))) if not mls: print("No mailing list found. Abort.") sys.exit() else: # Get domain names and mailing lists. domains = [i.lower() for i in args if is_domain(i)] mls = [i.lower() for i in args if is_email(i)] # Query SQL/LDAP to get all mailing lists under specified domains. if domains: print("Querying mailing lists under given domain(s): {}".format( ", ".join(domains))) if backend == "sql": qr = conn.select("maillists", vars={'domains': domains}, what="address", where="domain IN $domains AND active=1") for i in qr: addr = i["address"].lower() mls.append(addr) elif backend == "ldap":
def create_ml(mail, **kwargs): """Create required directories/files for a new mailing list on file system. WARNING: it doesn't check whether account already exists in backend. @mail - full email address of new mailing list you're going to create @kwargs - dict of parameter/value pairs used to set account profile """ if not utils.is_email(mail): return (False, 'INVALID_EMAIL') mail = str(mail).lower() _ml_dir = __get_ml_dir(mail=mail) if not os.path.exists(_ml_dir): try: os.makedirs(_ml_dir, mode=settings.MLMMJ_FILE_PERMISSION) except Exception as e: _msg = "error while creating base directory ({0}), {1}".format( _ml_dir, repr(e)) logger.error("[{0}] {1}, {2}".format(web.ctx.ip, mail, _msg)) return (False, _msg) # Create required sub-directories for _dir in settings.MLMMJ_DEFAULT_SUB_DIRS: _sub_dir = os.path.join(_ml_dir, _dir) if not os.path.exists(_sub_dir): try: os.makedirs(_sub_dir, mode=settings.MLMMJ_FILE_PERMISSION) except Exception as e: _msg = "error while creating sub-directory ({0}), {1}".format( _sub_dir, repr(e)) logger.error("[{0}] {1}, {2}".format(web.ctx.ip, mail, _msg)) return (False, _msg) else: qr = __set_file_permission(_sub_dir) if not qr[0]: return qr # Create file `control/listaddress` with primary address _f = os.path.join(_ml_dir, 'control/listaddress') with open(_f, 'w') as f: f.write('{0}\n'.format(mail)) # Create extra control file index_path = os.path.join(_ml_dir, 'index') open(index_path, 'w').close() # Copy skel/language template files _sub_dir_text = os.path.join(_ml_dir, 'text') _language = kwargs.get('language', 'en') _src_dir = os.path.join(settings.MLMMJ_SKEL_DIR, _language) if not os.path.exists(_src_dir): logger.error("Skel directory does not exist: {0}".format(_src_dir)) return (False, 'SKEL_DIR_NOT_EXIST') qr = __copy_dir_files(_src_dir, _sub_dir_text) if not qr[0]: return qr qr = __update_mlmmj_params(mail=mail, **kwargs) if not qr[0]: return qr return (True, )