This article attempts to provide an overview of the contact management system shipped with the pymsn library. In the following I assume you are already familiar with the basic pymsn API that allows you to connect to the server and attach the various event handlers.
Contact management is handled by the AddressBook object which manipulates AddressBookStorage, PendingContact, Group and Contact objects. I will try to describe each of these objects API and related event interfaces.
When you develop a client using pymsn, you generally start by instanciatiating the Client class, and then instanciating the event handlers you created. The Client instance holds an instance of the AddressBook that can be accessed through the address_book property:
The AddressBook instance provides a set of methods allowing you to interact with you address book stored remotely on the MSN servers, in fact each method call result in one or more SOAP requests (ouch). The results of those actions are then reflected on pymsn internal representation of data and the related methods from the AddressBookEventInterface are called to notify you that the changes have been done (contact added, group deleted, …). So all you have to do is to inherit from that event interface and fill the methods with your own needs then instanciate your instance.
Now let’s have a closer look on all those entities…
The AddressBook is the central object in contact management. It owns four important properties :
- contacts is an AddressBookStorage instance. It’s a collection containing Contact objects (actually representing the address book contact list). This object is very useful to request a subset of specific contacts using chained method calls.
- state is an AddressBookState value which describes the synchronization state of the address book. The address book is said to be synchronized when the local AddressBook data reflects excactly what’s stored on the server. When using the Client class, the given AddressBook instance is automatically synchronized at startup (else you would have to call the sync method).
- groups is a dictionary of Group objects indexed by their ids. It contains all the groups that are defined for that address book.
- pending_contacts is a set of PendingContact. Those objects are simple ones containing information on the contacts that asked to be added to the address book. Those pending invitations are to be accepted or declined.
The API is short, simple, and method actions are self explained by their name and the name of their parameters, however when can here explain some bloody details.
accept_contact_invitation(self, pending_contact, add_to_contact_list=True)
Method used to accept a pending invitation. It takes a PendingContact object from the pending_contacts set. You can specify if you want to add the new contact to your contact list (default behavior) or not. The pending contact will then be automatically removed from pending_contacts.
Method used to decline a pending invitation. It takes a PendingContact object from the pending_contacts set. The contact will be blocked and won’t appear in you contact list. The pending contact will then be automatically removed from pending_contacts.
add_messenger_contact(self, account, invite_display_name='', invite_message='')
Method used to add a “messenger contact” to the contact list. The “messenger contact” means a MSN or Yahoo contact (as opposed to “mail” or “mobile” contacts which are pending soon-to-be-added pymsn features). The main argument given to this method is the account (a valid email address). Giving a Yahoo domain email address, pymsn will try to add it both as a MSN account and a Yahoo account. You can also specify a display name and a message that may be displayed by the client used by the contact receiving the invitation.
Method used to delete a contact from the contact list. The given argument must be a Contact object from the contacts collection. The contact will then be automatically removed from contacts.
Method used to block a contact. The given argument must be a Contact object from the contacts collection.
Method used to unblock a contact. The given argument must be a Contact object from the contacts collection.
Method used to add a group to the address book.
Method used to delete a group from the address book. The given argument must be a Group object from the groups dictionary.
rename_group(self, group, new_name)
Method used to rename a group. The first argument must be a Group object from the groups dictionary. The second one is a string.
add_contact_to_group(self, group, contact)
Method used to add a contact to a group. The first argument must be a Group object from the groups dictionary. The second one must be a Contact object from the contacts collection.
delete_contact_from_group(self, group, contact)
Method used to delete a contact from a group. The first argument must be a Group object from the groups dictionary. The second one must be a Contact object from the contacts collection.
An AddressBookStorage is a set that contains Contact objects. This storage object provides several way to request for contacts. Queries are method calls that can be separated in two families : method beginning with “search_by” return sub address books (which are AddressBookStorage too) based on a field selection and method beginning with “group_by” group contacts together in a dictionary, based on a field value. The class provides some methods to query on not trivial Contact attributes :
This method returns an AddressBookStorage object that contains the Contact objects which match the given memberships parameter. That parameter is a bitwise OR of Membership lists. There are lists for blocked contacts, allowed contacts, contacts that got you in their contact list, etc.
This method returns an AddressBookStorage object that contains the Contact objects which are part of the given groups. Each group parameter must be a Group instance.
This method returns a dictionary in which each key is a Group and its linked data an AddressBookStorage object containing the Contact objects which are part of the key group.
In addition, pymsn makes use of the python __getattr__ method to provide custom query methods. Those are based on the next two methods that perform queries on the Contact object attributes :
search_by(self, field, value)
This method returns an AddressBookStorage containing the Contact objects for which the field attribute matched the given value.
This method returns a dictionary which associates values of field to the related Contact objects.
Since the “search_by” methods return AddressBookStorage objects, you can execute complex request chaining method calls. For instance, the next instruction will select all the Yahoo Messenger contacts from the address book and then group them in a dictionary using their presence as keys :
Contact, PendingContact and Group
Those objects are the ones manipulated by the address book but the best thing to do is to refer to the API documentation to learn more about them so they won’t be described here.
As with the other pymsn event interfaces, you’ll have to implement that interface and attach it to the Client. We won’t describe each method of the interface : almost each of the AddressBook methods fires an event method when its task is accomplished (the given arguments are then the concerned Contact or Group objects). We can however note that an event method exist to acknowledge you when there’s a new pending contact and that the errors that could occur performing the task (for instance when trying to add a contact who is already in the address book) are redirected to the client error handler.
Pymsn provides a powerful contact management through the address book. The API is still young and could certainly be improved : feel free to submit patched or bug reports. Feature requests are welcome too, we already have some pending ideas to be implemented : contact informations update (concerning mail addresses, birthdate and that kind of stuff), possibility to automatically add a contact to groups when adding him to the address book, etc.
If anybody find it useful, that blog post will become a page somewhere and will be updated to each API change.