source: asadb/util/mailinglist.py

stable
Last change on this file was 093448c, checked in by ASA Group Database <asa-db@…>, 10 years ago

Make listdiff diff the GSC and UA Finboard lists too

  • Property mode set to 100644
File size: 4.7 KB
Line 
1import subprocess
2
3import mit
4
5
6class MailingList(object):
7    def __init__(self, name, ):
8        self.name = name
9
10    def list_members(self, ):
11        raise NotImplementedError
12
13    def change_members(self, add_members, delete_members, ):
14        raise NotImplementedError
15
16
17BLANCHE_PATH="/usr/bin/blanche"
18class MoiraList(MailingList):
19    def __init__(self, *args, **kwargs):
20        super(MoiraList, self).__init__(*args, **kwargs)
21        self._ccache = None
22
23    @property
24    def ccache(self, ):
25        if not self._ccache:
26            self._ccache = mit.kinit()
27        return self._ccache
28
29    def list_members(self, ):
30        env = dict(KRB5CCNAME=self.ccache.name)
31        res = subprocess.Popen(
32            [BLANCHE_PATH, self.name, ],
33            stdout=subprocess.PIPE,
34            stderr=subprocess.PIPE,
35            env=env,
36        )
37        stdout, stderr = res.communicate()
38        if res.returncode:
39            raise RuntimeError("Failed to list members: %s" % (stderr, ))
40        members = [self.convert_moira_to_email(m) for m in stdout.strip().split("\n")]
41        return members
42
43    def convert_moira_to_email(self, email):
44        typ, colon, val = email.partition(":")
45        if typ in ('STRING', 'USER', 'LIST'):
46            email = val + "@mit.edu"
47        # Leave untouched: KERBEROS (shouldn't exist), untagged strings
48        assert email.count('@') == 1, "%s has wrong number of @'s" % (email, )
49        return email
50
51    def strip_mit(self, email):
52        if '@' in email:
53            local, domain = email.split('@')
54            if domain.lower() == 'mit.edu':
55                return local
56        return email
57
58    def canonicalize_member(self, member):
59        if type(member) == type(()):
60            name, email = member
61        else:
62            name = None
63            email = member
64        email = self.strip_mit(email)
65        return name, email
66
67    def change_members(self, add_members, delete_members, ):
68        """
69        Add and/or remove members from the list.
70        """
71
72        # Note that it passes all members on the commandline, so it shouldn't be
73        # used for large lists at the moment. OTOH, "large" appears to be
74        # 2M characters, so.
75        # If that becomes an issue, it should probably check the number of
76        # changes, and use -al / -dl with a tempfile as appropriate.
77
78        env = dict(KRB5CCNAME=self.ccache.name)
79        cmdline = [BLANCHE_PATH, self.name, ]
80
81        for member in add_members:
82            name, email = self.canonicalize_member(member)
83            if name:
84                cmdline.extend(('-at', email, name))
85            else:
86                cmdline.extend(('-a', email))
87
88        for member in delete_members:
89            name, email = self.canonicalize_member(member)
90            cmdline.extend(('-d', email))
91
92        res = subprocess.Popen(
93            cmdline,
94            stdout=subprocess.PIPE,
95            stderr=subprocess.STDOUT,
96            env=env,
97        )
98        stdout, stderr = res.communicate()
99        return stdout
100
101
102
103MMBLANCHE_PATH="/mit/consult/bin/mmblanche"
104class MailmanList(MailingList):
105    def list_members(self, ):
106        res = subprocess.Popen(
107            [MMBLANCHE_PATH, self.name, ],
108            stdout=subprocess.PIPE,
109            stderr=subprocess.PIPE,
110        )
111        stdout, stderr = res.communicate()
112        if res.returncode:
113            raise RuntimeError("Failed to list members: %s" % (stderr, ))
114        members = stdout.strip().split("\n")
115        return members
116
117    def change_members(self, add_members, delete_members, ):
118        """
119        Add and/or remove members from the list.
120        """
121
122        # Note that it passes all members on the commandline, so it shouldn't be
123        # used for large lists at the moment. OTOH, "large" appears to be
124        # 2M characters, so.
125        # If that becomes an issue, it should probably check the number of
126        # changes, and use -al / -dl with a tempfile as appropriate.
127
128        cmdline = [MMBLANCHE_PATH, self.name, ]
129        for member in add_members:
130            cmdline.append('-a')
131            if type(member) == type(()):
132                name, email = member
133                name = name.replace('"', "''")
134                member = '"%s" <%s>' % (name, email, )
135            cmdline.append(member)
136        for member in delete_members:
137            cmdline.append('-d')
138            if type(member) == type(()):
139                name, member = member
140            cmdline.append(member)
141        res = subprocess.Popen(
142            cmdline,
143            stdout=subprocess.PIPE,
144            stderr=subprocess.PIPE,
145        )
146        stdout, stderr = res.communicate()
147        assert stderr=="", ("stderr unexpectedly non-empty: %s" % (stderr, ))
148        return stdout
Note: See TracBrowser for help on using the repository browser.