/[drupal]/contributions/modules/mm2/xml-rpc.patch
ViewVC logotype

Contents of /contributions/modules/mm2/xml-rpc.patch

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.2 - (show annotations) (download) (as text)
Thu May 8 10:58:56 2008 UTC (18 months, 3 weeks ago) by lordrich
Branch: MAIN
CVS Tags: HEAD
Changes since 1.1: +10 -5 lines
File MIME type: text/x-patch
Updated xml-rpc.patch to run genaliases, or in more general terms to run mta-specific post-list-creation functions
1 Index: mailman-2.1.9/Mailman/Cgi/RPC2.py
2 ===================================================================
3 --- /dev/null 1970-01-01 00:00:00.000000000 +0000
4 +++ mailman-2.1.9/Mailman/Cgi/RPC2.py 2008-04-26 17:00:16.000000000 +0100
5 @@ -0,0 +1,47 @@
6 +'''RPC2.py
7 +An XML-RPC listener for interfacing with GNU/Mailman
8 +Joshua Ginsberg <[EMAIL PROTECTED]>
9 +'''
10 +
11 +import os, re, xmlrpclib
12 +from Mailman import XMLRPC, mm_cfg, MailList, Errors, i18n
13 +
14 +# Set up i18n
15 +_ = i18n._
16 +i18n.set_language(mm_cfg.DEFAULT_SERVER_LANGUAGE)
17 +
18 +def main():
19 + #0: Make sure we look like a CGI-like environment
20 + try:
21 + cgi_version = os.environ['GATEWAY_INTERFACE']
22 + except KeyError:
23 + raise xmlrpclib.Fault(-32300,
24 + _('Listener must be run within a CGI environment.'))
25 + if re.match('CGI/[0-9].[0-9]', cgi_version) is None:
26 + raise xmlrpclib.Fault(-32300,
27 + _('Listener must be run within a CGI environment.'))
28 +
29 + #1: What is the HTTP method?
30 + try:
31 + cgi_method = os.environ['REQUEST_METHOD']
32 + except KeyError:
33 + raise xmlrpclib.Fault(-32300,
34 + _('No HTTP method was found.'))
35 +
36 + if cgi_method == 'POST':
37 +
38 + #2: Content-type = text/xml
39 + try:
40 + content_type = os.environ['CONTENT_TYPE']
41 + except KeyError:
42 + raise xmlrpclib.Fault(-32300,
43 + _('Webserver did not provide a content type.'))
44 + if content_type != 'text/xml':
45 + raise xmlrpclib.Fault(-32300, _('Content type must be text/xml'))
46 +
47 + XMLRPC.handler.handle_request()
48 +
49 + elif cgi_method == 'GET':
50 + XMLRPC.handler.handle_get()
51 + else:
52 + raise xmlrpclib.Fault(-32300, _('Invalid HTTP Method.'))
53 Index: mailman-2.1.9/Mailman/XMLRPC.py
54 ===================================================================
55 --- /dev/null 1970-01-01 00:00:00.000000000 +0000
56 +++ mailman-2.1.9/Mailman/XMLRPC.py 2008-05-08 11:28:10.000000000 +0100
57 @@ -0,0 +1,331 @@
58 +'''XMLRPC
59 +
60 +This library implements an XML-RPC interface to the GNU/Mailman list manager
61 +software (http://list.org).
62 +
63 +Joshua Ginsberg <[EMAIL PROTECTED]>
64 +'''
65 +
66 +from Mailman import MailList, mm_cfg, i18n, Errors, Utils
67 +from Mailman.Logging.Syslog import syslog
68 +import os, signal, sys, os.path, shutil, xmlrpclib, sha, traceback, cgi
69 +from DocXMLRPCServer import DocCGIXMLRPCRequestHandler
70 +
71 +# Set up i18n
72 +_ = i18n._
73 +i18n.set_language(mm_cfg.DEFAULT_SERVER_LANGUAGE)
74 +
75 +def __authenhandler__(username, password, siteadmin):
76 + '''__authenhandler__(username, password, siteadmin)
77 +
78 + A helper script designed to verify the basic authentication data
79 +
80 + username -- the username provided
81 + password -- the password provided
82 + siteadmin -- If true, the username must be 'mailman' and the password must
83 + be the site administrator password. If false, the username must be the
84 + list to work with, and the password must be either the list admin
85 + password or the site admin password.
86 +
87 + Raises MMAuthenticationError if the authentication fails. Returns True
88 + otherwise.
89 + '''
90 + if siteadmin and username != 'mailman':
91 + raise Errors.MMBadUserError, _('This method requires site admin access.')
92 + if not siteadmin and username == 'mailman':
93 + raise Errors.MMBadUserError, \
94 + _('This method requires a list as a username.')
95 + if username == 'mailman':
96 + # if username is mailman, the only authentication that can happen is
97 + # as site administrator
98 + if Utils.check_global_password(password):
99 + return True
100 + else:
101 + raise Errors.MMAuthenticationError, _('Invalid login.')
102 + else:
103 + try:
104 + mlist = MailList.MailList(username, lock=0)
105 + except Errors.MMListError, e:
106 + # a missing list means a bad username
107 + # plus, we don't want to confirm what lists do or don't exist by
108 + # doing something different than if the u/p combination is bad
109 + syslog('error', _('''Mailing list %s not found''') % (username,))
110 + raise Errors.MMAuthenticationError, _('Invalid login.')
111 + if mlist.WebAuthenticate((mm_cfg.AuthListAdmin, mm_cfg.AuthSiteAdmin),
112 + password):
113 + return True
114 + else:
115 + raise Errors.MMAuthenticationError, _('Invalid login.')
116 +
117 +class BoboTheClown(object):
118 + '''Bobo the Clown is dumb. Just like this class.'''
119 + pass
120 +
121 +def add_member(listname, authpassword, address, fullname, password, digest,
122 + now):
123 + '''add_member(listname, authpassword, address, fullname, password, digest,
124 + now):
125 +
126 + Subscribes the email address provided to the mailing list.
127 +
128 + listname -- the name of the list to add a member to
129 + authpassword -- the site admin or list admin password for this list
130 + address -- the email address to add
131 + fullname -- the user's full name
132 + password -- the password the user would like to have
133 + digest -- True or False implying if they wish to receive batched digest
134 + delivery
135 + now -- True or False implying whether to bypass normal mailing list rules
136 + about confirmation/approval
137 +
138 + Returns True if everything succeeded
139 + '''
140 +
141 + __authenhandler__(listname, authpassword, False)
142 + ip = os.environ['REMOTE_ADDR']
143 +
144 + mlist = MailList.MailList(listname, lock=0)
145 + # switch to mailing list preferred language
146 + i18n.set_language(mlist.preferred_language)
147 + # taking my cues from other Cgi scripts, notably admin.py
148 +
149 + def freak_out(signum, frame, mlist=mlist):
150 + mlist.Unlock()
151 + sys.exit(0)
152 +
153 + signal.signal(signal.SIGTERM, freak_out)
154 + mlist.Lock()
155 + try:
156 + bobo = BoboTheClown()
157 + for attr in ['address', 'fullname', 'password', 'digest']:
158 + if eval(attr) is not None: setattr(bobo, attr, eval(attr))
159 + if now:
160 + mlist.ApprovedAddMember(bobo, whence='XMLRPC from %s' % (ip,))
161 + else:
162 + mlist.AddMember(bobo, remote='XMLRPC from %s' % (ip,))
163 + mlist.Save()
164 + finally:
165 + mlist.Unlock()
166 + return True
167 +
168 +def delete_member(listname, password, email, now):
169 + '''delete_member(listname, password, email, now):
170 +
171 + Unsubscribes a member from the list.
172 +
173 + listname -- the name of the list to delete a member from
174 + password -- the site admin or list admin password for this list
175 + email -- The email address to unsubscribe
176 + now -- True or False implying whether to bypass normal mailing list rules
177 + about approval
178 +
179 + Returns True if everything succeeded
180 + '''
181 +
182 + __authenhandler__(listname, password, False)
183 + ip = os.environ['REMOTE_ADDR']
184 +
185 + mlist = MailList.MailList(listname, lock=0)
186 + # switch to mailing list preferred language
187 + i18n.set_language(mlist.preferred_language)
188 + # taking my cues from other Cgi scripts, notably admin.py
189 +
190 + def freak_out(signum, frame, mlist=mlist):
191 + mlist.Unlock()
192 + sys.exit(0)
193 +
194 + signal.signal(signal.SIGTERM, freak_out)
195 + mlist.Lock()
196 + try:
197 + if now:
198 + mlist.ApprovedDeleteMember(email, whence='XMLRPC from %s' % (ip,))
199 + else:
200 + mlist.DeleteMember(email, whence='XMLRPC from %s' % (ip,))
201 + mlist.Save()
202 + finally:
203 + mlist.Unlock()
204 + return True
205 +
206 +def change_address(listname, password, old, new, keepold):
207 + '''change_address(listname, password, old, new, keepold):
208 +
209 + Changes an existing member's email address.
210 +
211 + listname -- the name of the list to update
212 + password -- the site admin or list admin password for this list
213 + old -- the old address
214 + new -- the new address
215 + keepold -- True or False whether to keep the old address subscribed as well
216 +
217 + Returns True if everything succeeded
218 + '''
219 +
220 + __authenhandler__(listname, password, False)
221 + ip = os.environ['REMOTE_ADDR']
222 +
223 + mlist = MailList.MailList(listname, lock=0)
224 + # switch to mailing list preferred language
225 + i18n.set_language(mlist.preferred_language)
226 + # taking my cues from other Cgi scripts, notably admin.py
227 +
228 + def freak_out(signum, frame, mlist=mlist):
229 + mlist.Unlock()
230 + sys.exit(0)
231 +
232 + signal.signal(signal.SIGTERM, freak_out)
233 + mlist.Lock()
234 +
235 + try:
236 + mlist.ApprovedChangeMemberAddress(old, new, keepold)
237 + finally:
238 + mlist.Unlock()
239 + return True
240 +
241 +def create_list(site_pw, listname, emaildomain, webhost, moderated, listadmin,
242 + listadmin_pw, languages):
243 + '''create_list(site_pw, listname, emaildomain, webhost, moderated, listadmin,
244 + listadmin_pw, languages):
245 +
246 + Creates a new mailing list.
247 +
248 + site_pw -- the site administrator password
249 + listname -- the name of the list you wish to create
250 + emaildomain -- the email domain this list will appear to come from
251 + webhost -- the hostname used to access the web interface for this list
252 + moderated -- True or False implying whether new members of the list are
253 + to be moderated by default
254 + listadmin -- The list administrator's email address
255 + listadmin_pw -- The list administrator's password
256 + languages -- a list of two-letter language codes for this list to support
257 +
258 + You must be logged in as the site administrator (no username, site admin
259 + password) for this method to be invoked.
260 +
261 + Returns True if everything succeded
262 + '''
263 +
264 + __authenhandler__('mailman', site_pw, True)
265 + ip = os.environ['REMOTE_ADDR']
266 +
267 + mlist = MailList.MailList()
268 + try:
269 + def freak_out(signum, frame, mlist=mlist):
270 + mlist.Unlock()
271 + sys.exit(0)
272 +
273 + signal.signal(signal.SIGTERM, freak_out)
274 + listadmin_pw = sha.new(listadmin_pw).hexdigest()
275 + # okay, I'm just plagiarizing from Cgi/create.py here
276 + oldmask = os.umask(002)
277 + try:
278 + mlist.Create(listname, listadmin, listadmin_pw, languages)
279 + finally:
280 + os.umask(oldmask)
281 + mlist.default_member_moderation = moderated
282 + mlist.web_page_url = mm_cfg.DEFAULT_URL_PATTERN % webhost
283 + mlist.host_name = emaildomain
284 + mlist.Save()
285 + finally:
286 + mlist.Unlock()
287 + # Now do the MTA-specific list creation tasks
288 + if mm_cfg.MTA:
289 + modname = 'Mailman.MTA.' + mm_cfg.MTA
290 + __import__(modname)
291 + sys.modules[modname].create(mlist)
292 + return True
293 +
294 +def delete_list(listname, site_pw, archives_too):
295 + '''delete_list(listname, site_pw, archives_too):
296 +
297 + Delete a list and possibly its archives too.
298 +
299 + listname -- The name of the list to be deleted
300 + site_pw -- The site administrator password
301 + archives_too -- True or False implying whether to remove the lists archives
302 +
303 + Returns True if everything succeded.
304 + '''
305 +
306 +
307 + __authenhandler__('mailman', site_pw, True)
308 + ip = os.environ['REMOTE_ADDR']
309 +
310 + mlist = MailList.MailList(listname, lock=0)
311 +
312 + # pretty much straight ripping off bin/rmlist
313 + if mm_cfg.MTA:
314 + modname = 'Mailman.MTA.' + mm_cfg.MTA
315 + __import__(modname)
316 + sys.modules[modname].remove(mlist)
317 +
318 + REMOVABLES = [os.path.join('lists', listname)]
319 +
320 + # Remove any stale locks associated with the list
321 + for filename in os.listdir(mm_cfg.LOCK_DIR):
322 + fn_listname = filename.split('.')[0]
323 + if fn_listname == listname:
324 + REMOVABLES.append(os.path.join(mm_cfg.LOCK_DIR, filename))
325 + if archives_too:
326 + REMOVABLES.extend([
327 + os.path.join('archives', 'private', listname),
328 + os.path.join('archives', 'private', listname + '.mbox'),
329 + os.path.join('archives', 'public', listname),
330 + os.path.join('archives', 'public', listname + '.mbox')
331 + ])
332 +
333 + for dirtmpl in REMOVABLES:
334 + filename = os.path.join(mm_cfg.VAR_PREFIX, dirtmpl)
335 + if os.path.islink(filename):
336 + os.unlink(filename)
337 + elif os.path.isdir(filename):
338 + shutil.rmtree(filename)
339 + elif os.path.isfile(filename):
340 + os.unlink(filename)
341 + return True
342 +
343 +def __method_wrapper__(method_func):
344 + '''__method_wrapper__(method_func):
345 +
346 + Python's XMLRPC library will catch any exceptions that are not of the class
347 + xmlrpclib.Fault and wrap then as xmlrpclib.Fault exceptions with an error
348 + code of 1. However, for XMLRPC Fault Interoperability, the code needs to be
349 + -32500. This function wraps method execution, catches Mailman errors, and
350 + raises them as xmlrpclib.Fault errors with the appropriate Fault code.
351 + '''
352 +
353 + def foo_lambda(*args):
354 + try:
355 + return method_func(*args)
356 + except Exception, e:
357 + tb_type, tb_value, tb = sys.exc_info()
358 + # default application error code is -32500
359 + code = -32500
360 + if tb_type == Errors.MMSubscribeNeedsConfirmation:
361 + code = -32501
362 + elif tb_type == Errors.MMNeedApproval:
363 + code = -32502
364 + elif tb_type == Errors.MMAuthenticationError:
365 + code = -32503
366 + error_message = str(e) + str(traceback.format_tb(tb))
367 + error_message = cgi.escape(error_message)
368 + raise xmlrpclib.Fault(code, error_message)
369 + foo_lambda.__doc__ = method_func.__doc__
370 + return foo_lambda
371 +
372 +# Set up the XMLRPC handler
373 +handler = DocCGIXMLRPCRequestHandler()
374 +handler.set_server_title(_('GNU/Mailman List Administration Interface'))
375 +handler.set_server_name(_('GNU/Mailman List Administration Interface'))
376 +handler.set_server_documentation = _(__doc__)
377 +handler.register_introspection_functions()
378 +
379 +__methodMap__ = {\
380 + 'Mailman.addMember': add_member,
381 + 'Mailman.deleteMember': delete_member,
382 + 'Mailman.changeMemberAddress': change_address,
383 + 'Mailman.createList': create_list,
384 + 'Mailman.deleteList': delete_list}
385 +
386 +for method in __methodMap__.keys():
387 + func = __methodMap__[method]
388 + handler.register_function(__method_wrapper__(func), method)
389 Index: mailman-2.1.9/src/Makefile.in
390 ===================================================================
391 --- mailman-2.1.9.orig/src/Makefile.in 2008-04-26 16:59:11.000000000 +0100
392 +++ mailman-2.1.9/src/Makefile.in 2008-05-08 11:24:42.000000000 +0100
393 @@ -71,7 +71,7 @@
394 # Fixed definitions
395
396 CGI_PROGS= admindb admin confirm create edithtml listinfo options \
397 - private rmlist roster subscribe
398 + private rmlist roster subscribe RPC2
399
400 COMMONOBJS= common.o vsnprintf.o
401

  ViewVC Help
Powered by ViewVC 1.1.2