Privacy Rewrite GSoC Project

Sulabh Mahajan at
Tue Jun 16 14:01:49 EDT 2009

 Here are some details of the plan to implement the privacy rewrite in view
of the discussions that have happened on the devel list:

1. We use the following structures to define the privacy states and types:

PurplePrivacyListType defines the types of possible privacy lists supported
by a protocol
typedef enum _PurplePrivacyListType
} PurplePrivacyListType;

Following structures are used to define the privacy states for an account,
or a list of these are used by a protocol to specify the supported privacy

typedef enum _PrivacyStateType
        ALLOW_ALL = 1,
} PrivacyStateType;

/* The following structure defines what we are allowing or blocking,
messages or presence or both */

typedef enum _PrivacyStateOf
        PRIVACY_STATE_BOTH, /* when msg, presence both tied together,
blocking blocks both */
        PRIVACY_STATE_EITHER /* when msg, presence can be blocked separately
for a contact */
} PrivacyStateOf;

The following structure combines the above two along with some flags to
define the scope of the features: local only or supported by the server;
Need a local list or not.

typedef struct _PurplePrivacyState
        PrivacyStateType privacytype;
        PrivacyStateOf privacyof;
        gboolean privacy_state_local; /* defines whether this features is
local only/faked or implemented on server */
        gboolean privacy_state_needs_local_storage; /* to keep track of
which states require storage of list locally */
} PurplePrivacyState;

privacy_state_needs_local_storage is required so as to NOT implement those
states which require locally storing a privacy list. As stated by Will such
states wont be of any use for Telepathy.

 2. Each protocol/prpl implements privacy features using the function
specified through PurplePluginProtocolInfo prpl_info:

   - void (*privacy_list_add)(PurpleConnection *, PurplePrivacyListType
   list_type, const char *name);
   - void (*privacy_list_rem)(PurpleConnection *, PurplePrivacyListType
   list_type, const char *name);
   - void (*set_privacy_state)(PurpleConnection *);
   - void (*define_supported_privacy_states)(PurpleConnection *);

 *privacy_list_add(), privacy_list_rem()* as the name suggest adds and
removes the given contact's id in the privacy lists of the server. The type
of list is given by the struct PurplePrivacyListType.

*set_privacy_state()* sets the privacy state for the particular
account. account->account_privacy_type
stores the state to be set for a particular account.

*define_supported_privacy_states()* is a function that necessarily be
implemented by each protocol. It registers a list of states of type
PurplePrivacyState that a protocol supports. It can also be replaced by a
linked list of elements of type PurplePrivacyState.

3. The idea is to define the complete list of supported states using these

For example,

For AIM:

PrivacyStateType                        PrivacyStateOf
privacy_state_local                privacy_state_needs_local_storage

ALLOW_ALL                         PRIVACY_STATE_BOTH
FALSE                                            FALSE




 FALSE                                            FALSE

BLOCK_ALL                           PRIVACY_STATE_EITHER
TRUE                                              FALSE

The last entry corresponds to the fact that we can "separately" block
messages from everyone and presence to everyone. This is a faked option,
where being invisible to everyone (blocking presence to everyone) is
supported on server, but, blocking messages from everyone while being
visible to everyone is faked by dropping messages locally (under ALLOW_ALL
state). The entry "BLOCK_ALL, PRIVACY_STATE_BOTH, FALSE" corresponds to
blocking both message and presence to everyone, which is different from
blocking either of message or presence at a time.

For IRC:

PrivacyStateType                         PrivacyStateOf
       privacy_state_local         privacy_state_needs_local_storage

ALLOW_ALL                          PRIVACY_STATE_BOTH
FALSE                                    FALSE

 TRUE                                       FALSE

 TRUE                                       TRUE

BLOCK_ALL                           PRIVACY_STATE_MESSAGE
 TRUE                                       FALSE

TRUE                                      TRUE

As you can see "completely" specifying supported privacy states for every
protocol can be a challenging task, especially since we can fake several of
the features the protocol doesn't provide. This is by far the best way I
have figured to solve this issue.

4. Privacy Public API:

(We will have a global PurplePrivacyState, or states can be set separately
for each account (account->account_privacy_type))

   - purple_privacy_state_set_global(...,PurplePrivacyState
   - purple_privacy_state_set_account(...,PurpleConnection *,
   PurplePrivacyState state,...)
   - purple_privacy_list_add(...,PurplePrivacyListType tp,
   PurplePrivacyListAddedCb cb,...)
   - purple_privacy_list_remove(...,PurplePrivacyListType tp,
   PurplePrivacyListRemovedCb cb,...)

 UI can register Cb that would be called on removing/adding a contact to a
list, specifying error with error type if any ( if list modification fails
asynchronously with the server, as stated by Will). Similarly callback will
be implemented for every function that interacts with the server and might
result in an error.

   - purple_privacy_allow_message(...,PurpleConnection *, const char *,...)
   - purple_privacy_allow_presence(...,PurpleConnection *, const char *,...)
   - purple_privacy_allow_both(...,PurpleConnection *, const char *,...)
   - purple_privacy_deny_message(...,PurpleConnection *, const char *,...)
   - purple_privacy_deny_presence(...,PurpleConnection *, const char *,...)
   - purple_privacy_deny_both(...,PurpleConnection *, const char *,...)
   - purple_privacy_check(...,PurpleConnection *, const char *,...)

 returns whether message/presence/both allowed?

   - purple_privacy_init(...,gboolean disable_local_features,...)

 UI can call privacy subsystem to disable the local/faked features, as
stated by Will needed by Telepathy

   - purple_privacy_set_ui_ops(..)
   - purple_privacy_get_ui_ops(..)
   - purple_privacy_item_blocked(...,PurplePrivacyItemType,...)

 libpurple on receiving an item (chat, notification, file transfer,
anything) calls this function, which in turns callbacks a function
registered by the UI/plugin. PurplePrivacyItemType is defined as the various
types of items we block from a contact:
typedef enum _PurplePrivacyItemType
} PurplePrivacyItemType;

5.  As discussed on the devel list, it is preferred to store the privacy
information about contacts in the blist itself. This is a great idea, but
another approach that we can follow is to construct a separate list for
privacy, "plist" stored in a file, "plist.xml". This list would contain an
entry to each and every contact that we ever encounter, including the
buddies as well. This follows the idea of having a super list which is the
union of buddy list, and all the various privacy lists.

Following an approach similar to blist, our plist structures will look
somewhat like:

struct _PurplePList
        PurplePlistNode *root;
        GHashTable *contacts;
        void *ui_data;

struct _PurplePlistNode
        PurplePlistNode *prev;
        PurplePlistNode *next;
        void *ui_data;
        void *proto_data;
        char *name;
        char *alias;
        PurpleAccount *account;
        PurplePrivacyContactType privacy;

PurplePrivacyContactType defines the privacy information associated with the

typedef struct _PurplePrivacyContactType
       gboolean purple_privacy_receive_message;
       gboolean purple_privacy_send_presence;
       gboolean contact_on_server_list;             /* whether this contact
is in some list on server or not */
} PurplePrivacyContactType;

plist xml tree would look like:

--<purple ver>

6. plist API: similar to blist API, probable functions that would be

plist management:
       purple_plist_new(), purple_set_plist(), purple_get_plist(),
       purple_plist_get_ui_data(), purple_plist_set_ui_data(),
       purple_plist_load(), purple_plist_save()

plist iteration, account addition/removing:
       purple_plist_get_root(), purple_plist_node_next(),
       purple_plist_add_account(), purple_plist_remove_account()

contact management:
       purple_plist_contact_new(), purple_plist_contact_destroy(),
       purple_plist_contact_add(), purple_plist_contact_remove(),
purple_plist_contact_set_ui_data(), purple_plist_contact_update_state(),
       purple_plist_contact_get_alias(), purple_plist_contact_set_alias()

ui ops:
       purple_plist_set_ui_ops(), purple_plist_get_ui_ops()

6. Apart from plist, buddies in blist will have PurplePrivacyBuddyType
structure as a member to structure PurpleBuddy so as to store privacy state
for easy access by buddy tooltip.
        typedef struct _PurplePrivacyContactType PurplePrivacyBuddytype;

blist API would have additions of following functions to enable showing the
least restrictive privacy state in buddy tooltip:
        PurplePrivacyState *purple_contact_get_priority_privacystate(...)

This is roughly an idea on how I am implementing the privacy rewrite. I have
tried to keep the mail short :-p , hence I am sure I might have missed a few
things, specifically I have not mentioned anything about multi user chat. I
don't really understand how we can have any level of privacy in MUC. I tried
searching but couldn't find anything about privacy in context of MUC.

MUC needs to be discussed, please feel free to write any idea you have
regarding privacy in MUC.

I am sure I have covered most of the points that have been discussed in the
devel list regarding privacy. Let me know if some idea sounds substandard or
if you have some better way to implement something.

Will and other telepathy developers are especially requested to present
their views. I have followed most of the suggestions Will proposed like
allowing UI to disable features that require storing lists locally, having
callback functions to report errors when some function dealing with server
can fail asynchronously, and using union of all the lists to store privacy

Florian, what are your views about this implementation in view of
Instantbird development.

Zachary, and other Adium developers are requested to comment upon the
mentioned ideas.

Also I would love to listen the views of Pidgin developers, especially
Sadrul, and John.

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <>

More information about the Devel mailing list