Mark Sapiro wrote:
C Nulk wrote:
While I waited, I did do some reading/researching on __init__ which lead me to reading about __getattr__ and getattr. If I understand correctly, the LDAPMemberships uses them to get the isMember() and getMembers() methods among others.
Not exactly. Since the MemberAdaptor is replaceable, it can't simply be a super class of the MailList class. Thus, it's methods are not in the name space of the MailList object so we need an __getattr__ method to access them from whatever class is assigned as the list's _memberadaptor. So when you reference a method such as mlist.isMember() that is not directly in the name space of the mlist instance so mlist.__getattr__('isMember') is called (behind the scenes) and it finds mlist._memberadaptor.isMember() and returns that.
Sorry about that. Your explanation is what I understood was the correct action(s) for the interaction between MailList and the MemberAdaptor. I just way to short in my explanation.
This is true whether _memberadaptor is the default OldStyleMemberships class or the LDAPMemberships class or something else. The only thing that is specific to LDAPMemberships is the fact that the list's extend.py module assigned LDAPMemberships to _memberadaptor.
From then on, whenever a member adaptor method is called for that list, the method that is called is the one defined in LDAPMemberships.py.
So, for example, if your Mailman version is 2.1.10 or later so that it supports the @LISTNAME entry in *_these_nonmembers, and you put say @list2 in accept_these_nonmembers of list1, list1's processing of a non-member post will call list2's isMember() method to see if the poster is a member of list2, and if list2 already uses LDAPMemberships, that's it - it's isMember() method will use its LDAP database. Unfortunately, I am stuck at v2.1.9 for now.
See the matches_p function in Mailman/Handlers/Moderate.py for more detail. I did look at Mailman/Handlers/Moderate.py, specifically the matches_p function. What I envisioned doing was to modify the matches_p function to single out "ldap" entries similar to the regex entries. Then for each "ldap" entry, call an LDAP2Dict function (to be written) which returns a dictionary of email addresses, then check if the sender was in the returned dictionary.
That would work, but if this dictionary could be equated to the membership of some list, it seems to me that it would be easier to just backport the @listname feature to 2.1.9. You can find the original patch at <http://sourceforge.net/tracker/?func=detail&aid=1220144&group_id=103&atid=300103>. The 2.1.10 implementation is a bit more elaborate, but the SourceForge patch should be sufficient for your purpose.
Note that there is nothing magic about the dictionary in
plainaddrs = [addr for addr in nonmembers if not addr.startswith('^')] addrdict = Utils.List2Dict(plainaddrs, foldcase=1) if addrdict.has_key(sender): return 1
This could just as easily have been spelled
plainaddrs = [addr.lower() for addr in nonmembers if not addr.startswith('^')] if sender in plainaddrs: return 1
I will have to take a closer look at the patch. And, I probably will apply it. From the quick glance on sourceforge, it looks like it should work for v2.1.9. All I should have to do is adjust the diff lines to point to the actual locations.
Being able to use another list as a source is great. I would still like to try to have everything defined/set within the list itself without cross-referencing other "management" lists. For us, it would be easier to manage.
The changes made to LDAPMemberships.py would help since you explained to me that one of your changes was to make members a dictionary. The getMembers() method would essentially return that dictionary.
No. getMembers() MUST return a list or everything breaks.
Okay. My mistake. Still trying to figure out Python and how things work. Since getMembers() returns a list, I suppose I could use the List2Dict() function to convert the list to a dictionary to be returned by my LDAP2Dict() function.
The key would be the changes to extend.py so everything works.
If you are accessing some LDAP directly (not via the @list construct) in the matches_p function, extend.py has nothing to do with it.
You will have to correct me if I am really off-base here on my understanding.
The extend.py module defines the extend() function which appears to set ldap (as an object of the LDAPMemberships class) ldap = LDAPMemberships(list) along with additional definitions, like ldap.ldapsearch = "(uid=somebody)" ldap.ldapserver = ldap.example.net and to tie it to the list, set the _memberadaptor to the object by list._memberadaptor = ldap
So when the list membership or some other method is accessed and not in the list namespace, your explanation above applies.
My idea of changing extend.py was to add additional objects of the LDAPMemberships class. Say an ldap2 and ldap3 like ldap2 = LDAPMemberships(list) ldap2.ldapsearch = "(uid=person1)" ldap2.ldapserver = ldap2.example.net list.<ldap2_identifier> = ldap2 ldap3 = LDAPMemberships(list) ldap3.ldapsearch = "(role=list-poster)" # as an example ldap3.ldapserver = ldap3.example.net list.<ldap3_identifier> = ldap3
both <ldap2_identifier> and <ldap3_identifier> are similar but not the same as the _memberadapter. The difference is <ldap2_identifier> and <ldap3_identifier> are specified in the accept_these_nonmembers (and the others) lists as LDAP=<ldap2_identifier> and likewise for any other "LDAP=" identifier.
The matches_p function (a parameter change would be needed, explained later) can separate out the "LDAP=" items and pass to the LDAP2Dict() function the list and ldap identifier.
The LDAP2Dict() function would use getattr(list, ldap-identifier) to locate the appropriate object of LDAPMemberships class.
So, for ldap2_identifier passed to LDAP2Dict(), getattr(list, ldap2_identifier) would return list.ldap2_identifier
Since I know that list.ldap2_identifier is an object with the getMembers() method, I should be able to get the "members" of the ldap2 search. And given that getMembers() returns a list, I can convert to a dictionary or possibly use List2Dict() to return the dictionary.
I do know that the list is not passed to the matches_p() function. For this to work, it would be added to the parameter list so the list can be passed to the LDAP2Dict() function.
I hope this helps. If you still have questions, keep asking.
It has helped. I have made some changes to Mailman/Handlers/Moderate.py and Utils.py (to add the LDAP2Dict function). Let me know if you would like to see what I came up with and I can send the diffs and explaination to you off-list. You may have a better way to implement what I am doing. Well, actually, you probably do have a better way. :)
See my remarks above.
I hope my explanations help you figure out what I am trying to do. The diffs may help you understand what I am trying to do.
I appreciate the help.
Thank you, Chris