2 #***************************************************************************
3 #* Copyright (C) 2004 polytechnique.org *
4 #* http://opensource.polytechnique.org/ *
6 #* This program is free software; you can redistribute it and/or modify *
7 #* it under the terms of the GNU General Public License as published by *
8 #* the Free Software Foundation; either version 2 of the License, or *
9 #* (at your option) any later version. *
11 #* This program is distributed in the hope that it will be useful, *
12 #* but WITHOUT ANY WARRANTY; without even the implied warranty of *
13 #* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14 #* GNU General Public License for more details. *
16 #* You should have received a copy of the GNU General Public License *
17 #* along with this program; if not, write to the Free Software *
18 #* Foundation, Inc., *
19 #* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *
20 #***************************************************************************
22 import base64
, MySQLdb
, os
, getopt
, sys
, sha
, signal
, re
, shutil
, ConfigParser
23 import MySQLdb
.converters
26 sys
.path
.append('/usr/lib/mailman/bin')
28 from pwd
import getpwnam
29 from grp
import getgrnam
31 from SimpleXMLRPCServer
import SimpleXMLRPCServer
32 from SimpleXMLRPCServer
import SimpleXMLRPCRequestHandler
35 from Mailman
import MailList
36 from Mailman
import Utils
37 from Mailman
import Message
38 from Mailman
import Errors
39 from Mailman
import mm_cfg
40 from Mailman
import i18n
41 from Mailman
.UserDesc
import UserDesc
42 from Mailman
.ListAdmin
import readMessage
43 from email
.Iterators
import typed_subpart_iterator
44 from threading
import Lock
46 class AuthFailed(Exception): pass
48 ################################################################################
52 #------------------------------------------------
54 config
= ConfigParser
.ConfigParser()
55 config
.read(os
.path
.dirname(__file__
)+'/../configs/platal.conf')
57 def get_config(sec
, val
, default
=None):
59 return config
.get(sec
, val
)[1:-1]
60 except ConfigParser
.NoOptionError
, e
:
67 MYSQL_USER
= get_config('Core', 'dbuser')
68 MYSQL_PASS
= get_config('Core', 'dbpwd')
70 PLATAL_DOMAIN
= get_config('Mail', 'domain')
71 PLATAL_DOMAIN2
= get_config('Mail', 'domain2', '')
73 VHOST_SEP
= get_config('Lists', 'vhost_sep', '_')
74 ON_CREATE_CMD
= get_config('Lists', 'on_create', '')
76 ################################################################################
80 #------------------------------------------------
81 # Manage Basic authentication
84 class BasicAuthXMLRPCRequestHandler(SimpleXMLRPCRequestHandler
):
86 """XMLRPC Request Handler
87 This request handler is used to provide BASIC HTTP user authentication.
88 It first overloads the do_POST() function, authenticates the user, then
89 calls the super.do_POST().
91 Moreover, we override _dispatch, so that we call functions with as first
92 argument a UserDesc taken from the database, containing name, email and perms
95 def _dispatch(self
, method
, params
):
96 # TODO: subclass in SimpleXMLRPCDispatcher and not here.
97 new_params
= list(params
)
98 new_params
.insert(0, self
.data
[2])
99 new_params
.insert(0, self
.data
[1])
100 new_params
.insert(0, self
.data
[0])
101 return self
.server
._dispatch(method
, new_params
)
105 _
, auth
= self
.headers
["authorization"].split()
106 uid
, md5
= base64
.decodestring(auth
).strip().split(':')
107 vhost
= self
.path
.split('/')[1].lower()
108 self
.data
= self
.getUser(uid
, md5
, vhost
)
109 if self
.data
is None:
111 # Call super.do_POST() to do the actual work
112 SimpleXMLRPCRequestHandler
.do_POST(self
)
114 self
.send_response(401)
117 def getUser(self
, uid
, md5
, vhost
):
118 res
= mysql_fetchone ("""SELECT CONCAT(u.prenom, ' ', u.nom), a.alias, u.perms
119 FROM auth_user_md5 AS u
120 INNER JOIN aliases AS a ON ( a.id=u.user_id AND a.type='a_vie' )
121 WHERE u.user_id = '%s' AND u.password = '%s' AND u.perms IN ('admin', 'user')
122 LIMIT 1""" %( uid
, md5
) )
124 name
, forlife
, perms
= res
125 if vhost
!= PLATAL_DOMAIN
:
126 res
= mysql_fetchone ("""SELECT uid
127 FROM groupex.membres AS m
128 INNER JOIN groupex.asso AS a ON (m.asso_id = a.id)
129 WHERE perms='admin' AND uid='%s' AND mail_domain='%s'""" %( uid
, vhost
) )
130 if res
: perms
= 'admin'
131 userdesc
= UserDesc(forlife
+'@'+PLATAL_DOMAIN
, name
, None, 0)
132 return (userdesc
, perms
, vhost
)
136 ################################################################################
140 #-------------------------------------------------------------------------------
145 db
= MySQLdb
.connect(
149 unix_socket
='/var/run/mysqld/mysqld.sock')
153 def mysql_fetchone(query
):
158 if int(mysql
.rowcount
) > 0:
159 ret
= mysql
.fetchone()
164 def is_admin_on(userdesc
, perms
, mlist
):
165 return ( perms
== 'admin' ) or ( userdesc
.address
in mlist
.owner
)
168 def quote(s
, is_header
=False):
170 h
= Utils
.oneline(s
, 'iso-8859-1')
173 h
= str('').join(re
.split('[\x00-\x09\x0B-\x1f]+', h
))
174 return Utils
.uquote(h
.replace('&', '&').replace('>', '>').replace('<', '<'))
176 def to_forlife(email
):
178 mbox
, fqdn
= email
.split('@')
182 if ( fqdn
== PLATAL_DOMAIN
) or ( fqdn
== PLATAL_DOMAIN2
):
183 res
= mysql_fetchone("""SELECT CONCAT(f.alias, '@%s'), CONCAT(u.prenom, ' ', u.nom)
184 FROM auth_user_md5 AS u
185 INNER JOIN aliases AS f ON (f.id=u.user_id AND f.type='a_vie')
186 INNER JOIN aliases AS a ON (a.id=u.user_id AND a.alias='%s' AND a.type!='homonyme')
187 WHERE u.perms IN ('admin', 'user')
188 LIMIT 1""" %( PLATAL_DOMAIN
, mbox
) )
196 # see /usr/lib/mailman/bin/rmlist
198 def remove_it(listname
, filename
):
199 if os
.path
.islink(filename
) or os
.path
.isfile(filename
):
201 elif os
.path
.isdir(filename
):
202 shutil
.rmtree(filename
)
204 #-------------------------------------------------------------------------------
208 def get_list_info(userdesc
, perms
, mlist
, front_page
=0):
209 members
= mlist
.getRegularMemberKeys()
210 is_member
= userdesc
.address
in members
211 is_owner
= userdesc
.address
in mlist
.owner
212 if mlist
.advertised
or is_member
or is_owner
or (not front_page
and perms
== 'admin'):
214 if not is_member
and (mlist
.subscribe_policy
> 1):
217 for id in mlist
.GetSubscriptionIds():
218 if userdesc
.address
== mlist
.GetRecord(id)[1]:
226 host
= mlist
.internal_name().split(VHOST_SEP
)[0].lower()
228 'list' : mlist
.real_name
,
229 'addr' : mlist
.real_name
.lower() + '@' + host
,
231 'desc' : quote(mlist
.description
),
232 'info' : quote(mlist
.info
),
233 'diff' : (mlist
.default_member_moderation
>0) + (mlist
.generic_nonmember_action
>0),
234 'ins' : mlist
.subscribe_policy
> 1,
235 'priv' : 1-mlist
.advertised
,
236 'sub' : 2*is_member
+ is_pending
,
238 'nbsub': len(members
)
240 return (details
, members
)
243 def get_options(userdesc
, perms
, vhost
, listname
, opts
):
245 mlist
= MailList
.MailList(vhost
+VHOST_SEP
+listname
.lower(), lock
=0)
249 if not is_admin_on(userdesc
, perms
, mlist
):
252 for (k
, v
) in mlist
.__dict__
.iteritems():
255 options
[k
] = quote(v
)
257 details
= get_list_info(userdesc
, perms
, mlist
)[0]
258 return (details
, options
)
262 def set_options(userdesc
, perms
, vhost
, listname
, opts
, vals
):
264 mlist
= MailList
.MailList(vhost
+VHOST_SEP
+listname
.lower(), lock
=0)
268 if not is_admin_on(userdesc
, perms
, mlist
):
271 for (k
, v
) in vals
.iteritems():
274 if k
== 'default_member_moderation':
275 for member
in mlist
.getMembers():
276 mlist
.setMemberOption(member
, mm_cfg
.Moderate
, int(v
))
277 t
= type(mlist
.__dict__
[k
])
278 if t
is bool: mlist
.__dict__
[k
] = bool(v
)
279 elif t
is int: mlist
.__dict__
[k
] = int(v
)
280 elif t
is str: mlist
.__dict__
[k
] = Utils
.uncanonstr(v
, 'fr')
281 else: mlist
.__dict__
[k
] = v
289 #-------------------------------------------------------------------------------
290 # users procedures for [ index.php ]
293 def get_lists(userdesc
, perms
, vhost
, email
=None):
297 udesc
= UserDesc(email
, email
, None, 0)
298 prefix
= vhost
.lower()+VHOST_SEP
299 names
= Utils
.list_names()
303 if not name
.startswith(prefix
):
306 mlist
= MailList
.MailList(name
, lock
=0)
310 details
= get_list_info(udesc
, perms
, mlist
, (email
is None and vhost
== PLATAL_DOMAIN
))[0]
311 result
.append(details
)
316 def subscribe(userdesc
, perms
, vhost
, listname
):
318 mlist
= MailList
.MailList(vhost
+VHOST_SEP
+listname
.lower(), lock
=0)
323 if ( mlist
.subscribe_policy
in (0, 1) ) or userdesc
.address
in mlist
.owner
:
324 mlist
.ApprovedAddMember(userdesc
)
329 mlist
.AddMember(userdesc
)
330 except Errors
.MMNeedApproval
:
338 def unsubscribe(userdesc
, perms
, vhost
, listname
):
340 mlist
= MailList
.MailList(vhost
+VHOST_SEP
+listname
.lower(), lock
=0)
345 mlist
.ApprovedDeleteMember(userdesc
.address
)
353 #-------------------------------------------------------------------------------
354 # users procedures for [ index.php ]
357 def get_members(userdesc
, perms
, vhost
, listname
):
359 mlist
= MailList
.MailList(vhost
+VHOST_SEP
+listname
.lower(), lock
=0)
363 details
, members
= get_list_info(userdesc
, perms
, mlist
)
365 members
= map(lambda member
: (quote(mlist
.getMemberName(member
)) or '', member
), members
)
366 return (details
, members
, mlist
.owner
)
370 #-------------------------------------------------------------------------------
371 # users procedures for [ trombi.php ]
374 def get_members_limit(userdesc
, perms
, vhost
, listname
, page
, nb_per_page
):
376 members
= get_members(userdesc
, perms
, vhost
, listname
.lower())[1]
379 i
= int(page
) * int(nb_per_page
)
380 return (len(members
), members
[i
:i
+int(nb_per_page
)])
382 def get_owners(userdesc
, perms
, vhost
, listname
):
384 details
, members
, owners
= get_members(userdesc
, perms
, vhost
, listname
.lower())
387 return (details
, owners
)
389 #-------------------------------------------------------------------------------
390 # owners procedures [ admin.php ]
393 def mass_subscribe(userdesc
, perms
, vhost
, listname
, users
):
395 mlist
= MailList
.MailList(vhost
+VHOST_SEP
+listname
.lower(), lock
=0)
399 if not is_admin_on(userdesc
, perms
, mlist
):
402 members
= mlist
.getRegularMemberKeys()
406 email
, name
= to_forlife(user
)
407 if ( email
is None ) or ( email
in members
):
409 userd
= UserDesc(email
, name
, None, 0)
410 mlist
.ApprovedAddMember(userd
)
411 added
.append( (quote(userd
.fullname
), userd
.address
) )
418 def mass_unsubscribe(userdesc
, perms
, vhost
, listname
, users
):
420 mlist
= MailList
.MailList(vhost
+VHOST_SEP
+listname
.lower(), lock
=0)
424 if not is_admin_on(userdesc
, perms
, mlist
):
428 map(lambda user
: mlist
.ApprovedDeleteMember(user
), users
)
435 def add_owner(userdesc
, perms
, vhost
, listname
, user
):
437 mlist
= MailList
.MailList(vhost
+VHOST_SEP
+listname
.lower(), lock
=0)
441 if not is_admin_on(userdesc
, perms
, mlist
):
443 email
= to_forlife(user
)[0]
446 if email
not in mlist
.owner
:
448 mlist
.owner
.append(email
)
455 def del_owner(userdesc
, perms
, vhost
, listname
, user
):
457 mlist
= MailList
.MailList(vhost
+VHOST_SEP
+listname
.lower(), lock
=0)
461 if not is_admin_on(userdesc
, perms
, mlist
):
463 if len(mlist
.owner
) < 2:
466 mlist
.owner
.remove(user
)
473 #-------------------------------------------------------------------------------
474 # owners procedures [ admin.php ]
477 def get_pending_ops(userdesc
, perms
, vhost
, listname
):
479 mlist
= MailList
.MailList(vhost
+VHOST_SEP
+listname
.lower(), lock
=0)
483 if not is_admin_on(userdesc
, perms
, mlist
):
491 for id in mlist
.GetSubscriptionIds():
492 time
, addr
, fullname
, passwd
, digest
, lang
= mlist
.GetRecord(id)
494 mlist
.HandleRequest(id, mm_cfg
.DISCARD
)
499 login
= re
.match("^[^.]*\.[^.]*\.\d\d\d\d$", addr
.split('@')[0]).group()
500 subs
.append({'id': id, 'name': quote(fullname
), 'addr': addr
, 'login': login
})
502 subs
.append({'id': id, 'name': quote(fullname
), 'addr': addr
})
505 for id in mlist
.GetHeldMessageIds():
506 ptime
, sender
, subject
, reason
, filename
, msgdata
= mlist
.GetRecord(id)
508 size
= os
.path
.getsize(os
.path
.join(mm_cfg
.DATA_DIR
, filename
))
510 if e
.errno
<> errno
.ENOENT
: raise
514 'sender': quote(sender
, True),
516 'subj' : quote(subject
, True),
519 if dosave
: mlist
.Save()
527 def handle_request(userdesc
, perms
, vhost
, listname
, id, value
, comment
):
529 mlist
= MailList
.MailList(vhost
+VHOST_SEP
+listname
.lower(), lock
=0)
533 if not is_admin_on(userdesc
, perms
, mlist
):
536 mlist
.HandleRequest(int(id), int(value
), comment
)
545 def get_pending_mail(userdesc
, perms
, vhost
, listname
, id, raw
=0):
547 mlist
= MailList
.MailList(vhost
+VHOST_SEP
+listname
.lower(), lock
=0)
551 if not is_admin_on(userdesc
, perms
, mlist
):
554 ptime
, sender
, subject
, reason
, filename
, msgdata
= mlist
.GetRecord(int(id))
555 fpath
= os
.path
.join(mm_cfg
.DATA_DIR
, filename
)
556 size
= os
.path
.getsize(fpath
)
557 msg
= readMessage(fpath
)
563 for part
in typed_subpart_iterator(msg
, 'text', 'plain'):
564 c
= part
.get_payload()
565 if c
is not None: results
.append (c
)
566 results
= map(lambda x
: quote(x
), results
)
568 'sender': quote(sender
, True),
570 'subj' : quote(subject
, True),
577 #-------------------------------------------------------------------------------
578 # owner options [ options.php ]
581 owner_opts
= ['accept_these_nonmembers', 'admin_notify_mchanges', 'description', \
582 'default_member_moderation', 'generic_nonmember_action', 'info', \
583 'subject_prefix', 'goodbye_msg', 'send_goodbye_msg', 'subscribe_policy', \
586 def get_owner_options(userdesc
, perms
, vhost
, listname
):
587 return get_options(userdesc
, perms
, vhost
, listname
.lower(), owner_opts
)
589 def set_owner_options(userdesc
, perms
, vhost
, listname
, values
):
590 return set_options(userdesc
, perms
, vhost
, listname
.lower(), owner_opts
, values
)
592 def add_to_wl(userdesc
, perms
, vhost
, listname
, addr
):
594 mlist
= MailList
.MailList(vhost
+VHOST_SEP
+listname
.lower(), lock
=0)
598 if not is_admin_on(userdesc
, perms
, mlist
):
601 mlist
.accept_these_nonmembers
.append(addr
)
609 def del_from_wl(userdesc
, perms
, vhost
, listname
, addr
):
611 mlist
= MailList
.MailList(vhost
+VHOST_SEP
+listname
.lower(), lock
=0)
615 if not is_admin_on(userdesc
, perms
, mlist
):
618 mlist
.accept_these_nonmembers
.remove(addr
)
626 def get_bogo_level(userdesc
, perms
, vhost
, listname
):
628 mlist
= MailList
.MailList(vhost
+VHOST_SEP
+listname
.lower(), lock
=0)
632 if not is_admin_on(userdesc
, perms
, mlist
):
634 if mlist
.header_filter_rules
== []:
636 action
= mlist
.header_filter_rules
[0][1]
637 if action
== mm_cfg
.HOLD
:
639 if action
== mm_cfg
.DISCARD
:
644 def set_bogo_level(userdesc
, perms
, vhost
, listname
, level
):
646 mlist
= MailList
.MailList(vhost
+VHOST_SEP
+listname
.lower(), lock
=0)
650 if not is_admin_on(userdesc
, perms
, mlist
):
654 hfr
.append(('X-Spam-Flag: Yes, tests=bogofilter', mm_cfg
.HOLD
, False))
655 elif int(level
) is 2:
656 hfr
.append(('X-Spam-Flag: Yes, tests=bogofilter', mm_cfg
.DISCARD
, False))
657 if mlist
.header_filter_rules
!= hfr
:
659 mlist
.header_filter_rules
= hfr
667 #-------------------------------------------------------------------------------
668 # admin procedures [ soptions.php ]
671 admin_opts
= [ 'advertised', 'archive', \
672 'max_message_size', 'msg_footer', 'msg_header']
674 def get_admin_options(userdesc
, perms
, vhost
, listname
):
677 return get_options(userdesc
, perms
, vhost
, listname
.lower(), admin_opts
)
679 def set_admin_options(userdesc
, perms
, vhost
, listname
, values
):
682 return set_options(userdesc
, perms
, vhost
, listname
.lower(), admin_opts
, values
)
684 #-------------------------------------------------------------------------------
685 # admin procedures [ check.php ]
689 'acceptable_aliases' : '',
690 'admin_immed_notify' : True,
691 'administrivia' : True,
692 'anonymous_list' : False,
693 'autorespond_admin' : False,
694 'autorespond_postings' : False,
695 'autorespond_requests' : False,
696 'available_languages' : ['fr'],
698 'bounce_matching_headers' : '',
699 'bounce_processing' : False,
700 'convert_html_to_plaintext' : False,
701 'digestable' : False,
702 'digest_is_default' : False,
703 'discard_these_nonmembers' : [],
705 'encode_ascii_prefixes' : 2,
706 'filter_content' : False,
707 'first_strip_reply_to' : False,
708 'forward_auto_discards' : True,
709 'hold_these_nonmembers' : [],
710 'host_name' : 'listes.polytechnique.org',
711 'include_list_post_header' : False,
712 'include_rfc2369_headers' : False,
713 'max_num_recipients' : 0,
714 'new_member_options' : 256,
715 'nondigestable' : True,
716 'obscure_addresses' : True,
717 'preferred_language' : 'fr',
718 'reject_these_nonmembers' : [],
719 'reply_goes_to_list' : 0,
720 'reply_to_address' : '',
721 'require_explicit_destination' : False,
722 'send_reminders' : 0,
723 'send_welcome_msg' : True,
724 'topics_enabled' : False,
725 'umbrella_list' : False,
726 'unsubscribe_policy' : 0,
729 def check_options(userdesc
, perms
, vhost
, listname
, correct
=False):
731 mlist
= MailList
.MailList(vhost
+VHOST_SEP
+listname
.lower(), lock
=0)
735 if perms
!= 'admin': return 0
739 for (k
, v
) in check_opts
.iteritems():
740 if mlist
.__dict__
[k
] != v
:
741 options
[k
] = v
, mlist
.__dict__
[k
]
742 if correct
: mlist
.__dict__
[k
] = v
743 if mlist
.real_name
.lower() != listname
:
744 options
['real_name'] = listname
, mlist
.real_name
745 if correct
: mlist
.real_name
= listname
749 details
= get_list_info(userdesc
, perms
, mlist
)[0]
750 return (details
, options
)
752 if correct
: mlist
.Unlock()
755 #-------------------------------------------------------------------------------
756 # super-admin procedures
759 def get_all_lists(userdesc
, perms
, vhost
):
760 prefix
= vhost
.lower()+VHOST_SEP
761 names
= Utils
.list_names()
765 if not name
.startswith(prefix
):
767 result
.append(name
.replace(prefix
, ''))
770 def create_list(userdesc
, perms
, vhost
, listname
, desc
, advertise
, modlevel
, inslevel
, owners
, members
):
773 name
= vhost
.lower()+VHOST_SEP
+listname
.lower();
774 if Utils
.list_exists(name
):
779 email
= to_forlife(o
)[0]
780 if email
is not None:
785 mlist
= MailList
.MailList()
787 oldmask
= os
.umask(002)
788 pw
= sha
.new('foobar').hexdigest()
791 mlist
.Create(name
, owner
[0], pw
)
795 mlist
.real_name
= listname
796 mlist
.host_name
= 'listes.polytechnique.org'
797 mlist
.description
= desc
799 mlist
.advertised
= int(advertise
) is 0
800 mlist
.default_member_moderation
= int(modlevel
) is 2
801 mlist
.generic_nonmember_action
= int(modlevel
) > 0
802 mlist
.subscribe_policy
= 2 * (int(inslevel
) is 1)
803 mlist
.admin_notify_mchanges
= (mlist
.subscribe_policy
or mlist
.generic_nonmember_action
or mlist
.default_member_moderation
or not mlist
.advertised
)
807 mlist
.subject_prefix
= '['+listname
+'] '
808 mlist
.max_message_size
= 0
810 mlist
.msg_footer
= "_______________________________________________\n" \
811 + "Liste de diffusion %(real_name)s\n"
813 mlist
.header_filter_rules
= []
814 mlist
.header_filter_rules
.append(('X-Spam-Flag: Yes, tests=bogofilter', mm_cfg
.HOLD
, False))
820 check_options(userdesc
, perms
, vhost
, listname
.lower(), True)
821 mass_subscribe(userdesc
, perms
, vhost
, listname
.lower(), members
)
823 # avoid the "-1 mail to moderate" bug
824 mlist
= MailList
.MailList(name
)
825 mlist
._UpdateRecords()
828 if ON_CREATE_CMD
!= '':
829 try: os
.system(ON_CREATE_CMD
+ ' ' + name
)
839 def delete_list(userdesc
, perms
, vhost
, listname
, del_archives
=0):
840 lname
= vhost
+VHOST_SEP
+listname
.lower()
842 mlist
= MailList
.MailList(lname
, lock
=0)
846 if not is_admin_on(userdesc
, perms
, mlist
):
849 REMOVABLES
= [ os
.path
.join('lists', lname
), ]
850 # remove stalled locks
851 for filename
in os
.listdir(mm_cfg
.LOCK_DIR
):
852 fn_lname
= filename
.split('.')[0]
853 if fn_lname
== lname
:
854 REMOVABLES
.append(os
.path
.join(mm_cfg
.LOCK_DIR
, filename
))
858 os
.path
.join('archives', 'private', lname
),
859 os
.path
.join('archives', 'private', lname
+'.mbox'),
860 os
.path
.join('archives', 'public', lname
),
861 os
.path
.join('archives', 'public', lname
+'.mbox')
863 map(lambda dir: remove_it(lname
, os
.path
.join(mm_cfg
.VAR_PREFIX
, dir)), REMOVABLES
)
868 def kill(userdesc
, perms
, vhost
, alias
, del_from_promo
):
870 if not del_from_promo
:
871 exclude
.append(PLATAL_DOMAIN
+VHOST_SEP
+'promo'+alias
[-4:])
872 for list in Utils
.list_names():
873 if list in exclude
: continue
875 mlist
= MailList
.MailList(list, lock
=0)
880 mlist
.ApprovedDeleteMember(alias
+'@'+PLATAL_DOMAIN
, None, 0, 0)
888 #-------------------------------------------------------------------------------
891 class FastXMLRPCServer(SocketServer
.ThreadingMixIn
, SimpleXMLRPCServer
):
892 allow_reuse_address
= True
894 ################################################################################
898 #-------------------------------------------------------------------------------
899 # use Mailman user and group (not root)
900 # fork in background if asked to
903 uid
= getpwnam(mm_cfg
.MAILMAN_USER
)[2]
904 gid
= getgrnam(mm_cfg
.MAILMAN_GROUP
)[2]
907 os
.setregid(gid
, gid
)
908 os
.setreuid(uid
, uid
)
910 signal
.signal(signal
.SIGHUP
, signal
.SIG_IGN
)
912 if ( os
.getuid() is not uid
) or ( os
.getgid() is not gid
):
915 opts
, args
= getopt
.getopt(sys
.argv
[1:], 'f')
917 if o
== '-f' and os
.fork():
920 i18n
.set_language('fr')
924 #-------------------------------------------------------------------------------
927 server
= FastXMLRPCServer(("localhost", 4949), BasicAuthXMLRPCRequestHandler
)
930 server
.register_function(get_lists
)
931 server
.register_function(subscribe
)
932 server
.register_function(unsubscribe
)
934 server
.register_function(get_members
)
936 server
.register_function(get_members_limit
)
937 server
.register_function(get_owners
)
939 server
.register_function(mass_subscribe
)
940 server
.register_function(mass_unsubscribe
)
941 server
.register_function(add_owner
)
942 server
.register_function(del_owner
)
944 server
.register_function(get_pending_ops
)
945 server
.register_function(handle_request
)
946 server
.register_function(get_pending_mail
)
948 server
.register_function(get_owner_options
)
949 server
.register_function(set_owner_options
)
950 server
.register_function(add_to_wl
)
951 server
.register_function(del_from_wl
)
952 server
.register_function(get_bogo_level
)
953 server
.register_function(set_bogo_level
)
955 server
.register_function(get_admin_options
)
956 server
.register_function(set_admin_options
)
958 server
.register_function(check_options
)
960 server
.register_function(get_all_lists
)
961 server
.register_function(create_list
)
962 server
.register_function(delete_list
)
964 server
.register_function(kill
)
966 server
.serve_forever()