cpw.sulabh.privacy_rewrite: 163883c5: Update privacy_rewrite with latest ipp c...

sulabh at pidgin.im sulabh at pidgin.im
Sun Oct 17 14:37:21 EDT 2010


----------------------------------------------------------------------
Revision: 163883c56577e83c2e0c11a2a7667c1a9e4d0a25
Parent:   440326c9fa8c9bf5f66376cfcbb63922fb74a822
Author:   sulabh at pidgin.im
Date:     10/17/10 13:29:58
Branch:   im.pidgin.cpw.sulabh.privacy_rewrite
URL: http://d.pidgin.im/viewmtn/revision/info/163883c56577e83c2e0c11a2a7667c1a9e4d0a25

Changelog: 

Update privacy_rewrite with latest ipp code, create new branch for future work

Changes against parent 440326c9fa8c9bf5f66376cfcbb63922fb74a822

  patched  libpurple/account.c
  patched  libpurple/account.h
  patched  libpurple/blist.c
  patched  libpurple/blist.h
  patched  libpurple/connection.c
  patched  libpurple/core.c
  patched  libpurple/plugins/psychic.c
  patched  libpurple/privacy.c
  patched  libpurple/privacy.h
  patched  libpurple/protocols/yahoo/libyahoo.c
  patched  libpurple/protocols/yahoo/libyahoojp.c
  patched  libpurple/protocols/yahoo/libymsg.c
  patched  libpurple/protocols/yahoo/libymsg.h
  patched  libpurple/protocols/yahoo/yahoo_picture.c
  patched  libpurple/protocols/yahoo/yahoochat.c
  patched  libpurple/prpl.h
  patched  libpurple/server.c
  patched  libpurple/server.h
  patched  pidgin/gtkblist.c
  patched  pidgin/gtkconv.c
  patched  pidgin/gtkprivacy.c

-------------- next part --------------
============================================================
--- libpurple/server.c	2b3ba919ea5bc2b9ec70760de3a2d49a1c13a074
+++ libpurple/server.c	c4de4ce3daa3a315d3baeacec475b8a9c16d5d03
@@ -370,7 +370,7 @@ void serv_move_buddy(PurpleBuddy *b, Pur
 	}
 }
 
-void serv_add_permit(PurpleConnection *gc, const char *name)
+void serv_privacy_list_add(PurpleConnection *gc, PurplePrivacyListType list_type, const char *name)
 {
 	PurplePlugin *prpl;
 	PurplePluginProtocolInfo *prpl_info;
@@ -379,73 +379,39 @@ void serv_add_permit(PurpleConnection *g
 		prpl = purple_connection_get_prpl(gc);
 		prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
 
-		if (prpl_info->add_permit)
-			prpl_info->add_permit(gc, name);
+		if (prpl_info->privacy_list_add)
+			prpl_info->privacy_list_add(gc, list_type, name);
 	}
 }
 
-void serv_add_deny(PurpleConnection *gc, const char *name)
+void serv_privacy_list_remove(PurpleConnection *gc, PurplePrivacyListType list_type, const char *name)
 {
 	PurplePlugin *prpl;
 	PurplePluginProtocolInfo *prpl_info;
 
-	if (gc) {
+	if (gc)	{
 		prpl = purple_connection_get_prpl(gc);
 		prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
 
-		if (prpl_info->add_deny)
-			prpl_info->add_deny(gc, name);
+		if (prpl_info->privacy_list_remove)
+			prpl_info->privacy_list_remove(gc, list_type, name);
 	}
 }
 
-void serv_rem_permit(PurpleConnection *gc, const char *name)
+void serv_privacy_set_state(PurpleConnection *gc)
 {
 	PurplePlugin *prpl;
 	PurplePluginProtocolInfo *prpl_info;
 
-	if (gc) {
+	if (gc)	{
 		prpl = purple_connection_get_prpl(gc);
 		prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
 
-		if (prpl_info->rem_permit)
-			prpl_info->rem_permit(gc, name);
+		if (prpl_info->privacy_set_state)
+			prpl_info->privacy_set_state(gc);
 	}
 }
 
-void serv_rem_deny(PurpleConnection *gc, const char *name)
-{
-	PurplePlugin *prpl;
-	PurplePluginProtocolInfo *prpl_info;
-
-	if (gc) {
-		prpl = purple_connection_get_prpl(gc);
-		prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
-
-		if (prpl_info->rem_deny)
-			prpl_info->rem_deny(gc, name);
-	}
-}
-
-void serv_set_permit_deny(PurpleConnection *gc)
-{
-	PurplePlugin *prpl;
-	PurplePluginProtocolInfo *prpl_info;
-
-	if (gc) {
-		prpl = purple_connection_get_prpl(gc);
-		prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
-
-		/*
-		 * this is called when either you import a buddy list, and make lots
-		 * of changes that way, or when the user toggles the permit/deny mode
-		 * in the prefs. In either case you should probably be resetting and
-		 * resending the permit/deny info when you get this.
-		 */
-		if (prpl_info->set_permit_deny)
-			prpl_info->set_permit_deny(gc);
-	}
-}
-
 void serv_join_chat(PurpleConnection *gc, GHashTable *data)
 {
 	PurplePlugin *prpl;
@@ -572,10 +538,11 @@ void serv_got_im(PurpleConnection *gc, c
 	 */
 	flags |= PURPLE_MESSAGE_RECV;
 
-	if (!purple_privacy_check(account, who)) {
-		purple_signal_emit(purple_conversations_get_handle(), "blocked-im-msg",
-				account, who, msg, flags, (unsigned int)mtime);
-		return;
+	if (purple_privacy_check(purple_connection_get_account(gc), who, PURPLE_PRIVACY_BLOCK_MESSAGE))
+	{
+		/* To-do Privacy : emit signal */
+		purple_debug_info("server","Privacy: Dropped message from %s\n", who);
+		return ;
 	}
 
 	/*
@@ -700,6 +667,11 @@ void serv_got_typing(PurpleConnection *g
 	PurpleConversation *conv;
 	PurpleConvIm *im = NULL;
 
+	if (purple_privacy_check(purple_connection_get_account(gc), name, PURPLE_PRIVACY_BLOCK_MESSAGE)) {
+		purple_debug_info("server","Privacy: Dropped typing.. from %s\n", name);
+		return ;
+	}
+
 	conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, name, gc->account);
 	if (conv != NULL) {
 		im = PURPLE_CONV_IM(conv);
@@ -732,6 +704,9 @@ void serv_got_typing_stopped(PurpleConne
 	PurpleConversation *conv;
 	PurpleConvIm *im;
 
+	if (purple_privacy_check(purple_connection_get_account(gc), name, PURPLE_PRIVACY_BLOCK_MESSAGE))
+		return ;
+
 	conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, name, gc->account);
 	if (conv != NULL)
 	{
@@ -790,10 +765,13 @@ void serv_got_chat_invite(PurpleConnecti
 	g_return_if_fail(who != NULL);
 
 	account = purple_connection_get_account(gc);
-	if (!purple_privacy_check(account, who)) {
+	if(purple_privacy_check(purple_connection_get_account(gc), who, PURPLE_PRIVACY_BLOCK_CONF)) {
+		/* To do privacy: emit signal: like
 		purple_signal_emit(purple_conversations_get_handle(), "chat-invite-blocked",
 				account, who, name, message, data);
-		return;
+		*/
+		purple_debug_info("server","Privacy: Dropped chat invite to room %s from %s\n", name, who);
+		return ;
 	}
 
 	cid = g_new0(struct chat_invite_data, 1);
============================================================
--- libpurple/prpl.h	b978e54f15e71fa817afe0f6b25c84852fee1d25
+++ libpurple/prpl.h	123e4946ba492505c4a4633c768999e628b97531
@@ -74,6 +74,7 @@ typedef struct _PurpleThumbnailSpec Purp
 #include "imgstore.h"
 #include "media.h"
 #include "notify.h"
+#include "privacy.h"
 #include "proxy.h"
 #include "plugin.h"
 #include "roomlist.h"
@@ -221,6 +222,7 @@ struct _PurplePluginProtocolInfo
 	GList *protocol_options; /**< A GList of PurpleAccountOption    */
 
 	PurpleBuddyIconSpec icon_spec; /**< The icon spec. */
+	PurplePrivacySpec privacy_spec;
 
 	/**
 	 * Returns the base icon name for the given buddy and account.
@@ -338,11 +340,9 @@ struct _PurplePluginProtocolInfo
 	void (*add_buddies)(PurpleConnection *, GList *buddies, GList *groups);
 	void (*remove_buddy)(PurpleConnection *, PurpleBuddy *buddy, PurpleGroup *group);
 	void (*remove_buddies)(PurpleConnection *, GList *buddies, GList *groups);
-	void (*add_permit)(PurpleConnection *, const char *name);
-	void (*add_deny)(PurpleConnection *, const char *name);
-	void (*rem_permit)(PurpleConnection *, const char *name);
-	void (*rem_deny)(PurpleConnection *, const char *name);
-	void (*set_permit_deny)(PurpleConnection *);
+	void (*privacy_list_add)(PurpleConnection *, PurplePrivacyListType list_type, const char *name);
+	void (*privacy_list_remove)(PurpleConnection *, PurplePrivacyListType list_type, const char *name);
+	void (*privacy_set_state)(PurpleConnection *);
 
 	/**
 	 * Called when the user requests joining a chat. Should arrange for
============================================================
--- libpurple/core.c	2431d70fed20726a6a5ad9ac00b90938d628f01d
+++ libpurple/core.c	9bf2fb3574c6d61fff50264c397276ab9bac507e
@@ -162,10 +162,10 @@ purple_core_init(const char *ui)
 	purple_notify_init();
 	purple_certificate_init();
 	purple_conversations_init();
+	purple_privacy_init();
 	purple_blist_init();
 	purple_log_init();
 	purple_network_init();
-	purple_privacy_init();
 	purple_pounces_init();
 	purple_proxy_init();
 	purple_dnsquery_init();
@@ -224,6 +224,7 @@ purple_core_quit(void)
 	purple_smileys_uninit();
 	purple_idle_uninit();
 	purple_pounces_uninit();
+	purple_privacy_uninit();
 	purple_blist_uninit();
 	purple_ciphers_uninit();
 	purple_notify_uninit();
============================================================
--- libpurple/protocols/yahoo/libymsg.c	ede49fc83fb4fba337d5bca27d26fa20595039b8
+++ libpurple/protocols/yahoo/libymsg.c	e44b77e5419629d79fd0d2075c328d5d527bf6da
@@ -504,6 +504,7 @@ static void yahoo_process_list_15(Purple
 	                       /* But what if you had no friends? */
 	YahooFederation fed = YAHOO_FEDERATION_NONE;
 	int stealth = 0;
+	GSList *buddy_list = NULL, *block_both_list = NULL, *invisible_list = NULL;
 
 	ht = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, (GDestroyNotify) g_slist_free);
 
@@ -558,12 +559,18 @@ static void yahoo_process_list_15(Purple
 						purple_blist_add_buddy(b, NULL, g, NULL);
 					}
 					yahoo_do_group_check(account, ht, norm_bud, yd->current_list15_grp);
+					/* Prepare buddy list to be passed to privacy subsystem */
+					buddy_list = g_slist_prepend(buddy_list, g_strdup(norm_bud));
 					if(fed) {
 						f->fed = fed;
 						purple_debug_info("yahoo", "Setting federation to %d\n", f->fed);
 					}
 					if(stealth == 2)
+					{
 						f->presence = YAHOO_PRESENCE_PERM_OFFLINE;
+						/* Prepare invisible list to be passed to privacy subsystem */
+						invisible_list = g_slist_prepend(invisible_list, g_strdup(norm_bud));
+					}
 
 					/* set p2p status not connected and no p2p packet sent */
 					if(fed == YAHOO_FEDERATION_NONE) {
@@ -574,7 +581,8 @@ static void yahoo_process_list_15(Purple
 				} else {
 					/* This buddy is on the ignore list (and therefore in no group) */
 					purple_debug_info("yahoo", "%s adding %s to the deny list because of the ignore list / no group was found\n",account->username, norm_bud);
-					purple_privacy_deny_add(account, norm_bud, 1);
+					/* Prepare block list (blocks message and presence) to be passed to privacy subsystem */
+					block_both_list = g_slist_prepend(block_both_list, g_strdup(norm_bud));
 				}
 
 				g_free(norm_bud);
@@ -611,6 +619,15 @@ static void yahoo_process_list_15(Purple
 
 	g_hash_table_foreach(ht, yahoo_do_group_cleanup, NULL);
 
+	/* Provide the privacy subsystem with the lists on the server*/ 
+	purple_privacy_sync_lists(account, buddy_list, NULL, NULL, block_both_list, NULL, invisible_list);
+	purple_debug_info("yahoo","Privacy Lists synchronized\n");
+	/* Set native privacy state */
+	if(block_both_list != NULL)
+		account->native_privacy_state = PURPLE_PRIVACY_NATIVE_DENY_USERS;
+	else
+		account->native_privacy_state = PURPLE_PRIVACY_NATIVE_ALLOW_ALL;
+
 	/* The reporter of ticket #9745 determined that we weren't retrieving the
 	 * aliases during buddy list retrieval, so we never updated aliases that
 	 * changed while we were signed off. */
@@ -627,6 +644,10 @@ static void yahoo_process_list_15(Purple
 	}
 	yahoo_set_status(account, purple_account_get_active_status(account));
 
+	g_slist_free(buddy_list);
+	g_slist_free(block_both_list);
+	g_slist_free(invisible_list);
+
 	g_hash_table_destroy(ht);
 	g_free(temp);
 }
@@ -739,7 +760,7 @@ static void yahoo_process_list(PurpleCon
 		for (bud = buddies; bud && *bud; bud++) {
 			/* The server is already ignoring the user */
 			got_serv_list = TRUE;
-			purple_privacy_deny_add(account, *bud, 1);
+			purple_privacy_set_block_all(account, *bud, TRUE, FALSE);
 		}
 		g_strfreev(buddies);
 
@@ -747,16 +768,6 @@ static void yahoo_process_list(PurpleCon
 		yd->tmp_serv_ilist = NULL;
 	}
 
-	if (got_serv_list &&
-		((account->perm_deny != PURPLE_PRIVACY_ALLOW_BUDDYLIST) &&
-		(account->perm_deny != PURPLE_PRIVACY_DENY_ALL) &&
-		(account->perm_deny != PURPLE_PRIVACY_ALLOW_USERS)))
-	{
-		account->perm_deny = PURPLE_PRIVACY_DENY_USERS;
-		purple_debug_info("yahoo", "%s privacy defaulting to PURPLE_PRIVACY_DENY_USERS.\n",
-				account->username);
-	}
-
 	if (yd->tmp_serv_plist) {
 		buddies = g_strsplit(yd->tmp_serv_plist->str, ",", -1);
 		for (bud = buddies; bud && *bud; bud++) {
@@ -820,8 +831,7 @@ static void yahoo_process_notify(PurpleC
 		return;
 	}
 
-	if (!g_ascii_strncasecmp(msg, "TYPING", strlen("TYPING"))
-		&& (purple_privacy_check(account, from)))
+	if (!g_ascii_strncasecmp(msg, "TYPING", strlen("TYPING")))
 	{
 		char *fed_from = from;
 		switch (fed) {
@@ -1040,7 +1050,7 @@ static void yahoo_process_message(Purple
 					{
 						PurpleWhiteboard *wb;
 
-						if (!purple_privacy_check(account, im->from)) {
+						if (purple_privacy_check(account, im->from, PURPLE_PRIVACY_BLOCK_ALL)) {
 							purple_debug_info("yahoo", "Doodle request from %s dropped.\n",
 												im->from);
 							g_free(im->fed_from);
@@ -1086,11 +1096,6 @@ static void yahoo_process_message(Purple
 			continue;
 		}
 
-		if (!purple_privacy_check(account, im->fed_from)) {
-			purple_debug_info("yahoo", "Message from %s dropped.\n", im->fed_from);
-			return;
-		}
-
 		/*
 		 * TODO: Is there anything else we should check when determining whether
 		 *       we should send an acknowledgement?
@@ -1424,7 +1429,7 @@ static void yahoo_buddy_auth_req_15(Purp
 		if (add_req->id && add_req->who) {
 			char *alias = NULL, *dec_msg = NULL;
 
-			if (!purple_privacy_check(account, add_req->who))
+			if (purple_privacy_check(account, add_req->who, PURPLE_PRIVACY_BLOCK_ALL))
 			{
 				purple_debug_misc("yahoo", "Auth. request from %s dropped and automatically denied due to privacy settings!\n",
 						  add_req->who);
@@ -1497,7 +1502,7 @@ static void yahoo_buddy_added_us(PurpleC
 	if (add_req->id && add_req->who) {
 		char *dec_msg = NULL;
 
-		if (!purple_privacy_check(account, add_req->who)) {
+		if (purple_privacy_check(account, add_req->who, PURPLE_PRIVACY_BLOCK_ALL)) {
 			purple_debug_misc("yahoo", "Auth. request from %s dropped and automatically denied due to privacy settings!\n",
 					  add_req->who);
 			yahoo_buddy_add_deny_cb(add_req, NULL);
@@ -2121,15 +2126,14 @@ static void ignore_buddy(PurpleBuddy *bu
 	purple_account_remove_buddy(account, buddy, group);
 	purple_blist_remove_buddy(buddy);
 
-	serv_add_deny(purple_account_get_connection(account), name);
+	serv_privacy_list_add(purple_account_get_connection(account), PURPLE_PRIVACY_BLOCK_BOTH_LIST, name);
 
 	g_free(name);
 }
 
 static void keep_buddy(PurpleBuddy *b)
 {
-	purple_privacy_deny_remove(purple_buddy_get_account(b),
-			purple_buddy_get_name(b), 1);
+	purple_privacy_unset_block_all(purple_buddy_get_account(b), purple_buddy_get_name(b), TRUE, FALSE);
 }
 
 static void yahoo_process_ignore(PurpleConnection *gc, struct yahoo_packet *pkt) {
@@ -2953,7 +2957,7 @@ static void yahoo_process_audible(Purple
 		purple_debug_misc("yahoo", "Warning, nonutf8 audible, ignoring!\n");
 		return;
 	}
-	if (!purple_privacy_check(account, who)) {
+	if (purple_privacy_check(account, who, PURPLE_PRIVACY_BLOCK_ALL)) {
 		purple_debug_misc("yahoo", "Audible message from %s for %s dropped!\n",
 				purple_account_get_username(account), who);
 		return;
@@ -4947,7 +4951,7 @@ void yahoo_add_buddy(PurpleConnection *g
 		return;
 
 	fed_bname = bname = purple_buddy_get_name(buddy);
-	if (!purple_privacy_check(purple_connection_get_account(gc), bname))
+	if (purple_privacy_check(purple_connection_get_account(gc), bname, PURPLE_PRIVACY_BLOCK_ALL))
 		return;
 
 	fed = yahoo_get_federation_from_name(bname);
@@ -5053,7 +5057,7 @@ void yahoo_remove_buddy(PurpleConnection
 	g_free(cg);
 }
 
-void yahoo_add_deny(PurpleConnection *gc, const char *who) {
+static void yahoo_add_deny(PurpleConnection *gc, const char *who) {
 	YahooData *yd = (YahooData *)gc->proto_data;
 	struct yahoo_packet *pkt;
 	YahooFederation fed = YAHOO_FEDERATION_NONE;
@@ -5076,7 +5080,7 @@ void yahoo_add_deny(PurpleConnection *gc
 	yahoo_packet_send_and_free(pkt, yd);
 }
 
-void yahoo_rem_deny(PurpleConnection *gc, const char *who) {
+static void yahoo_rem_deny(PurpleConnection *gc, const char *who) {
 	YahooData *yd = (YahooData *)gc->proto_data;
 	struct yahoo_packet *pkt;
 	YahooFederation fed = YAHOO_FEDERATION_NONE;
@@ -5098,28 +5102,100 @@ void yahoo_rem_deny(PurpleConnection *gc
 	yahoo_packet_send_and_free(pkt, yd);
 }
 
-void yahoo_set_permit_deny(PurpleConnection *gc)
+/* set = TRUE for setting perm invisible, FALSE to unset perm invisible */
+static void set_perm_invisible(PurpleConnection *gc, const char *who, gboolean set)
+{	
+	YahooData *yd = gc->proto_data;
+	struct yahoo_packet *pkt = NULL;
+	YahooFederation fed = YAHOO_FEDERATION_NONE;
+	int val_31;
+
+	if (!yd->logged_in)
+		return;
+
+	fed = yahoo_get_federation_from_name(who);
+
+	pkt = yahoo_packet_new(YAHOO_SERVICE_PRESENCE_SESSION, YAHOO_STATUS_AVAILABLE, yd->session_id);
+
+	val_31 = (set ? 1 : 2);
+
+	if(fed)
+		yahoo_packet_hash(pkt, "sissssiss",
+					1, purple_connection_get_display_name(gc),
+					31, val_31, 13, "1",
+					302, "319", 300, "319",
+					7, who+4, 241, 2,
+					301, "319", 303, "319");
+	else
+		yahoo_packet_hash(pkt, "sissssss",
+					1, purple_connection_get_display_name(gc),
+					31, val_31, 13, "1",
+					302, "319", 300, "319",
+					7, who, 301, "319", 303, "319");
+
+	yahoo_packet_send_and_free(pkt, yd);
+}
+
+void yahoo_privacy_list_add(PurpleConnection *gc, PurplePrivacyListType list_type, const char *who)
 {
-	PurpleAccount *account;
-	GSList *deny;
+	YahooData *yd = gc->proto_data;
 
-	account = purple_connection_get_account(gc);
+	if (!yd->logged_in)
+		return;
 
-	switch (account->perm_deny)
+	if (!who || who[0] == '\0')
+		return;
+
+	switch(list_type)
 	{
-		case PURPLE_PRIVACY_ALLOW_ALL:
-			for (deny = account->deny; deny; deny = deny->next)
-				yahoo_rem_deny(gc, deny->data);
+		case PURPLE_PRIVACY_ALLOW_LIST:
+		case PURPLE_PRIVACY_BLOCK_MESSAGE_LIST:
+		case PURPLE_PRIVACY_BUDDY_LIST:
+			/* either not supported or not the right place to edit the list */
 			break;
+		case PURPLE_PRIVACY_BLOCK_BOTH_LIST:
+			yahoo_add_deny(gc, who);
+			break;
+		case PURPLE_PRIVACY_VISIBLE_LIST:
+			/* Privacy laters: check */
+			yahoo_friend_update_presence(gc, who, YAHOO_PRESENCE_ONLINE);
+			break;
+		case PURPLE_PRIVACY_INVISIBLE_LIST:
+			set_perm_invisible(gc, who, TRUE);
+			break;
+	}
+	return;
+}
 
-		case PURPLE_PRIVACY_ALLOW_BUDDYLIST:
-		case PURPLE_PRIVACY_ALLOW_USERS:
-		case PURPLE_PRIVACY_DENY_USERS:
-		case PURPLE_PRIVACY_DENY_ALL:
-			for (deny = account->deny; deny; deny = deny->next)
-				yahoo_add_deny(gc, deny->data);
+void yahoo_privacy_list_remove(PurpleConnection *gc, PurplePrivacyListType list_type, const char *who)
+{
+	YahooData *yd = gc->proto_data;
+
+	if (!yd->logged_in)
+		return;
+
+	if (!who || who[0] == '\0')
+		return;
+
+	switch(list_type)
+	{
+		case PURPLE_PRIVACY_ALLOW_LIST:
+		case PURPLE_PRIVACY_BLOCK_MESSAGE_LIST:
+		case PURPLE_PRIVACY_BUDDY_LIST:
+			/* either not supported or not the right place to edit the list */
 			break;
+		case PURPLE_PRIVACY_BLOCK_BOTH_LIST:
+			yahoo_rem_deny(gc, who);
+			break;
+		case PURPLE_PRIVACY_VISIBLE_LIST:
+			/* Privacy laters */
+			yahoo_friend_update_presence(gc, who, YAHOO_PRESENCE_PERM_OFFLINE);
+			break;
+		case PURPLE_PRIVACY_INVISIBLE_LIST:
+			set_perm_invisible(gc, who, FALSE);
+			break;
 	}
+	return;
 }
 
 void yahoo_change_buddys_group(PurpleConnection *gc, const char *who,
============================================================
--- pidgin/gtkconv.c	fd98809f02bf50949648e402ede0f2622464edfe
+++ pidgin/gtkconv.c	89230815d14851fce59312c8bb07442d87eeb28a
@@ -6473,7 +6473,7 @@ gray_stuff_out(PidginConversation *gtkco
 		gtk_widget_show(win->menu.get_info);
 		gtk_widget_hide(win->menu.invite);
 		gtk_widget_show(win->menu.alias);
- 		if (purple_privacy_check(account, purple_conversation_get_name(conv))) {
+		if (!purple_privacy_check(account, purple_conversation_get_name(conv), PURPLE_PRIVACY_BLOCK_ALL)) {
  			gtk_widget_hide(win->menu.unblock);
  			gtk_widget_show(win->menu.block);
  		} else {
============================================================
--- libpurple/privacy.h	189d1f21abd1cdfce1f32b47bb45aef7f938a44a
+++ libpurple/privacy.h	2fd8523426bacbfbeb81565e0a2c51f869b70ce7
@@ -26,20 +26,58 @@
 #ifndef _PURPLE_PRIVACY_H_
 #define _PURPLE_PRIVACY_H_
 
+#define PURPLE_PRIVACY_GROUP	"_Privacy"
+
+#include "account.h"
+
 /**
  * Privacy data types.
  */
-typedef enum _PurplePrivacyType
+typedef enum _PurplePrivacySetting
 {
 	PURPLE_PRIVACY_ALLOW_ALL = 1,
-	PURPLE_PRIVACY_DENY_ALL,
-	PURPLE_PRIVACY_ALLOW_USERS,
-	PURPLE_PRIVACY_DENY_USERS,
-	PURPLE_PRIVACY_ALLOW_BUDDYLIST
-} PurplePrivacyType;
+	PURPLE_PRIVACY_BLOCK_MSG_NONBUDDY,
+	PURPLE_PRIVACY_ALLOW_BUDDYLIST,
+	PURPLE_PRIVACY_CUSTOM
+} PurplePrivacySetting;
 
-#include "account.h"
+typedef enum _NativePrivacySetting
+{
+	PURPLE_PRIVACY_NATIVE_ALLOW_ALL = 0x0004,
+	PURPLE_PRIVACY_NATIVE_DENY_ALL = 0x0008,	/* Both messages and presence blocked, add extra states if for a protocol only messages blocked */
+	PURPLE_PRIVACY_NATIVE_ALLOW_USERS = 0x0010,
+	PURPLE_PRIVACY_NATIVE_DENY_USERS = 0x0020,	/* Both messages and presence blocked, add extra states if for a protocol only messages blocked */
+	PURPLE_PRIVACY_NATIVE_ALLOW_BUDDYLIST = 0x0040
+} NativePrivacySetting;
 
+typedef enum _PurplePrivacyListType
+{
+	PURPLE_PRIVACY_ALLOW_LIST = 0x0004,
+	PURPLE_PRIVACY_BLOCK_MESSAGE_LIST = 0x0008,
+	PURPLE_PRIVACY_BLOCK_BOTH_LIST = 0x0010,
+	PURPLE_PRIVACY_VISIBLE_LIST = 0x0020,
+	PURPLE_PRIVACY_INVISIBLE_LIST = 0x0040,
+	PURPLE_PRIVACY_BUDDY_LIST = 0x0080
+} PurplePrivacyListType;
+
+typedef struct _PurpleAccountPrivacySpec
+{
+	NativePrivacySetting supported_privacy_states;	/* Stores the privacy states natively supported */
+	PurplePrivacyListType supported_privacy_lists;	/* Stores the privacy lists types natively supported */
+	gboolean visible_list_transient;	/* True for Yahoo visible lists, as these are lost across sessions/status changes */
+	gboolean invisible_to_all_supported;	/* whether invisible to all status is supported */
+	gboolean can_deny_buddy;		/* can a buddy be added to the deny list - FALSE for yahoo! */
+} PurplePrivacySpec;
+
+typedef enum _PurplePrivacyContext
+{
+	PURPLE_PRIVACY_BLOCK_ALL = 0x0004,
+	PURPLE_PRIVACY_BLOCK_MESSAGE = 0x0008,
+	PURPLE_PRIVACY_BLOCK_PRESENCE = 0x0010,
+	PURPLE_PRIVACY_BLOCK_FT = 0x0020,
+	PURPLE_PRIVACY_BLOCK_CONF = 0x0040
+} PurplePrivacyContext;
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -60,115 +98,8 @@ typedef struct
 	void (*_purple_reserved4)(void);
 } PurplePrivacyUiOps;
 
-/**
- * Adds a user to the account's permit list.
- *
- * @param account    The account.
- * @param name       The name of the user to add to the list.
- * @param local_only If TRUE, only the local list is updated, and not
- *                   the server.
- *
- * @return TRUE if the user was added successfully, or @c FALSE otherwise.
- */
-gboolean purple_privacy_permit_add(PurpleAccount *account, const char *name,
-								 gboolean local_only);
 
 /**
- * Removes a user from the account's permit list.
- *
- * @param account    The account.
- * @param name       The name of the user to add to the list.
- * @param local_only If TRUE, only the local list is updated, and not
- *                   the server.
- *
- * @return TRUE if the user was removed successfully, or @c FALSE otherwise.
- */
-gboolean purple_privacy_permit_remove(PurpleAccount *account, const char *name,
-									gboolean local_only);
-
-/**
- * Adds a user to the account's deny list.
- *
- * @param account    The account.
- * @param name       The name of the user to add to the list.
- * @param local_only If TRUE, only the local list is updated, and not
- *                   the server.
- *
- * @return TRUE if the user was added successfully, or @c FALSE otherwise.
- */
-gboolean purple_privacy_deny_add(PurpleAccount *account, const char *name,
-							   gboolean local_only);
-
-/**
- * Removes a user from the account's deny list.
- *
- * @param account    The account.
- * @param name       The name of the user to add to the list.
- * @param local_only If TRUE, only the local list is updated, and not
- *                   the server.
- *
- * @return TRUE if the user was removed successfully, or @c FALSE otherwise.
- */
-gboolean purple_privacy_deny_remove(PurpleAccount *account, const char *name,
-								  gboolean local_only);
-
-/**
- * Allow a user to send messages. If current privacy setting for the account is:
- *		PURPLE_PRIVACY_ALLOW_USERS:	The user is added to the allow-list.
- *		PURPLE_PRIVACY_DENY_USERS	:	The user is removed from the deny-list.
- *		PURPLE_PRIVACY_ALLOW_ALL	:	No changes made.
- *		PURPLE_PRIVACY_DENY_ALL	:	The privacy setting is changed to
- *									PURPLE_PRIVACY_ALLOW_USERS and the user
- *									is added to the allow-list.
- *		PURPLE_PRIVACY_ALLOW_BUDDYLIST: No changes made if the user is already in
- *									the buddy-list. Otherwise the setting is
- *									changed to PURPLE_PRIVACY_ALLOW_USERS, all the
- *									buddies are added to the allow-list, and the
- *									user is also added to the allow-list.
- *
- * @param account	The account.
- * @param who		The name of the user.
- * @param local		Whether the change is local-only.
- * @param restore	Should the previous allow/deny list be restored if the
- *					privacy setting is changed.
- */
-void purple_privacy_allow(PurpleAccount *account, const char *who, gboolean local,
-						gboolean restore);
-
-/**
- * Block messages from a user. If current privacy setting for the account is:
- *		PURPLE_PRIVACY_ALLOW_USERS:	The user is removed from the allow-list.
- *		PURPLE_PRIVACY_DENY_USERS	:	The user is added to the deny-list.
- *		PURPLE_PRIVACY_DENY_ALL	:	No changes made.
- *		PURPLE_PRIVACY_ALLOW_ALL	:	The privacy setting is changed to
- *									PURPLE_PRIVACY_DENY_USERS and the user is
- *									added to the deny-list.
- *		PURPLE_PRIVACY_ALLOW_BUDDYLIST: If the user is not in the buddy-list,
- *									then no changes made. Otherwise, the setting
- *									is changed to PURPLE_PRIVACY_ALLOW_USERS, all
- *									the buddies are added to the allow-list, and
- *									this user is removed from the list.
- *
- * @param account	The account.
- * @param who		The name of the user.
- * @param local		Whether the change is local-only.
- * @param restore	Should the previous allow/deny list be restored if the
- *					privacy setting is changed.
- */
-void purple_privacy_deny(PurpleAccount *account, const char *who, gboolean local,
-						gboolean restore);
-
-/**
- * Check the privacy-setting for a user.
- *
- * @param account	The account.
- * @param who		The name of the user.
- *
- * @return @c FALSE if the specified account's privacy settings block the user or @c TRUE otherwise. The meaning of "block" is protocol-dependent and generally relates to status and/or sending of messages.
- */
-gboolean purple_privacy_check(PurpleAccount *account, const char *who);
-
-/**
  * Sets the UI operations structure for the privacy subsystem.
  *
  * @param ops The UI operations structure.
@@ -187,6 +118,53 @@ void purple_privacy_init(void);
  */
 void purple_privacy_init(void);
 
+/* Returns account specific privacy lists */
+GSList *purple_privacy_list_get_members_by_account(PurpleAccount *account, PurplePrivacyListType type);
+
+/* called by prpls with all the privacy lists + buddy list. Synchronizes the local master list (blist) */
+gboolean purple_privacy_sync_lists(PurpleAccount *account, GSList *buddy_l, GSList *allow_l, GSList *block_msg_l, GSList *block_both_l, GSList *visible_l, GSList *invisible_l);
+
+/* returns TRUE if account supports "Invisible" status, otherwise FALSE */ 
+gboolean purple_privacy_account_supports_invisible_status (PurpleAccount *account);
+
+/* returns TRUE if account's current status is "Invisible", otherwise FALSE */ 
+gboolean purple_privacy_account_status_invisible(PurpleAccount *account);
+
+/* Sets account's status to "Invisible", returns TRUE if successful, "FALSE" if not */ 
+gboolean purple_privacy_set_account_status_invisible(PurpleAccount *account);
+
+/* Sets account's status visible , returns TRUE if successful, "FALSE" if not */
+/* Following order is used to test for a suitable visible status:
+	* Current active saved status
+	* Default saved status
+	* Available status
+*/
+gboolean purple_privacy_set_account_status_visible(PurpleAccount *account);
+
+/* Returns the gloabl privacy state */
+PurplePrivacySetting purple_privacy_obtain_global_state(void);
+PurplePrivacySetting purple_privacy_obtain_account_state(PurpleAccount *account);
+NativePrivacySetting purple_privacy_obtain_native_state(PurpleAccount *account);
+void purple_privacy_set_account_state(PurpleAccount *account, PurplePrivacySetting state);
+void purple_privacy_set_global_state(PurplePrivacySetting state);
+void *purple_privacy_get_handle(void);
+void purple_privacy_uninit(void);
+
+gboolean purple_privacy_set_blocking_context(PurpleAccount *account, const char *who, gboolean local_only, PurplePrivacyContext context);
+PurplePrivacyContext purple_privacy_get_blocking_context(PurpleAccount *account, const char *who);
+gboolean purple_privacy_set_block_all(PurpleAccount *account, const char *who, gboolean local, gboolean server);
+gboolean purple_privacy_set_block_presence(PurpleAccount *account, const char *who, gboolean local, gboolean server);
+gboolean purple_privacy_set_block_message(PurpleAccount *account, const char *who);
+gboolean purple_privacy_set_block_ft(PurpleAccount *account, const char *who);
+gboolean purple_privacy_set_block_conf(PurpleAccount *account, const char *who);
+gboolean purple_privacy_unset_block_message(PurpleAccount *account, const char *who);
+gboolean purple_privacy_unset_block_conf(PurpleAccount *account, const char *who);
+gboolean purple_privacy_unset_block_ft(PurpleAccount *account, const char *who);
+gboolean purple_privacy_unset_block_all(PurpleAccount *account, const char *who, gboolean local, gboolean server);
+gboolean purple_privacy_unset_block_presence(PurpleAccount *account, const char *who, gboolean local, gboolean server);
+gboolean purple_privacy_check(PurpleAccount *account, const char *who, PurplePrivacyContext context);
+gboolean purple_privacy_check_list_support(PurpleAccount *account, PurplePrivacyListType type);
+
 #ifdef __cplusplus
 }
 #endif
============================================================
--- libpurple/blist.c	2ca4596c2ca7f986298bd6037d31425976a2a5b2
+++ libpurple/blist.c	70801ba1df505a103dabd5a0308e2dde133c345b
@@ -183,8 +183,9 @@ buddy_to_xmlnode(PurpleBlistNode *bnode)
 static xmlnode *
 buddy_to_xmlnode(PurpleBlistNode *bnode)
 {
-	xmlnode *node, *child;
+	xmlnode *node, *child, *grandchild;
 	PurpleBuddy *buddy;
+	char *buf = NULL;
 
 	buddy = (PurpleBuddy *)bnode;
 
@@ -195,6 +196,16 @@ buddy_to_xmlnode(PurpleBlistNode *bnode)
 	child = xmlnode_new_child(node, "name");
 	xmlnode_insert_data(child, buddy->name, -1);
 
+	child = xmlnode_new_child(node, "privacy");
+	grandchild = xmlnode_new_child(child, "context");
+	xmlnode_set_attrib(grandchild, "type", "int");
+	buf = g_strdup_printf("%d", buddy->privacy_block_context);
+	xmlnode_insert_data(grandchild, buf, -1);
+	grandchild = xmlnode_new_child(child, "local_only");
+	xmlnode_set_attrib(grandchild, "type", "bool");
+	buf = g_strdup_printf("%d", buddy->local_only);
+	xmlnode_insert_data(grandchild, buf, -1);
+
 	if (buddy->alias != NULL)
 	{
 		child = xmlnode_new_child(node, "alias");
@@ -204,6 +215,7 @@ buddy_to_xmlnode(PurpleBlistNode *bnode)
 	/* Write buddy settings */
 	g_hash_table_foreach(buddy->node.settings, value_to_xmlnode, node);
 
+	g_free(buf);
 	return node;
 }
 
@@ -306,28 +318,15 @@ accountprivacy_to_xmlnode(PurpleAccount 
 static xmlnode *
 accountprivacy_to_xmlnode(PurpleAccount *account)
 {
-	xmlnode *node, *child;
-	GSList *cur;
+	xmlnode *node;
 	char buf[10];
 
 	node = xmlnode_new("account");
 	xmlnode_set_attrib(node, "proto", purple_account_get_protocol_id(account));
 	xmlnode_set_attrib(node, "name", purple_account_get_username(account));
-	g_snprintf(buf, sizeof(buf), "%d", account->perm_deny);
+	g_snprintf(buf, sizeof(buf), "%d", account->account_privacy_state);
 	xmlnode_set_attrib(node, "mode", buf);
 
-	for (cur = account->permit; cur; cur = cur->next)
-	{
-		child = xmlnode_new_child(node, "permit");
-		xmlnode_insert_data(child, cur->data, -1);
-	}
-
-	for (cur = account->deny; cur; cur = cur->next)
-	{
-		child = xmlnode_new_child(node, "block");
-		xmlnode_insert_data(child, cur->data, -1);
-	}
-
 	return node;
 }
 
@@ -337,6 +336,7 @@ blist_to_xmlnode(void)
 	xmlnode *node, *child, *grandchild;
 	PurpleBlistNode *gnode;
 	GList *cur;
+	char *buf;
 
 	node = xmlnode_new("purple");
 	xmlnode_set_attrib(node, "version", "1.0");
@@ -356,12 +356,20 @@ blist_to_xmlnode(void)
 
 	/* Write privacy settings */
 	child = xmlnode_new_child(node, "privacy");
+
+	grandchild = xmlnode_new_child(child, "global");
+	buf = g_strdup_printf("%d", purple_privacy_obtain_global_state());
+	xmlnode_set_attrib(grandchild, "state", buf);
+
+	grandchild = xmlnode_new_child(child, "per-account");
+	child = grandchild;
 	for (cur = purple_accounts_get_all(); cur != NULL; cur = cur->next)
 	{
 		grandchild = accountprivacy_to_xmlnode(cur->data);
 		xmlnode_insert_child(child, grandchild);
 	}
 
+	g_free(buf);
 	return node;
 }
 
@@ -459,9 +467,9 @@ parse_buddy(PurpleGroup *group, PurpleCo
 {
 	PurpleAccount *account;
 	PurpleBuddy *buddy;
-	char *name = NULL, *alias = NULL;
+	char *name = NULL, *alias = NULL, *temp = NULL;
 	const char *acct_name, *proto, *protocol;
-	xmlnode *x;
+	xmlnode *x, *y;
 
 	acct_name = xmlnode_get_attrib(bnode, "account");
 	protocol = xmlnode_get_attrib(bnode, "protocol");
@@ -490,6 +498,22 @@ parse_buddy(PurpleGroup *group, PurpleCo
 	purple_blist_add_buddy(buddy, contact, group,
 			purple_blist_get_last_child((PurpleBlistNode*)contact));
 
+	if ((x = xmlnode_get_child(bnode, "privacy")))
+	{
+		if ((y = xmlnode_get_child(x, "context")))
+		{
+			temp = xmlnode_get_data(y);
+			buddy->privacy_block_context = atoi(temp);
+			g_free(temp);
+		}
+		if ((y = xmlnode_get_child(x, "local_only")))
+		{
+			temp = xmlnode_get_data(y);
+			buddy->local_only = atoi(temp);
+			g_free(temp);
+		}
+	}
+
 	for (x = xmlnode_get_child(bnode, "setting"); x; x = xmlnode_get_next_twin(x)) {
 		parse_setting((PurpleBlistNode*)buddy, x);
 	}
@@ -604,7 +628,7 @@ purple_blist_load()
 void
 purple_blist_load()
 {
-	xmlnode *purple, *blist, *privacy;
+	xmlnode *purple, *blist, *privacy, *privacy_global, *privacy_acc;
 
 	blist_loaded = TRUE;
 
@@ -624,43 +648,41 @@ purple_blist_load()
 
 	privacy = xmlnode_get_child(purple, "privacy");
 	if (privacy) {
-		xmlnode *anode;
-		for (anode = privacy->child; anode; anode = anode->next) {
-			xmlnode *x;
-			PurpleAccount *account;
-			int imode;
-			const char *acct_name, *proto, *mode, *protocol;
+		privacy_global = xmlnode_get_child(privacy, "global");
+		if(privacy_global)
+		{
+			const char *global_setting;
+			int i_global_setting;
 
-			acct_name = xmlnode_get_attrib(anode, "name");
-			protocol = xmlnode_get_attrib(anode, "protocol");
-			proto = xmlnode_get_attrib(anode, "proto");
-			mode = xmlnode_get_attrib(anode, "mode");
+			global_setting = xmlnode_get_attrib(privacy_global, "state");
+			i_global_setting = ( atoi(global_setting) != 0 ? atoi(global_setting) : PURPLE_PRIVACY_ALLOW_BUDDYLIST ) ;
+			purple_privacy_set_global_state(i_global_setting);
+		}
 
-			if (!acct_name || (!proto && !protocol) || !mode)
-				continue;
+		privacy_acc = xmlnode_get_child(privacy, "per-account");
+		if(privacy_acc)
+		{
+			xmlnode *anode;
+			for (anode = privacy_acc->child; anode; anode = anode->next) {
+				PurpleAccount *account;
+				int imode;
+				const char *acct_name, *proto, *mode, *protocol;
 
-			account = purple_accounts_find(acct_name, proto ? proto : protocol);
+				acct_name = xmlnode_get_attrib(anode, "name");
+				protocol = xmlnode_get_attrib(anode, "protocol");
+				proto = xmlnode_get_attrib(anode, "proto");
+				mode = xmlnode_get_attrib(anode, "mode");
 
-			if (!account)
-				continue;
+				if (!acct_name || (!proto && !protocol) || !mode)
+					continue;
 
-			imode = atoi(mode);
-			account->perm_deny = (imode != 0 ? imode : PURPLE_PRIVACY_ALLOW_ALL);
+				account = purple_accounts_find(acct_name, proto ? proto : protocol);
 
-			for (x = anode->child; x; x = x->next) {
-				char *name;
-				if (x->type != XMLNODE_TYPE_TAG)
+				if (!account)
 					continue;
 
-				if (purple_strequal(x->name, "permit")) {
-					name = xmlnode_get_data(x);
-					purple_privacy_permit_add(account, name, TRUE);
-					g_free(name);
-				} else if (purple_strequal(x->name, "block")) {
-					name = xmlnode_get_data(x);
-					purple_privacy_deny_add(account, name, TRUE);
-					g_free(name);
-				}
+				imode = atoi(mode);
+				account->account_privacy_state = (imode != 0 ? imode : PURPLE_PRIVACY_ALLOW_ALL);
 			}
 		}
 	}
@@ -1381,6 +1403,10 @@ PurpleBuddy *purple_buddy_new(PurpleAcco
 
 	purple_blist_node_initialize_settings((PurpleBlistNode *)buddy);
 
+	/* Privacy Laters: Obtain new buddy's privacy context, and local settings */
+	buddy->privacy_block_context = 0;
+	buddy->local_only = FALSE;
+
 	if (ops && ops->new_node)
 		ops->new_node((PurpleBlistNode *)buddy);
 
@@ -2432,6 +2458,10 @@ PurpleBuddy *purple_find_buddy(PurpleAcc
 	g_return_val_if_fail(account != NULL, NULL);
 	g_return_val_if_fail((name != NULL) && (*name != '\0'), NULL);
 
+	/* If "name" is in PURPLE_PRIVACY_GROUP, it isn't a buddy */
+	if(purple_find_buddy_in_group(account, name, purple_find_group(PURPLE_PRIVACY_GROUP)))
+		return NULL;
+
 	hb.account = account;
 	hb.name = (gchar *)purple_normalize(account, name);
 
@@ -2464,6 +2494,22 @@ PurpleBuddy *purple_find_buddy_in_group(
 	return g_hash_table_lookup(purplebuddylist->buddies, &hb);
 }
 
+PurpleBuddy *purple_find_privacy_contact(PurpleAccount *account, const char *name)
+{
+	PurpleBuddy *b;
+
+	g_return_val_if_fail(purplebuddylist != NULL, NULL);
+	g_return_val_if_fail(account != NULL, NULL);
+	g_return_val_if_fail((name != NULL) && (*name != '\0'), NULL);
+
+	if((b = purple_find_buddy(account, name)))
+		return b;
+	if((b = purple_find_buddy_in_group(account, name, purple_find_group(PURPLE_PRIVACY_GROUP))))
+		return b;
+
+	return NULL;
+}
+
 static void find_acct_buddies(gpointer key, gpointer value, gpointer data)
 {
 	PurpleBuddy *buddy = value;
@@ -2472,7 +2518,7 @@ static void find_acct_buddies(gpointer k
 	*list = g_slist_prepend(*list, buddy);
 }
 
-GSList *purple_find_buddies(PurpleAccount *account, const char *name)
+GSList *purple_find_privacy_contacts(PurpleAccount *account, const char *name)
 {
 	PurpleBuddy *buddy;
 	PurpleBlistNode *node;
@@ -2484,7 +2530,7 @@ GSList *purple_find_buddies(PurpleAccoun
 	if ((name != NULL) && (*name != '\0')) {
 		struct _purple_hbuddy hb;
 
-		hb.name = (gchar *)purple_normalize(account, name);
+		hb.name = (char *)(purple_normalize(account, name));
 		hb.account = account;
 
 		for (node = purplebuddylist->root; node != NULL; node = node->next) {
@@ -2505,6 +2551,29 @@ GSList *purple_find_buddies(PurpleAccoun
 	return ret;
 }
 
+GSList *purple_find_buddies(PurpleAccount *account, const char *name)
+{
+	GSList *l_tmp = NULL, *lp = NULL;
+	PurpleBuddy *b = NULL;
+	const char *tmp = NULL;
+
+	g_return_val_if_fail(purplebuddylist != NULL, NULL);
+	g_return_val_if_fail(account != NULL, NULL);
+ 
+	if (!(lp = purple_find_privacy_contacts(account, name)))
+		return NULL;
+
+	for(l_tmp = lp; l_tmp; l_tmp = l_tmp->next)
+	{
+		b = l_tmp->data;
+		tmp = purple_group_get_name( purple_buddy_get_group(b) );
+		if( strcmp(tmp, PURPLE_PRIVACY_GROUP) == 0 )
+			lp = g_slist_remove(lp, l_tmp);
+	}
+
+	return lp;
+}
+
 PurpleGroup *purple_find_group(const char *name)
 {
 	gchar* key;
============================================================
--- libpurple/blist.h	8a1cb3e38b767107811af6ea4cf78abb0a1b64f0
+++ libpurple/blist.h	a80b63b3c81740e179a0433ea06010a17cbab67a
@@ -109,6 +109,7 @@ typedef enum
 #include "account.h"
 #include "buddyicon.h"
 #include "media.h"
+#include "privacy.h"
 #include "status.h"
 
 /**************************************************************************/
@@ -145,6 +146,8 @@ struct _PurpleBuddy {
 	PurpleAccount *account;					/**< the account this buddy belongs to */
 	PurplePresence *presence;
 	PurpleMediaCaps media_caps;		/**< The media capabilities of the buddy. */
+	PurplePrivacyContext privacy_block_context;	/**< What do we block from this buddy >**/
+	gboolean local_only;			/**< Specifies if this contact is on any of server's lists >**/
 };
 
 /**
@@ -1271,6 +1274,20 @@ void purple_blist_uninit(void);
 
 /*@}*/
 
+/**************************************************************************/
+/** @name Privacy Related Functions					  */
+/**************************************************************************/
+/*@{*/
+
+/* Return privacy contact, given name and account */
+PurpleBuddy *purple_find_privacy_contact(PurpleAccount *account, const char *name);
+
+/* Return list of privacy contacts for a given account */
+/* privacy laters: change name to be not so similar to purple_find_privacy_contact */
+GSList *purple_find_privacy_contacts(PurpleAccount *account, const char *name);
+
+/*@{*/
+
 #ifdef __cplusplus
 }
 #endif
============================================================
--- pidgin/gtkblist.c	849ad4c8761af32a534733bd3124544c69978fd6
+++ pidgin/gtkblist.c	2c7664a0eb92aef6c01a66d50e0ef70ba1c8d7a7
@@ -1382,6 +1382,7 @@ pidgin_blist_collapse_contact_cb(GtkWidg
 	}
 }
 
+/* To do Privacy : This needs to be modified  - disable function for now */
 static void
 toggle_privacy(GtkWidget *widget, PurpleBlistNode *node)
 {
@@ -1397,18 +1398,18 @@ toggle_privacy(GtkWidget *widget, Purple
 	account = purple_buddy_get_account(buddy);
 	name = purple_buddy_get_name(buddy);
 
-	permitted = purple_privacy_check(account, name);
+	permitted = !purple_privacy_check(account, name, PURPLE_PRIVACY_BLOCK_ALL);
 
 	/* XXX: Perhaps ask whether to restore the previous lists where appropirate? */
-
 	if (permitted)
-		purple_privacy_deny(account, name, FALSE, FALSE);
+		purple_privacy_set_block_all(account, name, TRUE, TRUE);
 	else
-		purple_privacy_allow(account, name, FALSE, FALSE);
+		purple_privacy_unset_block_all(account, name, TRUE, TRUE);
 
 	pidgin_blist_update(purple_get_blist(), node);
 }
 
+/* To do Privacy : This needs to be modified */
 void pidgin_append_blist_node_privacy_menu(GtkWidget *menu, PurpleBlistNode *node)
 {
 	PurpleBuddy *buddy = (PurpleBuddy *)node;
@@ -1416,7 +1417,7 @@ void pidgin_append_blist_node_privacy_me
 	gboolean permitted;
 
 	account = purple_buddy_get_account(buddy);
-	permitted = purple_privacy_check(account, purple_buddy_get_name(buddy));
+	permitted = !purple_privacy_check(account, purple_buddy_get_name(buddy), PURPLE_PRIVACY_BLOCK_ALL);
 
 	pidgin_new_item_from_stock(menu, permitted ? _("_Block") : _("Un_block"),
 						permitted ? PIDGIN_STOCK_TOOLBAR_BLOCK : PIDGIN_STOCK_TOOLBAR_UNBLOCK, G_CALLBACK(toggle_privacy),
@@ -4057,7 +4058,7 @@ pidgin_blist_get_emblem(PurpleBlistNode 
 
 	g_return_val_if_fail(buddy != NULL, NULL);
 
-	if (!purple_privacy_check(buddy->account, purple_buddy_get_name(buddy))) {
+	if (purple_privacy_check(buddy->account, purple_buddy_get_name(buddy), PURPLE_PRIVACY_BLOCK_ALL)) {
 		path = g_build_filename(DATADIR, "pixmaps", "pidgin", "emblems", "16", "blocked.png", NULL);
 		return _pidgin_blist_get_cached_emblem(path);
 	}
============================================================
--- libpurple/account.c	6604d1b1b68205a426ab77db867e2051722364fe
+++ libpurple/account.c	fb5f1ee3860ba3f16907f8913c10d14c30d26527
@@ -1007,8 +1007,6 @@ purple_account_new(const char *username,
 	account->ui_settings = g_hash_table_new_full(g_str_hash, g_str_equal,
 				g_free, (GDestroyNotify)g_hash_table_destroy);
 	account->system_log = NULL;
-	/* 0 is not a valid privacy setting */
-	account->perm_deny = PURPLE_PRIVACY_ALLOW_ALL;
 
 	purple_signal_emit(purple_accounts_get_handle(), "account-created", account);
 
@@ -1021,6 +1019,11 @@ purple_account_new(const char *username,
 	if (prpl_info != NULL && prpl_info->status_types != NULL)
 		purple_account_set_status_types(account, prpl_info->status_types(account));
 
+	if (prpl_info != NULL)	{
+		account->privacy_spec = g_new0(PurplePrivacySpec, 1);
+		account->privacy_spec = &prpl_info->privacy_spec;
+	}
+
 	account->presence = purple_presence_new_for_account(account);
 
 	status_type = purple_account_get_status_type_with_primitive(account, PURPLE_STATUS_AVAILABLE);
@@ -1072,16 +1075,6 @@ purple_account_destroy(PurpleAccount *ac
 	if(account->system_log)
 		purple_log_free(account->system_log);
 
-	while (account->deny) {
-		g_free(account->deny->data);
-		account->deny = g_slist_delete_link(account->deny, account->deny);
-	}
-
-	while (account->permit) {
-		g_free(account->permit->data);
-		account->permit = g_slist_delete_link(account->permit, account->permit);
-	}
-
 	priv = PURPLE_ACCOUNT_GET_PRIVATE(account);
 	PURPLE_DBUS_UNREGISTER_POINTER(priv->current_error);
 	if (priv->current_error) {
@@ -1731,14 +1724,6 @@ void
 }
 
 void
-purple_account_set_privacy_type(PurpleAccount *account, PurplePrivacyType privacy_type)
-{
-	g_return_if_fail(account != NULL);
-
-	account->perm_deny = privacy_type;
-}
-
-void
 purple_account_set_status_types(PurpleAccount *account, GList *status_types)
 {
 	g_return_if_fail(account != NULL);
@@ -2221,14 +2206,6 @@ purple_account_get_proxy_info(const Purp
 	return account->proxy_info;
 }
 
-PurplePrivacyType
-purple_account_get_privacy_type(const PurpleAccount *account)
-{
-	g_return_val_if_fail(account != NULL, PURPLE_PRIVACY_ALLOW_ALL);
-
-	return account->perm_deny;
-}
-
 PurpleStatus *
 purple_account_get_active_status(const PurpleAccount *account)
 {
============================================================
--- libpurple/account.h	7a5280dd166fe18d8674819f38bb21cff6603c94
+++ libpurple/account.h	005721307d60103562fe63a7d4c0535e737fc925
@@ -136,17 +136,10 @@ struct _PurpleAccount
 								/*   to NULL when the account inherits      */
 								/*   proxy settings from global prefs.      */
 
-	/*
-	 * TODO: Supplementing the next two linked lists with hash tables
-	 * should help performance a lot when these lists are long.  This
-	 * matters quite a bit for protocols like MSN, where all your
-	 * buddies are added to your permit list.  Currently we have to
-	 * iterate through the entire list if we want to check if someone
-	 * is permitted or denied.  We should do this for 3.0.0.
-	 */
-	GSList *permit;             /**< Permit list.                           */
-	GSList *deny;               /**< Deny list.                             */
-	PurplePrivacyType perm_deny;  /**< The permit/deny setting.               */
+	PurplePrivacySpec *privacy_spec;
+	NativePrivacySetting native_privacy_state;		/* Current native privacy state of protocol */
+	PurplePrivacySetting account_privacy_state;	/* Current privacy state of account */
+	gboolean privacy_list_active;			/* Marks local privacy list active or inactive */
 
 	GList *status_types;        /**< Status types.                          */
 
@@ -417,6 +410,7 @@ void purple_account_set_proxy_info(Purpl
  */
 void purple_account_set_proxy_info(PurpleAccount *account, PurpleProxyInfo *info);
 
+/* To do Privacy : check if needed */
 /**
  * Sets the account's privacy type.
  *
@@ -425,8 +419,9 @@ void purple_account_set_proxy_info(Purpl
  *
  * @since 2.7.0
  */
-void purple_account_set_privacy_type(PurpleAccount *account, PurplePrivacyType privacy_type);
 
+/* void purple_account_set_privacy_type(PurpleAccount *account, PurplePrivacyType privacy_type); */
+
 /**
  * Sets the account's status types.
  *
@@ -732,6 +727,7 @@ PurpleProxyInfo *purple_account_get_prox
  */
 PurpleProxyInfo *purple_account_get_proxy_info(const PurpleAccount *account);
 
+/* To do Privacy: check if needed .. */
 /**
  * Returns the account's privacy type.
  *
@@ -741,7 +737,7 @@ PurpleProxyInfo *purple_account_get_prox
  *
  * @since 2.7.0
  */
-PurplePrivacyType purple_account_get_privacy_type(const PurpleAccount *account);
+/* PurplePrivacyType purple_account_get_privacy_type(const PurpleAccount *account); */
 
 /**
  * Returns the active status for this account.  This looks through
============================================================
--- libpurple/connection.c	8222a7dfab98f7006c35fbe2dda7ff12e11da4b7
+++ libpurple/connection.c	6548c0783efc46b0d741d3b85928960e3caee886
@@ -374,7 +374,7 @@ purple_connection_set_state(PurpleConnec
 		purple_signal_emit(purple_connections_get_handle(), "signed-on", gc);
 		purple_signal_emit_return_1(purple_connections_get_handle(), "autojoin", gc);
 
-		serv_set_permit_deny(gc);
+		serv_privacy_set_state(gc);
 
 		update_keepalive(gc, TRUE);
 	}
============================================================
--- libpurple/server.h	84b7def8f897d33e967f703b87cbc7087bc65d6a
+++ libpurple/server.h	9c3ca0fd52223592a4288582c9bd426180d1d961
@@ -28,6 +28,7 @@
 
 #include "account.h"
 #include "conversation.h"
+#include "privacy.h"
 #include "prpl.h"
 
 #ifdef __cplusplus
@@ -90,11 +91,9 @@ void serv_set_info(PurpleConnection *, c
 void serv_get_info(PurpleConnection *, const char *);
 void serv_set_info(PurpleConnection *, const char *);
 
-void serv_add_permit(PurpleConnection *, const char *);
-void serv_add_deny(PurpleConnection *, const char *);
-void serv_rem_permit(PurpleConnection *, const char *);
-void serv_rem_deny(PurpleConnection *, const char *);
-void serv_set_permit_deny(PurpleConnection *);
+void serv_privacy_list_add(PurpleConnection *, PurplePrivacyListType list_type, const char *name);
+void serv_privacy_list_remove(PurpleConnection *, PurplePrivacyListType list_type, const char *name);
+void serv_privacy_set_state(PurpleConnection *);
 void serv_chat_invite(PurpleConnection *, int, const char *, const char *);
 void serv_chat_leave(PurpleConnection *, int);
 void serv_chat_whisper(PurpleConnection *, int, const char *, const char *);
============================================================
--- pidgin/gtkprivacy.c	18fdd26c09ac0b5c3e27b5d68dfa195c7a853bac
+++ pidgin/gtkprivacy.c	7093b04eeca3bf7e1b963026b423b4aec6c692d4
@@ -39,29 +39,44 @@ typedef struct
 typedef struct
 {
 	GtkWidget *win;
-
 	GtkWidget *type_menu;
-
-	GtkWidget *add_button;
-	GtkWidget *remove_button;
-	GtkWidget *removeall_button;
 	GtkWidget *close_button;
+	GtkWidget *vbox_pas;
+	GtkWidget *sw_contacts;
+	GtkWidget *add_contact_button;
 
-	GtkWidget *button_box;
-	GtkWidget *allow_widget;
-	GtkWidget *block_widget;
+	GtkListStore *model_presence;
+	GtkListStore *model_contacts;
 
-	GtkListStore *allow_store;
-	GtkListStore *block_store;
+	gboolean show_sw_contacts;
+	PurpleAccount *account;
 
-	GtkWidget *allow_list;
-	GtkWidget *block_list;
+} PidginPrivacyDialog;
 
-	gboolean in_allow_list;
+enum
+{
+	PRESENCE_COLUMN_ICON,
+	PRESENCE_COLUMN_USERNAME,
+	PRESENCE_COLUMN_INV_NONBUD,
+	PRESENCE_COLUMN_INV_ALL,
+	PRESENCE_COLUMN_PROTOCOL,
+	PRESENCE_COLUMN_DATA,
+	PRESENCE_NUM_COLUMNS
+};
 
-	PurpleAccount *account;
+enum
+{
+	CONTACTS_COLUMN_BUDDYNAME,
+	CONTACTS_COLUMN_BLOCK_ALL,
+	CONTACTS_COLUMN_INVISIBLE,
+	CONTACTS_COLUMN_BLOCK_CHAT,
+	CONTACTS_COLUMN_BLOCK_FT,
+	CONTACTS_COLUMN_BLOCK_CONF,
+	CONTACTS_COLUMN_DATA,
+	CONTACTS_NUM_COLUMNS
+};
 
-} PidginPrivacyDialog;
+static void show_contacts(PidginPrivacyDialog *dialog);
 
 typedef struct
 {
@@ -78,261 +93,494 @@ static struct
 
 } const menu_entries[] =
 {
-	{ N_("Allow all users to contact me"),         PURPLE_PRIVACY_ALLOW_ALL },
-	{ N_("Allow only the users on my buddy list"), PURPLE_PRIVACY_ALLOW_BUDDYLIST },
-	{ N_("Allow only the users below"),            PURPLE_PRIVACY_ALLOW_USERS },
-	{ N_("Block all users"),                       PURPLE_PRIVACY_DENY_ALL },
-	{ N_("Block only the users below"),            PURPLE_PRIVACY_DENY_USERS }
+	{ N_("Allow all users to contact me"), PURPLE_PRIVACY_ALLOW_ALL },
+	{ N_("Block messages from users not in buddly list"), PURPLE_PRIVACY_BLOCK_MSG_NONBUDDY },
+	{ N_("Block all users not in buddy list"), PURPLE_PRIVACY_ALLOW_BUDDYLIST },
+	{ N_("Per contact settings"), PURPLE_PRIVACY_CUSTOM }
 };
 
 static const size_t menu_entry_count = sizeof(menu_entries) / sizeof(*menu_entries);
 
 static PidginPrivacyDialog *privacy_dialog = NULL;
 
+static gint
+destroy_cb(GtkWidget *w, GdkEvent *event, PidginPrivacyDialog *dialog)
+{
+	pidgin_privacy_dialog_hide();
+
+	return 0;
+}
+
 static void
-rebuild_allow_list(PidginPrivacyDialog *dialog)
+select_account_cb(GtkWidget *dropdown, PurpleAccount *account,
+				  PidginPrivacyDialog *dialog)
 {
-	GSList *l;
-	GtkTreeIter iter;
+	int i;
 
-	gtk_list_store_clear(dialog->allow_store);
+	dialog->account = account;
+	gtk_option_menu_set_history(GTK_OPTION_MENU(dialog->type_menu), 0);
 
-	for (l = dialog->account->permit; l != NULL; l = l->next) {
-		gtk_list_store_append(dialog->allow_store, &iter);
-		gtk_list_store_set(dialog->allow_store, &iter, 0, l->data, -1);
+	for (i = 0; i < menu_entry_count; i++) {
+		if( (menu_entries[i].num == purple_privacy_obtain_account_state(account)) ) {
+			gtk_option_menu_set_history(GTK_OPTION_MENU(dialog->type_menu), i);
+			break;
+		}
 	}
 }
 
 static void
-rebuild_block_list(PidginPrivacyDialog *dialog)
+type_changed_cb(GtkOptionMenu *optmenu, PidginPrivacyDialog *dialog)
 {
-	GSList *l;
-	GtkTreeIter iter;
+	int new_type = menu_entries[gtk_option_menu_get_history(optmenu)].num;
 
-	gtk_list_store_clear(dialog->block_store);
+	purple_privacy_set_account_state(dialog->account, new_type);
 
-	for (l = dialog->account->deny; l != NULL; l = l->next) {
-		gtk_list_store_append(dialog->block_store, &iter);
-		gtk_list_store_set(dialog->block_store, &iter, 0, l->data, -1);
+	if(new_type == PURPLE_PRIVACY_CUSTOM) {
+		if(dialog->show_sw_contacts == FALSE)
+			show_contacts(dialog);
 	}
+	else {
+		if(dialog->show_sw_contacts == TRUE) {
+			/* destroy model_contacts */
+			gtk_widget_hide(dialog->sw_contacts);
+			gtk_widget_hide(dialog->add_contact_button);
+			dialog->show_sw_contacts = FALSE;
+		}
+	}
 }
 
 static void
-user_selected_cb(GtkTreeSelection *sel, PidginPrivacyDialog *dialog)
+close_cb(GtkWidget *button, PidginPrivacyDialog *dialog)
 {
-	gtk_widget_set_sensitive(dialog->remove_button, TRUE);
+	gtk_widget_destroy(dialog->win);
+
+	pidgin_privacy_dialog_hide();
 }
 
-static GtkWidget *
-build_list(PidginPrivacyDialog *dialog, GtkListStore *model,
-		   GtkWidget **ret_treeview)
+static void toggle_button_cb(GtkWidget *widget, gpointer data)
 {
-	GtkWidget *sw;
-	GtkWidget *treeview;
-	GtkCellRenderer *rend;
-	GtkTreeViewColumn *column;
-	GtkTreeSelection *sel;
+	PidginPrivacyDialog *dialog = data;
+	PurplePrivacySetting privacy_type = (PurplePrivacySetting) g_object_get_data(G_OBJECT(widget), "choice_id"); 
+	if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
+	{
+		if(privacy_type == PURPLE_PRIVACY_CUSTOM)
+			gtk_widget_show(dialog->vbox_pas);
+	}
+	else
+	{
+		if(privacy_type == PURPLE_PRIVACY_CUSTOM)
+			gtk_widget_hide(dialog->vbox_pas);
+	}
+}
 
-	sw = gtk_scrolled_window_new(NULL, NULL);
-	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw),
-					GTK_POLICY_AUTOMATIC,
-					GTK_POLICY_AUTOMATIC);
-	gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw), GTK_SHADOW_IN);
+static void show_offline_nonbud_cb(GtkWidget *widget, gpointer data)
+{
+}
 
-	treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model));
-	*ret_treeview = treeview;
+static void show_offline_all_cb(GtkCellRendererToggle *renderer, gchar *path_str, gpointer data)
+{
+	PidginPrivacyDialog *dialog = (PidginPrivacyDialog *)data;
+	PurpleAccount *account;
+	GtkTreeModel *model = GTK_TREE_MODEL(dialog->model_presence);
+	GtkTreeIter iter;
+	gboolean state;
+	gboolean new_state = FALSE;
 
-	rend = gtk_cell_renderer_text_new();
+	gtk_tree_model_get_iter_from_string(model, &iter, path_str);
+	gtk_tree_model_get(model, &iter,
+					   PRESENCE_COLUMN_DATA, &account,
+					   PRESENCE_COLUMN_INV_ALL, &state,
+					   -1);
 
-	column = gtk_tree_view_column_new_with_attributes(NULL, rend,
-													  "text", 0,
-													  NULL);
-	gtk_tree_view_column_set_clickable(GTK_TREE_VIEW_COLUMN(column), TRUE);
+	state = !state;
+	if(state) {
+		if(purple_privacy_account_supports_invisible_status(account))
+			new_state = purple_privacy_set_account_status_invisible(account);
+	}
+	else
+		new_state = !( purple_privacy_set_account_status_visible(account) );
+
+	gtk_list_store_set(dialog->model_presence, &iter,
+						PRESENCE_COLUMN_INV_ALL, new_state,
+						-1);
+}
+
+static void
+add_columns_show_offline(GtkWidget *treeview, PidginPrivacyDialog *dialog)
+{
+	GtkCellRenderer *renderer;
+	GtkTreeViewColumn *column;
+
+	/* Username column */
+	column = gtk_tree_view_column_new();
+	gtk_tree_view_column_set_title(column, _("Username"));
+	gtk_tree_view_column_set_resizable(column, TRUE);
 	gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column);
-	gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(treeview), FALSE);
-	gtk_container_add(GTK_CONTAINER(sw), treeview);
 
-	gtk_widget_show(treeview);
+	/* Username */
+	renderer = gtk_cell_renderer_text_new();
+	gtk_tree_view_column_pack_start(column, renderer, TRUE);
+	gtk_tree_view_column_add_attribute(column, renderer, "text", PRESENCE_COLUMN_USERNAME);
 
-	sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview));
+	/* Protocol column */
+	column = gtk_tree_view_column_new();
+	gtk_tree_view_column_set_title(column, _("Protocol"));
+	gtk_tree_view_column_set_resizable(column, FALSE);
+	gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column);
 
-	g_signal_connect(G_OBJECT(sel), "changed",
-					 G_CALLBACK(user_selected_cb), dialog);
+	/* Icon */
+	renderer = gtk_cell_renderer_pixbuf_new();
+	gtk_tree_view_column_pack_start(column, renderer, FALSE);
+	gtk_tree_view_column_add_attribute(column, renderer, "pixbuf", PRESENCE_COLUMN_ICON);
 
-	gtk_widget_set_size_request(sw, -1, 200);
+	/* Protocol */
+	renderer = gtk_cell_renderer_text_new();
+	gtk_tree_view_column_pack_start(column, renderer, TRUE);
+	gtk_tree_view_column_add_attribute(column, renderer, "text", PRESENCE_COLUMN_PROTOCOL);
 
-	return sw;
+	/* Show Offline to non-buddies */
+	renderer = gtk_cell_renderer_toggle_new();
+	g_signal_connect(G_OBJECT(renderer), "toggled", G_CALLBACK(show_offline_nonbud_cb), dialog); /* privacy laters: connect signal */
+	column = gtk_tree_view_column_new_with_attributes(_("Invisible to Non-Buddies"), renderer, "active", PRESENCE_COLUMN_INV_NONBUD, NULL);
+	gtk_tree_view_column_set_resizable(column, FALSE);
+	gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column);
+
+	/* Show Offline to everyone */
+	renderer = gtk_cell_renderer_toggle_new();
+	g_signal_connect(G_OBJECT(renderer), "toggled", G_CALLBACK(show_offline_all_cb), dialog); /* privacy laters: connect signal */
+	column = gtk_tree_view_column_new_with_attributes(_("Invisible to Everyone"), renderer, "active", PRESENCE_COLUMN_INV_ALL, NULL);
+	gtk_tree_view_column_set_resizable(column, FALSE);
+	gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column);
 }
 
-static GtkWidget *
-build_allow_list(PidginPrivacyDialog *dialog)
+static void populate_accounts_list(PidginPrivacyDialog *dialog)
 {
-	GtkWidget *widget;
-	GtkWidget *list;
+/* Privacy laters: this is trouble, it doesnt change the list when an account signs off or signs in */
+	GList *l;
+	GtkTreeIter iter;
+	PurpleAccount *account;
+	GdkPixbuf *pixbuf;
 
-	dialog->allow_store = gtk_list_store_new(1, G_TYPE_STRING);
+	gtk_list_store_clear(dialog->model_presence);
 
-	gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(dialog->allow_store), 0, GTK_SORT_ASCENDING);
+	for (l = purple_accounts_get_all_active(); l != NULL; l = g_list_delete_link(l,l)) {
+		account = l->data;
+		gtk_list_store_append(dialog->model_presence, &iter);
+		pixbuf = pidgin_create_prpl_icon(account, PIDGIN_PRPL_ICON_MEDIUM);
 
-	widget = build_list(dialog, dialog->allow_store, &list);
+		gtk_list_store_set(dialog->model_presence, &iter,
+			PRESENCE_COLUMN_ICON, pixbuf,
+			PRESENCE_COLUMN_USERNAME, purple_account_get_username(account),
+			PRESENCE_COLUMN_INV_NONBUD, TRUE,	/* replace with invisiblity check */
+			PRESENCE_COLUMN_INV_ALL, purple_privacy_account_status_invisible(account),
+			PRESENCE_COLUMN_PROTOCOL, purple_account_get_protocol_name(account),
+			PRESENCE_COLUMN_DATA, account,
+			-1);
 
-	dialog->allow_list = list;
+		if (pixbuf != NULL)
+			g_object_unref(G_OBJECT(pixbuf));
+	}
+}
 
-	rebuild_allow_list(dialog);
+static void contacts_block_all_cb(GtkCellRendererToggle *renderer, gchar *path_str, gpointer data)
+{
+	PidginPrivacyDialog *dialog = (PidginPrivacyDialog *)data;
+	PurpleAccount *account;
+	GtkTreeModel *model = GTK_TREE_MODEL(dialog->model_contacts);
+	GtkTreeIter iter;
+	gboolean state;
+	char *name;
 
-	return widget;
+	gtk_tree_model_get_iter_from_string(model, &iter, path_str);
+	gtk_tree_model_get(model, &iter,
+				CONTACTS_COLUMN_DATA, &account,
+				CONTACTS_COLUMN_BLOCK_ALL, &state,
+				CONTACTS_COLUMN_BUDDYNAME, &name,
+				-1);
+
+	state = !state;
+	if(state)
+		purple_privacy_set_block_all(account, name, TRUE, TRUE);
+	else
+		purple_privacy_unset_block_all(account, name, TRUE, TRUE);
+
+	gtk_list_store_set(dialog->model_contacts, &iter,
+				CONTACTS_COLUMN_BLOCK_ALL, purple_privacy_check(account, name, PURPLE_PRIVACY_BLOCK_ALL),
+				CONTACTS_COLUMN_INVISIBLE, purple_privacy_check(account, name, PURPLE_PRIVACY_BLOCK_PRESENCE),
+				CONTACTS_COLUMN_BLOCK_CHAT, purple_privacy_check(account, name, PURPLE_PRIVACY_BLOCK_MESSAGE),
+				CONTACTS_COLUMN_BLOCK_FT, purple_privacy_check(account, name, PURPLE_PRIVACY_BLOCK_FT),
+				CONTACTS_COLUMN_BLOCK_CONF, purple_privacy_check(account, name, PURPLE_PRIVACY_BLOCK_CONF),
+				-1);
 }
 
-static GtkWidget *
-build_block_list(PidginPrivacyDialog *dialog)
+static void contacts_invisible_cb(GtkCellRendererToggle *renderer, gchar *path_str, gpointer data)
 {
-	GtkWidget *widget;
-	GtkWidget *list;
+	PidginPrivacyDialog *dialog = (PidginPrivacyDialog *)data;
+	PurpleAccount *account;
+	GtkTreeModel *model = GTK_TREE_MODEL(dialog->model_contacts);
+	GtkTreeIter iter;
+	gboolean state;
+	char *name;
 
-	dialog->block_store = gtk_list_store_new(1, G_TYPE_STRING);
+	gtk_tree_model_get_iter_from_string(model, &iter, path_str);
+	gtk_tree_model_get(model, &iter,
+				CONTACTS_COLUMN_DATA, &account,
+				CONTACTS_COLUMN_INVISIBLE, &state,
+				CONTACTS_COLUMN_BUDDYNAME, &name,
+				-1);
 
-	gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(dialog->block_store), 0, GTK_SORT_ASCENDING);
+	state = !state;
+	if(state)
+		purple_privacy_set_block_presence(account, name, TRUE, TRUE);
+	else
+		purple_privacy_unset_block_presence(account, name, TRUE, TRUE);
 
-	widget = build_list(dialog, dialog->block_store, &list);
+	gtk_list_store_set(dialog->model_contacts, &iter,
+				CONTACTS_COLUMN_BLOCK_ALL, purple_privacy_check(account, name, PURPLE_PRIVACY_BLOCK_ALL),
+				CONTACTS_COLUMN_INVISIBLE, purple_privacy_check(account, name, PURPLE_PRIVACY_BLOCK_PRESENCE),
+				CONTACTS_COLUMN_BLOCK_CHAT, purple_privacy_check(account, name, PURPLE_PRIVACY_BLOCK_MESSAGE),
+				CONTACTS_COLUMN_BLOCK_FT, purple_privacy_check(account, name, PURPLE_PRIVACY_BLOCK_FT),
+				CONTACTS_COLUMN_BLOCK_CONF, purple_privacy_check(account, name, PURPLE_PRIVACY_BLOCK_CONF),
+				-1);
+}
 
-	dialog->block_list = list;
+static void contacts_block_chat_cb(GtkCellRendererToggle *renderer, gchar *path_str, gpointer data)
+{
+	PidginPrivacyDialog *dialog = (PidginPrivacyDialog *)data;
+	PurpleAccount *account;
+	GtkTreeModel *model = GTK_TREE_MODEL(dialog->model_contacts);
+	GtkTreeIter iter;
+	gboolean state;
+	char *name;
 
-	rebuild_block_list(dialog);
+	gtk_tree_model_get_iter_from_string(model, &iter, path_str);
+	gtk_tree_model_get(model, &iter,
+				CONTACTS_COLUMN_DATA, &account,
+				CONTACTS_COLUMN_BLOCK_CHAT, &state,
+				CONTACTS_COLUMN_BUDDYNAME, &name,
+				-1);
 
-	return widget;
+	state = !state;
+	if(state)
+		purple_privacy_set_block_message(account, name);
+	else
+		purple_privacy_unset_block_message(account, name);
+
+	gtk_list_store_set(dialog->model_contacts, &iter,
+				CONTACTS_COLUMN_BLOCK_ALL, purple_privacy_check(account, name, PURPLE_PRIVACY_BLOCK_ALL),
+				CONTACTS_COLUMN_INVISIBLE, purple_privacy_check(account, name, PURPLE_PRIVACY_BLOCK_PRESENCE),
+				CONTACTS_COLUMN_BLOCK_CHAT, purple_privacy_check(account, name, PURPLE_PRIVACY_BLOCK_MESSAGE),
+				CONTACTS_COLUMN_BLOCK_FT, purple_privacy_check(account, name, PURPLE_PRIVACY_BLOCK_FT),
+				CONTACTS_COLUMN_BLOCK_CONF, purple_privacy_check(account, name, PURPLE_PRIVACY_BLOCK_CONF),
+				-1);
 }
 
-static gint
-destroy_cb(GtkWidget *w, GdkEvent *event, PidginPrivacyDialog *dialog)
+static void contacts_block_ft_cb(GtkCellRendererToggle *renderer, gchar *path_str, gpointer data)
 {
-	pidgin_privacy_dialog_hide();
+	PidginPrivacyDialog *dialog = (PidginPrivacyDialog *)data;
+	PurpleAccount *account;
+	GtkTreeModel *model = GTK_TREE_MODEL(dialog->model_contacts);
+	GtkTreeIter iter;
+	gboolean state;
+	char *name;
 
-	return 0;
+	gtk_tree_model_get_iter_from_string(model, &iter, path_str);
+	gtk_tree_model_get(model, &iter,
+				CONTACTS_COLUMN_DATA, &account,
+				CONTACTS_COLUMN_BLOCK_FT, &state,
+				CONTACTS_COLUMN_BUDDYNAME, &name,
+				-1);
+
+	state = !state;
+	if(state)
+		purple_privacy_set_block_ft(account, name);
+	else
+		purple_privacy_unset_block_ft(account, name);
+
+	gtk_list_store_set(dialog->model_contacts, &iter,
+				CONTACTS_COLUMN_BLOCK_ALL, purple_privacy_check(account, name, PURPLE_PRIVACY_BLOCK_ALL),
+				CONTACTS_COLUMN_INVISIBLE, purple_privacy_check(account, name, PURPLE_PRIVACY_BLOCK_PRESENCE),
+				CONTACTS_COLUMN_BLOCK_CHAT, purple_privacy_check(account, name, PURPLE_PRIVACY_BLOCK_MESSAGE),
+				CONTACTS_COLUMN_BLOCK_FT, purple_privacy_check(account, name, PURPLE_PRIVACY_BLOCK_FT),
+				CONTACTS_COLUMN_BLOCK_CONF, purple_privacy_check(account, name, PURPLE_PRIVACY_BLOCK_CONF),
+				-1);
 }
 
-static void
-select_account_cb(GtkWidget *dropdown, PurpleAccount *account,
-				  PidginPrivacyDialog *dialog)
+static void contacts_block_conf_cb(GtkCellRendererToggle *renderer, gchar *path_str, gpointer data)
 {
-	int i;
+	PidginPrivacyDialog *dialog = (PidginPrivacyDialog *)data;
+	PurpleAccount *account;
+	GtkTreeModel *model = GTK_TREE_MODEL(dialog->model_contacts);
+	GtkTreeIter iter;
+	gboolean state;
+	char *name;
 
-	dialog->account = account;
+	gtk_tree_model_get_iter_from_string(model, &iter, path_str);
+	gtk_tree_model_get(model, &iter,
+				CONTACTS_COLUMN_DATA, &account,
+				CONTACTS_COLUMN_BLOCK_CONF, &state,
+				CONTACTS_COLUMN_BUDDYNAME, &name,
+				-1);
 
-	for (i = 0; i < menu_entry_count; i++) {
-		if (menu_entries[i].num == account->perm_deny) {
-			gtk_combo_box_set_active(GTK_COMBO_BOX(dialog->type_menu), i);
-			break;
-		}
-	}
+	state = !state;
+	if(state)
+		purple_privacy_set_block_conf(account, name);
+	else
+		purple_privacy_unset_block_conf(account, name);
 
-	rebuild_allow_list(dialog);
-	rebuild_block_list(dialog);
+	gtk_list_store_set(dialog->model_contacts, &iter,
+				CONTACTS_COLUMN_BLOCK_ALL, purple_privacy_check(account, name, PURPLE_PRIVACY_BLOCK_ALL),
+				CONTACTS_COLUMN_INVISIBLE, purple_privacy_check(account, name, PURPLE_PRIVACY_BLOCK_PRESENCE),
+				CONTACTS_COLUMN_BLOCK_CHAT, purple_privacy_check(account, name, PURPLE_PRIVACY_BLOCK_MESSAGE),
+				CONTACTS_COLUMN_BLOCK_FT, purple_privacy_check(account, name, PURPLE_PRIVACY_BLOCK_FT),
+				CONTACTS_COLUMN_BLOCK_CONF, purple_privacy_check(account, name, PURPLE_PRIVACY_BLOCK_CONF),
+				-1);
 }
 
-/*
- * TODO: Setting the permit/deny setting needs to go through privacy.c
- *       Even better: the privacy API needs to not suck.
- */
-static void
-type_changed_cb(GtkComboBox *combo, PidginPrivacyDialog *dialog)
+static void populate_contacts_list(PidginPrivacyDialog *dialog)
 {
-	int new_type = menu_entries[gtk_combo_box_get_active(combo)].num;
+	GSList *l;
+	GtkTreeIter iter;
+	PurpleAccount *account = dialog->account;
+	PurpleBuddy *c;
 
-	dialog->account->perm_deny = new_type;
-	serv_set_permit_deny(purple_account_get_connection(dialog->account));
+	gtk_list_store_clear(dialog->model_contacts);
 
-	gtk_widget_hide(dialog->allow_widget);
-	gtk_widget_hide(dialog->block_widget);
-	gtk_widget_hide_all(dialog->button_box);
+	/* add "All Others" meta contact */
+	gtk_list_store_append(dialog->model_contacts, &iter);
+	gtk_list_store_set(dialog->model_contacts, &iter,
+				CONTACTS_COLUMN_BUDDYNAME, "All Others",
+				CONTACTS_COLUMN_BLOCK_ALL, purple_privacy_check(account, "all-others", PURPLE_PRIVACY_BLOCK_ALL),
+				CONTACTS_COLUMN_INVISIBLE, purple_privacy_check(account, "all-others", PURPLE_PRIVACY_BLOCK_PRESENCE),
+				CONTACTS_COLUMN_BLOCK_CHAT, purple_privacy_check(account, "all-others", PURPLE_PRIVACY_BLOCK_MESSAGE),
+				CONTACTS_COLUMN_BLOCK_FT, purple_privacy_check(account, "all-others", PURPLE_PRIVACY_BLOCK_FT),
+				CONTACTS_COLUMN_BLOCK_CONF, purple_privacy_check(account, "all-others", PURPLE_PRIVACY_BLOCK_CONF),
+				CONTACTS_COLUMN_DATA, account,
+				-1);
 
-	if (new_type == PURPLE_PRIVACY_ALLOW_USERS) {
-		gtk_widget_show(dialog->allow_widget);
-		gtk_widget_show_all(dialog->button_box);
-		dialog->in_allow_list = TRUE;
+	/* Add the contacts now */	
+	for (l = purple_find_privacy_contacts(account, NULL); l != NULL; l = g_slist_delete_link(l,l))
+	{
+		c = l->data;
+		if(purple_strequal(c->name, "all-others") == FALSE)
+		{
+			gtk_list_store_append(dialog->model_contacts, &iter);
+			gtk_list_store_set(dialog->model_contacts, &iter,
+				CONTACTS_COLUMN_BUDDYNAME, purple_buddy_get_name(c),
+				CONTACTS_COLUMN_BLOCK_ALL, purple_privacy_check(account, purple_buddy_get_name(c), PURPLE_PRIVACY_BLOCK_ALL),
+				CONTACTS_COLUMN_INVISIBLE, purple_privacy_check(account, purple_buddy_get_name(c), PURPLE_PRIVACY_BLOCK_PRESENCE),
+				CONTACTS_COLUMN_BLOCK_CHAT, purple_privacy_check(account, purple_buddy_get_name(c), PURPLE_PRIVACY_BLOCK_MESSAGE),
+				CONTACTS_COLUMN_BLOCK_FT, purple_privacy_check(account, purple_buddy_get_name(c), PURPLE_PRIVACY_BLOCK_FT),
+				CONTACTS_COLUMN_BLOCK_CONF, purple_privacy_check(account, purple_buddy_get_name(c), PURPLE_PRIVACY_BLOCK_CONF),
+				CONTACTS_COLUMN_DATA, account,
+				-1);
+		}
 	}
-	else if (new_type == PURPLE_PRIVACY_DENY_USERS) {
-		gtk_widget_show(dialog->block_widget);
-		gtk_widget_show_all(dialog->button_box);
-		dialog->in_allow_list = FALSE;
-	}
-
-	gtk_widget_show_all(dialog->close_button);
-	gtk_widget_show(dialog->button_box);
-
-	purple_blist_schedule_save();
-	pidgin_blist_refresh(purple_get_blist());
 }
 
 static void
-add_cb(GtkWidget *button, PidginPrivacyDialog *dialog)
+add_columns_contacts(GtkWidget *treeview, PidginPrivacyDialog *dialog)
 {
-	if (dialog->in_allow_list)
-		pidgin_request_add_permit(dialog->account, NULL);
-	else
-		pidgin_request_add_block(dialog->account, NULL);
-}
+	GtkCellRenderer *renderer;
+	GtkTreeViewColumn *column;
 
-static void
-remove_cb(GtkWidget *button, PidginPrivacyDialog *dialog)
-{
-	GtkTreeIter iter;
-	GtkTreeModel *model;
-	GtkTreeSelection *sel;
-	char *name;
+	/* Buddyname column */
+	column = gtk_tree_view_column_new();
+	gtk_tree_view_column_set_title(column, _("Buddy"));
+	gtk_tree_view_column_set_resizable(column, TRUE);
+	gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column);
 
-	if (dialog->in_allow_list && dialog->allow_store == NULL)
-		return;
+	/* Buddyname */
+	renderer = gtk_cell_renderer_text_new();
+	gtk_tree_view_column_pack_start(column, renderer, TRUE);
+	gtk_tree_view_column_add_attribute(column, renderer, "text", CONTACTS_COLUMN_BUDDYNAME);
 
-	if (!dialog->in_allow_list && dialog->block_store == NULL)
-		return;
+	/* Block All */
+	renderer = gtk_cell_renderer_toggle_new();
+	g_signal_connect(G_OBJECT(renderer), "toggled", G_CALLBACK(contacts_block_all_cb), dialog); /* privacy laters: connect signal */
+	column = gtk_tree_view_column_new_with_attributes(_("Block All"), renderer, "active", CONTACTS_COLUMN_BLOCK_ALL, NULL);
+	gtk_tree_view_column_set_resizable(column, FALSE);
+	gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column);
 
-	if (dialog->in_allow_list) {
-		model = GTK_TREE_MODEL(dialog->allow_store);
-		sel   = gtk_tree_view_get_selection(GTK_TREE_VIEW(dialog->allow_list));
-	}
-	else {
-		model = GTK_TREE_MODEL(dialog->block_store);
-		sel   = gtk_tree_view_get_selection(GTK_TREE_VIEW(dialog->block_list));
-	}
+	/* Invisible */
+	renderer = gtk_cell_renderer_toggle_new();
+	g_signal_connect(G_OBJECT(renderer), "toggled", G_CALLBACK(contacts_invisible_cb), dialog); /* privacy laters: connect signal */
+	column = gtk_tree_view_column_new_with_attributes(_("Invisible"), renderer, "active", CONTACTS_COLUMN_INVISIBLE, NULL);
+	gtk_tree_view_column_set_resizable(column, FALSE);
+	gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column);
 
-	if (gtk_tree_selection_get_selected(sel, NULL, &iter))
-		gtk_tree_model_get(model, &iter, 0, &name, -1);
-	else
-		return;
+	/* Block Chat */
+	renderer = gtk_cell_renderer_toggle_new();
+	g_signal_connect(G_OBJECT(renderer), "toggled", G_CALLBACK(contacts_block_chat_cb), dialog); /* privacy laters: connect signal */
+	column = gtk_tree_view_column_new_with_attributes(_("Block Chat"), renderer, "active", CONTACTS_COLUMN_BLOCK_CHAT, NULL);
+	gtk_tree_view_column_set_resizable(column, FALSE);
+	gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column);
 
-	if (dialog->in_allow_list)
-		purple_privacy_permit_remove(dialog->account, name, FALSE);
-	else
-		purple_privacy_deny_remove(dialog->account, name, FALSE);
+	/* Block FT */
+	renderer = gtk_cell_renderer_toggle_new();
+	g_signal_connect(G_OBJECT(renderer), "toggled", G_CALLBACK(contacts_block_ft_cb), dialog); /* privacy laters: connect signal */
+	column = gtk_tree_view_column_new_with_attributes(_("Block File Transfer"), renderer, "active", CONTACTS_COLUMN_BLOCK_FT, NULL);
+	gtk_tree_view_column_set_resizable(column, FALSE);
+	gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column);
 
-	g_free(name);
+	/* Block CONF */
+	renderer = gtk_cell_renderer_toggle_new();
+	g_signal_connect(G_OBJECT(renderer), "toggled", G_CALLBACK(contacts_block_conf_cb), dialog); /* privacy laters: connect signal */
+	column = gtk_tree_view_column_new_with_attributes(_("Block Conference"), renderer, "active", CONTACTS_COLUMN_BLOCK_CONF, NULL);
+	gtk_tree_view_column_set_resizable(column, FALSE);
+	gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column);
 }
 
-static void
-removeall_cb(GtkWidget *button, PidginPrivacyDialog *dialog)
+/* Callback to add a contact */
+static void add_contact_cb(GtkWidget *button, PidginPrivacyDialog *dialog)
 {
-	GSList *l;
-	if (dialog->in_allow_list)
-		l = dialog->account->permit;
-	else
-		l = dialog->account->deny;
-	while (l) {
-		char *user;
-		user = l->data;
-		l = l->next;
-		if (dialog->in_allow_list)
-			purple_privacy_permit_remove(dialog->account, user, FALSE);
-		else
-			purple_privacy_deny_remove(dialog->account, user, FALSE);
-	}
 }
 
-static void
-close_cb(GtkWidget *button, PidginPrivacyDialog *dialog)
+/* Create scroll box - Contacts and add contact button */
+static void show_contacts(PidginPrivacyDialog *dialog)
 {
-	gtk_widget_destroy(dialog->win);
+	GtkWidget *treeview;
+	GtkWidget *align;
 
-	pidgin_privacy_dialog_hide();
+	dialog->sw_contacts = gtk_scrolled_window_new(NULL, NULL);
+	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(dialog->sw_contacts), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
+	gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(dialog->sw_contacts), GTK_SHADOW_IN);
+	gtk_box_pack_start(GTK_BOX(dialog->vbox_pas), dialog->sw_contacts, TRUE, TRUE, 0);
+	gtk_widget_show(dialog->sw_contacts);
+
+	/* Add items to the scroll box - Contacts */
+	dialog->model_contacts = gtk_list_store_new(CONTACTS_NUM_COLUMNS,
+					G_TYPE_STRING,		/* CONTACTS_COLUMN_BUDDYNAME */
+					G_TYPE_BOOLEAN,		/* CONTACTS_COLUMN_BLOCK_ALL */
+					G_TYPE_BOOLEAN,		/* CONTACTS_COLUMN_INVISIBLE */
+					G_TYPE_BOOLEAN,		/* CONTACTS_COLUMN_BLOCK_CHAT */
+					G_TYPE_BOOLEAN,		/* CONTACTS_COLUMN_BLOCK_FT */
+					G_TYPE_BOOLEAN,		/* CONTACTS_COLUMN_BLOCK_CONF */
+					G_TYPE_POINTER		/* CONTACTS_COLUMN_DATA */
+					);
+
+	treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(dialog->model_contacts));
+	gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(treeview), TRUE);
+	gtk_widget_set_size_request(treeview, -1, 150);
+	gtk_container_add(GTK_CONTAINER(dialog->sw_contacts), treeview);
+
+	add_columns_contacts(treeview, dialog);
+	gtk_tree_view_columns_autosize(GTK_TREE_VIEW(treeview));
+	populate_contacts_list(dialog);
+
+	gtk_widget_show_all(treeview);
+	gtk_widget_show_all(treeview);
+
+	/* Add contact button */
+	align = gtk_alignment_new(1,1,0,0);
+	gtk_box_pack_start(GTK_BOX(dialog->vbox_pas), align, FALSE, FALSE, 0);
+	dialog->add_contact_button = gtk_button_new_from_stock(GTK_STOCK_ADD);
+	g_signal_connect(G_OBJECT(dialog->add_contact_button), "clicked", G_CALLBACK(add_contact_cb), dialog);
+	gtk_container_add(GTK_CONTAINER(align), dialog->add_contact_button);
+	gtk_widget_show(dialog->add_contact_button);
+	gtk_widget_show(align);
+
+	dialog->show_sw_contacts = TRUE;
 }
 
 static PidginPrivacyDialog *
@@ -340,96 +588,148 @@ privacy_dialog_new(void)
 {
 	PidginPrivacyDialog *dialog;
 	GtkWidget *vbox;
-	GtkWidget *button;
+	GtkWidget *label;
+	GtkWidget *radio = NULL;
+	GtkWidget *vbox_radio;
+	GtkWidget *presence_expander;
+	GtkWidget *vbox_presence_expander;
+	GtkWidget *sw_presence;
+	GtkWidget *treeview_presence;
 	GtkWidget *dropdown;
-	GtkWidget *label;
-	int selected = -1;
+	GtkWidget *menu;
+	int selected = 0;
 	int i;
+	PurplePrivacySetting state_global;
 
+	GtkWidget *button;
+
 	dialog = g_new0(PidginPrivacyDialog, 1);
 
-	dialog->win = pidgin_create_dialog(_("Privacy"), PIDGIN_HIG_BORDER, "privacy", TRUE);
+	dialog->win = pidgin_create_dialog(_("Privacy"), PIDGIN_HIG_BORDER , "privacy", TRUE);
 
-	g_signal_connect(G_OBJECT(dialog->win), "delete_event",
-					 G_CALLBACK(destroy_cb), dialog);
+	g_signal_connect(G_OBJECT(dialog->win), "delete_event", G_CALLBACK(destroy_cb), dialog);
 
 	/* Main vbox */
 	vbox = pidgin_dialog_get_vbox_with_properties(GTK_DIALOG(dialog->win), FALSE, PIDGIN_HIG_BORDER);
 
 	/* Description label */
-	label = gtk_label_new(
-		_("Changes to privacy settings take effect immediately."));
+	label = gtk_label_new(_("Changes to privacy settings take effect immediately."));
 
 	gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
 	gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
 	gtk_widget_show(label);
 
+	/* Radio buttons */
+	vbox_radio = gtk_vbox_new(FALSE, PIDGIN_HIG_BOX_SPACE);
+	gtk_box_pack_start(GTK_BOX(vbox), vbox_radio, FALSE, FALSE, 0);
+	state_global = purple_privacy_obtain_global_state();
+
+	radio = gtk_radio_button_new_with_label(NULL, _("Allow all users"));
+	gtk_box_pack_start(GTK_BOX(vbox_radio), radio, FALSE, FALSE, 0);
+	g_signal_connect(G_OBJECT(radio), "toggled", G_CALLBACK(toggle_button_cb), (gpointer) dialog);
+	g_object_set_data(G_OBJECT(radio), "choice_id", GINT_TO_POINTER(PURPLE_PRIVACY_ALLOW_ALL));
+	if(state_global == PURPLE_PRIVACY_ALLOW_ALL)
+		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(radio), TRUE);
+	gtk_widget_show(radio);
+
+	radio = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(radio), _("Block messages from the users not in the buddy list"));
+	gtk_box_pack_start(GTK_BOX(vbox_radio), radio, FALSE, FALSE, 0);
+	g_signal_connect(G_OBJECT(radio), "toggled", G_CALLBACK(toggle_button_cb), (gpointer) dialog);
+	g_object_set_data(G_OBJECT(radio), "choice_id", GINT_TO_POINTER(PURPLE_PRIVACY_BLOCK_MSG_NONBUDDY));
+	if(state_global == PURPLE_PRIVACY_BLOCK_MSG_NONBUDDY)
+		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(radio), TRUE);
+	gtk_widget_show(radio);
+
+	radio = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(radio), _("Block users not in the buddy list"));
+	gtk_box_pack_start(GTK_BOX(vbox_radio), radio, FALSE, FALSE, 0);
+	g_signal_connect(G_OBJECT(radio), "toggled", G_CALLBACK(toggle_button_cb), (gpointer) dialog);
+	g_object_set_data(G_OBJECT(radio), "choice_id", GINT_TO_POINTER(PURPLE_PRIVACY_ALLOW_BUDDYLIST));
+	if(state_global == PURPLE_PRIVACY_ALLOW_BUDDYLIST)
+		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(radio), TRUE);
+	gtk_widget_show(radio);
+
+	radio = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(radio), _("Per account settings"));
+	gtk_box_pack_start(GTK_BOX(vbox_radio), radio, FALSE, FALSE, 0);
+	g_signal_connect(G_OBJECT(radio), "toggled", G_CALLBACK(toggle_button_cb), (gpointer) dialog);
+	g_object_set_data(G_OBJECT(radio), "choice_id", GINT_TO_POINTER(PURPLE_PRIVACY_CUSTOM));
+	if(state_global == PURPLE_PRIVACY_CUSTOM)
+		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(radio), TRUE);
+	gtk_widget_show(radio);
+
+	/* Prepare box for widgets under "Per account settings (pas) */
+	dialog->vbox_pas = gtk_vbox_new(FALSE, PIDGIN_HIG_BOX_SPACE/2);
+	gtk_box_pack_start(GTK_BOX(vbox_radio), dialog->vbox_pas, FALSE, FALSE, 0);
+
+	gtk_widget_show(vbox_radio);
+
+	/* Prepare widgets under PAS */
 	/* Accounts drop-down */
-	dropdown = pidgin_account_option_menu_new(NULL, FALSE,
-												G_CALLBACK(select_account_cb), NULL, dialog);
-	pidgin_add_widget_to_vbox(GTK_BOX(vbox), _("Set privacy for:"), NULL, dropdown, TRUE, NULL);
+	dropdown = pidgin_account_option_menu_new(NULL, FALSE, G_CALLBACK(select_account_cb), NULL, dialog);
+	pidgin_add_widget_to_vbox(GTK_BOX(dialog->vbox_pas), _("Set privacy for:"), NULL, dropdown, TRUE, NULL);
 	dialog->account = pidgin_account_option_menu_get_selected(dropdown);
 
-	/* Add the drop-down list with the allow/block types. */
-	dialog->type_menu = gtk_combo_box_new_text();
-	gtk_box_pack_start(GTK_BOX(vbox), dialog->type_menu, FALSE, FALSE, 0);
-	gtk_widget_show(dialog->type_menu);
+	/* Privacy State drop down */
+	dialog->type_menu = gtk_option_menu_new();
+	pidgin_add_widget_to_vbox(GTK_BOX(dialog->vbox_pas), _("Privacy State: "), NULL, dialog->type_menu, TRUE, NULL);
+	menu = gtk_menu_new();
 
-	for (i = 0; i < menu_entry_count; i++) {
-		gtk_combo_box_append_text(GTK_COMBO_BOX(dialog->type_menu),
-		                          _(menu_entries[i].text));
+	if(state_global == PURPLE_PRIVACY_CUSTOM)
+		gtk_widget_show(dialog->vbox_pas);
 
-		if (menu_entries[i].num == dialog->account->perm_deny)
+	for (i = 0; i < menu_entry_count; i++) {
+		pidgin_new_item(menu, _(menu_entries[i].text));
+		if ( (menu_entries[i].num == purple_privacy_obtain_account_state(dialog->account)) )
 			selected = i;
 	}
 
-	gtk_combo_box_set_active(GTK_COMBO_BOX(dialog->type_menu), selected);
+	gtk_option_menu_set_menu(GTK_OPTION_MENU(dialog->type_menu), menu);
+	gtk_option_menu_set_history(GTK_OPTION_MENU(dialog->type_menu), selected);
+	g_signal_connect(G_OBJECT(dialog->type_menu), "changed", G_CALLBACK(type_changed_cb), dialog);
 
-	g_signal_connect(G_OBJECT(dialog->type_menu), "changed",
-					 G_CALLBACK(type_changed_cb), dialog);
+	/* If custom options selected: Construct and show contacts scroll window, add contact button */
+	dialog->show_sw_contacts = FALSE;	/* Currently we are not showing contacts scroll window */
+	if( menu_entries[selected].num == PURPLE_PRIVACY_CUSTOM )
+		type_changed_cb(GTK_OPTION_MENU(dialog->type_menu), dialog);
 
-	/* Build the treeview for the allow list. */
-	dialog->allow_widget = build_allow_list(dialog);
-	gtk_box_pack_start(GTK_BOX(vbox), dialog->allow_widget, TRUE, TRUE, 0);
+	/* Expander for Presence */
+	presence_expander = gtk_expander_new(_("Presence Settings"));
+	gtk_box_pack_start(GTK_BOX(vbox), presence_expander, FALSE, FALSE, 0);
+	gtk_widget_show(presence_expander);
+	vbox_presence_expander = gtk_vbox_new(FALSE, 20);
+	gtk_container_add(GTK_CONTAINER(presence_expander), vbox_presence_expander);
+	gtk_widget_show(presence_expander);
+	
+	/* Create scroll box for Presence Settings */
+	sw_presence = gtk_scrolled_window_new(NULL, NULL);
+	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw_presence), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
+	gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw_presence), GTK_SHADOW_IN);
+	gtk_box_pack_start(GTK_BOX(vbox_presence_expander), sw_presence, TRUE, TRUE, 0);
+	gtk_widget_show(sw_presence);
+	gtk_widget_show(vbox_presence_expander);
 
-	/* Build the treeview for the block list. */
-	dialog->block_widget = build_block_list(dialog);
-	gtk_box_pack_start(GTK_BOX(vbox), dialog->block_widget, TRUE, TRUE, 0);
+	/* Add items to the scroll box - (SOPNL)*/
+	dialog->model_presence = gtk_list_store_new(PRESENCE_NUM_COLUMNS,
+					GDK_TYPE_PIXBUF,   /* PRESENCE_COLUMN_ICON */
+					G_TYPE_STRING,     /* PRESENCE_COLUMN_USERNAME */
+					G_TYPE_BOOLEAN,    /* PRESENCE_COLUMN_INV_NONBUD */
+					G_TYPE_BOOLEAN,    /* PRESENCE_COLUMN_INV_ALL */
+					G_TYPE_STRING,     /* PRESENCE_COLUMN_PROTOCOL */
+					G_TYPE_POINTER     /* PRESENCE_COLUMN_DATA */
+					);
+	treeview_presence = gtk_tree_view_new_with_model(GTK_TREE_MODEL(dialog->model_presence));
+	gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(treeview_presence), TRUE);
+	gtk_widget_set_size_request(treeview_presence, -1, 150);
+	gtk_container_add(GTK_CONTAINER(sw_presence), treeview_presence);
 
-	/* Add the button box for Add, Remove, Remove All */
-	dialog->button_box = pidgin_dialog_get_action_area(GTK_DIALOG(dialog->win));
+	add_columns_show_offline(treeview_presence, dialog);
+	gtk_tree_view_columns_autosize(GTK_TREE_VIEW(treeview_presence));
+	populate_accounts_list(dialog);
+	gtk_widget_show_all(treeview_presence);
 
-	/* Add button */
-	button = pidgin_dialog_add_button(GTK_DIALOG(dialog->win), GTK_STOCK_ADD, G_CALLBACK(add_cb), dialog);
-	dialog->add_button = button;
-
-	/* Remove button */
-	button = pidgin_dialog_add_button(GTK_DIALOG(dialog->win), GTK_STOCK_REMOVE, G_CALLBACK(remove_cb), dialog);
-	dialog->remove_button = button;
-	/* TODO: This button should be sensitive/invisitive more cleverly */
-	gtk_widget_set_sensitive(button, FALSE);
-
-	/* Remove All button */
-	button = pidgin_dialog_add_button(GTK_DIALOG(dialog->win), _("Remove Al_l"), G_CALLBACK(removeall_cb), dialog);
-	dialog->removeall_button = button;
-
 	/* Close button */
 	button = pidgin_dialog_add_button(GTK_DIALOG(dialog->win), GTK_STOCK_CLOSE, G_CALLBACK(close_cb), dialog);
 	dialog->close_button = button;
 
-	type_changed_cb(GTK_COMBO_BOX(dialog->type_menu), dialog);
-#if 0
-	if (dialog->account->perm_deny == PURPLE_PRIVACY_ALLOW_USERS) {
-		gtk_widget_show(dialog->allow_widget);
-		gtk_widget_show(dialog->button_box);
-		dialog->in_allow_list = TRUE;
-	}
-	else if (dialog->account->perm_deny == PURPLE_PRIVACY_DENY_USERS) {
-		gtk_widget_show(dialog->block_widget);
-		gtk_widget_show(dialog->button_box);
-		dialog->in_allow_list = FALSE;
-	}
-#endif
 	return dialog;
 }
 
@@ -451,8 +751,7 @@ pidgin_privacy_dialog_hide(void)
 	if (privacy_dialog == NULL)
 		return;
 
-	g_object_unref(G_OBJECT(privacy_dialog->allow_store));
-	g_object_unref(G_OBJECT(privacy_dialog->block_store));
+	/* privacy laters: un ref stores, free data */
 	g_free(privacy_dialog);
 	privacy_dialog = NULL;
 }
@@ -464,24 +763,16 @@ destroy_request_data(PidginPrivacyReques
 	g_free(data);
 }
 
-static void
-confirm_permit_block_cb(PidginPrivacyRequestData *data, int option)
+/* privacy laters: remove laters */
+
+static void confirm_permit_block_cb(PidginPrivacyRequestData *data, int option)
 {
-	if (data->block)
-		purple_privacy_deny(data->account, data->name, FALSE, FALSE);
-	else
-		purple_privacy_allow(data->account, data->name, FALSE, FALSE);
-
-	destroy_request_data(data);
 }
 
-static void
-add_permit_block_cb(PidginPrivacyRequestData *data, const char *name)
+static void add_permit_block_cb(PidginPrivacyRequestData *data, const char *name)
 {
-	data->name = g_strdup(name);
-
-	confirm_permit_block_cb(data, 0);
 }
+/* privacy laters */
 
 void
 pidgin_request_add_permit(PurpleAccount *account, const char *name)
@@ -567,15 +858,15 @@ pidgin_permit_added_removed(PurpleAccoun
 static void
 pidgin_permit_added_removed(PurpleAccount *account, const char *name)
 {
-	if (privacy_dialog != NULL)
-		rebuild_allow_list(privacy_dialog);
+	/*if (privacy_dialog != NULL)
+		rebuild_allow_list(privacy_dialog); */
 }
 
 static void
 pidgin_deny_added_removed(PurpleAccount *account, const char *name)
 {
-	if (privacy_dialog != NULL)
-		rebuild_block_list(privacy_dialog);
+	/*if (privacy_dialog != NULL)
+		rebuild_block_list(privacy_dialog); */
 }
 
 static PurplePrivacyUiOps privacy_ops =
============================================================
--- libpurple/privacy.c	d0ea5addf9ad746869966e8b5334c7e3faa54f4b
+++ libpurple/privacy.c	eacf1a8c0768c1b2d24e665eac720d4887fc12e1
@@ -22,390 +22,841 @@
 #include "internal.h"
 
 #include "account.h"
+#include "debug.h"
 #include "privacy.h"
+#include "savedstatuses.h"
 #include "server.h"
 #include "util.h"
 
+static int privacy_handle;
+
+static PurplePrivacySetting purple_privacy_state;
+
 static PurplePrivacyUiOps *privacy_ops = NULL;
+GSList *get_account_members(PurpleAccount *account, PurplePrivacyListType type);
+static void acc_signed_on_cb(PurpleConnection *gc, void *data);
+static void acc_signed_off_cb(PurpleConnection *gc, void *data);
 
-gboolean
-purple_privacy_permit_add(PurpleAccount *account, const char *who,
-						gboolean local_only)
+/* To do: Privacy
+check for synchronization on list change with copy on disk
+To synchronize:
+
+PurpleBlistUiOps *blist_ops;
+//blah blah
+blist_ops = purple_blist_get_ui_ops();
+	if (blist_ops != NULL && blist_ops->save_account != NULL)
+		blist_ops->save_account(account);
+*/
+
+void
+purple_privacy_set_ui_ops(PurplePrivacyUiOps *ops)
 {
-	GSList *l;
-	char *name;
-	PurpleBuddy *buddy;
-	PurpleBlistUiOps *blist_ops;
+	privacy_ops = ops;
+}
 
+PurplePrivacyUiOps *
+purple_privacy_get_ui_ops(void)
+{
+	return privacy_ops;
+}
+
+void
+purple_privacy_init(void)
+{
+	/* Set default purple privacy state to PURPLE_PRIVACY_ALLOW_BUDDYLIST */
+	purple_privacy_state = PURPLE_PRIVACY_ALLOW_BUDDYLIST;
+
+	/* Register the purple event callbacks. */
+	purple_signal_connect(purple_connections_get_handle(), "signed-on",
+						purple_privacy_get_handle(), PURPLE_CALLBACK(acc_signed_on_cb), NULL);
+	purple_signal_connect(purple_connections_get_handle(), "signed-off",
+						purple_privacy_get_handle(), PURPLE_CALLBACK(acc_signed_off_cb), NULL);
+}
+
+void
+purple_privacy_uninit(void)
+{
+	purple_signals_disconnect_by_handle(purple_privacy_get_handle());
+	purple_signals_unregister_by_instance(purple_privacy_get_handle());
+}
+
+gboolean purple_privacy_set_blocking_context(PurpleAccount *account, const char *who, gboolean local_only, PurplePrivacyContext context)
+{
+	PurpleBuddy *b;
+	PurpleGroup *g;
+	char *name = NULL;
+
 	g_return_val_if_fail(account != NULL, FALSE);
 	g_return_val_if_fail(who     != NULL, FALSE);
 
-	name = g_strdup(purple_normalize(account, who));
+	if(purple_strequal(who, "all-others"))
+		name = g_strdup(who);
+	else
+		name = g_strdup(purple_normalize(account, who));
 
-	for (l = account->permit; l != NULL; l = l->next) {
-		if (g_str_equal(name, l->data))
-			/* This buddy already exists */
-			break;
+	if((b = purple_find_privacy_contact(account, name)))
+	{
+		b->privacy_block_context = context;
+		b->local_only = local_only;
 	}
+	else
+	{
+		if(!(g = purple_find_group(PURPLE_PRIVACY_GROUP)))
+		{
+			g = purple_group_new(PURPLE_PRIVACY_GROUP);
+			purple_blist_add_group(g, NULL);
+		}
 
-	if (l != NULL)
+		b = purple_buddy_new(account, name, NULL);
+		b->privacy_block_context = context;
+		b->local_only = local_only;
+		purple_blist_add_buddy(b, NULL, g, NULL);
+	}
+
+	g_free(name);
+	return TRUE;
+}
+
+PurplePrivacyContext purple_privacy_get_blocking_context(PurpleAccount *account, const char *who)
+{
+	PurpleBuddy *b;
+	char *name = NULL;
+
+	g_return_val_if_fail(account != NULL, FALSE);
+	g_return_val_if_fail(who     != NULL, FALSE);
+
+	if(purple_strequal(who, "all-others"))
+		name = g_strdup(who);
+	else
+		name = g_strdup(purple_normalize(account, who));
+
+	if((b = purple_find_privacy_contact(account, name)))
+		return b->privacy_block_context;
+	else
 	{
-		/* This buddy already exists, so bail out */
-		g_free(name);
-		return FALSE;
+		if((b = purple_find_privacy_contact(account, "all-others")))
+			return b->privacy_block_context;
+		else
+			return 0;
 	}
+}
 
-	account->permit = g_slist_append(account->permit, name);
+gboolean purple_privacy_set_block_all(PurpleAccount *account, const char *who, gboolean local, gboolean server)
+{
+	char *name;
+	PurplePrivacyContext context;
 
-	if (!local_only && purple_account_is_connected(account))
-		serv_add_permit(purple_account_get_connection(account), who);
+	g_return_val_if_fail(account != NULL, FALSE);
+	g_return_val_if_fail(who     != NULL, FALSE);
 
-	if (privacy_ops != NULL && privacy_ops->permit_added != NULL)
-		privacy_ops->permit_added(account, who);
+	context = PURPLE_PRIVACY_BLOCK_ALL | PURPLE_PRIVACY_BLOCK_MESSAGE | PURPLE_PRIVACY_BLOCK_PRESENCE |
+			PURPLE_PRIVACY_BLOCK_FT | PURPLE_PRIVACY_BLOCK_CONF;
 
-	blist_ops = purple_blist_get_ui_ops();
-	if (blist_ops != NULL && blist_ops->save_account != NULL)
-		blist_ops->save_account(account);
+	if(purple_strequal(who, "all-others"))
+		name = g_strdup(who);
+	else
+		name = g_strdup(purple_normalize(account, who));
 
-	/* This lets the UI know a buddy has had its privacy setting changed */
-	buddy = purple_find_buddy(account, name);
-	if (buddy != NULL) {
-		purple_signal_emit(purple_blist_get_handle(),
-                "buddy-privacy-changed", buddy);
+	if(local)
+		purple_privacy_set_blocking_context(account, name, !server, context);
+
+	if(server && purple_account_is_connected(account) && 
+				purple_privacy_check_list_support(account, PURPLE_PRIVACY_BLOCK_BOTH_LIST) &&
+				(!purple_strequal(name, "all-others")) )
+		serv_privacy_list_add(purple_account_get_connection(account), PURPLE_PRIVACY_BLOCK_BOTH_LIST, name);
+
+	g_free(name);
+	return TRUE;
+}
+
+gboolean purple_privacy_set_block_presence(PurpleAccount *account, const char *who, gboolean local, gboolean server)
+{
+	char *name;
+	PurplePrivacyContext context;
+
+	g_return_val_if_fail(account != NULL, FALSE);
+	g_return_val_if_fail(who     != NULL, FALSE);
+
+	if(purple_strequal(who, "all-others"))
+		name = g_strdup(who);
+	else
+		name = g_strdup(purple_normalize(account, who));
+
+	if(!purple_privacy_check(account, name, PURPLE_PRIVACY_BLOCK_PRESENCE))
+	{
+		if(local)
+		{
+			context = ( purple_privacy_get_blocking_context(account, name) | PURPLE_PRIVACY_BLOCK_PRESENCE );
+			purple_privacy_set_blocking_context(account, name, !server, context);
+		}
+
+		if(server && purple_account_is_connected(account) && purple_privacy_check_list_support(account, PURPLE_PRIVACY_INVISIBLE_LIST) )
+			serv_privacy_list_add(purple_account_get_connection(account), PURPLE_PRIVACY_INVISIBLE_LIST, name);
 	}
+
+	g_free(name);
 	return TRUE;
 }
 
-gboolean
-purple_privacy_permit_remove(PurpleAccount *account, const char *who,
-						   gboolean local_only)
+gboolean purple_privacy_set_block_message(PurpleAccount *account, const char *who)
 {
-	GSList *l;
-	const char *name;
-	PurpleBuddy *buddy;
-	char *del;
-	PurpleBlistUiOps *blist_ops;
+	char *name;
+	PurplePrivacyContext context;
 
 	g_return_val_if_fail(account != NULL, FALSE);
 	g_return_val_if_fail(who     != NULL, FALSE);
 
-	name = purple_normalize(account, who);
+	if(purple_strequal(who, "all-others"))
+		name = g_strdup(who);
+	else
+		name = g_strdup(purple_normalize(account, who));
 
-	for (l = account->permit; l != NULL; l = l->next) {
-		if (g_str_equal(name, l->data))
-			/* We found the buddy we were looking for */
-			break;
+	if(!purple_privacy_check(account, name, PURPLE_PRIVACY_BLOCK_MESSAGE))
+	{
+		context = ( purple_privacy_get_blocking_context(account, name) | PURPLE_PRIVACY_BLOCK_MESSAGE );
+		purple_privacy_set_blocking_context(account, name, TRUE, context);
 	}
 
-	if (l == NULL)
-		/* We didn't find the buddy we were looking for, so bail out */
-		return FALSE;
+	g_free(name);
+	return TRUE;
+}
 
-	/* We should not free l->data just yet. There can be occasions where
-	 * l->data == who. In such cases, freeing l->data here can cause crashes
-	 * later when who is used. */
-	del = l->data;
-	account->permit = g_slist_delete_link(account->permit, l);
+gboolean purple_privacy_set_block_ft(PurpleAccount *account, const char *who)
+{
+	char *name;
+	PurplePrivacyContext context;
 
-	if (!local_only && purple_account_is_connected(account))
-		serv_rem_permit(purple_account_get_connection(account), who);
+	g_return_val_if_fail(account != NULL, FALSE);
+	g_return_val_if_fail(who     != NULL, FALSE);
 
-	if (privacy_ops != NULL && privacy_ops->permit_removed != NULL)
-		privacy_ops->permit_removed(account, who);
+	if(purple_strequal(who, "all-others"))
+		name = g_strdup(who);
+	else
+		name = g_strdup(purple_normalize(account, who));
 
-	blist_ops = purple_blist_get_ui_ops();
-	if (blist_ops != NULL && blist_ops->save_account != NULL)
-		blist_ops->save_account(account);
+	if(!purple_privacy_check(account, name, PURPLE_PRIVACY_BLOCK_FT))
+	{
+		context = ( purple_privacy_get_blocking_context(account, name) | PURPLE_PRIVACY_BLOCK_FT );
+		purple_privacy_set_blocking_context(account, name, TRUE, context);
+	}
 
-	buddy = purple_find_buddy(account, name);
-	if (buddy != NULL) {
-		purple_signal_emit(purple_blist_get_handle(),
-                "buddy-privacy-changed", buddy);
+	g_free(name);
+	return TRUE;
+}
+
+gboolean purple_privacy_set_block_conf(PurpleAccount *account, const char *who)
+{
+	char *name;
+	PurplePrivacyContext context;
+
+	g_return_val_if_fail(account != NULL, FALSE);
+	g_return_val_if_fail(who     != NULL, FALSE);
+
+	if(purple_strequal(who, "all-others"))
+		name = g_strdup(who);
+	else
+		name = g_strdup(purple_normalize(account, who));
+
+	if(!purple_privacy_check(account, name, PURPLE_PRIVACY_BLOCK_CONF))
+	{
+		context = ( purple_privacy_get_blocking_context(account, name) | PURPLE_PRIVACY_BLOCK_CONF );
+		purple_privacy_set_blocking_context(account, name, TRUE, context);
 	}
-	g_free(del);
+
+	g_free(name);
 	return TRUE;
 }
 
-gboolean
-purple_privacy_deny_add(PurpleAccount *account, const char *who,
-					  gboolean local_only)
+gboolean purple_privacy_unset_block_message(PurpleAccount *account, const char *who)
 {
-	GSList *l;
 	char *name;
-	PurpleBuddy *buddy;
-	PurpleBlistUiOps *blist_ops;
 
 	g_return_val_if_fail(account != NULL, FALSE);
 	g_return_val_if_fail(who     != NULL, FALSE);
 
-	name = g_strdup(purple_normalize(account, who));
+	if(purple_strequal(who, "all-others"))
+		name = g_strdup(who);
+	else
+		name = g_strdup(purple_normalize(account, who));
 
-	for (l = account->deny; l != NULL; l = l->next) {
-		if (g_str_equal(name, l->data))
-			/* This buddy already exists */
-			break;
+	if(purple_privacy_check(account, name, PURPLE_PRIVACY_BLOCK_MESSAGE))
+	{
+		if(purple_privacy_check(account, name, PURPLE_PRIVACY_BLOCK_ALL))
+		{
+			purple_privacy_unset_block_all(account, name, TRUE, TRUE);
+			purple_privacy_set_block_presence(account, name, TRUE, TRUE);
+			purple_privacy_set_block_ft(account, name);
+			purple_privacy_set_block_conf(account, name);
+		}
+		else
+		{
+			PurplePrivacyContext context;
+			context = purple_privacy_get_blocking_context(account, name) & (~PURPLE_PRIVACY_BLOCK_MESSAGE);
+			purple_privacy_set_blocking_context(account, name, TRUE, context);
+		}
 	}
 
-	if (l != NULL)
+	g_free(name);
+	return TRUE;
+}
+
+gboolean purple_privacy_unset_block_conf(PurpleAccount *account, const char *who)
+{
+	char *name;
+
+	g_return_val_if_fail(account != NULL, FALSE);
+	g_return_val_if_fail(who     != NULL, FALSE);
+
+	if(purple_strequal(who, "all-others"))
+		name = g_strdup(who);
+	else
+		name = g_strdup(purple_normalize(account, who));
+
+	if(purple_privacy_check(account, name, PURPLE_PRIVACY_BLOCK_CONF))
 	{
-		/* This buddy already exists, so bail out */
-		g_free(name);
-		return FALSE;
+		if(purple_privacy_check(account, name, PURPLE_PRIVACY_BLOCK_ALL))
+		{
+			purple_privacy_unset_block_all(account, name, TRUE, TRUE);
+			purple_privacy_set_block_presence(account, name, TRUE, TRUE);
+			purple_privacy_set_block_ft(account, name);
+			purple_privacy_set_block_message(account, name);
+		}
+		else
+		{
+			PurplePrivacyContext context;
+			context = purple_privacy_get_blocking_context(account, name) & (~PURPLE_PRIVACY_BLOCK_CONF);
+			purple_privacy_set_blocking_context(account, name, TRUE, context);
+		}
 	}
 
-	account->deny = g_slist_append(account->deny, name);
+	g_free(name);
+	return TRUE;
+}
 
-	if (!local_only && purple_account_is_connected(account))
-		serv_add_deny(purple_account_get_connection(account), who);
+gboolean purple_privacy_unset_block_ft(PurpleAccount *account, const char *who)
+{
+	char *name;
 
-	if (privacy_ops != NULL && privacy_ops->deny_added != NULL)
-		privacy_ops->deny_added(account, who);
+	g_return_val_if_fail(account != NULL, FALSE);
+	g_return_val_if_fail(who     != NULL, FALSE);
 
-	blist_ops = purple_blist_get_ui_ops();
-	if (blist_ops != NULL && blist_ops->save_account != NULL)
-		blist_ops->save_account(account);
+	if(purple_strequal(who, "all-others"))
+		name = g_strdup(who);
+	else
+		name = g_strdup(purple_normalize(account, who));
 
-	buddy = purple_find_buddy(account, name);
-	if (buddy != NULL) {
-		purple_signal_emit(purple_blist_get_handle(),
-                "buddy-privacy-changed", buddy);
+	if(purple_privacy_check(account, name, PURPLE_PRIVACY_BLOCK_FT))
+	{
+		if(purple_privacy_check(account, name, PURPLE_PRIVACY_BLOCK_ALL))
+		{
+			purple_privacy_unset_block_all(account, name, TRUE, TRUE);
+			purple_privacy_set_block_presence(account, name, TRUE, TRUE);
+			purple_privacy_set_block_conf(account, name);
+			purple_privacy_set_block_message(account, name);
+		}
+		else
+		{
+			PurplePrivacyContext context;
+			context = purple_privacy_get_blocking_context(account, name) & (~PURPLE_PRIVACY_BLOCK_FT);
+			purple_privacy_set_blocking_context(account, name, TRUE, context);
+		}
 	}
+
+	g_free(name);
 	return TRUE;
 }
 
-gboolean
-purple_privacy_deny_remove(PurpleAccount *account, const char *who,
-						 gboolean local_only)
+gboolean purple_privacy_unset_block_all(PurpleAccount *account, const char *who, gboolean local, gboolean server)
 {
-	GSList *l;
-	const char *normalized;
 	char *name;
-	PurpleBuddy *buddy;
-	PurpleBlistUiOps *blist_ops;
 
 	g_return_val_if_fail(account != NULL, FALSE);
 	g_return_val_if_fail(who     != NULL, FALSE);
 
-	normalized = purple_normalize(account, who);
+	if(purple_strequal(who, "all-others"))
+		name = g_strdup(who);
+	else
+		name = g_strdup(purple_normalize(account, who));
 
-	for (l = account->deny; l != NULL; l = l->next) {
-		if (g_str_equal(normalized, l->data))
-			/* We found the buddy we were looking for */
-			break;
+	if(purple_privacy_check(account, name, PURPLE_PRIVACY_BLOCK_ALL))
+	{
+		if(local)
+			purple_privacy_set_blocking_context(account, name, !server, 0);
+
+		if(server && purple_account_is_connected(account) && 
+				purple_privacy_check_list_support(account, PURPLE_PRIVACY_BLOCK_BOTH_LIST) &&
+					(!purple_strequal(who, "all-others")) )
+			serv_privacy_list_remove(purple_account_get_connection(account), PURPLE_PRIVACY_BLOCK_BOTH_LIST, name);
 	}
 
-	if (l == NULL)
-		/* We didn't find the buddy we were looking for, so bail out */
-		return FALSE;
+	g_free(name);
+	return TRUE;
+}
 
-	buddy = purple_find_buddy(account, normalized);
+gboolean purple_privacy_unset_block_presence(PurpleAccount *account, const char *who, gboolean local, gboolean server)
+{
+	char *name;
 
-	name = l->data;
-	account->deny = g_slist_delete_link(account->deny, l);
+	g_return_val_if_fail(account != NULL, FALSE);
+	g_return_val_if_fail(who     != NULL, FALSE);
 
-	if (!local_only && purple_account_is_connected(account))
-		serv_rem_deny(purple_account_get_connection(account), name);
+	if(purple_strequal(who, "all-others"))
+		name = g_strdup(who);
+	else
+		name = g_strdup(purple_normalize(account, who));
 
-	if (privacy_ops != NULL && privacy_ops->deny_removed != NULL)
-		privacy_ops->deny_removed(account, who);
+	if(purple_privacy_check(account, name, PURPLE_PRIVACY_BLOCK_PRESENCE))
+	{
+		if(local)
+		{
+			if(purple_privacy_check(account, name, PURPLE_PRIVACY_BLOCK_ALL))
+			{
+				purple_privacy_unset_block_all(account, name, TRUE, TRUE);
+				purple_privacy_set_block_conf(account, name);
+				purple_privacy_set_block_message(account, name);
+				purple_privacy_set_block_ft(account, name);
+			}
+			else
+			{
+				PurplePrivacyContext context;
+				
+				context = ( purple_privacy_get_blocking_context(account, who) & (~PURPLE_PRIVACY_BLOCK_PRESENCE) );
+				purple_privacy_set_blocking_context(account, name, !server, context);
+			}
+		}
 
-	if (buddy != NULL) {
-		purple_signal_emit(purple_blist_get_handle(),
-                "buddy-privacy-changed", buddy);
+		if(server && purple_account_is_connected(account) && 
+				purple_privacy_check_list_support(account, PURPLE_PRIVACY_INVISIBLE_LIST) &&
+					(!purple_strequal(who, "all-others")) )
+			serv_privacy_list_remove(purple_account_get_connection(account), PURPLE_PRIVACY_INVISIBLE_LIST, name);
 	}
 
 	g_free(name);
+	return TRUE;
+}
 
-	blist_ops = purple_blist_get_ui_ops();
-	if (blist_ops != NULL && blist_ops->save_account != NULL)
-		blist_ops->save_account(account);
+gboolean purple_privacy_check(PurpleAccount *account, const char *who, PurplePrivacyContext context)
+{
+	char *name;
+	gboolean value;
 
-	return TRUE;
+	g_return_val_if_fail(account != NULL, FALSE);
+	g_return_val_if_fail(who     != NULL, FALSE);
+
+	if(purple_strequal(who, "all-others"))
+		name = g_strdup(who);
+	else
+		name = g_strdup(purple_normalize(account, who));
+
+	if((purple_privacy_get_blocking_context(account, name) & context) == context)
+		value = TRUE;
+	else
+		value = FALSE;
+
+	g_free(name);
+	return value;
 }
+	
+gboolean purple_privacy_check_list_support(PurpleAccount *account, PurplePrivacyListType type)
+{
+	return ( (account->privacy_spec->supported_privacy_lists & type) == type ? TRUE : FALSE );
+}
 
-/**
- * This makes sure your permit list contains all buddies from your
- * buddy list and ONLY buddies from your buddy list.
- */
-static void
-add_all_buddies_to_permit_list(PurpleAccount *account, gboolean local)
+GSList *get_account_members(PurpleAccount *account, PurplePrivacyListType type)
 {
-	GSList *list;
+	GSList *account_buddies = NULL, *list = NULL, *l_tmp = NULL;
+	PurpleBuddy *b = NULL;
+	PurplePrivacyContext context = 0;
 
-	/* Remove anyone in the permit list who is not in the buddylist */
-	for (list = account->permit; list != NULL; ) {
-		char *person = list->data;
-		list = list->next;
-		if (!purple_find_buddy(account, person))
-			purple_privacy_permit_remove(account, person, local);
+	switch(type)
+	{
+		case PURPLE_PRIVACY_ALLOW_LIST:
+			context = 0;
+			break;
+		case PURPLE_PRIVACY_BLOCK_MESSAGE_LIST:
+			context = PURPLE_PRIVACY_BLOCK_MESSAGE;
+			break;
+		case PURPLE_PRIVACY_BLOCK_BOTH_LIST:
+			context = PURPLE_PRIVACY_BLOCK_ALL;
+			break;
+		case PURPLE_PRIVACY_INVISIBLE_LIST:
+			context = PURPLE_PRIVACY_BLOCK_PRESENCE;
+			break;
+		case PURPLE_PRIVACY_BUDDY_LIST:
+		case PURPLE_PRIVACY_VISIBLE_LIST:
+			/* do nothing, we won't reach here anyways */
+			break;
 	}
 
-	/* Now make sure everyone in the buddylist is in the permit list */
-	list = purple_find_buddies(account, NULL);
-	while (list != NULL)
+	account_buddies = purple_find_privacy_contacts(account, NULL);
+	for(l_tmp = account_buddies; l_tmp ; l_tmp=l_tmp->next)
 	{
-		PurpleBuddy *buddy = list->data;
-		const gchar *name = purple_buddy_get_name(buddy);
+		b = l_tmp->data;
+		if( ((b->privacy_block_context & context) == context ) && (purple_strequal(b->name, "all-others") == FALSE) )
+			list = g_slist_prepend(list, b->name);
+	}
 
-		if (!g_slist_find_custom(account->permit, name, (GCompareFunc)g_utf8_collate))
-			purple_privacy_permit_add(account, name, local);
-		list = g_slist_delete_link(list, list);
+	g_slist_free(account_buddies);
+	return list;
+}
+
+/* Privacy laters: GSList *purple_privacy_list_get_members(PurplePrivacyListType type) */
+
+GSList *purple_privacy_list_get_members_by_account(PurpleAccount *account, PurplePrivacyListType type)
+{
+	g_return_val_if_fail(account != NULL, FALSE);
+
+	if(type == PURPLE_PRIVACY_BUDDY_LIST)
+		return purple_find_buddies(account, NULL);
+
+	if(type != PURPLE_PRIVACY_VISIBLE_LIST)
+		return get_account_members(account, type);
+	else
+	{
+		GSList *l_allow = NULL, *l_block_msg = NULL;
+		l_allow = get_account_members(account, PURPLE_PRIVACY_ALLOW_LIST);
+		l_block_msg = get_account_members(account, PURPLE_PRIVACY_BLOCK_MESSAGE_LIST);
+		return g_slist_concat(l_allow, l_block_msg);
 	}
 }
 
-/*
- * TODO: All callers of this function pass in FALSE for local and
- *       restore and I don't understand when you would ever want to
- *       use TRUE for either of them.  I think both parameters could
- *       safely be removed in the next major version bump.
- */
-void
-purple_privacy_allow(PurpleAccount *account, const char *who, gboolean local,
-						gboolean restore)
+gboolean purple_privacy_sync_lists(PurpleAccount *account, GSList *buddy_l, GSList *allow_l, GSList *block_msg_l, GSList *block_both_l, GSList *visible_l, GSList *invisible_l)
 {
-	GSList *list;
-	PurplePrivacyType type = account->perm_deny;
+	GSList *p_contacts = NULL, *l_tmp = NULL;
+	PurpleBuddy *b = NULL;
+	
+	g_return_val_if_fail(account != NULL, FALSE);
+	
+	p_contacts = purple_find_privacy_contacts(account, NULL);
 
-	switch (account->perm_deny) {
-		case PURPLE_PRIVACY_ALLOW_ALL:
-			return;
-		case PURPLE_PRIVACY_ALLOW_USERS:
-			purple_privacy_permit_add(account, who, local);
+	/* Remove any contact not local, and not in any of the lists */
+	for(l_tmp = p_contacts; l_tmp != NULL; l_tmp = l_tmp->next)
+	{
+		b = l_tmp->data;
+		if(b->local_only == FALSE)
+			if(	(g_slist_find_custom(buddy_l, b->name,(GCompareFunc)strcmp) == NULL) &&
+				(g_slist_find_custom(allow_l, b->name,(GCompareFunc)strcmp) == NULL) &&
+				(g_slist_find_custom(block_msg_l, b->name,(GCompareFunc)strcmp) == NULL) &&
+				(g_slist_find_custom(block_both_l, b->name,(GCompareFunc)strcmp) == NULL) &&
+				(g_slist_find_custom(visible_l, b->name,(GCompareFunc)strcmp) == NULL) &&
+				(g_slist_find_custom(invisible_l, b->name,(GCompareFunc)strcmp) == NULL) )
+
+					purple_blist_remove_buddy(b);
+	}
+
+	/* remove contact from privacy group, if now it is in the buddy list */
+	for(l_tmp = buddy_l; l_tmp != NULL; l_tmp = l_tmp->next)
+		if((b = purple_find_buddy_in_group(account, (const char *)l_tmp->data, purple_find_group(PURPLE_PRIVACY_GROUP))))
+			purple_blist_remove_buddy(b);
+
+	/* Add the contacts from the master list to the blist */
+	/* Process buddy list first. Assuming that we want to receive message
+	and send presence from buddies in case they don't exist on any other list */
+
+	for(l_tmp = buddy_l ; l_tmp != NULL; l_tmp = l_tmp->next)
+		purple_privacy_unset_block_all(account, l_tmp->data, TRUE, FALSE);
+
+	for(l_tmp = allow_l ; l_tmp != NULL; l_tmp = l_tmp->next)
+		purple_privacy_unset_block_all(account, l_tmp->data, TRUE, FALSE);
+
+	/* Privacy laters: this is not correct */
+	for(l_tmp = block_msg_l ; l_tmp != NULL; l_tmp = l_tmp->next)
+		purple_privacy_set_block_message(account, l_tmp->data);
+
+	for(l_tmp = block_both_l ; l_tmp != NULL; l_tmp = l_tmp->next)
+		purple_privacy_set_block_all(account, l_tmp->data, TRUE, FALSE);
+
+	for(l_tmp = visible_l ; l_tmp != NULL; l_tmp = l_tmp->next)
+		purple_privacy_unset_block_presence(account, l_tmp->data, TRUE, FALSE);
+
+	for(l_tmp = invisible_l ; l_tmp != NULL; l_tmp = l_tmp->next)
+		purple_privacy_set_block_presence(account, l_tmp->data, TRUE, FALSE);
+
+	g_slist_free(p_contacts);
+
+	return TRUE;	
+}
+
+gboolean purple_privacy_account_supports_invisible_status(PurpleAccount *account)
+{
+	g_return_val_if_fail(account != NULL, FALSE);
+
+	if (purple_account_get_status_type_with_primitive(account, PURPLE_STATUS_INVISIBLE))
+		return TRUE;
+	else
+		return FALSE;
+}
+
+gboolean purple_privacy_account_status_invisible(PurpleAccount *account)
+{
+	PurpleStatus *status;
+	PurpleStatusType *status_type;
+
+	g_return_val_if_fail(account != NULL, FALSE);
+
+	status = purple_account_get_active_status(account);
+	status_type = purple_status_get_type(status);
+	
+	if(purple_status_type_get_primitive(status_type) == PURPLE_STATUS_INVISIBLE)
+		return TRUE;
+	else
+		return FALSE;
+}
+
+gboolean purple_privacy_set_account_status_invisible(PurpleAccount *account)
+{
+	PurpleStatusType *status_type;
+
+	g_return_val_if_fail(account != NULL, FALSE);
+
+	/* Check whether this account supports invisible status */
+	if ( !(status_type = purple_account_get_status_type_with_primitive(account, PURPLE_STATUS_INVISIBLE)) )
+		return FALSE;
+
+	/* Enable the status type with primitive "PURPLE_STATUS_INVISIBLE" */
+	purple_account_set_status(account, purple_status_type_get_id(status_type), TRUE, NULL);
+	
+	return TRUE;
+}
+
+static gboolean test_status(PurpleSavedStatus *saved_status)
+{
+	gboolean ret = FALSE;
+	PurpleStatusPrimitive prim;
+
+	g_return_val_if_fail(saved_status != NULL, FALSE);
+
+	prim = purple_savedstatus_get_type(saved_status);
+
+	switch(prim)
+	{
+		case PURPLE_STATUS_INVISIBLE:
+		case PURPLE_STATUS_OFFLINE:
+		case PURPLE_STATUS_UNSET:
+		case PURPLE_STATUS_NUM_PRIMITIVES: /* shouldn't have this value */
+			ret = FALSE;
 			break;
-		case PURPLE_PRIVACY_DENY_USERS:
-			purple_privacy_deny_remove(account, who, local);
-			break;
-		case PURPLE_PRIVACY_DENY_ALL:
-			if (!restore) {
-				/* Empty the allow-list. */
-				const char *norm = purple_normalize(account, who);
-				for (list = account->permit; list != NULL;) {
-					char *person = list->data;
-					list = list->next;
-					if (!purple_strequal(norm, person))
-						purple_privacy_permit_remove(account, person, local);
-				}
-			}
-			purple_privacy_permit_add(account, who, local);
-			account->perm_deny = PURPLE_PRIVACY_ALLOW_USERS;
-			break;
-		case PURPLE_PRIVACY_ALLOW_BUDDYLIST:
-			if (!purple_find_buddy(account, who)) {
-				add_all_buddies_to_permit_list(account, local);
-				purple_privacy_permit_add(account, who, local);
-				account->perm_deny = PURPLE_PRIVACY_ALLOW_USERS;
-			}
-			break;
 		default:
-			g_return_if_reached();
+			ret = TRUE;
+			break;
 	}
 
-	/* Notify the server if the privacy setting was changed */
-	if (type != account->perm_deny && purple_account_is_connected(account))
-		serv_set_permit_deny(purple_account_get_connection(account));
+	return ret;
 }
 
-/*
- * TODO: All callers of this function pass in FALSE for local and
- *       restore and I don't understand when you would ever want to
- *       use TRUE for either of them.  I think both parameters could
- *       safely be removed in the next major version bump.
- */
-void
-purple_privacy_deny(PurpleAccount *account, const char *who, gboolean local,
-					gboolean restore)
+/* Privacy Laters: this next function isn't perfect just yet.
+Doesn't change status window status when current status is invisible and we change it to 
+visible from the privacy UI */
+gboolean purple_privacy_set_account_status_visible(PurpleAccount *account)
 {
-	GSList *list;
-	PurplePrivacyType type = account->perm_deny;
+	PurpleSavedStatus *saved_status;
 
-	switch (account->perm_deny) {
+	g_return_val_if_fail(account != NULL, FALSE);
+
+	saved_status = purple_savedstatus_get_current();
+	if( test_status(saved_status) ) {
+		purple_savedstatus_activate_for_account(saved_status, account);
+		return TRUE;
+	}
+	else	{
+		/* Our current saved status is Invisible or not Online, check default status */
+		saved_status = purple_savedstatus_get_default();
+		if( test_status(saved_status) ) {
+			purple_savedstatus_activate_for_account(saved_status, account);
+			return TRUE;
+		}
+		else	{
+			/* Both current and default saved status are Invisible or not online, we choose "available" */
+			if( (saved_status = purple_savedstatus_find_transient_by_type_and_message(PURPLE_STATUS_AVAILABLE, NULL)) )
+				purple_savedstatus_activate_for_account(saved_status, account);
+			else
+				purple_account_set_status(account, "available", TRUE, NULL);
+
+			return TRUE;
+		}
+	}
+	/* Couldn't find any suitable status */
+	return FALSE;
+}
+
+PurplePrivacySetting purple_privacy_obtain_global_state(void)
+{
+	return purple_privacy_state;
+}
+
+PurplePrivacySetting purple_privacy_obtain_account_state(PurpleAccount *account)
+{
+	g_return_val_if_fail(account != NULL, FALSE);
+
+	return account->account_privacy_state;
+}
+
+NativePrivacySetting purple_privacy_obtain_native_state(PurpleAccount *account)
+{
+	g_return_val_if_fail(account != NULL, FALSE);
+
+	return account->native_privacy_state;
+}
+
+void *purple_privacy_get_handle(void)
+{
+	return &privacy_handle;
+}
+
+/* Checks for the existence of "all-others" meta contact, adds it to blist if not found */
+static void set_all_others_meta_contact(PurpleAccount *account)
+{
+	PurplePrivacyContext context;
+	PurplePrivacySetting state;
+
+	if(account == NULL)
+		return;
+
+	state = purple_privacy_obtain_account_state(account);
+
+	switch (state)
+	{
 		case PURPLE_PRIVACY_ALLOW_ALL:
-			if (!restore) {
-				/* Empty the deny-list. */
-				const char *norm = purple_normalize(account, who);
-				for (list = account->deny; list != NULL; ) {
-					char *person = list->data;
-					list = list->next;
-					if (!purple_strequal(norm, person))
-						purple_privacy_deny_remove(account, person, local);
-				}
-			}
-			purple_privacy_deny_add(account, who, local);
-			account->perm_deny = PURPLE_PRIVACY_DENY_USERS;
+			context = 0;
 			break;
-		case PURPLE_PRIVACY_ALLOW_USERS:
-			purple_privacy_permit_remove(account, who, local);
+		case PURPLE_PRIVACY_BLOCK_MSG_NONBUDDY:
+			context = PURPLE_PRIVACY_BLOCK_MESSAGE;
 			break;
-		case PURPLE_PRIVACY_DENY_USERS:
-			purple_privacy_deny_add(account, who, local);
-			break;
-		case PURPLE_PRIVACY_DENY_ALL:
-			break;
 		case PURPLE_PRIVACY_ALLOW_BUDDYLIST:
-			if (purple_find_buddy(account, who)) {
-				add_all_buddies_to_permit_list(account, local);
-				purple_privacy_permit_remove(account, who, local);
-				account->perm_deny = PURPLE_PRIVACY_ALLOW_USERS;
-			}
+		case PURPLE_PRIVACY_CUSTOM:
+			context = PURPLE_PRIVACY_BLOCK_ALL | PURPLE_PRIVACY_BLOCK_MESSAGE | PURPLE_PRIVACY_BLOCK_PRESENCE |
+						PURPLE_PRIVACY_BLOCK_FT | PURPLE_PRIVACY_BLOCK_CONF;
 			break;
-		default:
-			g_return_if_reached();
 	}
 
-	/* Notify the server if the privacy setting was changed */
-	if (type != account->perm_deny && purple_account_is_connected(account))
-		serv_set_permit_deny(purple_account_get_connection(account));
+	purple_privacy_set_blocking_context(account, "all-others", TRUE, context);
 }
 
-gboolean
-purple_privacy_check(PurpleAccount *account, const char *who)
+static void
+acc_signed_on_cb(PurpleConnection *gc, void *data)
 {
-	GSList *list;
+	PurplePrivacySetting state;
+	PurpleAccount *account = purple_connection_get_account(gc);
 
-	switch (account->perm_deny) {
-		case PURPLE_PRIVACY_ALLOW_ALL:
-			return TRUE;
+	state = account->account_privacy_state;
 
-		case PURPLE_PRIVACY_DENY_ALL:
-			return FALSE;
+	if( (account->native_privacy_state == PURPLE_PRIVACY_NATIVE_DENY_USERS) &&
+			(account->account_privacy_state == PURPLE_PRIVACY_ALLOW_ALL) )
+	{
+			if(purple_privacy_state != PURPLE_PRIVACY_ALLOW_ALL)
+				state = purple_privacy_state;
+			else
+				state = PURPLE_PRIVACY_CUSTOM;
+	}
 
-		case PURPLE_PRIVACY_ALLOW_USERS:
-			who = purple_normalize(account, who);
-			for (list=account->permit; list!=NULL; list=list->next) {
-				if (g_str_equal(who, list->data))
-					return TRUE;
-			}
-			return FALSE;
+	purple_privacy_set_account_state(account, state);
+}
 
-		case PURPLE_PRIVACY_DENY_USERS:
-			who = purple_normalize(account, who);
-			for (list=account->deny; list!=NULL; list=list->next) {
-				if (g_str_equal(who, list->data))
-					return FALSE;
-			}
-			return TRUE;
+static void autoset_global_state(void)
+{
+	GList *list = NULL, *l = NULL;
+	PurpleAccount *account;
+	PurplePrivacySetting state;
 
-		case PURPLE_PRIVACY_ALLOW_BUDDYLIST:
-			return (purple_find_buddy(account, who) != NULL);
+	state = PURPLE_PRIVACY_ALLOW_BUDDYLIST;
+	list = purple_accounts_get_all_active();
+	if(list)
+	{
+		account = list->data;
+		state = purple_privacy_obtain_account_state(account);
+	}
+	for( l = list; l != NULL; l = l->next )
+	{
+		account = l->data;
+		if( state != purple_privacy_obtain_account_state(account) ) {
+			purple_privacy_state = PURPLE_PRIVACY_CUSTOM;
+			return;
+		}
+	}
 
-		default:
-			g_return_val_if_reached(TRUE);
-	}
+	purple_privacy_state = state;
 }
 
-void
-purple_privacy_set_ui_ops(PurplePrivacyUiOps *ops)
+static void acc_signed_off_cb(PurpleConnection *gc, void *data)
 {
-	privacy_ops = ops;
+	autoset_global_state();
 }
 
-PurplePrivacyUiOps *
-purple_privacy_get_ui_ops(void)
+static void set_list_local(PurpleAccount *account, GSList *l, gboolean local)
 {
-	return privacy_ops;
+	PurpleBuddy *b;
+
+	while( l != NULL)
+	{
+		b = purple_find_privacy_contact(account, (char *)l->data);
+		if(b)
+			b->local_only = local;
+
+		l = l->next;
+	}
 }
 
-void
-purple_privacy_init(void)
+void purple_privacy_set_account_state(PurpleAccount *account, PurplePrivacySetting state)
 {
+	GSList *list = NULL, *l = NULL;
+
+	if(state == account->account_privacy_state)
+		return;
+
+	account->account_privacy_state = state;
+	autoset_global_state();
+
+	if(state == PURPLE_PRIVACY_ALLOW_ALL)
+	{
+		if ( (list = purple_privacy_list_get_members_by_account(account, PURPLE_PRIVACY_BLOCK_BOTH_LIST)) )
+		{
+			/* We empty deny list on the server, set local list inactive so we have the list to retrieve laters */
+			for(l = list; l != NULL; l = l->next)
+				serv_privacy_list_remove(purple_account_get_connection(account), PURPLE_PRIVACY_BLOCK_BOTH_LIST, (char *)l->data);
+
+			set_list_local(account, list, TRUE);
+			account->privacy_list_active = FALSE;
+		}
+		g_slist_free(list);
+		account->native_privacy_state = PURPLE_PRIVACY_NATIVE_ALLOW_ALL;
+	}
+	else
+	{
+		/* Retrieve local deny list and sync with the server : in case privacy list is inactive */
+		if( !(account->privacy_list_active) )
+		{
+			if ( (list = purple_privacy_list_get_members_by_account(account, PURPLE_PRIVACY_BLOCK_BOTH_LIST)) )
+			{
+				for(l = list; l != NULL; l = l->next)
+					serv_privacy_list_add(purple_account_get_connection(account), PURPLE_PRIVACY_BLOCK_BOTH_LIST, (char *)l->data);
+
+				account->native_privacy_state = PURPLE_PRIVACY_NATIVE_DENY_USERS;
+			}
+			else
+				account->native_privacy_state = PURPLE_PRIVACY_NATIVE_ALLOW_ALL;
+				
+			g_slist_free(list);
+			set_list_local(account, list, FALSE);		
+			account->privacy_list_active = TRUE;
+		}
+	}
+	set_all_others_meta_contact(account);
 }
+
+void purple_privacy_set_global_state(PurplePrivacySetting state)
+{
+	GList *l = NULL, *list = NULL;
+	PurpleAccount *account;
+
+	list = purple_accounts_get_all_active();
+	
+	if(state != PURPLE_PRIVACY_CUSTOM)	{
+		for( l = list; l != NULL; l = l->next )	{
+			account = l->data;
+			purple_privacy_set_account_state(account, state);
+		}
+	}
+
+	g_list_free(list);
+}
+
============================================================
--- libpurple/protocols/yahoo/libymsg.h	98f98d355250b495d3e26f25e945b0ce4fd1ec7f
+++ libpurple/protocols/yahoo/libymsg.h	3c36b72868e987e7978676955b7c7abebc7bba1a
@@ -27,6 +27,7 @@
 
 #include "circbuffer.h"
 #include "cmds.h"
+#include "privacy.h"
 #include "prpl.h"
 
 #define YAHOO_PAGER_HOST_REQ_URL "http://vcs1.msg.yahoo.com/capacity"
@@ -371,9 +372,8 @@ void yahoo_remove_buddy(PurpleConnection
 void yahoo_set_idle(PurpleConnection *gc, int idle);
 void yahoo_add_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *g);
 void yahoo_remove_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group);
-void yahoo_add_deny(PurpleConnection *gc, const char *who);
-void yahoo_rem_deny(PurpleConnection *gc, const char *who);
-void yahoo_set_permit_deny(PurpleConnection *gc);
+void yahoo_privacy_list_add(PurpleConnection *gc, PurplePrivacyListType list_type, const char *who);
+void yahoo_privacy_list_remove(PurpleConnection *gc, PurplePrivacyListType list_type, const char *who);
 void yahoo_keepalive(PurpleConnection *gc);
 void yahoo_change_buddys_group(PurpleConnection *gc, const char *who, const char *old_group, const char *new_group);
 void yahoo_rename_group(PurpleConnection *gc, const char *old_name, PurpleGroup *group, GList *moved_buddies);
============================================================
--- libpurple/protocols/yahoo/yahoochat.c	6d9b388512012554c254c6e8e4ab40d0c0ee7902
+++ libpurple/protocols/yahoo/yahoochat.c	9807b8af631f904532b5597ace06bf1b0f1fbdf8
@@ -181,17 +181,6 @@ void yahoo_process_conference_invite(Pur
 		return;
 	}
 
-	if (!purple_privacy_check(account, who) ||
-			(purple_account_get_bool(account, "ignore_invites", FALSE)))
-	{
-		purple_debug_info("yahoo",
-		    "Invite to conference %s from %s has been dropped.\n", room, who);
-		g_free(room);
-		g_free(msg);
-		g_string_free(members, TRUE);
-		return;
-	}
-
 	components = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
 	g_hash_table_replace(components, g_strdup("room"), room);
 	if (msg)
@@ -231,12 +220,6 @@ void yahoo_process_conference_decline(Pu
 			break;
 		}
 	}
-	if (!purple_privacy_check(purple_connection_get_account(gc), who))
-	{
-		g_free(room);
-		g_free(msg);
-		return;
-	}
 
 	if (who && room) {
 		/* make sure we're in the room before we process a decline message for it */
@@ -464,7 +447,7 @@ void yahoo_process_chat_join(PurpleConne
 	PurpleAccount *account = purple_connection_get_account(gc);
 	YahooData *yd = (YahooData *) gc->proto_data;
 	PurpleConversation *c = NULL;
-	GSList *l;
+	GSList *l = NULL, *deny = NULL;
 	GList *members = NULL;
 	GList *roomies = NULL;
 	char *room = NULL;
@@ -594,9 +577,11 @@ void yahoo_process_chat_join(PurpleConne
 		yahoo_chat_add_users(PURPLE_CONV_CHAT(c), members);
 	}
 
-	if (account->deny && c) {
+	deny = purple_privacy_list_get_members_by_account(account, PURPLE_PRIVACY_BLOCK_BOTH_LIST);
+
+	if (deny && c) {
 		PurpleConversationUiOps *ops = purple_conversation_get_ui_ops(c);
-		for (l = account->deny; l != NULL; l = l->next) {
+		for (l = deny; l != NULL; l = l->next) {
 			for (roomies = members; roomies; roomies = roomies->next) {
 				if (!purple_utf8_strcasecmp((char *)l->data, roomies->data)) {
 					purple_debug_info("yahoo", "Ignoring room member %s in room %s\n" , (char *)roomies->data, room ? room : "");
@@ -606,6 +591,7 @@ void yahoo_process_chat_join(PurpleConne
 			}
 		}
 	}
+	g_slist_free(deny);
 	g_list_free(roomies);
 	g_list_free(members);
 	g_free(room);
@@ -734,8 +720,7 @@ void yahoo_process_chat_addinvite(Purple
 	if (room && who) {
 		GHashTable *components;
 
-		if (!purple_privacy_check(account, who) ||
-				(purple_account_get_bool(account, "ignore_invites", FALSE)))
+		if (purple_account_get_bool(account, "ignore_invites", FALSE))
 		{
 			purple_debug_info("yahoo", "Invite to room %s from %s has been dropped.\n", room, who);
 			g_free(room);
============================================================
--- libpurple/protocols/yahoo/yahoo_picture.c	07dd300f6c6820faad574d4567ebd8b7480022e0
+++ libpurple/protocols/yahoo/yahoo_picture.c	0414e597a4142f45ba8e1a2b56bf7faf1ad00dbf
@@ -113,7 +113,7 @@ void yahoo_process_picture(PurpleConnect
 	if (!who)
 		return;
 
-	if (!purple_privacy_check(purple_connection_get_account(gc), who)) {
+	if (purple_privacy_check(purple_connection_get_account(gc), who, PURPLE_PRIVACY_BLOCK_ALL)) {
 		purple_debug_info("yahoo", "Picture packet from %s dropped.\n", who);
 		return;
 	}
============================================================
--- libpurple/plugins/psychic.c	5634b4ed4220ee9fc7a24cd903dc5600aef4b694
+++ libpurple/plugins/psychic.c	1aa4035e38e51ab6f548655c96a30abfffcd64c8
@@ -48,7 +48,7 @@ buddy_typing_cb(PurpleAccount *acct, con
     return;
   }
 
-  if(FALSE == purple_privacy_check(acct, name)) {
+  if(purple_privacy_check(acct, name, PURPLE_PRIVACY_BLOCK_ALL)) {
     purple_debug_info("psychic", "user %s is blocked\n", name);
     return;
   }
============================================================
--- libpurple/protocols/yahoo/libyahoo.c	875b38564e0465d1d3f278991eb20e9cc118127e
+++ libpurple/protocols/yahoo/libyahoo.c	4297cc5ae666c3014f8e6f4926960eb3f9e594bd
@@ -198,6 +198,11 @@ static PurplePluginProtocolInfo prpl_inf
 	NULL, /* user_splits */
 	NULL, /* protocol_options */
 	{"png,gif,jpeg", 96, 96, 96, 96, 0, PURPLE_ICON_SCALE_SEND},
+	{
+		PURPLE_PRIVACY_NATIVE_ALLOW_ALL | PURPLE_PRIVACY_NATIVE_DENY_USERS,
+		PURPLE_PRIVACY_BLOCK_BOTH_LIST | PURPLE_PRIVACY_VISIBLE_LIST | PURPLE_PRIVACY_INVISIBLE_LIST | PURPLE_PRIVACY_BUDDY_LIST,
+		TRUE, TRUE, FALSE
+	},
 	yahoo_list_icon,
 	yahoo_list_emblem,
 	yahoo_status_text,
@@ -219,11 +224,9 @@ static PurplePluginProtocolInfo prpl_inf
 	NULL, /* add_buddies */
 	yahoo_remove_buddy,
 	NULL, /* remove_buddies */
-	NULL, /* add_permit */
-	yahoo_add_deny,
-	NULL, /* rem_permit */
-	yahoo_rem_deny,
-	yahoo_set_permit_deny,
+	yahoo_privacy_list_add, /* add to privacy lists */
+	yahoo_privacy_list_remove, /* remove from privacy lists */
+	NULL,		/* Yahoo only allows "Block the following" state, so no change of state possible */
 	yahoo_c_join,
 	NULL, /* reject chat invite */
 	yahoo_get_chat_name,
============================================================
--- libpurple/protocols/yahoo/libyahoojp.c	3a6cf95dce97904c0262b7e9401fda5e4460913f
+++ libpurple/protocols/yahoo/libyahoojp.c	28729d8b4b06bdddcb7c89564cf4375c2f397b45
@@ -94,6 +94,11 @@ static PurplePluginProtocolInfo prpl_inf
 	NULL, /* user_splits */
 	NULL, /* protocol_options */
 	{"png,gif,jpeg", 96, 96, 96, 96, 0, PURPLE_ICON_SCALE_SEND},
+	{
+		PURPLE_PRIVACY_NATIVE_ALLOW_ALL | PURPLE_PRIVACY_NATIVE_DENY_USERS,
+		PURPLE_PRIVACY_BLOCK_BOTH_LIST | PURPLE_PRIVACY_VISIBLE_LIST | PURPLE_PRIVACY_INVISIBLE_LIST | PURPLE_PRIVACY_BUDDY_LIST,
+		TRUE, TRUE, FALSE
+	},
 	yahoo_list_icon,
 	yahoo_list_emblem,
 	yahoo_status_text,
@@ -115,11 +120,9 @@ static PurplePluginProtocolInfo prpl_inf
 	NULL, /* add_buddies */
 	yahoo_remove_buddy,
 	NULL, /* remove_buddies */
-	NULL, /* add_permit */
-	yahoo_add_deny,
-	NULL, /* rem_permit */
-	yahoo_rem_deny,
-	yahoo_set_permit_deny,
+	yahoo_privacy_list_add, /* add to privacy lists */
+	yahoo_privacy_list_remove, /* remove from privacy lists */
+	NULL,		/* Yahoo only allows "Block the following" state, so no change of state possible */
 	yahoo_c_join,
 	NULL, /* reject chat invite */
 	yahoo_get_chat_name,


More information about the Commits mailing list