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.ini')
56 config
.read(os
.path
.dirname(__file__
)+'/../configs/platal.conf')
58 def get_config(sec
, val
, default
=None):
60 return config
.get(sec
, val
)[1:-1]
61 except ConfigParser
.NoOptionError
, e
:
68 MYSQL_USER
= get_config('Core', 'dbuser')
69 MYSQL_PASS
= get_config('Core', 'dbpwd')
71 PLATAL_DOMAIN
= get_config('Mail', 'domain')
72 PLATAL_DOMAIN2
= get_config('Mail', 'domain2', '')
74 VHOST_SEP
= get_config('Lists', 'vhost_sep', '_')
75 ON_CREATE_CMD
= get_config('Lists', 'on_create', '')
77 ################################################################################
81 #------------------------------------------------
82 # Manage Basic authentication
85 class BasicAuthXMLRPCRequestHandler(SimpleXMLRPCRequestHandler
):
87 """XMLRPC Request Handler
88 This request handler is used to provide BASIC HTTP user authentication.
89 It first overloads the do_POST() function, authenticates the user, then
90 calls the super.do_POST().
92 Moreover, we override _dispatch, so that we call functions with as first
93 argument a UserDesc taken from the database, containing name, email and perms
96 def _dispatch(self
, method
, params
):
97 # TODO: subclass in SimpleXMLRPCDispatcher and not here.
98 new_params
= list(params
)
99 new_params
.insert(0, self
.data
[2])
100 new_params
.insert(0, self
.data
[1])
101 new_params
.insert(0, self
.data
[0])
102 return self
.server
._dispatch(method
, new_params
)
106 _
, auth
= self
.headers
["authorization"].split()
107 uid
, md5
= base64
.decodestring(auth
).strip().split(':')
108 vhost
= self
.path
.split('/')[1].lower()
109 self
.data
= self
.getUser(uid
, md5
, vhost
)
110 if self
.data
is None:
112 # Call super.do_POST() to do the actual work
113 SimpleXMLRPCRequestHandler
.do_POST(self
)
115 self
.send_response(401)
118 def getUser(self
, uid
, md5
, vhost
):
119 res
= mysql_fetchone ("""SELECT CONCAT(u.prenom, ' ', u.nom), a.alias, u.perms
120 FROM auth_user_md5 AS u
121 INNER JOIN aliases AS a ON ( a.id=u.user_id AND a.type='a_vie' )
122 WHERE u.user_id = '%s' AND u.password = '%s' AND u.perms IN ('admin', 'user')
123 LIMIT 1""" %( uid
, md5
) )
125 name
, forlife
, perms
= res
126 if vhost
!= PLATAL_DOMAIN
:
127 res
= mysql_fetchone ("""SELECT uid
128 FROM groupex.membres AS m
129 INNER JOIN groupex.asso AS a ON (m.asso_id = a.id)
130 WHERE perms='admin' AND uid='%s' AND mail_domain='%s'""" %( uid
, vhost
) )
131 if res
: perms
= 'admin'
132 userdesc
= UserDesc(forlife
+'@'+PLATAL_DOMAIN
, name
, None, 0)
133 return (userdesc
, perms
, vhost
)
137 ################################################################################
141 #-------------------------------------------------------------------------------
146 db
= MySQLdb
.connect(
150 unix_socket
='/var/run/mysqld/mysqld.sock')
154 def mysql_fetchone(query
):
159 if int(mysql
.rowcount
) > 0:
160 ret
= mysql
.fetchone()
165 def is_admin_on(userdesc
, perms
, mlist
):
166 return ( perms
== 'admin' ) or ( userdesc
.address
in mlist
.owner
)
169 def quote(s
, is_header
=False):
171 h
= Utils
.oneline(s
, 'iso-8859-1')
174 h
= str('').join(re
.split('[\x00-\x09\x0B-\x1f]+', h
))
175 return Utils
.uquote(h
.replace('&', '&').replace('>', '>').replace('<', '<'))
177 def to_forlife(email
):
179 mbox
, fqdn
= email
.split('@')
183 if ( fqdn
== PLATAL_DOMAIN
) or ( fqdn
== PLATAL_DOMAIN2
):
184 res
= mysql_fetchone("""SELECT CONCAT(f.alias, '@%s'), CONCAT(u.prenom, ' ', u.nom)
185 FROM auth_user_md5 AS u
186 INNER JOIN aliases AS f ON (f.id=u.user_id AND f.type='a_vie')
187 INNER JOIN aliases AS a ON (a.id=u.user_id AND a.alias='%s' AND a.type!='homonyme')
188 WHERE u.perms IN ('admin', 'user')
189 LIMIT 1""" %( PLATAL_DOMAIN
, mbox
) )
197 # see /usr/lib/mailman/bin/rmlist
199 def remove_it(listname
, filename
):
200 if os
.path
.islink(filename
) or os
.path
.isfile(filename
):
202 elif os
.path
.isdir(filename
):
203 shutil
.rmtree(filename
)
205 #-------------------------------------------------------------------------------
209 def get_list_info(userdesc
, perms
, mlist
, front_page
=0):
210 members
= mlist
.getRegularMemberKeys()
211 is_member
= userdesc
.address
in members
212 is_owner
= userdesc
.address
in mlist
.owner
213 if mlist
.advertised
or is_member
or is_owner
or (not front_page
and perms
== 'admin'):
215 if not is_member
and (mlist
.subscribe_policy
> 1):
218 for id in mlist
.GetSubscriptionIds():
219 if userdesc
.address
== mlist
.GetRecord(id)[1]:
227 host
= mlist
.internal_name().split(VHOST_SEP
)[0].lower()
229 'list' : mlist
.real_name
,
230 'addr' : mlist
.real_name
.lower() + '@' + host
,
232 'desc' : quote(mlist
.description
),
233 'info' : quote(mlist
.info
),
234 'diff' : (mlist
.default_member_moderation
>0) + (mlist
.generic_nonmember_action
>0),
235 'ins' : mlist
.subscribe_policy
> 1,
236 'priv' : 1-mlist
.advertised
,
237 'sub' : 2*is_member
+ is_pending
,
239 'nbsub': len(members
)
241 return (details
, members
)
244 def get_options(userdesc
, perms
, vhost
, listname
, opts
):
246 mlist
= MailList
.MailList(vhost
+VHOST_SEP
+listname
.lower(), lock
=0)
250 if not is_admin_on(userdesc
, perms
, mlist
):
253 for (k
, v
) in mlist
.__dict__
.iteritems():
256 options
[k
] = quote(v
)
258 details
= get_list_info(userdesc
, perms
, mlist
)[0]
259 return (details
, options
)
263 def set_options(userdesc
, perms
, vhost
, listname
, opts
, vals
):
265 mlist
= MailList
.MailList(vhost
+VHOST_SEP
+listname
.lower(), lock
=0)
269 if not is_admin_on(userdesc
, perms
, mlist
):
272 for (k
, v
) in vals
.iteritems():
275 if k
== 'default_member_moderation':
276 for member
in mlist
.getMembers():
277 mlist
.setMemberOption(member
, mm_cfg
.Moderate
, int(v
))
278 t
= type(mlist
.__dict__
[k
])
279 if t
is bool: mlist
.__dict__
[k
] = bool(v
)
280 elif t
is int: mlist
.__dict__
[k
] = int(v
)
281 elif t
is str: mlist
.__dict__
[k
] = Utils
.uncanonstr(v
, 'fr')
282 else: mlist
.__dict__
[k
] = v
290 #-------------------------------------------------------------------------------
291 # users procedures for [ index.php ]
294 def get_lists(userdesc
, perms
, vhost
, email
=None):
298 udesc
= UserDesc(email
, email
, None, 0)
299 prefix
= vhost
.lower()+VHOST_SEP
300 names
= Utils
.list_names()
304 if not name
.startswith(prefix
):
307 mlist
= MailList
.MailList(name
, lock
=0)
311 details
= get_list_info(udesc
, perms
, mlist
, (email
is None and vhost
== PLATAL_DOMAIN
))[0]
312 result
.append(details
)
317 def subscribe(userdesc
, perms
, vhost
, listname
):
319 mlist
= MailList
.MailList(vhost
+VHOST_SEP
+listname
.lower(), lock
=0)
324 if ( mlist
.subscribe_policy
in (0, 1) ) or userdesc
.address
in mlist
.owner
:
325 mlist
.ApprovedAddMember(userdesc
)
330 mlist
.AddMember(userdesc
)
331 except Errors
.MMNeedApproval
:
339 def unsubscribe(userdesc
, perms
, vhost
, listname
):
341 mlist
= MailList
.MailList(vhost
+VHOST_SEP
+listname
.lower(), lock
=0)
346 mlist
.ApprovedDeleteMember(userdesc
.address
)
354 #-------------------------------------------------------------------------------
355 # users procedures for [ index.php ]
358 def get_members(userdesc
, perms
, vhost
, listname
):
360 mlist
= MailList
.MailList(vhost
+VHOST_SEP
+listname
.lower(), lock
=0)
364 details
, members
= get_list_info(userdesc
, perms
, mlist
)
366 members
= map(lambda member
: (quote(mlist
.getMemberName(member
)) or '', member
), members
)
367 return (details
, members
, mlist
.owner
)
371 #-------------------------------------------------------------------------------
372 # users procedures for [ trombi.php ]
375 def get_members_limit(userdesc
, perms
, vhost
, listname
, page
, nb_per_page
):
377 members
= get_members(userdesc
, perms
, vhost
, listname
.lower())[1]
380 i
= int(page
) * int(nb_per_page
)
381 return (len(members
), members
[i
:i
+int(nb_per_page
)])
383 def get_owners(userdesc
, perms
, vhost
, listname
):
385 details
, members
, owners
= get_members(userdesc
, perms
, vhost
, listname
.lower())
388 return (details
, owners
)
390 #-------------------------------------------------------------------------------
391 # owners procedures [ admin.php ]
394 def mass_subscribe(userdesc
, perms
, vhost
, listname
, users
):
396 mlist
= MailList
.MailList(vhost
+VHOST_SEP
+listname
.lower(), lock
=0)
400 if not is_admin_on(userdesc
, perms
, mlist
):
403 members
= mlist
.getRegularMemberKeys()
407 email
, name
= to_forlife(user
)
408 if ( email
is None ) or ( email
in members
):
410 userd
= UserDesc(email
, name
, None, 0)
411 mlist
.ApprovedAddMember(userd
)
412 added
.append( (quote(userd
.fullname
), userd
.address
) )
419 def mass_unsubscribe(userdesc
, perms
, vhost
, listname
, users
):
421 mlist
= MailList
.MailList(vhost
+VHOST_SEP
+listname
.lower(), lock
=0)
425 if not is_admin_on(userdesc
, perms
, mlist
):
429 map(lambda user
: mlist
.ApprovedDeleteMember(user
), users
)
436 def add_owner(userdesc
, perms
, vhost
, listname
, user
):
438 mlist
= MailList
.MailList(vhost
+VHOST_SEP
+listname
.lower(), lock
=0)
442 if not is_admin_on(userdesc
, perms
, mlist
):
444 email
= to_forlife(user
)[0]
447 if email
not in mlist
.owner
:
449 mlist
.owner
.append(email
)
456 def del_owner(userdesc
, perms
, vhost
, listname
, user
):
458 mlist
= MailList
.MailList(vhost
+VHOST_SEP
+listname
.lower(), lock
=0)
462 if not is_admin_on(userdesc
, perms
, mlist
):
464 if len(mlist
.owner
) < 2:
467 mlist
.owner
.remove(user
)
474 #-------------------------------------------------------------------------------
475 # owners procedures [ admin.php ]
478 def get_pending_ops(userdesc
, perms
, vhost
, listname
):
480 mlist
= MailList
.MailList(vhost
+VHOST_SEP
+listname
.lower(), lock
=0)
484 if not is_admin_on(userdesc
, perms
, mlist
):
492 for id in mlist
.GetSubscriptionIds():
493 time
, addr
, fullname
, passwd
, digest
, lang
= mlist
.GetRecord(id)
495 mlist
.HandleRequest(id, mm_cfg
.DISCARD
)
500 login
= re
.match("^[^.]*\.[^.]*\.\d\d\d\d$", addr
.split('@')[0]).group()
501 subs
.append({'id': id, 'name': quote(fullname
), 'addr': addr
, 'login': login
})
503 subs
.append({'id': id, 'name': quote(fullname
), 'addr': addr
})
506 for id in mlist
.GetHeldMessageIds():
507 ptime
, sender
, subject
, reason
, filename
, msgdata
= mlist
.GetRecord(id)
509 size
= os
.path
.getsize(os
.path
.join(mm_cfg
.DATA_DIR
, filename
))
511 if e
.errno
<> errno
.ENOENT
: raise
515 'sender': quote(sender
, True),
517 'subj' : quote(subject
, True),
520 if dosave
: mlist
.Save()
528 def handle_request(userdesc
, perms
, vhost
, listname
, id, value
, comment
):
530 mlist
= MailList
.MailList(vhost
+VHOST_SEP
+listname
.lower(), lock
=0)
534 if not is_admin_on(userdesc
, perms
, mlist
):
537 mlist
.HandleRequest(int(id), int(value
), comment
)
546 def get_pending_mail(userdesc
, perms
, vhost
, listname
, id, raw
=0):
548 mlist
= MailList
.MailList(vhost
+VHOST_SEP
+listname
.lower(), lock
=0)
552 if not is_admin_on(userdesc
, perms
, mlist
):
555 ptime
, sender
, subject
, reason
, filename
, msgdata
= mlist
.GetRecord(int(id))
556 fpath
= os
.path
.join(mm_cfg
.DATA_DIR
, filename
)
557 size
= os
.path
.getsize(fpath
)
558 msg
= readMessage(fpath
)
564 for part
in typed_subpart_iterator(msg
, 'text', 'plain'):
565 c
= part
.get_payload()
566 if c
is not None: results
.append (c
)
567 results
= map(lambda x
: quote(x
), results
)
569 'sender': quote(sender
, True),
571 'subj' : quote(subject
, True),
578 #-------------------------------------------------------------------------------
579 # owner options [ options.php ]
582 owner_opts
= ['accept_these_nonmembers', 'admin_notify_mchanges', 'description', \
583 'default_member_moderation', 'generic_nonmember_action', 'info', \
584 'subject_prefix', 'goodbye_msg', 'send_goodbye_msg', 'subscribe_policy', \
587 def get_owner_options(userdesc
, perms
, vhost
, listname
):
588 return get_options(userdesc
, perms
, vhost
, listname
.lower(), owner_opts
)
590 def set_owner_options(userdesc
, perms
, vhost
, listname
, values
):
591 return set_options(userdesc
, perms
, vhost
, listname
.lower(), owner_opts
, values
)
593 def add_to_wl(userdesc
, perms
, vhost
, listname
, addr
):
595 mlist
= MailList
.MailList(vhost
+VHOST_SEP
+listname
.lower(), lock
=0)
599 if not is_admin_on(userdesc
, perms
, mlist
):
602 mlist
.accept_these_nonmembers
.append(addr
)
610 def del_from_wl(userdesc
, perms
, vhost
, listname
, addr
):
612 mlist
= MailList
.MailList(vhost
+VHOST_SEP
+listname
.lower(), lock
=0)
616 if not is_admin_on(userdesc
, perms
, mlist
):
619 mlist
.accept_these_nonmembers
.remove(addr
)
627 def get_bogo_level(userdesc
, perms
, vhost
, listname
):
629 mlist
= MailList
.MailList(vhost
+VHOST_SEP
+listname
.lower(), lock
=0)
633 if not is_admin_on(userdesc
, perms
, mlist
):
635 if mlist
.header_filter_rules
== []:
637 action
= mlist
.header_filter_rules
[0][1]
638 if action
== mm_cfg
.HOLD
:
640 if action
== mm_cfg
.DISCARD
:
645 def set_bogo_level(userdesc
, perms
, vhost
, listname
, level
):
647 mlist
= MailList
.MailList(vhost
+VHOST_SEP
+listname
.lower(), lock
=0)
651 if not is_admin_on(userdesc
, perms
, mlist
):
655 hfr
.append(('X-Spam-Flag: Yes, tests=bogofilter', mm_cfg
.HOLD
, False))
656 elif int(level
) is 2:
657 hfr
.append(('X-Spam-Flag: Yes, tests=bogofilter', mm_cfg
.DISCARD
, False))
658 if mlist
.header_filter_rules
!= hfr
:
660 mlist
.header_filter_rules
= hfr
668 #-------------------------------------------------------------------------------
669 # admin procedures [ soptions.php ]
672 admin_opts
= [ 'advertised', 'archive', \
673 'max_message_size', 'msg_footer', 'msg_header']
675 def get_admin_options(userdesc
, perms
, vhost
, listname
):
678 return get_options(userdesc
, perms
, vhost
, listname
.lower(), admin_opts
)
680 def set_admin_options(userdesc
, perms
, vhost
, listname
, values
):
683 return set_options(userdesc
, perms
, vhost
, listname
.lower(), admin_opts
, values
)
685 #-------------------------------------------------------------------------------
686 # admin procedures [ check.php ]
690 'acceptable_aliases' : '',
691 'admin_immed_notify' : True,
692 'administrivia' : True,
693 'anonymous_list' : False,
694 'autorespond_admin' : False,
695 'autorespond_postings' : False,
696 'autorespond_requests' : False,
697 'available_languages' : ['fr'],
699 'bounce_matching_headers' : '',
700 'bounce_processing' : False,
701 'convert_html_to_plaintext' : False,
702 'digestable' : False,
703 'digest_is_default' : False,
704 'discard_these_nonmembers' : [],
706 'encode_ascii_prefixes' : 2,
707 'filter_content' : False,
708 'first_strip_reply_to' : False,
709 'forward_auto_discards' : True,
710 'hold_these_nonmembers' : [],
711 'host_name' : 'listes.polytechnique.org',
712 'include_list_post_header' : False,
713 'include_rfc2369_headers' : False,
714 'max_num_recipients' : 0,
715 'new_member_options' : 256,
716 'nondigestable' : True,
717 'obscure_addresses' : True,
718 'preferred_language' : 'fr',
719 'reject_these_nonmembers' : [],
720 'reply_goes_to_list' : 0,
721 'reply_to_address' : '',
722 'require_explicit_destination' : False,
723 'send_reminders' : 0,
724 'send_welcome_msg' : True,
725 'topics_enabled' : False,
726 'umbrella_list' : False,
727 'unsubscribe_policy' : 0,
730 def check_options(userdesc
, perms
, vhost
, listname
, correct
=False):
732 mlist
= MailList
.MailList(vhost
+VHOST_SEP
+listname
.lower(), lock
=0)
736 if perms
!= 'admin': return 0
740 for (k
, v
) in check_opts
.iteritems():
741 if mlist
.__dict__
[k
] != v
:
742 options
[k
] = v
, mlist
.__dict__
[k
]
743 if correct
: mlist
.__dict__
[k
] = v
744 if mlist
.real_name
.lower() != listname
:
745 options
['real_name'] = listname
, mlist
.real_name
746 if correct
: mlist
.real_name
= listname
750 details
= get_list_info(userdesc
, perms
, mlist
)[0]
751 return (details
, options
)
753 if correct
: mlist
.Unlock()
756 #-------------------------------------------------------------------------------
757 # super-admin procedures
760 def get_all_lists(userdesc
, perms
, vhost
):
761 prefix
= vhost
.lower()+VHOST_SEP
762 names
= Utils
.list_names()
766 if not name
.startswith(prefix
):
768 result
.append(name
.replace(prefix
, ''))
771 def create_list(userdesc
, perms
, vhost
, listname
, desc
, advertise
, modlevel
, inslevel
, owners
, members
):
774 name
= vhost
.lower()+VHOST_SEP
+listname
.lower();
775 if Utils
.list_exists(name
):
780 email
= to_forlife(o
)[0]
781 if email
is not None:
786 mlist
= MailList
.MailList()
788 oldmask
= os
.umask(002)
789 pw
= sha
.new('foobar').hexdigest()
792 mlist
.Create(name
, owner
[0], pw
)
796 mlist
.real_name
= listname
797 mlist
.host_name
= 'listes.polytechnique.org'
798 mlist
.description
= desc
800 mlist
.advertised
= int(advertise
) is 0
801 mlist
.default_member_moderation
= int(modlevel
) is 2
802 mlist
.generic_nonmember_action
= int(modlevel
) > 0
803 mlist
.subscribe_policy
= 2 * (int(inslevel
) is 1)
804 mlist
.admin_notify_mchanges
= (mlist
.subscribe_policy
or mlist
.generic_nonmember_action
or mlist
.default_member_moderation
or not mlist
.advertised
)
808 mlist
.subject_prefix
= '['+listname
+'] '
809 mlist
.max_message_size
= 0
811 mlist
.msg_footer
= "_______________________________________________\n" \
812 + "Liste de diffusion %(real_name)s\n"
814 mlist
.header_filter_rules
= []
815 mlist
.header_filter_rules
.append(('X-Spam-Flag: Yes, tests=bogofilter', mm_cfg
.HOLD
, False))
821 check_options(userdesc
, perms
, vhost
, listname
.lower(), True)
822 mass_subscribe(userdesc
, perms
, vhost
, listname
.lower(), members
)
824 # avoid the "-1 mail to moderate" bug
825 mlist
= MailList
.MailList(name
)
826 mlist
._UpdateRecords()
829 if ON_CREATE_CMD
!= '':
830 try: os
.system(ON_CREATE_CMD
+ ' ' + name
)
840 def delete_list(userdesc
, perms
, vhost
, listname
, del_archives
=0):
841 lname
= vhost
+VHOST_SEP
+listname
.lower()
843 mlist
= MailList
.MailList(lname
, lock
=0)
847 if not is_admin_on(userdesc
, perms
, mlist
):
850 REMOVABLES
= [ os
.path
.join('lists', lname
), ]
851 # remove stalled locks
852 for filename
in os
.listdir(mm_cfg
.LOCK_DIR
):
853 fn_lname
= filename
.split('.')[0]
854 if fn_lname
== lname
:
855 REMOVABLES
.append(os
.path
.join(mm_cfg
.LOCK_DIR
, filename
))
859 os
.path
.join('archives', 'private', lname
),
860 os
.path
.join('archives', 'private', lname
+'.mbox'),
861 os
.path
.join('archives', 'public', lname
),
862 os
.path
.join('archives', 'public', lname
+'.mbox')
864 map(lambda dir: remove_it(lname
, os
.path
.join(mm_cfg
.VAR_PREFIX
, dir)), REMOVABLES
)
869 def kill(userdesc
, perms
, vhost
, alias
, del_from_promo
):
871 if not del_from_promo
:
872 exclude
.append(PLATAL_DOMAIN
+VHOST_SEP
+'promo'+alias
[-4:])
873 for list in Utils
.list_names():
874 if list in exclude
: continue
876 mlist
= MailList
.MailList(list, lock
=0)
881 mlist
.ApprovedDeleteMember(alias
+'@'+PLATAL_DOMAIN
, None, 0, 0)
889 #-------------------------------------------------------------------------------
892 class FastXMLRPCServer(SocketServer
.ThreadingMixIn
, SimpleXMLRPCServer
):
893 allow_reuse_address
= True
895 ################################################################################
899 #-------------------------------------------------------------------------------
900 # use Mailman user and group (not root)
901 # fork in background if asked to
904 uid
= getpwnam(mm_cfg
.MAILMAN_USER
)[2]
905 gid
= getgrnam(mm_cfg
.MAILMAN_GROUP
)[2]
908 os
.setregid(gid
, gid
)
909 os
.setreuid(uid
, uid
)
911 signal
.signal(signal
.SIGHUP
, signal
.SIG_IGN
)
913 if ( os
.getuid() is not uid
) or ( os
.getgid() is not gid
):
916 opts
, args
= getopt
.getopt(sys
.argv
[1:], 'f')
918 if o
== '-f' and os
.fork():
921 i18n
.set_language('fr')
925 #-------------------------------------------------------------------------------
928 server
= FastXMLRPCServer(("localhost", 4949), BasicAuthXMLRPCRequestHandler
)
931 server
.register_function(get_lists
)
932 server
.register_function(subscribe
)
933 server
.register_function(unsubscribe
)
935 server
.register_function(get_members
)
937 server
.register_function(get_members_limit
)
938 server
.register_function(get_owners
)
940 server
.register_function(mass_subscribe
)
941 server
.register_function(mass_unsubscribe
)
942 server
.register_function(add_owner
)
943 server
.register_function(del_owner
)
945 server
.register_function(get_pending_ops
)
946 server
.register_function(handle_request
)
947 server
.register_function(get_pending_mail
)
949 server
.register_function(get_owner_options
)
950 server
.register_function(set_owner_options
)
951 server
.register_function(add_to_wl
)
952 server
.register_function(del_from_wl
)
953 server
.register_function(get_bogo_level
)
954 server
.register_function(set_bogo_level
)
956 server
.register_function(get_admin_options
)
957 server
.register_function(set_admin_options
)
959 server
.register_function(check_options
)
961 server
.register_function(get_all_lists
)
962 server
.register_function(create_list
)
963 server
.register_function(delete_list
)
965 server
.register_function(kill
)
967 server
.serve_forever()