def check_permission(self, action, username, resource, perm):

        # maybe we need to reorganise a little, to factor up the
        # "isinstance" business.
        
        if action is "ATTACHMENT_VIEW":
            self.log.debug("Deciding if %s can do %s on %s", username, action, resource)
            if resource and resource.parent and resource.parent.realm == "mailinglist":
                return "MAILINGLIST_VIEW" in perm(resource.parent)

        elif action is "MAILINGLIST_VIEW":
            self.log.debug("Deciding if %s can do %s on %s", username, action, resource)
            # if no resource, then it's up to the general permissions table
            if resource and resource.realm == "mailinglist":
                instance = MailinglistSystem(self.env).get_instance_for_resource(resource)
                if isinstance(instance, MailinglistMessage):
                    return action in perm(instance.conversation.resource)
                elif isinstance(instance, MailinglistConversation):
                    return action in perm(instance.mailinglist.resource)
                elif instance.private == False:
                    # it's a mailinglist
                    return None # it's up to the general permissions table
                elif instance.private == True:
                    # it's a mailinglist
                    return username in instance.subscribers()
            
        elif action is "MAILINGLIST_POST":
            self.log.debug("Deciding if %s can do %s on %s", username, action, resource)            
            if resource is None:
                # In general, people can post...
                return True
            if resource.realm == "mailinglist":
                instance = MailinglistSystem(self.env).get_instance_for_resource(resource)
                if isinstance(instance, MailinglistMessage):
                    return action in perm(instance.conversation.resource)
                elif isinstance(instance, MailinglistConversation):
                    return action in perm(instance.mailinglist.resource)
                elif instance.postperm == "OPEN":
                    return True
                elif instance.postperm == "RESTRICTED":
                    try:
                        return instance.subscribers()[username]['poster']
                    except KeyError, e:
                        return False
                elif instance.postperm == "MEMBERS":
                    return username in instance.subscribers()
    def setUp(self):
        self.env = EnvironmentStub(enable=[MailinglistPermissionPolicy,
                                           DefaultPermissionPolicy,
                                           MailinglistSystem,
                                           DefaultPermissionStore,
                                           SQLiteConnector])
        self.env.config.set('trac', 'permission_policies', 'MailinglistPermissionPolicy, DefaultPermissionPolicy')

        self.mailinglist_system = MailinglistSystem(self.env)
        self.mailinglist_system.environment_created()

        self.perm_system = PermissionSystem(self.env)
    def render_macro(self, req, name, content):
        args,kwargs = parse_args(content)
        if len(args) == 0:
            ul = tag.ul(class_="mailinglistlist")

            for mailinglist in Mailinglist.select(self.env):
                if "MAILINGLIST_VIEW" in req.perm(mailinglist.resource):         
                    ul.append(tag.li(tag.a(mailinglist.name,
                                           href=get_resource_url(self.env, mailinglist.resource, req.href))))
                        
            return ul
        if kwargs.has_key('limit'):
            limit = int(kwargs['limit'])
        elif len(args) > 1:
            limit = int(args[1])
        else:
            limit = 10
        resource = Resource("mailinglist",args[0])
        instance = MailinglistSystem(self.env).get_instance_for_resource(resource)

        if isinstance(instance, Mailinglist):
            if not req.perm(instance.resource).has_permission('MAILINGLIST_VIEW'):
                return system_message("Permission denied viewing mailinglist: %s" % instance.name)
            ul = tag.ul()
            for message in instance.messages(limit=limit, insubject=kwargs.get('insubject', None),desc=True):
                ul.append(tag.li(
                    tag.a(tag.span(message.subject, class_="messagesubject"),
                          href=get_resource_url(self.env, message.resource, req.href)),
                    " (",
                    dateinfo(message.date),
                    ")",
                    ))
            ul.append(tag.li(tag.a("(%d messages...)" % instance.count_messages(insubject=kwargs.get('insubject', None)),
                                   href=get_resource_url(self.env, instance.resource, req.href))))
            return tag.div("Mailinglist: ",
                           tag.a(instance.name,
                                 href=get_resource_url(self.env, instance.resource, req.href)),
                           ul,
                           class_="mailinglistfeed")
        elif isinstance(instance, MailinglistMessage):
            if not req.perm(instance.resource).has_permission('MAILINGLIST_VIEW'):
                return system_message("Permission denied viewing mail.")


            else:
                limit = None
            text = wrap_and_quote(instance.body, 78)[0]
            if limit:
                text = "\n".join(text.split("\n")[0:limit])
                textelement = tag.pre(text) + tag.a(tag.pre("(More...)"),
                                                    href=get_resource_url(self.env, instance.resource, req.href))
            else:
                textelement = tag.pre(text)                
            return tag.div(
                tag.div("Mailinglist: ",
                        tag.a(instance.conversation.mailinglist.name,
                              href=get_resource_url(self.env, instance.conversation.mailinglist.resource, req.href))),
                tag.div("Subject: ",
                        tag.a(instance.subject, href=get_resource_url(self.env, instance.resource, req.href))),
                tag.div("From: ",
                        tag.a(instance.from_name, href="mailto:%s" % instance.from_email)),
                tag.div("To: ", instance.to_header),
                tag.div("Date: ", dateinfo(instance.date)),
                tag.div(textelement),
                class_="mailinglistmessage")            
            
        return system_message("Unknown Mailinglist: %s" % content)
class MailinglistTestCase(unittest.TestCase):

    def setUp(self):
        self.env = EnvironmentStub(enable=[MailinglistPermissionPolicy,
                                           DefaultPermissionPolicy,
                                           MailinglistSystem,
                                           DefaultPermissionStore,
                                           SQLiteConnector])
        self.env.config.set('trac', 'permission_policies', 'MailinglistPermissionPolicy, DefaultPermissionPolicy')

        self.mailinglist_system = MailinglistSystem(self.env)
        self.mailinglist_system.environment_created()

        self.perm_system = PermissionSystem(self.env)
        
    def tearDown(self):
        self.env.reset_db()

    def test_str_list(self):
        mailinglist = Mailinglist(self.env,
                                  emailaddress="list", name="Sample List", private=True,
                                  postperm="OPEN")
        str(mailinglist)

    def test_adding_lists(self):
        for i in range(0,10):
            mailinglist = Mailinglist(self.env,
                                      emailaddress="list%s" % i, name="Sample List", private=True,
                                      postperm="OPEN")
            mailinglist.insert()
            assert mailinglist.addr()
            assert mailinglist.addr(bounce=True)            

    def test_removing_lists(self):
        l = []
        for i in range(0,10):
            mailinglist = Mailinglist(self.env,
                                      emailaddress="list%s" % i, name="Sample List", private=True,
                                      postperm="OPEN")
            mailinglist.insert()
            l.append(mailinglist.id)
            
        for i in l:
            Mailinglist(self.env, i).delete()
            
    @raises(StandardError) # would be nice to be more specific, but
                           # that depends on which db is used?
    def test_add_duplicate_lists(self):
        Mailinglist(self.env, emailaddress="list", name="Sample List", private=True,
                    postperm="OPEN").insert()
        Mailinglist(self.env, emailaddress="list", name="Sample List", private=True,
                    postperm="OPEN").insert()

    def test_load_list(self):
        mailinglist = Mailinglist(self.env,
                                  emailaddress="list", name="Sample List", private=True,
                                  postperm="OPEN")
        assert mailinglist.id is None
        mailinglist.insert()
        assert mailinglist.id is not None
        found = Mailinglist(self.env, mailinglist.id)
        assert found.id is mailinglist.id
        
    def test_update_private(self):
        mailinglist = Mailinglist(self.env,
                                  emailaddress="list", name="Sample List", private=True,
                                  postperm="OPEN")
        assert mailinglist.private == True
        newid = mailinglist.insert()
        mailinglist.private = False
        mailinglist.save_changes()
        assert Mailinglist(self.env, newid).private is False

    def test_add_messages(self):
        mailinglist = Mailinglist(self.env,
                                  emailaddress="LIST1", name="Sample List 1", private=True,
                                  postperm="OPEN")
        mailinglist.insert()
        mailinglist = Mailinglist(self.env,
                                  emailaddress="list2", name="Sample List 2", private=True,
                                  postperm="OPEN")
        mailinglist.insert()

        for rawmsg in rawmsgs:
            for listname in ("list1", "list2"):
                bytes = rawmsg % dict(sender="Jack Sparrow",
                                      email="*****@*****.**",
                                      list=listname,
                                      domain="example.com",
                                      subject="Boats",
                                      asctime=time.asctime(),
                                      id="asdfasdf",
                                      body="Need boats.")

                mailinglist = Mailinglist.select_by_address(self.env,
                                                            "*****@*****.**" % listname)
                message = mailinglist.insert_raw_email(bytes)
                
        assert len(list(Mailinglist.select(self.env))) == 2
        
        for mailinglist in Mailinglist.select(self.env):
            for conversation in mailinglist.conversations():
                assert conversation.get_first() is not None
                for message in conversation.messages():
                    assert message
                    #for attachment in Attachment.select(self.env, 'mailinglistmessage', message.id):
                    #    assert attachment

            mailinglist.delete()
            
        assert len(list(Mailinglist.select(self.env))) == 0
        

    def test_add_message_with_attachment(self):
        mailinglist = Mailinglist(self.env,
                                  emailaddress="LIST1", name="Sample List 1", private=True,
                                  postperm="OPEN")
        mailinglist.insert()
        
        mailinglist.insert_raw_email(raw_message_with_attachment % dict(sender="Jack Sparrow",
                                                                        email="*****@*****.**",
                                                                        list="list1",
                                                                        domain="example.com",
                                                                        subject="Boats",
                                                                        asctime=time.asctime(),
                                                                        id="asdfasdf",
                                                                        body="Need images of boats."))
        
        message = mailinglist.conversations().next().messages().next()
        attachment_path = Attachment.select(self.env, message.resource.realm, message.resource.id).next().path
        assert os.path.exists(attachment_path)        
        message.delete()
        assert not os.path.exists(attachment_path)

    def test_add_list_member(self):
        mailinglist = Mailinglist(self.env,
                                  emailaddress="LIST1", private=True, postperm="MEMBERS")
        mailinglist.insert()
        mailinglist.subscribe(user="******", poster=True)
        assert "sparrowj" in mailinglist.subscribers()

    @raises(PermissionError)
    def test_post_to_private_list_denied_members(self):
        """Not a member of this list."""
        mailinglist = Mailinglist(self.env,
                                  emailaddress="LIST1", private=True, postperm="MEMBERS")
        mailinglist.insert()
        mailinglist.subscribe(user="******", poster=True)
        PermissionCache(self.env, 'sparrowj',
                        mailinglist.resource).assert_permission('MAILINGLIST_POST')

    @raises(PermissionError)
    def test_post_to_private_list_denied_restricted(self):
        """Non-posting member of this list."""        
        mailinglist = Mailinglist(self.env,
                                  emailaddress="LIST1", private=True, postperm="RESTRICTED")
        mailinglist.insert()
        mailinglist.subscribe(user="******", poster=False)
        PermissionCache(self.env, 'sparrowj',
                        mailinglist.resource).assert_permission('MAILINGLIST_POST')

    @raises(PermissionError)
    def test_post_to_private_list_denied_restricted_nonmember(self):
        """Non-posting member of this list."""        
        mailinglist = Mailinglist(self.env,
                                  emailaddress="LIST1", private=True, postperm="RESTRICTED")
        mailinglist.insert()
        mailinglist.subscribe(user="******", poster=False)
        PermissionCache(self.env, 'smithj',
                        mailinglist.resource).assert_permission('MAILINGLIST_POST')

    def test_post_to_private_list_accepted_members(self):
        mailinglist = Mailinglist(self.env,
                                  emailaddress="LIST1", private=True, postperm="MEMBERS")
        mailinglist.insert()
        mailinglist.subscribe(user="******", poster=True)
        PermissionCache(self.env, 'sparrowj',
                        mailinglist.resource).assert_permission('MAILINGLIST_POST')

    def test_post_to_private_list_accepted_members_group(self):
        mailinglist = Mailinglist(self.env,
                                  emailaddress="LIST1", private=True, postperm="MEMBERS")
        mailinglist.insert()
        PermissionSystem(self.env).grant_permission('sparrowj', 'group1')
        PermissionSystem(self.env).grant_permission('smithj', 'group1')        
        mailinglist.subscribe(group="group1", poster=True)
        PermissionCache(self.env, 'sparrowj',
                        mailinglist.resource).assert_permission('MAILINGLIST_POST')

    def test_post_to_private_list_accepted_restricted(self):
        mailinglist = Mailinglist(self.env,
                                  emailaddress="LIST1", private=True, postperm="RESTRICTED")
        mailinglist.insert()
        mailinglist.subscribe(user="******", poster=False)        
        mailinglist.subscribe(user="******", poster=True)
        PermissionCache(self.env, 'sparrowj',
                        mailinglist.resource).assert_permission('MAILINGLIST_POST')

    def test_subscribers(self):
        mailinglist = Mailinglist(self.env,
                                  emailaddress="LIST1", private=True, postperm="MEMBERS")
        mailinglist.insert()
        PermissionSystem(self.env).grant_permission('sparrowj', 'group1')
        PermissionSystem(self.env).grant_permission('smithj', 'group1')
        PermissionSystem(self.env).grant_permission('pipern', 'group2')
        mailinglist.subscribe(group="group1", poster=True)
        mailinglist.subscribe(group="group2", poster=True)
        mailinglist.unsubscribe(user="******")

        assert mailinglist.subscribers()["smithj"]['decline'] == True
        assert "sparrowj" in mailinglist.subscribers()
        assert "pipern" in mailinglist.subscribers()

        mailinglist.unsubscribe(group="group1")
        assert "sparrowj" not in mailinglist.subscribers()        

    def test_read_private_list_accepted(self):
        mailinglist = Mailinglist(self.env,
                                  emailaddress="LIST1", private=True, postperm="RESTRICTED")
        mailinglist.insert()
        mailinglist.subscribe(user="******", poster=False)        
        mailinglist.subscribe(user="******", poster=True)
        PermissionCache(self.env, 'sparrowj',
                        mailinglist.resource).assert_permission('MAILINGLIST_VIEW')

    def test_read_nonprivate_list_accepted(self):
        PermissionSystem(self.env).grant_permission('members', 'MAILINGLIST_VIEW')
        PermissionSystem(self.env).grant_permission('randomuser', 'members')
        mailinglist = Mailinglist(self.env,
                                  emailaddress="LIST1", private=False, postperm="RESTRICTED")
        mailinglist.insert()
        mailinglist.subscribe(user="******", poster=False)        
        mailinglist.subscribe(user="******", poster=True)
        PermissionCache(self.env, 'randomuser',
                        mailinglist.resource).assert_permission('MAILINGLIST_VIEW')

    @raises(PermissionError)
    def test_read_nonprivate_list_denied(self):
        # not a private list, but in general the user isn't allowed to
        # view mailing lists (e.g., not a member of this project at all.)
        mailinglist = Mailinglist(self.env,
                                  emailaddress="LIST1", private=False, postperm="RESTRICTED")
        mailinglist.insert()
        mailinglist.subscribe(user="******", poster=False)        
        mailinglist.subscribe(user="******", poster=True)
        PermissionCache(self.env, 'randomuser',
                        mailinglist.resource).assert_permission('MAILINGLIST_VIEW')

    @raises(PermissionError)
    def test_read_private_list_denied(self):
        mailinglist = Mailinglist(self.env,
                                  emailaddress="LIST1", private=True, postperm="RESTRICTED")
        mailinglist.insert()
        mailinglist.subscribe(user="******", poster=False)        
        mailinglist.subscribe(user="******", poster=True)
        PermissionCache(self.env, 'randomuser',
                        mailinglist.resource).assert_permission('MAILINGLIST_VIEW')