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, )
Exemple #2
0
    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)
Exemple #3
0
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
Exemple #4
0
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, )
Exemple #5
0
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, )
Exemple #6
0
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, )
Exemple #7
0
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))
Exemple #8
0
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
Exemple #9
0
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
Exemple #10
0
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))
Exemple #11
0
    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))
Exemple #12
0
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
Exemple #13
0
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, )
Exemple #14
0
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)
Exemple #15
0
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
Exemple #16
0
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
Exemple #17
0
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, )
Exemple #18
0
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))
Exemple #19
0
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)
Exemple #20
0
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))
Exemple #21
0
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, )
Exemple #22
0
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, )
Exemple #23
0
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))
Exemple #24
0
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))
Exemple #25
0
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)
Exemple #26
0
    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)
Exemple #27
0
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':
Exemple #28
0
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, )
Exemple #29
0
        _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":
Exemple #30
0
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, )