changeset 8933:6663ad2386d9

[gaim-migrate @ 9703] "Initial Comment: * Added support for privacy settings * Added support for invites - ability to initiate multi-user conferences (chats). * Changed the license notice (to the standard GPL notice) * Fixed 64 bit issues * Incorporated Joe Shaw's patch for better error messages * Fixed the buddy list sync problems" --Mike Stoddard of Novell committer: Tailor Script <tailor@pidgin.im>
author Luke Schierer <lschiere@pidgin.im>
date Sat, 15 May 2004 14:00:31 +0000
parents 849507541e86
children 535449a13b07
files ChangeLog src/protocols/novell/nmconference.c src/protocols/novell/nmconference.h src/protocols/novell/nmconn.c src/protocols/novell/nmconn.h src/protocols/novell/nmcontact.c src/protocols/novell/nmcontact.h src/protocols/novell/nmevent.c src/protocols/novell/nmevent.h src/protocols/novell/nmfield.c src/protocols/novell/nmfield.h src/protocols/novell/nmmessage.c src/protocols/novell/nmmessage.h src/protocols/novell/nmrequest.c src/protocols/novell/nmrequest.h src/protocols/novell/nmuser.c src/protocols/novell/nmuser.h src/protocols/novell/nmuserrecord.c src/protocols/novell/nmuserrecord.h src/protocols/novell/novell.c
diffstat 20 files changed, 2285 insertions(+), 730 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Sat May 15 06:24:52 2004 +0000
+++ b/ChangeLog	Sat May 15 14:00:31 2004 +0000
@@ -12,8 +12,13 @@
 	* The history plugin now shows history for chats in addition to IMs
 	* Menu item to view log (Tom Samstag)
 	* Conversation and Chat sizes automatically saved (Stu Tomlinson)
+	* Added support for Novell privacy settings (Mike Stoddard of Novell)
+	* Added ability to initiate multi-user conferences (chats) in Novell (Mike
+	  Stoddard of Novell)
 
 	Bug Fixes:
+	* Novell 64bit fixes, better error messages, and buddy list sync fixes
+	  (Mike Stoddard of Novell)
 	* Compiles again with gcc 2.96 (Ignacio J. Elia)
 	* Gtk2.0 compatibility fixes (Tim Ringenbach)
 	* Massive rewrite of MSN support, which should fix a number of issues
--- a/src/protocols/novell/nmconference.c	Sat May 15 06:24:52 2004 +0000
+++ b/src/protocols/novell/nmconference.c	Sat May 15 14:00:31 2004 +0000
@@ -1,22 +1,20 @@
 /*
  * nmconference.c
  *
- * Copyright © 2004 Unpublished Work of Novell, Inc. All Rights Reserved.
+ * Copyright (c) 2004 Novell, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
  *
- * THIS WORK IS AN UNPUBLISHED WORK OF NOVELL, INC. NO PART OF THIS WORK MAY BE
- * USED, PRACTICED, PERFORMED, COPIED, DISTRIBUTED, REVISED, MODIFIED,
- * TRANSLATED, ABRIDGED, CONDENSED, EXPANDED, COLLECTED, COMPILED, LINKED,
- * RECAST, TRANSFORMED OR ADAPTED WITHOUT THE PRIOR WRITTEN CONSENT OF NOVELL,
- * INC. ANY USE OR EXPLOITATION OF THIS WORK WITHOUT AUTHORIZATION COULD SUBJECT
- * THE PERPETRATOR TO CRIMINAL AND CIVIL LIABILITY.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
  *
- * AS BETWEEN [GAIM] AND NOVELL, NOVELL GRANTS [GAIM] THE RIGHT TO REPUBLISH
- * THIS WORK UNDER THE GPL (GNU GENERAL PUBLIC LICENSE) WITH ALL RIGHTS AND
- * LICENSES THEREUNDER.  IF YOU HAVE RECEIVED THIS WORK DIRECTLY OR INDIRECTLY
- * FROM [GAIM] AS PART OF SUCH A REPUBLICATION, YOU HAVE ALL RIGHTS AND LICENSES
- * GRANTED BY [GAIM] UNDER THE GPL.  IN CONNECTION WITH SUCH A REPUBLICATION, IF
- * ANYTHING IN THIS NOTICE CONFLICTS WITH THE TERMS OF THE GPL, SUCH TERMS
- * PREVAIL.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA	02111-1307	USA
  *
  */
 
@@ -63,8 +61,8 @@
 	conf->ref_count = 1;
 
 	gaim_debug(GAIM_DEBUG_INFO, "novell",
-			   "Creating a conference 0x%x, total=%d\n",
-			   (guint32) conf, conf_count++);
+			   "Creating a conference %p, total=%d\n",
+			   conf, conf_count++);
 
 	return conf;
 }
@@ -75,13 +73,13 @@
 	GSList *node;
 
 	gaim_debug(GAIM_DEBUG_INFO, "novell",
-			   "In release conference 0x%x, refs=%d\n",
-			   (guint32) conference, conference->ref_count);
+			   "In release conference %p, refs=%d\n",
+			   conference, conference->ref_count);
 	if (conference != NULL && (--conference->ref_count == 0)) {
 
 		gaim_debug(GAIM_DEBUG_INFO, "novell",
-				   "Releasing conference 0x%x, total=%d\n",
-				   (guint32) conference, --conf_count);
+				   "Releasing conference %p, total=%d\n",
+				   conference, --conf_count);
 
 		if (conference->guid)
 			g_free(conference->guid);
--- a/src/protocols/novell/nmconference.h	Sat May 15 06:24:52 2004 +0000
+++ b/src/protocols/novell/nmconference.h	Sat May 15 14:00:31 2004 +0000
@@ -1,22 +1,20 @@
 /*
  * nmconference.h
  *
- * Copyright © 2004 Unpublished Work of Novell, Inc. All Rights Reserved.
+ * Copyright (c) 2004 Novell, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
  *
- * THIS WORK IS AN UNPUBLISHED WORK OF NOVELL, INC. NO PART OF THIS WORK MAY BE
- * USED, PRACTICED, PERFORMED, COPIED, DISTRIBUTED, REVISED, MODIFIED,
- * TRANSLATED, ABRIDGED, CONDENSED, EXPANDED, COLLECTED, COMPILED, LINKED,
- * RECAST, TRANSFORMED OR ADAPTED WITHOUT THE PRIOR WRITTEN CONSENT OF NOVELL,
- * INC. ANY USE OR EXPLOITATION OF THIS WORK WITHOUT AUTHORIZATION COULD SUBJECT
- * THE PERPETRATOR TO CRIMINAL AND CIVIL LIABILITY.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
  *
- * AS BETWEEN [GAIM] AND NOVELL, NOVELL GRANTS [GAIM] THE RIGHT TO REPUBLISH
- * THIS WORK UNDER THE GPL (GNU GENERAL PUBLIC LICENSE) WITH ALL RIGHTS AND
- * LICENSES THEREUNDER.  IF YOU HAVE RECEIVED THIS WORK DIRECTLY OR INDIRECTLY
- * FROM [GAIM] AS PART OF SUCH A REPUBLICATION, YOU HAVE ALL RIGHTS AND LICENSES
- * GRANTED BY [GAIM] UNDER THE GPL.  IN CONNECTION WITH SUCH A REPUBLICATION, IF
- * ANYTHING IN THIS NOTICE CONFLICTS WITH THE TERMS OF THE GPL, SUCH TERMS
- * PREVAIL.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA	02111-1307	USA
  *
  */
 
--- a/src/protocols/novell/nmconn.c	Sat May 15 06:24:52 2004 +0000
+++ b/src/protocols/novell/nmconn.c	Sat May 15 14:00:31 2004 +0000
@@ -1,22 +1,20 @@
 /*
  * nmconn.c
  *
- * Copyright © 2004 Unpublished Work of Novell, Inc. All Rights Reserved.
+ * Copyright (c) 2004 Novell, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
  *
- * THIS WORK IS AN UNPUBLISHED WORK OF NOVELL, INC. NO PART OF THIS WORK MAY BE
- * USED, PRACTICED, PERFORMED, COPIED, DISTRIBUTED, REVISED, MODIFIED,
- * TRANSLATED, ABRIDGED, CONDENSED, EXPANDED, COLLECTED, COMPILED, LINKED,
- * RECAST, TRANSFORMED OR ADAPTED WITHOUT THE PRIOR WRITTEN CONSENT OF NOVELL,
- * INC. ANY USE OR EXPLOITATION OF THIS WORK WITHOUT AUTHORIZATION COULD SUBJECT
- * THE PERPETRATOR TO CRIMINAL AND CIVIL LIABILITY.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
  *
- * AS BETWEEN [GAIM] AND NOVELL, NOVELL GRANTS [GAIM] THE RIGHT TO REPUBLISH
- * THIS WORK UNDER THE GPL (GNU GENERAL PUBLIC LICENSE) WITH ALL RIGHTS AND
- * LICENSES THEREUNDER.  IF YOU HAVE RECEIVED THIS WORK DIRECTLY OR INDIRECTLY
- * FROM [GAIM] AS PART OF SUCH A REPUBLICATION, YOU HAVE ALL RIGHTS AND LICENSES
- * GRANTED BY [GAIM] UNDER THE GPL.  IN CONNECTION WITH SUCH A REPUBLICATION, IF
- * ANYTHING IN THIS NOTICE CONFLICTS WITH THE TERMS OF THE GPL, SUCH TERMS
- * PREVAIL.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA	02111-1307	USA
  *
  */
 
@@ -310,7 +308,7 @@
 				case NMFIELD_TYPE_UTF8:
 				case NMFIELD_TYPE_DN:
 
-					value = url_escape_string((char *) field->value);
+					value = url_escape_string((char *) field->ptr_value);
 					bytes_to_send = g_snprintf(buffer, sizeof(buffer),
 											   "&val=%s", value);
 					if (bytes_to_send > (int)sizeof(buffer)) {
@@ -330,7 +328,7 @@
 				case NMFIELD_TYPE_ARRAY:
 				case NMFIELD_TYPE_MV:
 
-					val = nm_count_fields((NMField *) field->value);
+					val = nm_count_fields((NMField *) field->ptr_value);
 					bytes_to_send = g_snprintf(buffer, sizeof(buffer),
 											   "&val=%u", val);
 					ret = nm_tcp_write(conn, buffer, bytes_to_send);
@@ -368,7 +366,7 @@
 			if (field->type == NMFIELD_TYPE_ARRAY ||
 				field->type == NMFIELD_TYPE_MV) {
 
-				rc = nm_write_fields(conn, (NMField *) field->value);
+				rc = nm_write_fields(conn, (NMField *) field->ptr_value);
 
 			}
 		}
@@ -421,9 +419,9 @@
 		if (request) {
 			char *str = g_strdup_printf("%d", ++(conn->trans_id));
 
-			request = nm_add_field(request, NM_A_SZ_TRANSACTION_ID, 0,
-								   NMFIELD_METHOD_VALID, 0,
-								   (guint32) str, NMFIELD_TYPE_UTF8);
+			request = nm_field_add_pointer(request, NM_A_SZ_TRANSACTION_ID, 0,
+										   NMFIELD_METHOD_VALID, 0,
+										   str, NMFIELD_TYPE_UTF8);
 		}
 	}
 
@@ -493,11 +491,8 @@
 		rc = read_line(conn, buffer, sizeof(buffer));
 	}
 
-	if (rc == NM_OK && rtn_code == 301) {
-		conn->use_ssl = TRUE;
-		conn->redirect = TRUE;
-		rc = NMERR_SSL_REDIRECT;
-	}
+	if (rc == NM_OK && rtn_code == 301)
+		rc = NMERR_SERVER_REDIRECT;
 
 	return rc;
 }
@@ -522,11 +517,11 @@
 		}
 
 		/* Read the field type, method, and tag */
-		rc = nm_read_all(conn, &type, sizeof(type));
+		rc = nm_read_all(conn, (char *)&type, sizeof(type));
 		if (rc != NM_OK || type == 0)
 			break;
 
-		rc = nm_read_all(conn, &method, sizeof(method));
+		rc = nm_read_all(conn, (char *)&method, sizeof(method));
 		if (rc != NM_OK)
 			break;
 
@@ -556,8 +551,8 @@
 					break;
 			}
 
-			*fields = nm_add_field(*fields, tag, 0, method, 0,
-								   (guint32) sub_fields, type);
+			*fields = nm_field_add_pointer(*fields, tag, 0, method,
+									   0, sub_fields, type);
 
 			sub_fields = NULL;
 
@@ -580,8 +575,8 @@
 				if (rc != NM_OK)
 					break;
 
-				*fields = nm_add_field(*fields, tag, 0, method, 0,
-									   (guint32) str, type);
+				*fields = nm_field_add_pointer(*fields, tag, 0, method,
+											   0, str, type);
 				str = NULL;
 			}
 
@@ -592,7 +587,8 @@
 			if (rc != NM_OK)
 				break;
 
-			*fields = nm_add_field(*fields, tag, 0, method, 0, val, type);
+			*fields = nm_field_add_number(*fields, tag, 0, method,
+										  0, val, type);
 		}
 
 	} while ((type != 0) && (count != 0));
--- a/src/protocols/novell/nmconn.h	Sat May 15 06:24:52 2004 +0000
+++ b/src/protocols/novell/nmconn.h	Sat May 15 14:00:31 2004 +0000
@@ -1,22 +1,20 @@
 /*
  * nmconn.h
  *
- * Copyright © 2004 Unpublished Work of Novell, Inc. All Rights Reserved.
+ * Copyright (c) 2004 Novell, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
  *
- * THIS WORK IS AN UNPUBLISHED WORK OF NOVELL, INC. NO PART OF THIS WORK MAY BE
- * USED, PRACTICED, PERFORMED, COPIED, DISTRIBUTED, REVISED, MODIFIED,
- * TRANSLATED, ABRIDGED, CONDENSED, EXPANDED, COLLECTED, COMPILED, LINKED,
- * RECAST, TRANSFORMED OR ADAPTED WITHOUT THE PRIOR WRITTEN CONSENT OF NOVELL,
- * INC. ANY USE OR EXPLOITATION OF THIS WORK WITHOUT AUTHORIZATION COULD SUBJECT
- * THE PERPETRATOR TO CRIMINAL AND CIVIL LIABILITY.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
  *
- * AS BETWEEN [GAIM] AND NOVELL, NOVELL GRANTS [GAIM] THE RIGHT TO REPUBLISH
- * THIS WORK UNDER THE GPL (GNU GENERAL PUBLIC LICENSE) WITH ALL RIGHTS AND
- * LICENSES THEREUNDER.  IF YOU HAVE RECEIVED THIS WORK DIRECTLY OR INDIRECTLY
- * FROM [GAIM] AS PART OF SUCH A REPUBLICATION, YOU HAVE ALL RIGHTS AND LICENSES
- * GRANTED BY [GAIM] UNDER THE GPL.  IN CONNECTION WITH SUCH A REPUBLICATION, IF
- * ANYTHING IN THIS NOTICE CONFLICTS WITH THE TERMS OF THE GPL, SUCH TERMS
- * PREVAIL.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA	02111-1307	USA
  *
  */
 
--- a/src/protocols/novell/nmcontact.c	Sat May 15 06:24:52 2004 +0000
+++ b/src/protocols/novell/nmcontact.c	Sat May 15 14:00:31 2004 +0000
@@ -1,22 +1,20 @@
 /*
  * nmcontact.c
  *
- * Copyright © 2004 Unpublished Work of Novell, Inc. All Rights Reserved.
+ * Copyright (c) 2004 Novell, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
  *
- * THIS WORK IS AN UNPUBLISHED WORK OF NOVELL, INC. NO PART OF THIS WORK MAY BE
- * USED, PRACTICED, PERFORMED, COPIED, DISTRIBUTED, REVISED, MODIFIED,
- * TRANSLATED, ABRIDGED, CONDENSED, EXPANDED, COLLECTED, COMPILED, LINKED,
- * RECAST, TRANSFORMED OR ADAPTED WITHOUT THE PRIOR WRITTEN CONSENT OF NOVELL,
- * INC. ANY USE OR EXPLOITATION OF THIS WORK WITHOUT AUTHORIZATION COULD SUBJECT
- * THE PERPETRATOR TO CRIMINAL AND CIVIL LIABILITY.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
  *
- * AS BETWEEN [GAIM] AND NOVELL, NOVELL GRANTS [GAIM] THE RIGHT TO REPUBLISH
- * THIS WORK UNDER THE GPL (GNU GENERAL PUBLIC LICENSE) WITH ALL RIGHTS AND
- * LICENSES THEREUNDER.  IF YOU HAVE RECEIVED THIS WORK DIRECTLY OR INDIRECTLY
- * FROM [GAIM] AS PART OF SUCH A REPUBLICATION, YOU HAVE ALL RIGHTS AND LICENSES
- * GRANTED BY [GAIM] UNDER THE GPL.  IN CONNECTION WITH SUCH A REPUBLICATION, IF
- * ANYTHING IN THIS NOTICE CONFLICTS WITH THE TERMS OF THE GPL, SUCH TERMS
- * PREVAIL.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA	02111-1307	USA
  *
  */
 
@@ -84,7 +82,7 @@
 	NMContact *contact;
 	NMField *field;
 
-	if ( fields == NULL || fields->tag == NULL || fields->value == 0 ||
+	if ( fields == NULL || fields->tag == NULL || fields->ptr_value == 0 ||
 		 strcmp(fields->tag, NM_A_FA_CONTACT) )
 	{
 		return NULL;
@@ -92,40 +90,40 @@
 
 	contact = nm_create_contact();
 
-	if ((field = nm_locate_field(NM_A_SZ_OBJECT_ID, (NMField *) fields->value))) {
+	if ((field = nm_locate_field(NM_A_SZ_OBJECT_ID, (NMField *) fields->ptr_value))) {
 
-		if (field->value)
-			contact->id = atoi((char *) field->value);
+		if (field->ptr_value)
+			contact->id = atoi((char *) field->ptr_value);
 
 	}
 
-	if ((field = nm_locate_field(NM_A_SZ_PARENT_ID, (NMField *) fields->value))) {
+	if ((field = nm_locate_field(NM_A_SZ_PARENT_ID, (NMField *) fields->ptr_value))) {
 
-		if (field->value)
-			contact->parent_id = atoi((char *) field->value);
+		if (field->ptr_value)
+			contact->parent_id = atoi((char *) field->ptr_value);
 
 	}
 
 	if ((field =
-		 nm_locate_field(NM_A_SZ_SEQUENCE_NUMBER, (NMField *) fields->value))) {
+		 nm_locate_field(NM_A_SZ_SEQUENCE_NUMBER, (NMField *) fields->ptr_value))) {
 
-		if (field->value)
-			contact->seq = atoi((char *) field->value);
+		if (field->ptr_value)
+			contact->seq = atoi((char *) field->ptr_value);
 
 	}
 
 	if ((field =
-		 nm_locate_field(NM_A_SZ_DISPLAY_NAME, (NMField *) fields->value))) {
+		 nm_locate_field(NM_A_SZ_DISPLAY_NAME, (NMField *) fields->ptr_value))) {
 
-		if (field->value)
-			contact->display_name = g_strdup((char *) field->value);
+		if (field->ptr_value)
+			contact->display_name = g_strdup((char *) field->ptr_value);
 
 	}
 
-	if ((field = nm_locate_field(NM_A_SZ_DN, (NMField *) fields->value))) {
+	if ((field = nm_locate_field(NM_A_SZ_DN, (NMField *) fields->ptr_value))) {
 
-		if (field->value)
-			contact->dn = g_strdup((char *) field->value);
+		if (field->ptr_value)
+			contact->dn = g_strdup((char *) field->ptr_value);
 
 	}
 
@@ -137,50 +135,50 @@
 {
 	NMField *field;
 
-	if (contact == NULL || fields == NULL || fields->value == 0)
+	if (contact == NULL || fields == NULL || fields->ptr_value == 0)
 		return;
 
-	if ((field = nm_locate_field(NM_A_SZ_OBJECT_ID, (NMField *) fields->value))) {
+	if ((field = nm_locate_field(NM_A_SZ_OBJECT_ID, (NMField *) fields->ptr_value))) {
 
-		if (field->value)
-			contact->id = atoi((char *)field->value);
+		if (field->ptr_value)
+			contact->id = atoi((char *)field->ptr_value);
 
 	}
 
-	if ((field = nm_locate_field(NM_A_SZ_PARENT_ID, (NMField *) fields->value))) {
+	if ((field = nm_locate_field(NM_A_SZ_PARENT_ID, (NMField *) fields->ptr_value))) {
 
-		if (field->value)
-			contact->parent_id = atoi((char *) field->value);
+		if (field->ptr_value)
+			contact->parent_id = atoi((char *) field->ptr_value);
 
 	}
 
 	if ((field =
-		 nm_locate_field(NM_A_SZ_SEQUENCE_NUMBER, (NMField *) fields->value))) {
+		 nm_locate_field(NM_A_SZ_SEQUENCE_NUMBER, (NMField *) fields->ptr_value))) {
 
-		if (field->value)
-			contact->seq = atoi((char *) field->value);
+		if (field->ptr_value)
+			contact->seq = atoi((char *) field->ptr_value);
 
 	}
 
 	if ((field =
-		 nm_locate_field(NM_A_SZ_DISPLAY_NAME, (NMField *) fields->value))) {
+		 nm_locate_field(NM_A_SZ_DISPLAY_NAME, (NMField *) fields->ptr_value))) {
 
-		if (field->value) {
+		if (field->ptr_value) {
 			if (contact->display_name)
 				g_free(contact->display_name);
 
-			contact->display_name = g_strdup((char *) field->value);
+			contact->display_name = g_strdup((char *) field->ptr_value);
 		}
 
 	}
 
-	if ((field = nm_locate_field(NM_A_SZ_DN, (NMField *) fields->value))) {
+	if ((field = nm_locate_field(NM_A_SZ_DN, (NMField *) fields->ptr_value))) {
 
-		if (field->value) {
+		if (field->ptr_value) {
 			if (contact->dn)
 				g_free(contact->dn);
 
-			contact->dn = g_strdup((char *) field->value);
+			contact->dn = g_strdup((char *) field->ptr_value);
 		}
 
 	}
@@ -194,29 +192,23 @@
 	if (contact == NULL)
 		return NULL;
 
-	fields = nm_add_field(fields, NM_A_SZ_OBJECT_ID, 0, NMFIELD_METHOD_VALID, 0,
-						  (guint32) g_strdup_printf("%d", contact->id),
-						  NMFIELD_TYPE_UTF8);
+	fields = nm_field_add_pointer(fields, NM_A_SZ_OBJECT_ID, 0, NMFIELD_METHOD_VALID, 0,
+								  g_strdup_printf("%d", contact->id), NMFIELD_TYPE_UTF8);
 
-	fields = nm_add_field(fields, NM_A_SZ_PARENT_ID, 0, NMFIELD_METHOD_VALID, 0,
-						  (guint32) g_strdup_printf("%d", contact->parent_id),
-						  NMFIELD_TYPE_UTF8);
+	fields = nm_field_add_pointer(fields, NM_A_SZ_PARENT_ID, 0, NMFIELD_METHOD_VALID, 0,
+								  g_strdup_printf("%d", contact->parent_id), NMFIELD_TYPE_UTF8);
 
-	fields =
-		nm_add_field(fields, NM_A_SZ_SEQUENCE_NUMBER, 0, NMFIELD_METHOD_VALID, 0,
-					 (guint32) g_strdup_printf("%d", contact->seq),
-					 NMFIELD_TYPE_UTF8);
+	fields = nm_field_add_pointer(fields, NM_A_SZ_SEQUENCE_NUMBER, 0, NMFIELD_METHOD_VALID, 0,
+								  g_strdup_printf("%d", contact->seq), NMFIELD_TYPE_UTF8);
 
 	if (contact->display_name != NULL) {
-		fields =
-			nm_add_field(fields, NM_A_SZ_DISPLAY_NAME, 0, NMFIELD_METHOD_VALID, 0,
-						 (guint32) g_strdup(contact->display_name),
-						 NMFIELD_TYPE_UTF8);
+		fields = nm_field_add_pointer(fields, NM_A_SZ_DISPLAY_NAME, 0, NMFIELD_METHOD_VALID, 0,
+									  g_strdup(contact->display_name), NMFIELD_TYPE_UTF8);
 	}
 
 	if (contact->dn != NULL) {
-		fields = nm_add_field(fields, NM_A_SZ_DN, 0, NMFIELD_METHOD_VALID, 0,
-							  (guint32) g_strdup(contact->dn), NMFIELD_TYPE_UTF8);
+		fields = nm_field_add_pointer(fields, NM_A_SZ_DN, 0, NMFIELD_METHOD_VALID, 0,
+									  g_strdup(contact->dn), NMFIELD_TYPE_UTF8);
 	}
 
 	return fields;
@@ -466,29 +458,29 @@
 	NMField *field;
 	NMFolder *folder;
 
-	if (fields == NULL || fields->value == 0)
+	if (fields == NULL || fields->ptr_value == 0)
 		return NULL;
 
 	folder = g_new0(NMFolder, 1);
 
-	if ((field = nm_locate_field(NM_A_SZ_OBJECT_ID, (NMField *) fields->value))) {
+	if ((field = nm_locate_field(NM_A_SZ_OBJECT_ID, (NMField *) fields->ptr_value))) {
 
-		if (field->value)
-			folder->id = atoi((char *) field->value);
+		if (field->ptr_value)
+			folder->id = atoi((char *) field->ptr_value);
 	}
 
 	if ((field =
-		 nm_locate_field(NM_A_SZ_SEQUENCE_NUMBER, (NMField *) fields->value))) {
+		 nm_locate_field(NM_A_SZ_SEQUENCE_NUMBER, (NMField *) fields->ptr_value))) {
 
-		if (field->value)
-			folder->seq = atoi((char *) field->value);
+		if (field->ptr_value)
+			folder->seq = atoi((char *) field->ptr_value);
 	}
 
 	if ((field =
-		 nm_locate_field(NM_A_SZ_DISPLAY_NAME, (NMField *) fields->value))) {
+		 nm_locate_field(NM_A_SZ_DISPLAY_NAME, (NMField *) fields->ptr_value))) {
 
-		if (field->value)
-			folder->name = g_strdup((char *) field->value);
+		if (field->ptr_value)
+			folder->name = g_strdup((char *) field->ptr_value);
 	}
 
 	folder->ref_count = 1;
@@ -503,25 +495,21 @@
 	if (folder == NULL)
 		return NULL;
 
-	fields = nm_add_field(fields, NM_A_SZ_OBJECT_ID, 0, NMFIELD_METHOD_VALID, 0,
-						  (guint32) g_strdup_printf("%d", folder->id),
-						  NMFIELD_TYPE_UTF8);
+	fields = nm_field_add_pointer(fields, NM_A_SZ_OBJECT_ID, 0, NMFIELD_METHOD_VALID, 0,
+								  g_strdup_printf("%d", folder->id), NMFIELD_TYPE_UTF8);
 
-	fields = nm_add_field(fields, NM_A_SZ_PARENT_ID, 0, NMFIELD_METHOD_VALID, 0,
-						  (guint32) g_strdup("0"), NMFIELD_TYPE_UTF8);
+	fields = nm_field_add_pointer(fields, NM_A_SZ_PARENT_ID, 0, NMFIELD_METHOD_VALID, 0,
+								  g_strdup("0"), NMFIELD_TYPE_UTF8);
 
-	fields = nm_add_field(fields, NM_A_SZ_TYPE, 0, NMFIELD_METHOD_VALID, 0,
-						  (guint32) g_strdup("1"), NMFIELD_TYPE_UTF8);
+	fields = nm_field_add_pointer(fields, NM_A_SZ_TYPE, 0, NMFIELD_METHOD_VALID, 0,
+								  g_strdup("1"), NMFIELD_TYPE_UTF8);
 
-	fields =
-		nm_add_field(fields, NM_A_SZ_SEQUENCE_NUMBER, 0, NMFIELD_METHOD_VALID, 0,
-					 (guint32) g_strdup_printf("%d", folder->seq),
-					 NMFIELD_TYPE_UTF8);
+	fields = nm_field_add_pointer(fields, NM_A_SZ_SEQUENCE_NUMBER, 0, NMFIELD_METHOD_VALID, 0,
+								  g_strdup_printf("%d", folder->seq), NMFIELD_TYPE_UTF8);
 
 	if (folder->name != NULL) {
-		fields =
-			nm_add_field(fields, NM_A_SZ_DISPLAY_NAME, 0, NMFIELD_METHOD_VALID, 0,
-						 (guint32) g_strdup(folder->name), NMFIELD_TYPE_UTF8);
+		fields = nm_field_add_pointer(fields, NM_A_SZ_DISPLAY_NAME, 0, NMFIELD_METHOD_VALID, 0,
+									  g_strdup(folder->name), NMFIELD_TYPE_UTF8);
 	}
 
 
@@ -533,32 +521,32 @@
 {
 	NMField *field;
 
-	if (folder == NULL || fields == NULL || fields->value == 0)
+	if (folder == NULL || fields == NULL || fields->ptr_value == 0)
 		return;
 
-	if ((field = nm_locate_field(NM_A_SZ_OBJECT_ID, (NMField *) fields->value))) {
+	if ((field = nm_locate_field(NM_A_SZ_OBJECT_ID, (NMField *) fields->ptr_value))) {
 
-		if (field->value)
-			folder->id = atoi((char *) field->value);
+		if (field->ptr_value)
+			folder->id = atoi((char *) field->ptr_value);
 
 	}
 
 	if ((field =
-		 nm_locate_field(NM_A_SZ_SEQUENCE_NUMBER, (NMField *) fields->value))) {
+		 nm_locate_field(NM_A_SZ_SEQUENCE_NUMBER, (NMField *) fields->ptr_value))) {
 
-		if (field->value)
-			folder->seq = atoi((char *) field->value);
+		if (field->ptr_value)
+			folder->seq = atoi((char *) field->ptr_value);
 
 	}
 
 	if ((field =
-		 nm_locate_field(NM_A_SZ_DISPLAY_NAME, (NMField *) fields->value))) {
+		 nm_locate_field(NM_A_SZ_DISPLAY_NAME, (NMField *) fields->ptr_value))) {
 
-		if (field->value) {
+		if (field->ptr_value) {
 			if (folder->name)
 				g_free(folder->name);
 
-			folder->name = g_strdup((char *) field->value);
+			folder->name = g_strdup((char *) field->ptr_value);
 		}
 
 	}
@@ -707,7 +695,6 @@
 		return;
 
 	node = folder->contacts;
-
 	while (node) {
 		if (contact->id == ((NMContact *) (node->data))->id) {
 			folder->contacts = g_slist_remove(folder->contacts, node->data);
@@ -841,6 +828,27 @@
 }
 
 NMContact *
+nm_folder_find_contact_by_display_id(NMFolder * folder, const char *display_id)
+{
+	int cnt, i;
+	NMContact *tmp, *contact = NULL;
+
+	if (folder == NULL || display_id == NULL)
+		return NULL;
+
+	cnt = nm_folder_get_contact_count(folder);
+	for (i = 0; i < cnt; i++) {
+		tmp = nm_folder_get_contact(folder, i);
+		if (tmp && nm_utf8_str_equal(nm_contact_get_display_id(tmp), display_id)) {
+			contact = tmp;
+			break;
+		}
+	}
+
+	return contact;
+}
+
+NMContact *
 nm_folder_find_contact(NMFolder * folder, const char *dn)
 {
 	int cnt, i;
@@ -946,7 +954,7 @@
 
 		/* Update the user record cache */
 		if ((details = nm_locate_field(NM_A_FA_USER_DETAILS,
-									   (NMField *) locate->value))) {
+									   (NMField *) locate->ptr_value))) {
 			user_record = nm_find_user_record(user, nm_contact_get_dn(contact));
 			if (user_record == NULL) {
 				user_record = nm_create_user_record_from_fields(details);
--- a/src/protocols/novell/nmcontact.h	Sat May 15 06:24:52 2004 +0000
+++ b/src/protocols/novell/nmcontact.h	Sat May 15 14:00:31 2004 +0000
@@ -1,22 +1,20 @@
 /*
  * nmcontact.h
  *
- * Copyright © 2004 Unpublished Work of Novell, Inc. All Rights Reserved.
+ * Copyright (c) 2004 Novell, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
  *
- * THIS WORK IS AN UNPUBLISHED WORK OF NOVELL, INC. NO PART OF THIS WORK MAY BE
- * USED, PRACTICED, PERFORMED, COPIED, DISTRIBUTED, REVISED, MODIFIED,
- * TRANSLATED, ABRIDGED, CONDENSED, EXPANDED, COLLECTED, COMPILED, LINKED,
- * RECAST, TRANSFORMED OR ADAPTED WITHOUT THE PRIOR WRITTEN CONSENT OF NOVELL,
- * INC. ANY USE OR EXPLOITATION OF THIS WORK WITHOUT AUTHORIZATION COULD SUBJECT
- * THE PERPETRATOR TO CRIMINAL AND CIVIL LIABILITY.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
  *
- * AS BETWEEN [GAIM] AND NOVELL, NOVELL GRANTS [GAIM] THE RIGHT TO REPUBLISH
- * THIS WORK UNDER THE GPL (GNU GENERAL PUBLIC LICENSE) WITH ALL RIGHTS AND
- * LICENSES THEREUNDER.  IF YOU HAVE RECEIVED THIS WORK DIRECTLY OR INDIRECTLY
- * FROM [GAIM] AS PART OF SUCH A REPUBLICATION, YOU HAVE ALL RIGHTS AND LICENSES
- * GRANTED BY [GAIM] UNDER THE GPL.  IN CONNECTION WITH SUCH A REPUBLICATION, IF
- * ANYTHING IN THIS NOTICE CONFLICTS WITH THE TERMS OF THE GPL, SUCH TERMS
- * PREVAIL.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA	02111-1307	USA
  *
  */
 
@@ -391,6 +389,19 @@
  */
 NMContact *nm_folder_find_contact_by_userid(NMFolder * folder,
 											const char *userid);
+
+/**
+ * Find a contact in a folder by display id
+ *
+ * @param	folder		The folder to search
+ * @param	display_id	The userid of the contact to find
+ *
+ * @return	The contact if found, NULL otherwise
+ *
+ */
+NMContact *
+nm_folder_find_contact_by_display_id(NMFolder * folder, const char *display_id);
+
 /**
  * Return a field array (NM_A_FA_FOLDER) representing the folder
  *
--- a/src/protocols/novell/nmevent.c	Sat May 15 06:24:52 2004 +0000
+++ b/src/protocols/novell/nmevent.c	Sat May 15 14:00:31 2004 +0000
@@ -1,22 +1,20 @@
 /*
  * nmevent.c
  *
- * Copyright © 2004 Unpublished Work of Novell, Inc. All Rights Reserved.
+ * Copyright (c) 2004 Novell, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
  *
- * THIS WORK IS AN UNPUBLISHED WORK OF NOVELL, INC. NO PART OF THIS WORK MAY BE
- * USED, PRACTICED, PERFORMED, COPIED, DISTRIBUTED, REVISED, MODIFIED,
- * TRANSLATED, ABRIDGED, CONDENSED, EXPANDED, COLLECTED, COMPILED, LINKED,
- * RECAST, TRANSFORMED OR ADAPTED WITHOUT THE PRIOR WRITTEN CONSENT OF NOVELL,
- * INC. ANY USE OR EXPLOITATION OF THIS WORK WITHOUT AUTHORIZATION COULD SUBJECT
- * THE PERPETRATOR TO CRIMINAL AND CIVIL LIABILITY.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
  *
- * AS BETWEEN [GAIM] AND NOVELL, NOVELL GRANTS [GAIM] THE RIGHT TO REPUBLISH
- * THIS WORK UNDER THE GPL (GNU GENERAL PUBLIC LICENSE) WITH ALL RIGHTS AND
- * LICENSES THEREUNDER.  IF YOU HAVE RECEIVED THIS WORK DIRECTLY OR INDIRECTLY
- * FROM [GAIM] AS PART OF SUCH A REPUBLICATION, YOU HAVE ALL RIGHTS AND LICENSES
- * GRANTED BY [GAIM] UNDER THE GPL.  IN CONNECTION WITH SUCH A REPUBLICATION, IF
- * ANYTHING IN THIS NOTICE CONFLICTS WITH THE TERMS OF THE GPL, SUCH TERMS
- * PREVAIL.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA	02111-1307	USA
  *
  */
 
@@ -591,6 +589,8 @@
 			/* Add the new user to the participants list */
 			user_record = nm_find_user_record(user, nm_event_get_source(event));
 			if (user_record) {
+				nm_conference_remove_participant(conference,
+												 nm_user_record_get_dn(user_record));
 				nm_conference_add_participant(conference, user_record);
 			} else {
 
--- a/src/protocols/novell/nmevent.h	Sat May 15 06:24:52 2004 +0000
+++ b/src/protocols/novell/nmevent.h	Sat May 15 14:00:31 2004 +0000
@@ -1,22 +1,20 @@
 /*
  * nmevent.h
  *
- * Copyright © 2004 Unpublished Work of Novell, Inc. All Rights Reserved.
+ * Copyright (c) 2004 Novell, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
  *
- * THIS WORK IS AN UNPUBLISHED WORK OF NOVELL, INC. NO PART OF THIS WORK MAY BE
- * USED, PRACTICED, PERFORMED, COPIED, DISTRIBUTED, REVISED, MODIFIED,
- * TRANSLATED, ABRIDGED, CONDENSED, EXPANDED, COLLECTED, COMPILED, LINKED,
- * RECAST, TRANSFORMED OR ADAPTED WITHOUT THE PRIOR WRITTEN CONSENT OF NOVELL,
- * INC. ANY USE OR EXPLOITATION OF THIS WORK WITHOUT AUTHORIZATION COULD SUBJECT
- * THE PERPETRATOR TO CRIMINAL AND CIVIL LIABILITY.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
  *
- * AS BETWEEN [GAIM] AND NOVELL, NOVELL GRANTS [GAIM] THE RIGHT TO REPUBLISH
- * THIS WORK UNDER THE GPL (GNU GENERAL PUBLIC LICENSE) WITH ALL RIGHTS AND
- * LICENSES THEREUNDER.  IF YOU HAVE RECEIVED THIS WORK DIRECTLY OR INDIRECTLY
- * FROM [GAIM] AS PART OF SUCH A REPUBLICATION, YOU HAVE ALL RIGHTS AND LICENSES
- * GRANTED BY [GAIM] UNDER THE GPL.  IN CONNECTION WITH SUCH A REPUBLICATION, IF
- * ANYTHING IN THIS NOTICE CONFLICTS WITH THE TERMS OF THE GPL, SUCH TERMS
- * PREVAIL.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA	02111-1307	USA
  *
  */
 
--- a/src/protocols/novell/nmfield.c	Sat May 15 06:24:52 2004 +0000
+++ b/src/protocols/novell/nmfield.c	Sat May 15 14:00:31 2004 +0000
@@ -1,21 +1,20 @@
 /*
  * nmfield.c
  *
- * Copyright © 2004 Unpublished Work of Novell, Inc. All Rights Reserved.
+ * Copyright (c) 2004 Novell, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
  *
- * THIS WORK IS AN UNPUBLISHED WORK OF NOVELL, INC. NO PART OF THIS WORK MAY BE
- * USED, PRACTICED, PERFORMED, COPIED, DISTRIBUTED, REVISED, MODIFIED, TRANSLATED,
- * ABRIDGED, CONDENSED, EXPANDED, COLLECTED, COMPILED, LINKED, RECAST, TRANSFORMED
- * OR ADAPTED WITHOUT THE PRIOR WRITTEN CONSENT OF NOVELL, INC. ANY USE OR
- * EXPLOITATION OF THIS WORK WITHOUT AUTHORIZATION COULD SUBJECT THE PERPETRATOR
- * TO CRIMINAL AND CIVIL LIABILITY.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
  *
- * AS BETWEEN [GAIM] AND NOVELL, NOVELL GRANTS [GAIM] THE RIGHT TO REPUBLISH THIS
- * WORK UNDER THE GPL (GNU GENERAL PUBLIC LICENSE) WITH ALL RIGHTS AND LICENSES
- * THEREUNDER.  IF YOU HAVE RECEIVED THIS WORK DIRECTLY OR INDIRECTLY FROM [GAIM]
- * AS PART OF SUCH A REPUBLICATION, YOU HAVE ALL RIGHTS AND LICENSES GRANTED BY
- * [GAIM] UNDER THE GPL.  IN CONNECTION WITH SUCH A REPUBLICATION, IF ANYTHING IN
- * THIS NOTICE CONFLICTS WITH THE TERMS OF THE GPL, SUCH TERMS PREVAIL.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA	02111-1307	USA
  *
  */
 
@@ -38,25 +37,33 @@
 /* Create a string from a value -- for debugging */
 static char *_value_to_string(NMField * field);
 
-NMField *
-nm_add_field(NMField * fields, char *tag, guint32 size, guint8 method,
-			 guint8 flags, guint32 value, guint8 type)
+static NMField *
+_add_blank_field(NMField *fields, guint32 count)
 {
-	guint32 count, new_len;
-	NMField *field = NULL;
+	guint32 new_len;
 
 	if (fields == NULL) {
 		fields = g_new0(NMField, 10);
 		fields->len = 10;
-		count = 0;
 	} else {
-		count = nm_count_fields(fields);
 		if (fields->len < count + 2) {
 			new_len = count + 10;
 			fields = g_realloc(fields, new_len * sizeof(NMField));
 			fields->len = new_len;
 		}
 	}
+	return fields;
+}
+
+NMField *
+nm_field_add_number(NMField * fields, const char *tag, guint32 size, guint8 method,
+					guint8 flags, guint32 value, guint8 type)
+{
+	guint32 count;
+	NMField *field;
+
+	count = nm_count_fields(fields);
+	fields = _add_blank_field(fields, count);
 
 	field = &(fields[count]);
 	field->tag = g_strdup(tag);
@@ -70,6 +77,34 @@
 	field = &((fields)[count + 1]);
 	field->tag = NULL;
 	field->value = 0;
+	field->ptr_value = NULL;
+
+	return fields;
+}
+
+NMField *
+nm_field_add_pointer(NMField * fields, const char *tag, guint32 size, guint8 method,
+					 guint8 flags, gpointer value, guint8 type)
+{
+	guint32 count;
+	NMField *field = NULL;
+
+	count = nm_count_fields(fields);
+	fields = _add_blank_field(fields, count);
+
+	field = &(fields[count]);
+	field->tag = g_strdup(tag);
+	field->size = size;
+	field->method = method;
+	field->flags = flags;
+	field->ptr_value = value;
+	field->type = type;
+
+	/* Null terminate the field array */
+	field = &((fields)[count + 1]);
+	field->tag = NULL;
+	field->value = 0;
+	field->ptr_value = NULL;
 
 	return fields;
 }
@@ -126,25 +161,25 @@
 		return;
 
 	switch (field->type) {
-	case NMFIELD_TYPE_BINARY:
-	case NMFIELD_TYPE_UTF8:
-	case NMFIELD_TYPE_DN:
-		if ((gpointer) field->value != NULL) {
-			g_free((gpointer) field->value);
-		}
-		break;
+		case NMFIELD_TYPE_BINARY:
+		case NMFIELD_TYPE_UTF8:
+		case NMFIELD_TYPE_DN:
+			if (field->ptr_value != NULL) {
+				g_free(field->ptr_value);
+			}
+			break;
 
-	case NMFIELD_TYPE_ARRAY:
-	case NMFIELD_TYPE_MV:
-		nm_free_fields((NMField **) & field->value);
-		break;
+		case NMFIELD_TYPE_ARRAY:
+		case NMFIELD_TYPE_MV:
+			nm_free_fields((NMField **)&field->ptr_value);
+			break;
 
-	default:
-		break;
+		default:
+			break;
 	}
 
 	field->size = 0;
-	field->value = 0;
+	field->ptr_value = NULL;
 }
 
 NMField *
@@ -204,30 +239,28 @@
 {
 	dest->type = src->type;
 	switch (dest->type) {
-	case NMFIELD_TYPE_UTF8:
-	case NMFIELD_TYPE_DN:
-		if (src->size == 0 && src->value != 0) {
-			src->size = strlen((char *) src->value) + 1;
-		}
-		/* fall through */
-	case NMFIELD_TYPE_BINARY:
-		if (src->size != 0 && src->value != 0) {
-			dest->value = (guint32) g_new0(char, src->size);
+		case NMFIELD_TYPE_UTF8:
+		case NMFIELD_TYPE_DN:
+			if (src->size == 0 && src->ptr_value != NULL) {
+				src->size = strlen((char *) src->ptr_value) + 1;
+			}
+			/* fall through */
+		case NMFIELD_TYPE_BINARY:
+			if (src->size != 0 && src->ptr_value != NULL) {
+				dest->ptr_value = g_new0(char, src->size);
+				memcpy(dest->ptr_value, src->ptr_value, src->size);
+			}
+			break;
 
-			memcpy((gpointer) dest->value, (gpointer) src->value, src->size);
-		}
-		break;
+		case NMFIELD_TYPE_ARRAY:
+		case NMFIELD_TYPE_MV:
+			dest->ptr_value = nm_copy_field_array((NMField *)src->ptr_value);
+			break;
 
-	case NMFIELD_TYPE_ARRAY:
-	case NMFIELD_TYPE_MV:
-		dest->value = 0;
-		dest->value = (guint32) nm_copy_field_array((NMField *) src->value);
-		break;
-
-	default:
-		/* numeric value */
-		dest->value = src->value;
-		break;
+		default:
+			/* numeric value */
+			dest->value = src->value;
+			break;
 	}
 
 	dest->size = src->size;
@@ -273,7 +306,7 @@
 	while (field->tag != NULL) {
 		if (field->type == NMFIELD_TYPE_ARRAY || field->type == NMFIELD_TYPE_MV) {
 			printf("Subarray START: %s Method = %d\n", field->tag, field->method);
-			nm_print_fields((NMField *) field->value);
+			nm_print_fields((NMField *) field->ptr_value);
 			printf("Subarray END: %s\n", field->tag);
 		} else {
 			str = _value_to_string(field);
@@ -296,12 +329,11 @@
 
 	/* This is a single value attribute */
 	if (((field->type == NMFIELD_TYPE_UTF8) ||
-		 (field->type == NMFIELD_TYPE_DN)) && (field->value != 0)) {
-		value = g_strdup((const char *) field->value);
-	} else if (field->type == NMFIELD_TYPE_BINARY && field->value != 0) {
+		 (field->type == NMFIELD_TYPE_DN)) && (field->ptr_value != NULL)) {
+		value = g_strdup((const char *) field->ptr_value);
+	} else if (field->type == NMFIELD_TYPE_BINARY && field->ptr_value != NULL) {
 		value = g_new0(char, field->size);
-
-		memcpy(value, (const char *) field->value, field->size);
+		memcpy(value, (const char *) field->ptr_value, field->size);
 	} else if (field->type == NMFIELD_TYPE_BOOL) {
 		if (field->value) {
 			value = g_strdup(NM_FIELD_TRUE);
--- a/src/protocols/novell/nmfield.h	Sat May 15 06:24:52 2004 +0000
+++ b/src/protocols/novell/nmfield.h	Sat May 15 14:00:31 2004 +0000
@@ -1,22 +1,20 @@
 /*
  * nmfield.h
  *
- * Copyright © 2004 Unpublished Work of Novell, Inc. All Rights Reserved.
+ * Copyright (c) 2004 Novell, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
  *
- * THIS WORK IS AN UNPUBLISHED WORK OF NOVELL, INC. NO PART OF THIS WORK MAY BE
- * USED, PRACTICED, PERFORMED, COPIED, DISTRIBUTED, REVISED, MODIFIED,
- * TRANSLATED, ABRIDGED, CONDENSED, EXPANDED, COLLECTED, COMPILED, LINKED,
- * RECAST, TRANSFORMED OR ADAPTED WITHOUT THE PRIOR WRITTEN CONSENT OF NOVELL,
- * INC. ANY USE OR EXPLOITATION OF THIS WORK WITHOUT AUTHORIZATION COULD SUBJECT
- * THE PERPETRATOR TO CRIMINAL AND CIVIL LIABILITY.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
  *
- * AS BETWEEN [GAIM] AND NOVELL, NOVELL GRANTS [GAIM] THE RIGHT TO REPUBLISH
- * THIS WORK UNDER THE GPL (GNU GENERAL PUBLIC LICENSE) WITH ALL RIGHTS AND
- * LICENSES THEREUNDER.  IF YOU HAVE RECEIVED THIS WORK DIRECTLY OR INDIRECTLY
- * FROM [GAIM] AS PART OF SUCH A REPUBLICATION, YOU HAVE ALL RIGHTS AND LICENSES
- * GRANTED BY [GAIM] UNDER THE GPL.  IN CONNECTION WITH SUCH A REPUBLICATION, IF
- * ANYTHING IN THIS NOTICE CONFLICTS WITH THE TERMS OF THE GPL, SUCH TERMS
- * PREVAIL.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA	02111-1307	USA
  *
  */
 
@@ -28,19 +26,13 @@
 typedef struct NMField_t
 {
 	char *tag;				/* Field tag */
-
 	guint8 method;			/* Method of the field */
-
 	guint8 flags;			/* Flags */
-
 	guint8 type;			/* Type of value */
-
 	guint32 size;			/* Size of value if binary */
-
-	guint32 value;			/* Value of field */
-
+	guint32 value;			/* Value of a numeric field */
+	gpointer ptr_value;		/* Value of a string or sub array field */
 	guint32 len;			/* Length of the array */
-
 } NMField;
 
 /* Field types */
@@ -120,6 +112,12 @@
 #define	NM_A_SZ_AUTH_ATTRIBUTE			"NM_A_SZ_AUTH_ATTRIBUTE"
 #define	NM_A_UD_KEEPALIVE				"NM_A_UD_KEEPALIVE"
 #define NM_A_SZ_USER_AGENT				"NM_A_SZ_USER_AGENT"
+#define NM_A_BLOCKING					"nnmBlocking"
+#define NM_A_BLOCKING_DENY_LIST			"nnmBlockingDenyList"
+#define NM_A_BLOCKING_ALLOW_LIST		"nnmBlockingAllowList"
+#define	NM_A_SZ_BLOCKING_ALLOW_ITEM		"NM_A_SZ_BLOCKING_ALLOW_ITEM"
+#define	NM_A_SZ_BLOCKING_DENY_ITEM		"NM_A_SZ_BLOCKING_DENY_ITEM"
+#define NM_A_LOCKED_ATTR_LIST			"nnmLockedAttrList"
 
 #define NM_PROTOCOL_VERSION		 		2
 
@@ -139,9 +137,12 @@
 guint32 nm_count_fields(NMField * fields);
 
 /**
- * Add a field to the field array. NOTE: field array that is passed
- * in may be realloced so you should use the returned field array pointer
- * not the passed in pointer after calling this function.
+ * Add a field to the field array. The field should be of type NMFIELD_TYPE_UTF8,
+ * NMFIELD_TYPE_DN, NMFIELD_TYPE_ARRAY, or NMFIELD_TYPE_MV
+ *
+ * NOTE: field array that is passed in may be realloc'd so you should use
+ * the returned field array pointer not the passed in pointer after calling
+ * this function.
  *
  * @param fields	Field array
  * @param tag		Tag for the new field
@@ -154,8 +155,29 @@
  * @return			Pointer to the updated field array
  *
  */
-NMField *nm_add_field(NMField * fields, char *tag, guint32 size, guint8 method,
-					  guint8 flags, guint32 value, guint8 type);
+NMField *nm_field_add_pointer(NMField *fields, const char *tag, guint32 size, guint8 method,
+							  guint8 flags, gpointer value, guint8 type);
+
+/**
+ * Add a numeric field to the field array.
+ *
+ * NOTE: field array that is passed in may be realloc'd so you should use
+ * the returned field array pointer not the passed in pointer after calling
+ * this function.
+ *
+ * @param fields	Field array
+ * @param tag		Tag for the new field
+ * @param size		Size of the field value (if type = binary)
+ * @param method	Field method (see method defines above)
+ * @param flags		Flags for new field
+ * @param value		The value of the field
+ * @param type		The type of the field value
+ *
+ * @return			Pointer to the updated field array
+ *
+ */
+NMField *nm_field_add_number(NMField *fields, const char *tag, guint32 size, guint8 method,
+							 guint8 flags, guint32 value, guint8 type);
 
 /**
  * Recursively free an array of fields and set pointer to NULL.
--- a/src/protocols/novell/nmmessage.c	Sat May 15 06:24:52 2004 +0000
+++ b/src/protocols/novell/nmmessage.c	Sat May 15 14:00:31 2004 +0000
@@ -1,22 +1,20 @@
 /*
  * nmmessage.c
  *
- * Copyright © 2004 Unpublished Work of Novell, Inc. All Rights Reserved.
+ * Copyright (c) 2004 Novell, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
  *
- * THIS WORK IS AN UNPUBLISHED WORK OF NOVELL, INC. NO PART OF THIS WORK MAY BE
- * USED, PRACTICED, PERFORMED, COPIED, DISTRIBUTED, REVISED, MODIFIED,
- * TRANSLATED, ABRIDGED, CONDENSED, EXPANDED, COLLECTED, COMPILED, LINKED,
- * RECAST, TRANSFORMED OR ADAPTED WITHOUT THE PRIOR WRITTEN CONSENT OF NOVELL,
- * INC. ANY USE OR EXPLOITATION OF THIS WORK WITHOUT AUTHORIZATION COULD SUBJECT
- * THE PERPETRATOR TO CRIMINAL AND CIVIL LIABILITY.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
  *
- * AS BETWEEN [GAIM] AND NOVELL, NOVELL GRANTS [GAIM] THE RIGHT TO REPUBLISH
- * THIS WORK UNDER THE GPL (GNU GENERAL PUBLIC LICENSE) WITH ALL RIGHTS AND
- * LICENSES THEREUNDER.  IF YOU HAVE RECEIVED THIS WORK DIRECTLY OR INDIRECTLY
- * FROM [GAIM] AS PART OF SUCH A REPUBLICATION, YOU HAVE ALL RIGHTS AND LICENSES
- * GRANTED BY [GAIM] UNDER THE GPL.  IN CONNECTION WITH SUCH A REPUBLICATION, IF
- * ANYTHING IN THIS NOTICE CONFLICTS WITH THE TERMS OF THE GPL, SUCH TERMS
- * PREVAIL.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA	02111-1307	USA
  *
  */
 
@@ -46,6 +44,13 @@
 }
 
 void
+nm_message_add_ref(NMMessage * msg)
+{
+	if (msg)
+		msg->ref_count++;
+}
+
+void
 nm_release_message(NMMessage * msg)
 {
 	if (msg && (--(msg->ref_count) == 0)) {
--- a/src/protocols/novell/nmmessage.h	Sat May 15 06:24:52 2004 +0000
+++ b/src/protocols/novell/nmmessage.h	Sat May 15 14:00:31 2004 +0000
@@ -1,22 +1,20 @@
 /*
  * nmmessage.h
  *
- * Copyright © 2004 Unpublished Work of Novell, Inc. All Rights Reserved.
+ * Copyright (c) 2004 Novell, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
  *
- * THIS WORK IS AN UNPUBLISHED WORK OF NOVELL, INC. NO PART OF THIS WORK MAY BE
- * USED, PRACTICED, PERFORMED, COPIED, DISTRIBUTED, REVISED, MODIFIED,
- * TRANSLATED, ABRIDGED, CONDENSED, EXPANDED, COLLECTED, COMPILED, LINKED,
- * RECAST, TRANSFORMED OR ADAPTED WITHOUT THE PRIOR WRITTEN CONSENT OF NOVELL,
- * INC. ANY USE OR EXPLOITATION OF THIS WORK WITHOUT AUTHORIZATION COULD SUBJECT
- * THE PERPETRATOR TO CRIMINAL AND CIVIL LIABILITY.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
  *
- * AS BETWEEN [GAIM] AND NOVELL, NOVELL GRANTS [GAIM] THE RIGHT TO REPUBLISH
- * THIS WORK UNDER THE GPL (GNU GENERAL PUBLIC LICENSE) WITH ALL RIGHTS AND
- * LICENSES THEREUNDER.  IF YOU HAVE RECEIVED THIS WORK DIRECTLY OR INDIRECTLY
- * FROM [GAIM] AS PART OF SUCH A REPUBLICATION, YOU HAVE ALL RIGHTS AND LICENSES
- * GRANTED BY [GAIM] UNDER THE GPL.  IN CONNECTION WITH SUCH A REPUBLICATION, IF
- * ANYTHING IN THIS NOTICE CONFLICTS WITH THE TERMS OF THE GPL, SUCH TERMS
- * PREVAIL.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA	02111-1307	USA
  *
  */
 
@@ -39,6 +37,13 @@
 NMMessage *nm_create_message(const char *text);
 
 /**
+ * Increment the reference count for the message object.
+ *
+ * @param	msg		The message
+ */
+void nm_message_add_ref(NMMessage * msg);
+
+/**
  * Releases a message.
  *
  * @param	msg		The message
--- a/src/protocols/novell/nmrequest.c	Sat May 15 06:24:52 2004 +0000
+++ b/src/protocols/novell/nmrequest.c	Sat May 15 14:00:31 2004 +0000
@@ -1,22 +1,20 @@
 /*
  * nmrequest.c
  *
- * Copyright © 2004 Unpublished Work of Novell, Inc. All Rights Reserved.
+ * Copyright (c) 2004 Novell, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
  *
- * THIS WORK IS AN UNPUBLISHED WORK OF NOVELL, INC. NO PART OF THIS WORK MAY BE
- * USED, PRACTICED, PERFORMED, COPIED, DISTRIBUTED, REVISED, MODIFIED,
- * TRANSLATED, ABRIDGED, CONDENSED, EXPANDED, COLLECTED, COMPILED, LINKED,
- * RECAST, TRANSFORMED OR ADAPTED WITHOUT THE PRIOR WRITTEN CONSENT OF NOVELL,
- * INC. ANY USE OR EXPLOITATION OF THIS WORK WITHOUT AUTHORIZATION COULD SUBJECT
- * THE PERPETRATOR TO CRIMINAL AND CIVIL LIABILITY.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
  *
- * AS BETWEEN [GAIM] AND NOVELL, NOVELL GRANTS [GAIM] THE RIGHT TO REPUBLISH
- * THIS WORK UNDER THE GPL (GNU GENERAL PUBLIC LICENSE) WITH ALL RIGHTS AND
- * LICENSES THEREUNDER.  IF YOU HAVE RECEIVED THIS WORK DIRECTLY OR INDIRECTLY
- * FROM [GAIM] AS PART OF SUCH A REPUBLICATION, YOU HAVE ALL RIGHTS AND LICENSES
- * GRANTED BY [GAIM] UNDER THE GPL.  IN CONNECTION WITH SUCH A REPUBLICATION, IF
- * ANYTHING IN THIS NOTICE CONFLICTS WITH THE TERMS OF THE GPL, SUCH TERMS
- * PREVAIL.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA	02111-1307	USA
  *
  */
 
--- a/src/protocols/novell/nmrequest.h	Sat May 15 06:24:52 2004 +0000
+++ b/src/protocols/novell/nmrequest.h	Sat May 15 14:00:31 2004 +0000
@@ -1,22 +1,20 @@
 /*
  * nmrequest.h
  *
- * Copyright © 2004 Unpublished Work of Novell, Inc. All Rights Reserved.
+ * Copyright (c) 2004 Novell, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
  *
- * THIS WORK IS AN UNPUBLISHED WORK OF NOVELL, INC. NO PART OF THIS WORK MAY BE
- * USED, PRACTICED, PERFORMED, COPIED, DISTRIBUTED, REVISED, MODIFIED,
- * TRANSLATED, ABRIDGED, CONDENSED, EXPANDED, COLLECTED, COMPILED, LINKED,
- * RECAST, TRANSFORMED OR ADAPTED WITHOUT THE PRIOR WRITTEN CONSENT OF NOVELL,
- * INC. ANY USE OR EXPLOITATION OF THIS WORK WITHOUT AUTHORIZATION COULD SUBJECT
- * THE PERPETRATOR TO CRIMINAL AND CIVIL LIABILITY.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
  *
- * AS BETWEEN [GAIM] AND NOVELL, NOVELL GRANTS [GAIM] THE RIGHT TO REPUBLISH
- * THIS WORK UNDER THE GPL (GNU GENERAL PUBLIC LICENSE) WITH ALL RIGHTS AND
- * LICENSES THEREUNDER.  IF YOU HAVE RECEIVED THIS WORK DIRECTLY OR INDIRECTLY
- * FROM [GAIM] AS PART OF SUCH A REPUBLICATION, YOU HAVE ALL RIGHTS AND LICENSES
- * GRANTED BY [GAIM] UNDER THE GPL.  IN CONNECTION WITH SUCH A REPUBLICATION, IF
- * ANYTHING IN THIS NOTICE CONFLICTS WITH THE TERMS OF THE GPL, SUCH TERMS
- * PREVAIL.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA	02111-1307	USA
  *
  */
 
--- a/src/protocols/novell/nmuser.c	Sat May 15 06:24:52 2004 +0000
+++ b/src/protocols/novell/nmuser.c	Sat May 15 14:00:31 2004 +0000
@@ -1,27 +1,26 @@
 /*
  * nmuser.c
  *
- * Copyright © 2004 Unpublished Work of Novell, Inc. All Rights Reserved.
+ * Copyright (c) 2004 Novell, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
  *
- * THIS WORK IS AN UNPUBLISHED WORK OF NOVELL, INC. NO PART OF THIS WORK MAY BE
- * USED, PRACTICED, PERFORMED, COPIED, DISTRIBUTED, REVISED, MODIFIED,
- * TRANSLATED, ABRIDGED, CONDENSED, EXPANDED, COLLECTED, COMPILED, LINKED,
- * RECAST, TRANSFORMED OR ADAPTED WITHOUT THE PRIOR WRITTEN CONSENT OF NOVELL,
- * INC. ANY USE OR EXPLOITATION OF THIS WORK WITHOUT AUTHORIZATION COULD SUBJECT
- * THE PERPETRATOR TO CRIMINAL AND CIVIL LIABILITY.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
  *
- * AS BETWEEN [GAIM] AND NOVELL, NOVELL GRANTS [GAIM] THE RIGHT TO REPUBLISH
- * THIS WORK UNDER THE GPL (GNU GENERAL PUBLIC LICENSE) WITH ALL RIGHTS AND
- * LICENSES THEREUNDER.  IF YOU HAVE RECEIVED THIS WORK DIRECTLY OR INDIRECTLY
- * FROM [GAIM] AS PART OF SUCH A REPUBLICATION, YOU HAVE ALL RIGHTS AND LICENSES
- * GRANTED BY [GAIM] UNDER THE GPL.  IN CONNECTION WITH SUCH A REPUBLICATION, IF
- * ANYTHING IN THIS NOTICE CONFLICTS WITH THE TERMS OF THE GPL, SUCH TERMS
- * PREVAIL.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA	02111-1307	USA
  *
  */
 
 #include <glib.h>
 #include <string.h>
+#include "internal.h"
 #include "nmfield.h"
 #include "nmuser.h"
 #include "nmconn.h"
@@ -37,11 +36,16 @@
                         "Microsoft Sans Serif;}}\n{\\colortbl ;\\red0"\
                         "\\green0\\blue0;}\n\\viewkind4\\uc1\\pard\\ltrpar"\
                         "\\li50\\ri50\\cf1\\f0\\fs20 %s\\par\n}"
+#define NM_MAX_MESSAGE_SIZE 2048
 
 static NMERR_T nm_process_response(NMUser * user);
 
 static void _update_contact_list(NMUser * user, NMField * fields);
 
+static void
+_handle_multiple_get_details_login_cb(NMUser * user, NMERR_T ret_code,
+									  gpointer resp_data, gpointer user_data);
+
 /**
  * See header for comments on on "public" functions
  */
@@ -125,21 +129,20 @@
 		return NMERR_BAD_PARM;
 	}
 
-	fields = nm_add_field(fields, NM_A_SZ_USERID, 0, NMFIELD_METHOD_VALID, 0,
-						  (guint32) g_strdup(user->name), NMFIELD_TYPE_UTF8);
-
-	fields = nm_add_field(fields, NM_A_SZ_CREDENTIALS, 0, NMFIELD_METHOD_VALID, 0,
-						  (guint32) g_strdup(pwd), NMFIELD_TYPE_UTF8);
-
-	fields = nm_add_field(fields, NM_A_SZ_USER_AGENT, 0, NMFIELD_METHOD_VALID, 0,
-						  (guint32) g_strdup(user_agent), NMFIELD_TYPE_UTF8);
-
-	fields = nm_add_field(fields, NM_A_UD_BUILD, 0, NMFIELD_METHOD_VALID, 0,
-						  (guint32) NM_PROTOCOL_VERSION,
-						  NMFIELD_TYPE_UDWORD);
+	fields = nm_field_add_pointer(fields, NM_A_SZ_USERID, 0, NMFIELD_METHOD_VALID, 0,
+								  g_strdup(user->name), NMFIELD_TYPE_UTF8);
+
+	fields = nm_field_add_pointer(fields, NM_A_SZ_CREDENTIALS, 0, NMFIELD_METHOD_VALID, 0,
+								  g_strdup(pwd), NMFIELD_TYPE_UTF8);
+
+	fields = nm_field_add_pointer(fields, NM_A_SZ_USER_AGENT, 0, NMFIELD_METHOD_VALID, 0,
+								  g_strdup(user_agent), NMFIELD_TYPE_UTF8);
+
+	fields = nm_field_add_number(fields, NM_A_UD_BUILD, 0, NMFIELD_METHOD_VALID, 0,
+								 NM_PROTOCOL_VERSION, NMFIELD_TYPE_UDWORD);
 	if (my_addr) {
-		fields = nm_add_field(fields, NM_A_IP_ADDRESS, 0, NMFIELD_METHOD_VALID, 0,
-							  (guint32) g_strdup(my_addr), NMFIELD_TYPE_UTF8);
+		fields = nm_field_add_pointer(fields, NM_A_IP_ADDRESS, 0, NMFIELD_METHOD_VALID, 0,
+									  g_strdup(my_addr), NMFIELD_TYPE_UTF8);
 	}
 
 	/* Send the login */
@@ -173,21 +176,20 @@
 		return NMERR_BAD_PARM;
 
 	/* Add the status */
-	fields = nm_add_field(fields, NM_A_SZ_STATUS, 0, NMFIELD_METHOD_VALID, 0,
-						  (guint32) g_strdup_printf("%d", status),
-						  NMFIELD_TYPE_UTF8);
+	fields = nm_field_add_pointer(fields, NM_A_SZ_STATUS, 0, NMFIELD_METHOD_VALID, 0,
+								  g_strdup_printf("%d", status), NMFIELD_TYPE_UTF8);
 
 	/* Add the status text and auto reply text if there is any */
 	if (text) {
-		fields = nm_add_field(fields, NM_A_SZ_STATUS_TEXT,
-							  0, NMFIELD_METHOD_VALID, 0,
-							  (guint32) g_strdup(text), NMFIELD_TYPE_UTF8);
+		fields = nm_field_add_pointer(fields, NM_A_SZ_STATUS_TEXT, 0,
+									  NMFIELD_METHOD_VALID, 0, g_strdup(text),
+									  NMFIELD_TYPE_UTF8);
 	}
 
 	if (auto_resp) {
-		fields = nm_add_field(fields, NM_A_SZ_MESSAGE_BODY, 0,
-							  NMFIELD_METHOD_VALID, 0,
-							  (guint32) g_strdup(auto_resp), NMFIELD_TYPE_UTF8);
+		fields = nm_field_add_pointer(fields, NM_A_SZ_MESSAGE_BODY, 0,
+									  NMFIELD_METHOD_VALID, 0, g_strdup(auto_resp),
+									  NMFIELD_TYPE_UTF8);
 	}
 
 	rc = nm_send_request(user->conn, "setstatus", fields, &req);
@@ -209,6 +211,40 @@
 }
 
 NMERR_T
+nm_send_multiple_get_details(NMUser * user, GSList *names,
+							 nm_response_cb callback, gpointer data)
+{
+	NMERR_T rc = NM_OK;
+	NMField *fields = NULL;
+	NMRequest *req = NULL;
+	GSList *node;
+
+	if (user == NULL || names == NULL)
+		return NMERR_BAD_PARM;
+
+	/* Add in DN or display id */
+	for (node = names; node; node = node->next) {
+		fields = nm_field_add_pointer(fields, NM_A_SZ_USERID, 0, NMFIELD_METHOD_VALID, 0,
+									  g_strdup(node->data), NMFIELD_TYPE_UTF8);
+	}
+
+	rc = nm_send_request(user->conn, "getdetails", fields, &req);
+	if (rc == NM_OK) {
+		nm_request_set_callback(req, callback);
+		nm_request_set_user_define(req, data);
+		nm_conn_add_request_item(user->conn, req);
+	}
+
+	if (fields)
+		nm_free_fields(&fields);
+
+	if (req)
+		nm_release_request(req);
+
+	return rc;
+}
+
+NMERR_T
 nm_send_get_details(NMUser * user, const char *name,
 					nm_response_cb callback, gpointer data)
 {
@@ -221,19 +257,19 @@
 
 	/* Add in DN or display id */
 	if (strstr("=", name)) {
-		fields = nm_add_field(fields, NM_A_SZ_DN, 0, NMFIELD_METHOD_VALID, 0,
-							  (guint32) g_strdup(name), NMFIELD_TYPE_DN);
+		fields = nm_field_add_pointer(fields, NM_A_SZ_DN, 0, NMFIELD_METHOD_VALID, 0,
+									  g_strdup(name), NMFIELD_TYPE_DN);
 	} else {
 
 		const char *dn = nm_lookup_dn(user, name);
 
 		if (dn) {
-			fields = nm_add_field(fields, NM_A_SZ_DN, 0, NMFIELD_METHOD_VALID, 0,
-								  (guint32) g_strdup(name), NMFIELD_TYPE_DN);
+			fields = nm_field_add_pointer(fields, NM_A_SZ_DN, 0, NMFIELD_METHOD_VALID, 0,
+										  g_strdup(name), NMFIELD_TYPE_DN);
 		} else {
 			fields =
-				nm_add_field(fields, NM_A_SZ_USERID, 0, NMFIELD_METHOD_VALID, 0,
-							 (guint32) g_strdup(name), NMFIELD_TYPE_UTF8);
+				nm_field_add_pointer(fields, NM_A_SZ_USERID, 0, NMFIELD_METHOD_VALID, 0,
+									 g_strdup(name), NMFIELD_TYPE_UTF8);
 		}
 
 	}
@@ -269,40 +305,41 @@
 		return NMERR_BAD_PARM;
 
 	/* Add in a blank guid */
-	tmp = nm_add_field(tmp, NM_A_SZ_OBJECT_ID, 0, NMFIELD_METHOD_VALID, 0,
-					   (guint32) g_strdup(BLANK_GUID), NMFIELD_TYPE_UTF8);
-
-	fields = nm_add_field(fields, NM_A_FA_CONVERSATION, 0,
-						  NMFIELD_METHOD_VALID, 0, (guint32) tmp,
-						  NMFIELD_TYPE_ARRAY);
+	tmp = nm_field_add_pointer(tmp, NM_A_SZ_OBJECT_ID, 0, NMFIELD_METHOD_VALID, 0,
+							   g_strdup(BLANK_GUID), NMFIELD_TYPE_UTF8);
+
+	fields = nm_field_add_pointer(fields, NM_A_FA_CONVERSATION, 0,
+								  NMFIELD_METHOD_VALID, 0, tmp,
+								  NMFIELD_TYPE_ARRAY);
 	tmp = NULL;
 
+
 	/* Add participants in */
 	count = nm_conference_get_participant_count(conference);
 	for (i = 0; i < count; i++) {
 		NMUserRecord *user_record = nm_conference_get_participant(conference, i);
 
 		if (user_record) {
-			fields = nm_add_field(fields, NM_A_SZ_DN,
-								  0, NMFIELD_METHOD_VALID, 0,
-								  (guint32)
-								  g_strdup(nm_user_record_get_dn(user_record)),
-								  NMFIELD_TYPE_DN);
+			fields = nm_field_add_pointer(fields, NM_A_SZ_DN,
+										  0, NMFIELD_METHOD_VALID, 0,
+										  g_strdup(nm_user_record_get_dn(user_record)),
+										  NMFIELD_TYPE_DN);
 		}
 	}
 
 	/* Add our user in */
 	field = nm_locate_field(NM_A_SZ_DN, user->fields);
 	if (field) {
-		fields = nm_add_field(fields, NM_A_SZ_DN,
-							  0, NMFIELD_METHOD_VALID, 0,
-							  (guint32) g_strdup((char *) field->value),
-							  NMFIELD_TYPE_DN);
+		fields = nm_field_add_pointer(fields, NM_A_SZ_DN,
+									  0, NMFIELD_METHOD_VALID, 0,
+									  g_strdup((char *) field->ptr_value),
+									  NMFIELD_TYPE_DN);
 	}
 
 	rc = nm_send_request(user->conn, "createconf", fields, &req);
 	if (rc == NM_OK && req) {
 		nm_request_set_callback(req, callback);
+		nm_conference_add_ref(conference);
 		nm_request_set_data(req, conference);
 		nm_request_set_user_define(req, message);
 		nm_conn_add_request_item(user->conn, req);
@@ -331,13 +368,13 @@
 		return NMERR_BAD_PARM;
 
 	/* Add in the conference guid */
-	tmp = nm_add_field(tmp, NM_A_SZ_OBJECT_ID, 0, NMFIELD_METHOD_VALID, 0,
-					   (guint32) g_strdup(nm_conference_get_guid(conference)),
-					   NMFIELD_TYPE_UTF8);
-
-	fields = nm_add_field(fields, NM_A_FA_CONVERSATION, 0,
-						  NMFIELD_METHOD_VALID, 0, (guint32) tmp,
-						  NMFIELD_TYPE_ARRAY);
+	tmp = nm_field_add_pointer(tmp, NM_A_SZ_OBJECT_ID, 0, NMFIELD_METHOD_VALID, 0,
+							   g_strdup(nm_conference_get_guid(conference)),
+							   NMFIELD_TYPE_UTF8);
+
+	fields = nm_field_add_pointer(fields, NM_A_FA_CONVERSATION, 0,
+								  NMFIELD_METHOD_VALID, 0, tmp,
+								  NMFIELD_TYPE_ARRAY);
 	tmp = NULL;
 
 	/* Send the request to the server */
@@ -370,13 +407,13 @@
 		return NMERR_BAD_PARM;
 
 	/* Add in the conference guid */
-	tmp = nm_add_field(tmp, NM_A_SZ_OBJECT_ID, 0, NMFIELD_METHOD_VALID, 0,
-					   (guint32) g_strdup(nm_conference_get_guid(conference)),
-					   NMFIELD_TYPE_UTF8);
-
-	fields = nm_add_field(fields, NM_A_FA_CONVERSATION, 0,
-						  NMFIELD_METHOD_VALID, 0, (guint32) tmp,
-						  NMFIELD_TYPE_ARRAY);
+	tmp = nm_field_add_pointer(tmp, NM_A_SZ_OBJECT_ID, 0, NMFIELD_METHOD_VALID, 0,
+							   g_strdup(nm_conference_get_guid(conference)),
+							   NMFIELD_TYPE_UTF8);
+
+	fields = nm_field_add_pointer(fields, NM_A_FA_CONVERSATION, 0,
+								  NMFIELD_METHOD_VALID, 0, tmp,
+								  NMFIELD_TYPE_ARRAY);
 	tmp = NULL;
 
 	/* Send the request to the server */
@@ -414,13 +451,13 @@
 		return NMERR_BAD_PARM;
 
 	/* Add in the conference guid */
-	tmp = nm_add_field(tmp, NM_A_SZ_OBJECT_ID, 0, NMFIELD_METHOD_VALID, 0,
-					   (guint32) g_strdup(nm_conference_get_guid(conference)),
-					   NMFIELD_TYPE_UTF8);
-
-	fields = nm_add_field(fields, NM_A_FA_CONVERSATION, 0,
-						  NMFIELD_METHOD_VALID, 0, (guint32) tmp,
-						  NMFIELD_TYPE_ARRAY);
+	tmp = nm_field_add_pointer(tmp, NM_A_SZ_OBJECT_ID, 0, NMFIELD_METHOD_VALID, 0,
+							   g_strdup(nm_conference_get_guid(conference)),
+							   NMFIELD_TYPE_UTF8);
+
+	fields = nm_field_add_pointer(fields, NM_A_FA_CONVERSATION, 0,
+								  NMFIELD_METHOD_VALID, 0, tmp,
+								  NMFIELD_TYPE_ARRAY);
 	tmp = NULL;
 
 	/* Send the request to the server */
@@ -446,10 +483,64 @@
 }
 
 NMERR_T
+nm_send_conference_invite(NMUser *user, NMConference *conference, NMUserRecord *user_record,
+						  const char *message, nm_response_cb callback, gpointer data)
+{
+	NMERR_T rc = NM_OK;
+	NMField *fields = NULL;
+	NMField *tmp = NULL;
+	NMRequest *req = NULL;
+
+	if (user == NULL || conference == NULL || user_record == NULL)
+		return NMERR_BAD_PARM;
+
+	/* Add in the conference guid */
+	tmp = nm_field_add_pointer(tmp, NM_A_SZ_OBJECT_ID, 0, NMFIELD_METHOD_VALID, 0,
+							   g_strdup(nm_conference_get_guid(conference)),
+							   NMFIELD_TYPE_UTF8);
+
+	fields = nm_field_add_pointer(fields, NM_A_FA_CONVERSATION, 0,
+								  NMFIELD_METHOD_VALID, 0, tmp,
+								  NMFIELD_TYPE_ARRAY);
+	tmp = NULL;
+
+	/* Add in DN of user to invite */
+	fields = nm_field_add_pointer(fields, NM_A_SZ_DN, 0, NMFIELD_METHOD_VALID, 0,
+								  g_strdup(nm_user_record_get_dn(user_record)),
+								  NMFIELD_TYPE_DN);
+
+	/* Add the invite message if there is one */
+	if (message)
+		fields = nm_field_add_pointer(fields, NM_A_SZ_MESSAGE_BODY, 0, NMFIELD_METHOD_VALID, 0,
+									  g_strdup(message), NMFIELD_TYPE_UTF8);
+
+	/* Send the request to the server */
+	rc = nm_send_request(user->conn, "sendinvite", fields, &req);
+
+	/* Set up the request object so that we know what to do
+	 * when we get a response
+	 */
+	if (rc == NM_OK && req) {
+		nm_request_set_callback(req, callback);
+		nm_request_set_data(req, conference);
+		nm_request_set_user_define(req, data);
+		nm_conn_add_request_item(user->conn, req);
+	}
+
+	if (req)
+		nm_release_request(req);
+
+	if (fields)
+		nm_free_fields(&fields);
+
+	return rc;
+}
+
+NMERR_T
 nm_send_message(NMUser * user, NMMessage * message, nm_response_cb callback)
 {
 	NMERR_T rc = NM_OK;
-	const char *text;
+	char *text;
 	NMField *fields = NULL, *tmp = NULL;
 	NMRequest *req = NULL;
 	NMConference *conf;
@@ -465,42 +556,46 @@
 		rc = NMERR_CONFERENCE_NOT_INSTANTIATED;
 	} else {
 
-		tmp = nm_add_field(tmp, NM_A_SZ_OBJECT_ID, 0, NMFIELD_METHOD_VALID, 0,
-						   (guint32) g_strdup(nm_conference_get_guid(conf)),
-						   NMFIELD_TYPE_UTF8);
+		tmp = nm_field_add_pointer(tmp, NM_A_SZ_OBJECT_ID, 0, NMFIELD_METHOD_VALID, 0,
+								   g_strdup(nm_conference_get_guid(conf)),
+								   NMFIELD_TYPE_UTF8);
 
 		fields =
-			nm_add_field(fields, NM_A_FA_CONVERSATION, 0, NMFIELD_METHOD_VALID, 0,
-						 (guint32) tmp, NMFIELD_TYPE_ARRAY);
+			nm_field_add_pointer(fields, NM_A_FA_CONVERSATION, 0, NMFIELD_METHOD_VALID, 0,
+								 tmp, NMFIELD_TYPE_ARRAY);
 		tmp = NULL;
 
 		/* Add RTF and plain text versions of the message */
-		text = nm_message_get_text(message);
-
-		tmp = nm_add_field(tmp, NM_A_SZ_MESSAGE_BODY, 0, NMFIELD_METHOD_VALID, 0,
-						   (guint32) g_strdup_printf(RTF_TEMPLATE, text),
-						   NMFIELD_TYPE_UTF8);
-
-		tmp = nm_add_field(tmp, NM_A_UD_MESSAGE_TYPE, 0, NMFIELD_METHOD_VALID, 0,
-						   (guint32) 0, NMFIELD_TYPE_UDWORD);
-
-		tmp = nm_add_field(tmp, NM_A_SZ_MESSAGE_TEXT, 0, NMFIELD_METHOD_VALID, 0,
-						   (guint32) g_strdup(text), NMFIELD_TYPE_UTF8);
-
-		fields = nm_add_field(fields, NM_A_FA_MESSAGE, 0, NMFIELD_METHOD_VALID, 0,
-							  (guint32) tmp, NMFIELD_TYPE_ARRAY);
+		text = g_strdup(nm_message_get_text(message));
+
+		/* Truncate if necessary */
+		if (strlen(text) > NM_MAX_MESSAGE_SIZE)
+			text[NM_MAX_MESSAGE_SIZE] = 0;
+
+		tmp = nm_field_add_pointer(tmp, NM_A_SZ_MESSAGE_BODY, 0, NMFIELD_METHOD_VALID, 0,
+								   g_strdup_printf(RTF_TEMPLATE, text), NMFIELD_TYPE_UTF8);
+
+		tmp = nm_field_add_number(tmp, NM_A_UD_MESSAGE_TYPE, 0, NMFIELD_METHOD_VALID, 0,
+								  0, NMFIELD_TYPE_UDWORD);
+
+		tmp = nm_field_add_pointer(tmp, NM_A_SZ_MESSAGE_TEXT, 0, NMFIELD_METHOD_VALID, 0,
+								   g_strdup(text), NMFIELD_TYPE_UTF8);
+
+		fields = nm_field_add_pointer(fields, NM_A_FA_MESSAGE, 0, NMFIELD_METHOD_VALID, 0,
+									  tmp, NMFIELD_TYPE_ARRAY);
 		tmp = NULL;
 
+		g_free(text);
+
 		/* Add participants */
 		count = nm_conference_get_participant_count(conf);
 		for (i = 0; i < count; i++) {
 			user_record = nm_conference_get_participant(conf, i);
 			if (user_record) {
 				fields =
-					nm_add_field(fields, NM_A_SZ_DN, 0, NMFIELD_METHOD_VALID, 0,
-								 (guint32)
-								 g_strdup(nm_user_record_get_dn(user_record)),
-								 NMFIELD_TYPE_DN);
+					nm_field_add_pointer(fields, NM_A_SZ_DN, 0, NMFIELD_METHOD_VALID, 0,
+										 g_strdup(nm_user_record_get_dn(user_record)),
+										 NMFIELD_TYPE_DN);
 			}
 		}
 
@@ -540,21 +635,21 @@
 		rc = NMERR_CONFERENCE_NOT_INSTANTIATED;
 	} else {
 		/* Add the conference GUID */
-		tmp = nm_add_field(tmp, NM_A_SZ_OBJECT_ID, 0, NMFIELD_METHOD_VALID, 0,
-						   (guint32) g_strdup(nm_conference_get_guid(conf)),
-						   NMFIELD_TYPE_UTF8);
+		tmp = nm_field_add_pointer(tmp, NM_A_SZ_OBJECT_ID, 0, NMFIELD_METHOD_VALID, 0,
+								   g_strdup(nm_conference_get_guid(conf)),
+								   NMFIELD_TYPE_UTF8);
 
 		/* Add typing type */
 		str = g_strdup_printf("%d",
 							  (typing ? NMEVT_USER_TYPING :
 							   NMEVT_USER_NOT_TYPING));
 
-		tmp = nm_add_field(tmp, NM_A_SZ_TYPE, 0, NMFIELD_METHOD_VALID, 0,
-						   (guint32) str, NMFIELD_TYPE_UTF8);
+		tmp = nm_field_add_pointer(tmp, NM_A_SZ_TYPE, 0, NMFIELD_METHOD_VALID, 0,
+								   str, NMFIELD_TYPE_UTF8);
 
 		fields =
-			nm_add_field(fields, NM_A_FA_CONVERSATION, 0, NMFIELD_METHOD_VALID, 0,
-						 (guint32) tmp, NMFIELD_TYPE_ARRAY);
+			nm_field_add_pointer(fields, NM_A_FA_CONVERSATION, 0, NMFIELD_METHOD_VALID, 0,
+								 tmp, NMFIELD_TYPE_ARRAY);
 		tmp = NULL;
 
 		rc = nm_send_request(user->conn, "sendtyping", fields, &req);
@@ -589,10 +684,9 @@
 	}
 
 	/* Add parent ID */
-	fields = nm_add_field(fields, NM_A_SZ_PARENT_ID, 0, NMFIELD_METHOD_VALID, 0,
-						  (guint32) g_strdup_printf("%d",
-													nm_folder_get_id(folder)),
-						  NMFIELD_TYPE_UTF8);
+	fields = nm_field_add_pointer(fields, NM_A_SZ_PARENT_ID, 0, NMFIELD_METHOD_VALID, 0,
+								  g_strdup_printf("%d", nm_folder_get_id(folder)),
+								  NMFIELD_TYPE_UTF8);
 
 	/* Check to see if userid is current user and return an error? */
 
@@ -604,18 +698,18 @@
 		return NMERR_BAD_PARM;
 
 	if (strstr("=", name)) {
-		fields = nm_add_field(fields, NM_A_SZ_DN, 0, NMFIELD_METHOD_VALID, 0,
-							  (guint32) g_strdup(name), NMFIELD_TYPE_DN);
+		fields = nm_field_add_pointer(fields, NM_A_SZ_DN, 0, NMFIELD_METHOD_VALID, 0,
+									  g_strdup(name), NMFIELD_TYPE_DN);
 	} else {
-		fields = nm_add_field(fields, NM_A_SZ_USERID, 0, NMFIELD_METHOD_VALID, 0,
-							  (guint32) g_strdup(name), NMFIELD_TYPE_UTF8);
+		fields = nm_field_add_pointer(fields, NM_A_SZ_USERID, 0, NMFIELD_METHOD_VALID, 0,
+									  g_strdup(name), NMFIELD_TYPE_UTF8);
 	}
 
 	/* Add display name */
 	display_name = nm_contact_get_display_name(contact);
 	if (display_name)
-		fields = nm_add_field(fields, NM_A_SZ_DISPLAY_NAME, 0, NMFIELD_METHOD_VALID, 0,
-							  (guint32) g_strdup(display_name), NMFIELD_TYPE_UTF8);
+		fields = nm_field_add_pointer(fields, NM_A_SZ_DISPLAY_NAME, 0, NMFIELD_METHOD_VALID, 0,
+									  g_strdup(display_name), NMFIELD_TYPE_UTF8);
 
 	/* Dispatch the request */
 	rc = nm_send_request(user->conn, "createcontact", fields, &req);
@@ -649,16 +743,14 @@
 	}
 
 	/* Add parent id */
-	fields = nm_add_field(fields, NM_A_SZ_PARENT_ID, 0, NMFIELD_METHOD_VALID, 0,
-						  (guint32) g_strdup_printf("%d",
-													nm_folder_get_id(folder)),
-						  NMFIELD_TYPE_UTF8);
+	fields = nm_field_add_pointer(fields, NM_A_SZ_PARENT_ID, 0, NMFIELD_METHOD_VALID, 0,
+								  g_strdup_printf("%d", nm_folder_get_id(folder)),
+								  NMFIELD_TYPE_UTF8);
 
 	/* Add object id */
-	fields = nm_add_field(fields, NM_A_SZ_OBJECT_ID, 0, NMFIELD_METHOD_VALID, 0,
-						  (guint32) g_strdup_printf("%d",
-													nm_contact_get_id(contact)),
-						  NMFIELD_TYPE_UTF8);
+	fields = nm_field_add_pointer(fields, NM_A_SZ_OBJECT_ID, 0, NMFIELD_METHOD_VALID, 0,
+								  g_strdup_printf("%d", nm_contact_get_id(contact)),
+								  NMFIELD_TYPE_UTF8);
 
 	/* Dispatch the request */
 	rc = nm_send_request(user->conn, "deletecontact", fields, &req);
@@ -691,18 +783,18 @@
 	}
 
 	/* Add parent ID */
-	fields = nm_add_field(fields, NM_A_SZ_PARENT_ID, 0, NMFIELD_METHOD_VALID, 0,
-						  (guint32) g_strdup("0"), NMFIELD_TYPE_UTF8);
+	fields = nm_field_add_pointer(fields, NM_A_SZ_PARENT_ID, 0, NMFIELD_METHOD_VALID, 0,
+								  g_strdup("0"), NMFIELD_TYPE_UTF8);
 
 	/* Add name of the folder to add */
 	fields =
-		nm_add_field(fields, NM_A_SZ_DISPLAY_NAME, 0, NMFIELD_METHOD_VALID, 0,
-					 (guint32) g_strdup(name), NMFIELD_TYPE_UTF8);
+		nm_field_add_pointer(fields, NM_A_SZ_DISPLAY_NAME, 0, NMFIELD_METHOD_VALID, 0,
+							 g_strdup(name), NMFIELD_TYPE_UTF8);
 
 	/* Add sequence, for now just put it at the bottom */
 	fields =
-		nm_add_field(fields, NM_A_SZ_SEQUENCE_NUMBER, 0, NMFIELD_METHOD_VALID, 0,
-					 (guint32) g_strdup("-1"), NMFIELD_TYPE_UTF8);
+		nm_field_add_pointer(fields, NM_A_SZ_SEQUENCE_NUMBER, 0, NMFIELD_METHOD_VALID, 0,
+							 g_strdup("-1"), NMFIELD_TYPE_UTF8);
 
 	/* Dispatch the request */
 	rc = nm_send_request(user->conn, "createfolder", fields, &req);
@@ -735,9 +827,9 @@
 	}
 
 	/* Add the object id */
-	fields = nm_add_field(fields, NM_A_SZ_OBJECT_ID, 0, NMFIELD_METHOD_VALID, 0,
-						  (guint32) g_strdup_printf("%d", nm_folder_get_id(folder)),
-						  NMFIELD_TYPE_UTF8);
+	fields = nm_field_add_pointer(fields, NM_A_SZ_OBJECT_ID, 0, NMFIELD_METHOD_VALID, 0,
+								  g_strdup_printf("%d", nm_folder_get_id(folder)),
+								  NMFIELD_TYPE_UTF8);
 
 	/* Dispatch the request */
 	rc = nm_send_request(user->conn, "deletecontact", fields, &req);
@@ -774,8 +866,8 @@
 	if (dn == NULL)
 		return (NMERR_T) -1;
 
-	fields = nm_add_field(fields, NM_A_SZ_DN, 0, NMFIELD_METHOD_VALID, 0,
-						  (guint32) g_strdup(dn), NMFIELD_TYPE_UTF8);
+	fields = nm_field_add_pointer(fields, NM_A_SZ_DN, 0, NMFIELD_METHOD_VALID, 0,
+								  g_strdup(dn), NMFIELD_TYPE_UTF8);
 
 	/* Dispatch the request */
 	rc = nm_send_request(user->conn, "getstatus", fields, &req);
@@ -812,8 +904,8 @@
 	if (field) {
 
 		fields =
-			nm_add_field(fields, NM_A_FA_CONTACT, 0, NMFIELD_METHOD_DELETE, 0,
-						 (guint32) field, NMFIELD_TYPE_ARRAY);
+			nm_field_add_pointer(fields, NM_A_FA_CONTACT, 0, NMFIELD_METHOD_DELETE, 0,
+								 field, NMFIELD_TYPE_ARRAY);
 		field = NULL;
 
 		/* Update the contacts display name locally */
@@ -823,14 +915,14 @@
 		field = nm_contact_to_fields(contact);
 		if (field) {
 			fields =
-				nm_add_field(fields, NM_A_FA_CONTACT, 0, NMFIELD_METHOD_ADD, 0,
-							 (guint32) field, NMFIELD_TYPE_ARRAY);
+				nm_field_add_pointer(fields, NM_A_FA_CONTACT, 0, NMFIELD_METHOD_ADD, 0,
+									 field, NMFIELD_TYPE_ARRAY);
 			field = NULL;
 
 			/* Package it up */
 			list =
-				nm_add_field(list, NM_A_FA_CONTACT_LIST, 0, NMFIELD_METHOD_VALID,
-							 0, (guint32) fields, NMFIELD_TYPE_ARRAY);
+				nm_field_add_pointer(list, NM_A_FA_CONTACT_LIST, 0, NMFIELD_METHOD_VALID,
+									 0, fields, NMFIELD_TYPE_ARRAY);
 			fields = NULL;
 
 			rc = nm_send_request(user->conn, "updateitem", list, &req);
@@ -868,8 +960,8 @@
 	field = nm_folder_to_fields(folder);
 	if (field) {
 
-		fields = nm_add_field(fields, NM_A_FA_FOLDER, 0, NMFIELD_METHOD_DELETE, 0,
-							  (guint32) field, NMFIELD_TYPE_ARRAY);
+		fields = nm_field_add_pointer(fields, NM_A_FA_FOLDER, 0, NMFIELD_METHOD_DELETE, 0,
+									  field, NMFIELD_TYPE_ARRAY);
 		field = NULL;
 
 		/* Update the folders display name locally */
@@ -878,15 +970,13 @@
 		/* Create field list for updated folder */
 		field = nm_folder_to_fields(folder);
 		if (field) {
-			fields =
-				nm_add_field(fields, NM_A_FA_FOLDER, 0, NMFIELD_METHOD_ADD, 0,
-							 (guint32) field, NMFIELD_TYPE_ARRAY);
+			fields = nm_field_add_pointer(fields, NM_A_FA_FOLDER, 0, NMFIELD_METHOD_ADD, 0,
+										  field, NMFIELD_TYPE_ARRAY);
 			field = NULL;
 
 			/* Package it up */
-			list =
-				nm_add_field(list, NM_A_FA_CONTACT_LIST, 0, NMFIELD_METHOD_VALID,
-							 0, (guint32) fields, NMFIELD_TYPE_ARRAY);
+			list = nm_field_add_pointer(list, NM_A_FA_CONTACT_LIST, 0, NMFIELD_METHOD_VALID,
+										0, fields, NMFIELD_TYPE_ARRAY);
 			fields = NULL;
 
 			rc = nm_send_request(user->conn, "updateitem", list, &req);
@@ -920,27 +1010,23 @@
 	field = nm_contact_to_fields(contact);
 	if (field) {
 
-		fields =
-			nm_add_field(fields, NM_A_FA_CONTACT, 0, NMFIELD_METHOD_DELETE, 0,
-						 (guint32) field, NMFIELD_TYPE_ARRAY);
+		fields = nm_field_add_pointer(fields, NM_A_FA_CONTACT, 0, NMFIELD_METHOD_DELETE, 0,
+									  field, NMFIELD_TYPE_ARRAY);
 		field = NULL;
 
 		/* Wrap the contact up and add it to the request field list */
-		list =
-			nm_add_field(list, NM_A_FA_CONTACT_LIST, 0, NMFIELD_METHOD_VALID, 0,
-						 (guint32) fields, NMFIELD_TYPE_ARRAY);
+		list = nm_field_add_pointer(list, NM_A_FA_CONTACT_LIST, 0, NMFIELD_METHOD_VALID, 0,
+									fields, NMFIELD_TYPE_ARRAY);
 		fields = NULL;
 
 		/* Add sequence number */
-		list =
-			nm_add_field(list, NM_A_SZ_SEQUENCE_NUMBER, 0, NMFIELD_METHOD_VALID,
-						 0, (guint32) g_strdup("-1"), NMFIELD_TYPE_UTF8);
+		list = nm_field_add_pointer(list, NM_A_SZ_SEQUENCE_NUMBER, 0, NMFIELD_METHOD_VALID,
+									0, g_strdup("-1"), NMFIELD_TYPE_UTF8);
 
 		/* Add parent ID */
-		list = nm_add_field(list, NM_A_SZ_PARENT_ID, 0, NMFIELD_METHOD_VALID, 0,
-							(guint32) g_strdup_printf("%d",
-													  nm_folder_get_id(folder)),
-							NMFIELD_TYPE_UTF8);
+		list = nm_field_add_pointer(list, NM_A_SZ_PARENT_ID, 0, NMFIELD_METHOD_VALID, 0,
+									g_strdup_printf("%d",  nm_folder_get_id(folder)),
+									NMFIELD_TYPE_UTF8);
 
 		/* Dispatch the request */
 		rc = nm_send_request(user->conn, "movecontact", list, &req);
@@ -961,6 +1047,114 @@
 
 
 NMERR_T
+nm_send_create_privacy_item(NMUser *user, const char *who, gboolean allow_list,
+							nm_response_cb callback, gpointer data)
+{
+	NMERR_T rc = NM_OK;
+	NMField *fields = NULL;
+	NMRequest *req = NULL;
+	const char *tag;
+
+	if (user == NULL || who == NULL)
+		return NMERR_BAD_PARM;
+
+	if (allow_list)
+		tag = NM_A_SZ_BLOCKING_ALLOW_ITEM;
+	else
+		tag = NM_A_SZ_BLOCKING_DENY_ITEM;
+
+    fields = nm_field_add_pointer(fields, tag, 0, NMFIELD_METHOD_ADD, 0,
+								  g_strdup(who), NMFIELD_TYPE_UTF8);
+
+	rc = nm_send_request(user->conn, "createblock", fields, &req);
+	if (rc == NM_OK && req) {
+		nm_request_set_callback(req, callback);
+		nm_request_set_user_define(req, data);
+		nm_conn_add_request_item(user->conn, req);
+	}
+
+	if (fields)
+		nm_free_fields(&fields);
+
+	return rc;
+}
+
+NMERR_T
+nm_send_remove_privacy_item(NMUser *user, const char *dn, gboolean allow_list,
+							nm_response_cb callback, gpointer data)
+{
+	NMERR_T rc = NM_OK;
+	NMField *fields = NULL;
+	NMRequest *req = NULL;
+	const char *tag;
+	GSList **list_ptr, *node;
+
+	if (user == NULL || dn == NULL)
+		return NMERR_BAD_PARM;
+
+	if (allow_list) {
+		tag = NM_A_BLOCKING_ALLOW_LIST;
+		list_ptr = &user->allow_list;
+	} else {
+		tag = NM_A_BLOCKING_DENY_LIST;
+		list_ptr = &user->deny_list;
+	}
+
+	/* Remove item from the cached list */
+	if ((node = g_slist_find_custom(*list_ptr, dn, (GCompareFunc)nm_utf8_strcasecmp))) {
+		*list_ptr = g_slist_remove_link(*list_ptr, node);
+		g_slist_free_1(node);
+	}
+
+    fields = nm_field_add_pointer(fields, tag, 0, NMFIELD_METHOD_DELETE, 0,
+								  g_strdup(dn), NMFIELD_TYPE_DN);
+
+	rc = nm_send_request(user->conn, "updateblocks", fields, &req);
+	if (rc == NM_OK && req) {
+		nm_request_set_callback(req, callback);
+		nm_request_set_user_define(req, data);
+		nm_conn_add_request_item(user->conn, req);
+	}
+
+	if (rc == NM_OK) {
+	}
+
+	if (fields)
+		nm_free_fields(&fields);
+
+	return rc;
+
+}
+
+NMERR_T
+nm_send_set_privacy_default(NMUser *user, gboolean default_deny,
+							nm_response_cb callback, gpointer data)
+{
+	NMERR_T rc = NM_OK;
+	NMField *fields = NULL;
+	NMRequest *req = NULL;
+
+	if (user == NULL)
+		return NMERR_BAD_PARM;
+
+	fields = nm_field_add_pointer(fields, NM_A_BLOCKING, 0, NMFIELD_METHOD_UPDATE, 0,
+								  (default_deny ? g_strdup("1") : g_strdup("0")),
+								  NMFIELD_TYPE_UTF8);
+
+	rc = nm_send_request(user->conn, "updateblocks", fields, &req);
+	if (rc == NM_OK && req) {
+		nm_request_set_callback(req, callback);
+		nm_request_set_user_define(req, data);
+		nm_conn_add_request_item(user->conn, req);
+	}
+
+	if (fields)
+		nm_free_fields(&fields);
+
+	return rc;
+}
+
+NMERR_T
 nm_process_new_data(NMUser * user)
 {
 	NMConn *conn;
@@ -1154,13 +1348,116 @@
 
 		/* Add the folders and then the contacts */
 		nm_folder_add_contacts_and_folders(user, user->root_folder,
-										   (NMField *) (locate->value));
+										   (NMField *) (locate->ptr_value));
 
 	}
 
 	return rc;
 }
 
+gboolean nm_user_is_privacy_locked(NMUser *user)
+{
+	if (user) {
+		return user->privacy_locked;
+	}
+
+	return FALSE;
+}
+
+static gboolean
+_create_privacy_list(NMUser * user, NMRequest *request)
+{
+	NMField *locate = NULL;
+	GSList *need_details = NULL;
+
+	/* Are the privacy settings locked */
+	locate = nm_locate_field(NM_A_LOCKED_ATTR_LIST, user->fields);
+	if (locate && locate->ptr_value) {
+		if (locate->type == NMFIELD_TYPE_UTF8 &&
+			(nm_utf8_strcasecmp(locate->ptr_value, NM_A_BLOCKING) == 0)) {
+			user->privacy_locked = TRUE;
+		} else if (locate->type == NMFIELD_TYPE_MV ||
+				   locate->type == NMFIELD_TYPE_ARRAY) {
+			NMField *tmp = (NMField *)locate->ptr_value;
+			while (tmp && tmp->tag) {
+				if (nm_utf8_strcasecmp(tmp->ptr_value, NM_A_BLOCKING) == 0) {
+					user->privacy_locked = TRUE;
+					break;
+				}
+				tmp++;
+			}
+		}
+	}
+
+	/* Set default deny flag */
+	locate = nm_locate_field(NM_A_BLOCKING, user->fields);
+	if (locate && locate->ptr_value) {
+		user->default_deny = atoi((char *)locate->ptr_value);
+	}
+
+	/* Read internal blocking allow list */
+	locate = nm_locate_field(NM_A_BLOCKING_ALLOW_LIST, user->fields);
+	if (locate && locate->ptr_value) {
+
+		if (locate->type == NMFIELD_TYPE_MV) {
+			locate = (NMField *)locate->ptr_value;
+			for (; locate->tag != NULL; locate++) {
+				if (locate->ptr_value) {
+
+					user->allow_list = g_slist_append(user->allow_list, (char *)locate->ptr_value);
+
+					if (nm_find_user_record(user, (char *)locate->ptr_value) == NULL)
+						need_details = g_slist_append(need_details, (char *)locate->ptr_value);
+
+				}
+			}
+		} else {
+
+			user->allow_list = g_slist_append(user->allow_list, (char *)locate->ptr_value);
+
+			if (nm_find_user_record(user, (char *)locate->ptr_value) == NULL)
+				need_details = g_slist_append(need_details, (char *)locate->ptr_value);
+
+		}
+	}
+
+	/* Read internal blocking deny list */
+	locate = nm_locate_field(NM_A_BLOCKING_DENY_LIST, user->fields);
+	if (locate && locate->ptr_value) {
+
+		if (locate->type == NMFIELD_TYPE_MV) {
+			locate =  (NMField *)locate->ptr_value;
+			for (; locate->tag != NULL; locate++) {
+				if (locate->ptr_value) {
+
+					user->deny_list = g_slist_append(user->deny_list, (char *)locate->ptr_value);
+
+					if (nm_find_user_record(user, (char *)locate->ptr_value) == NULL)
+						need_details = g_slist_append(need_details, (char *)locate->ptr_value);
+
+				}
+			}
+		} else {
+
+			user->deny_list = g_slist_append(user->deny_list, (char *)locate->ptr_value);
+
+			if (nm_find_user_record(user, (char *)locate->ptr_value) == NULL)
+				need_details = g_slist_append(need_details, (char *)locate->ptr_value);
+
+		}
+	}
+
+	if (need_details) {
+
+		nm_send_multiple_get_details(user, need_details,
+									 _handle_multiple_get_details_login_cb, request);
+
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
 void
 nm_destroy_contact_list(NMUser * user)
 {
@@ -1305,7 +1602,6 @@
 	for (i = 0; i < num_folders; i++) {
 		temp = nm_folder_get_subfolder(user->root_folder, i);
 		tname = nm_folder_get_name(temp);
-
 		if (tname && (strcmp(tname, name) == 0)) {
 			folder = temp;
 			break;
@@ -1340,6 +1636,22 @@
 }
 
 static void
+_handle_multiple_get_details_login_cb(NMUser * user, NMERR_T ret_code,
+									  gpointer resp_data, gpointer user_data)
+{
+	nm_response_cb cb;
+	NMRequest *request = user_data;
+
+	if (user == NULL || request == NULL)
+		return;
+
+	if ((cb = nm_request_get_callback(request))) {
+		cb(user, ret_code, nm_request_get_data(request),
+		   nm_request_get_user_define(request));
+	}
+}
+
+static void
 _handle_multiple_get_details_joinconf_cb(NMUser * user, NMERR_T ret_code,
 										 gpointer resp_data, gpointer user_data)
 {
@@ -1401,7 +1713,7 @@
 	/* Get the return code */
 	field = nm_locate_field(NM_A_SZ_RESULT_CODE, fields);
 	if (field) {
-		ret_code = atoi((char *) field->value);
+		ret_code = atoi((char *) field->ptr_value);
 	} else {
 		ret_code = NMERR_PROTOCOL;
 	}
@@ -1416,6 +1728,9 @@
 			/* Save the users fields */
 			user->fields = nm_copy_field_array(fields);
 
+			nm_create_contact_list(user);
+			done = _create_privacy_list(user, request);
+
 		} else if (strcmp("setstatus", cmd) == 0) {
 
 			/* Nothing to do */
@@ -1428,13 +1743,14 @@
 			locate = nm_locate_field(NM_A_FA_CONVERSATION, fields);
 			if (locate) {
 				field =
-					nm_locate_field(NM_A_SZ_OBJECT_ID, (NMField *) fields->value);
+					nm_locate_field(NM_A_SZ_OBJECT_ID, (NMField *) fields->ptr_value);
 				if (field) {
-					nm_conference_set_guid(conf, (char *) field->value);
+					nm_conference_set_guid(conf, (char *) field->ptr_value);
 				}
 			}
 
 			nm_conference_list_add(user, conf);
+			nm_release_conference(conf);
 
 		} else if (strcmp("leaveconf", cmd) == 0) {
 
@@ -1447,26 +1763,26 @@
 			conf = nm_request_get_data(request);
 
 			locate = nm_locate_field(NM_A_FA_CONTACT_LIST, fields);
-			if (locate && locate->value != 0) {
-
-				field = (NMField *) locate->value;
+			if (locate && locate->ptr_value != 0) {
+
+				field = (NMField *) locate->ptr_value;
 				while ((field = nm_locate_field(NM_A_SZ_DN, field))) {
-					if (field && field->value != 0) {
+					if (field && field->ptr_value != 0) {
 
 						if (nm_utf8_str_equal
 							(nm_user_record_get_dn(user->user_record),
-							 (const char *) field->value)) {
+							 (const char *) field->ptr_value)) {
 							field++;
 							continue;
 						}
 
 						user_record =
 							nm_find_user_record(user,
-												(const char *) field->value);
+												(const char *) field->ptr_value);
 						if (user_record == NULL) {
 							list =
 								g_slist_append(list,
-											   g_strdup((char *) field->value));
+											   g_strdup((char *) field->ptr_value));
 						} else {
 							nm_conference_add_participant(conf, user_record);
 						}
@@ -1491,7 +1807,7 @@
 		} else if (strcmp("getdetails", cmd) == 0) {
 
 			locate = nm_locate_field(NM_A_FA_RESULTS, fields);
-			if (locate && locate->value != 0) {
+			while (locate && locate->ptr_value != 0) {
 
 				user_record = nm_create_user_record_from_fields(locate);
 				if (user_record) {
@@ -1508,16 +1824,15 @@
 						user_record = tmp;
 
 					} else {
-
 						nm_user_add_user_record(user, user_record);
 						nm_release_user_record(user_record);
-
 					}
 
 					/* Response data is new user record */
 					nm_request_set_data(request, (gpointer) user_record);
 				}
 
+				locate = nm_locate_field(NM_A_FA_RESULTS, locate+1);
 			}
 
 		} else if (strcmp("createfolder", cmd) == 0) {
@@ -1529,13 +1844,12 @@
 			_update_contact_list(user, fields);
 
 			locate =
-				nm_locate_field(NM_A_SZ_OBJECT_ID, (NMField *) fields->value);
+				nm_locate_field(NM_A_SZ_OBJECT_ID, (NMField *) fields->ptr_value);
 			if (locate) {
 
 				NMContact *new_contact =
 					nm_folder_find_item_by_object_id(user->root_folder,
-													 atoi((char *) locate->
-														  value));
+													 atoi((char *)locate->ptr_value));
 
 				if (new_contact) {
 
@@ -1563,13 +1877,25 @@
 			if (locate) {
 				nm_user_record_set_status((NMUserRecord *)
 										  nm_request_get_data(request),
-										  atoi((char *) locate->value), NULL);
+										  atoi((char *) locate->ptr_value), NULL);
 			}
 
 		} else if (strcmp("updateitem", cmd) == 0) {
 
 			/* Nothing extra to do here */
 
+		} else if (strcmp("createblock", cmd) == 0) {
+			if ((locate = nm_locate_field(NM_A_BLOCKING_DENY_LIST, fields))) {
+				if (locate->ptr_value) {
+					user->deny_list = g_slist_append(user->deny_list, g_strdup((char *)locate->ptr_value));
+				}
+			} else if ((locate = nm_locate_field(NM_A_BLOCKING_ALLOW_LIST, fields))) {
+				if (locate->ptr_value) {
+					user->allow_list = g_slist_append(user->allow_list, g_strdup((char *)locate->ptr_value));
+				}
+			}
+		} else if (strcmp("updateblocks", cmd) == 0) {
+			/* nothing to do here */
 		} else {
 
 			/* Nothing to do, just print debug message  */
@@ -1605,8 +1931,8 @@
 
 	if (rc == NM_OK) {
 		field = nm_locate_field(NM_A_SZ_TRANSACTION_ID, fields);
-		if (field != NULL && field->value != 0) {
-			req = nm_conn_find_request(conn, atoi((char *) field->value));
+		if (field != NULL && field->ptr_value != 0) {
+			req = nm_conn_find_request(conn, atoi((char *) field->ptr_value));
 			if (req != NULL) {
 				rc = nm_call_handler(user, req, fields);
 			}
@@ -1687,6 +2013,115 @@
 	return dotted;
 }
 
+const char *
+nm_error_to_string(NMERR_T err)
+{
+	static char *unknown_msg = NULL;
+
+	g_free(unknown_msg);
+	unknown_msg = NULL;
+
+	switch (err) {
+
+		case NMERR_BAD_PARM:
+			return _("Required parameters not passed in");
+
+		case NMERR_TCP_WRITE:
+			return _("Unable to write to network");
+
+		case NMERR_TCP_READ:
+			return _("Unable to read from network");
+
+		case NMERR_PROTOCOL:
+			return _("Error communicating with server");
+
+		case NMERR_CONFERENCE_NOT_FOUND:
+		case NMERR_CONFERENCE_NOT_FOUND_2:
+			return _("Conference not found");
+
+		case NMERR_CONFERENCE_NOT_INSTANTIATED:
+			return _("Conference does not exist");
+
+		case NMERR_DUPLICATE_FOLDER:
+		case NMERR_FOLDER_EXISTS:
+			return _("A folder with that name already exists");
+
+		case NMERR_NOT_SUPPORTED:
+			return _("Not supported");
+
+		case NMERR_PASSWORD_EXPIRED:
+		case NMERR_PASSWORD_EXPIRED_2:
+			return _("Password has expired");
+
+		case NMERR_PASSWORD_INVALID:
+			return _("Invalid password");
+
+		case NMERR_USER_NOT_FOUND:
+			return _("User not found");
+
+		case NMERR_USER_DISABLED:
+			return _("Account has been disabled");
+
+		case NMERR_DIRECTORY_FAILURE:
+			return _("The server could not access the directory");
+
+		case NMERR_ADMIN_LOCKED:
+			return _("Your system administrator has disabled this operation");
+
+		case NMERR_SERVER_BUSY:
+			return _("The server is unavailable; try again later");
+
+		case NMERR_DUPLICATE_CONTACT:
+			return _("Cannot add a contact to the same folder twice");
+
+		case NMERR_USER_NOT_ALLOWED:
+			return _("Cannot add yourself");
+
+		case NMERR_MASTER_ARCHIVE_MISSING:
+			return _("Master archive is misconfigured");
+
+		case NMERR_AUTHENTICATION_FAILED:
+		case NMERR_CREDENTIALS_MISSING:
+			return _("Invalid username or password");
+
+		case NMERR_HOST_NOT_FOUND:
+			return _("Could not recognize the host of the username you entered");
+
+		case NMERR_ACCESS_DENIED:
+			return _("Your account has been disabled because too many invalid passwords were entered");
+
+		case NMERR_DUPLICATE_PARTICIPANT:
+			return _("You cannot add the same person twice to a conversation");
+
+		case NMERR_TOO_MANY_CONTACTS:
+		case NMERR_TOO_MANY_FOLDERS:
+			return _("You have reached your limit for the number of contacts allowed");
+
+		case NMERR_OBJECT_NOT_FOUND:
+			return _("You have entered an invalid username");
+
+		case NMERR_DIRECTORY_UPDATE:
+			return _("An error occurred while updating the directory");
+
+		case NMERR_SERVER_PROTOCOL:
+			return _("Incompatible protocol version");
+
+		case NMERR_USER_BLOCKED:
+			return _("The user has blocked you");
+
+		case NMERR_EVAL_CONNECTION_LIMIT:
+			return _("This evaluation version does not allow more than ten users to log in at one time");
+
+		case NMERR_CONVERSATION_INVITE:
+			return _("The user is either offline or you are blocked");
+
+		default:
+			unknown_msg = g_strdup_printf (_("Unknown error: 0x%X"), err);
+
+			return unknown_msg;
+	}
+}
+
 static void
 _update_contact_list(NMUser * user, NMField * fields)
 {
@@ -1701,21 +2136,21 @@
 
 	/* Is it wrapped in a RESULTS array? */
 	if (strcmp(fields->tag, NM_A_FA_RESULTS) == 0) {
-		list = (NMField *) fields->value;
+		list = (NMField *) fields->ptr_value;
 	} else {
 		list = fields;
 	}
 
 	/* Update the cached contact list */
-	cursor = (NMField *) list->value;
+	cursor = (NMField *) list->ptr_value;
 	while (cursor->tag != NULL) {
 		if ((g_ascii_strcasecmp(cursor->tag, NM_A_FA_CONTACT) == 0) ||
 			(g_ascii_strcasecmp(cursor->tag, NM_A_FA_FOLDER) == 0)) {
 
 			locate =
-				nm_locate_field(NM_A_SZ_OBJECT_ID, (NMField *) cursor->value);
-			if (locate != NULL && locate->value != 0) {
-				objid1 = atoi((char *) locate->value);
+				nm_locate_field(NM_A_SZ_OBJECT_ID, (NMField *) cursor->ptr_value);
+			if (locate != NULL && locate->ptr_value != 0) {
+				objid1 = atoi((char *) locate->ptr_value);
 				item =
 					nm_folder_find_item_by_object_id(user->root_folder, objid1);
 				if (item != NULL) {
@@ -1757,9 +2192,9 @@
 
 							locate =
 								nm_locate_field(NM_A_SZ_DN,
-												(NMField *) cursor->value);
-							if (locate != NULL && locate->value != 0) {
-								dn = (const char *) locate->value;
+												(NMField *) cursor->ptr_value);
+							if (locate != NULL && locate->ptr_value != 0) {
+								dn = (const char *) locate->ptr_value;
 								if (dn != NULL) {
 									contact =
 										nm_create_contact_from_fields(cursor);
--- a/src/protocols/novell/nmuser.h	Sat May 15 06:24:52 2004 +0000
+++ b/src/protocols/novell/nmuser.h	Sat May 15 14:00:31 2004 +0000
@@ -1,22 +1,20 @@
 /*
  * nmuser.h
  *
- * Copyright © 2004 Unpublished Work of Novell, Inc. All Rights Reserved.
+ * Copyright (c) 2004 Novell, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
  *
- * THIS WORK IS AN UNPUBLISHED WORK OF NOVELL, INC. NO PART OF THIS WORK MAY BE
- * USED, PRACTICED, PERFORMED, COPIED, DISTRIBUTED, REVISED, MODIFIED,
- * TRANSLATED, ABRIDGED, CONDENSED, EXPANDED, COLLECTED, COMPILED, LINKED,
- * RECAST, TRANSFORMED OR ADAPTED WITHOUT THE PRIOR WRITTEN CONSENT OF NOVELL,
- * INC. ANY USE OR EXPLOITATION OF THIS WORK WITHOUT AUTHORIZATION COULD SUBJECT
- * THE PERPETRATOR TO CRIMINAL AND CIVIL LIABILITY.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
  *
- * AS BETWEEN [GAIM] AND NOVELL, NOVELL GRANTS [GAIM] THE RIGHT TO REPUBLISH
- * THIS WORK UNDER THE GPL (GNU GENERAL PUBLIC LICENSE) WITH ALL RIGHTS AND
- * LICENSES THEREUNDER.  IF YOU HAVE RECEIVED THIS WORK DIRECTLY OR INDIRECTLY
- * FROM [GAIM] AS PART OF SUCH A REPUBLICATION, YOU HAVE ALL RIGHTS AND LICENSES
- * GRANTED BY [GAIM] UNDER THE GPL.  IN CONNECTION WITH SUCH A REPUBLICATION, IF
- * ANYTHING IN THIS NOTICE CONFLICTS WITH THE TERMS OF THE GPL, SUCH TERMS
- * PREVAIL.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA	02111-1307	USA
  *
  */
 
@@ -106,6 +104,12 @@
 	/* Called when we receive an event */
 	nm_event_cb evt_callback;
 
+	/* Privacy settings */
+	gboolean privacy_locked;
+	gboolean default_deny;
+	GSList *allow_list;
+	GSList *deny_list;
+
 	/* Pending requests. If we need to go to the server to more info
 	 * before processing a request we will queue it up and process when
 	 * we get a response
@@ -122,7 +126,6 @@
 
 };
 
-
 #define	NM_STATUS_UNKNOWN			0
 #define	NM_STATUS_OFFLINE			1
 #define NM_STATUS_AVAILABLE			2
@@ -137,11 +140,40 @@
 #define NMERR_TCP_WRITE						(NMERR_BASE + 0x0002)
 #define NMERR_TCP_READ						(NMERR_BASE + 0x0003)
 #define NMERR_PROTOCOL						(NMERR_BASE + 0x0004)
-#define NMERR_SSL_REDIRECT					(NMERR_BASE + 0x0005)
+#define NMERR_SERVER_REDIRECT				(NMERR_BASE + 0x0005)
 #define NMERR_CONFERENCE_NOT_FOUND 			(NMERR_BASE + 0x0006)
 #define NMERR_CONFERENCE_NOT_INSTANTIATED 	(NMERR_BASE + 0x0007)
 #define NMERR_FOLDER_EXISTS					(NMERR_BASE + 0x0008)
 
+/* Errors that are returned from the server */
+#define NMERR_SERVER_BASE			 	0xD100L
+#define NMERR_ACCESS_DENIED			 	(NMERR_SERVER_BASE + 0x0006)
+#define NMERR_NOT_SUPPORTED          	(NMERR_SERVER_BASE + 0x000A)
+#define NMERR_PASSWORD_EXPIRED       	(NMERR_SERVER_BASE + 0x000B)
+#define NMERR_PASSWORD_INVALID       	(NMERR_SERVER_BASE + 0x000C)
+#define NMERR_USER_NOT_FOUND         	(NMERR_SERVER_BASE + 0x000D)
+#define NMERR_USER_DISABLED          	(NMERR_SERVER_BASE + 0x0010)
+#define NMERR_DIRECTORY_FAILURE      	(NMERR_SERVER_BASE + 0x0011)
+#define NMERR_HOST_NOT_FOUND		 	(NMERR_SERVER_BASE + 0x0019)
+#define NMERR_ADMIN_LOCKED           	(NMERR_SERVER_BASE + 0x001C)
+#define NMERR_DUPLICATE_PARTICIPANT  	(NMERR_SERVER_BASE + 0x001F)
+#define NMERR_SERVER_BUSY            	(NMERR_SERVER_BASE + 0x0023)
+#define NMERR_OBJECT_NOT_FOUND       	(NMERR_SERVER_BASE + 0x0024)
+#define NMERR_DIRECTORY_UPDATE       	(NMERR_SERVER_BASE + 0x0025)
+#define NMERR_DUPLICATE_FOLDER       	(NMERR_SERVER_BASE + 0x0026)
+#define NMERR_DUPLICATE_CONTACT      	(NMERR_SERVER_BASE + 0x0027)
+#define NMERR_USER_NOT_ALLOWED       	(NMERR_SERVER_BASE + 0x0028)
+#define NMERR_TOO_MANY_CONTACTS      	(NMERR_SERVER_BASE + 0x0029)
+#define NMERR_CONFERENCE_NOT_FOUND_2   	(NMERR_SERVER_BASE + 0x002B)
+#define NMERR_TOO_MANY_FOLDERS       	(NMERR_SERVER_BASE + 0x002C)
+#define NMERR_SERVER_PROTOCOL        	(NMERR_SERVER_BASE + 0x0030)
+#define NMERR_CONVERSATION_INVITE		(NMERR_SERVER_BASE + 0x0035)
+#define NMERR_USER_BLOCKED	         	(NMERR_SERVER_BASE + 0x0039)
+#define NMERR_MASTER_ARCHIVE_MISSING 	(NMERR_SERVER_BASE + 0x003A)
+#define NMERR_PASSWORD_EXPIRED_2     	(NMERR_SERVER_BASE + 0x0042)
+#define NMERR_CREDENTIALS_MISSING   	(NMERR_SERVER_BASE + 0x0046)
+#define NMERR_AUTHENTICATION_FAILED		(NMERR_SERVER_BASE + 0x0049)
+#define NMERR_EVAL_CONNECTION_LIMIT		(NMERR_SERVER_BASE + 0x004A)
 
 /**
  *	Initialize the user that we are going to login to the system as.
@@ -207,10 +239,11 @@
  *
  *	The response data sent to the callback will be NULL.
  *
- *  @param	user		The logged in User
- *	@param	conference	Conference to create
- *	@param	callback	Function to call when we get the response from the server
- *	@param	data		User defined data to be passed to the callback function
+ *  @param	user			 The logged in User
+ *	@param	conference		 Conference to create
+ *	@param	add_participants Add participant list on create?
+ *	@param	callback		 Function to call when we get the response from the server
+ *	@param	data			 User defined data to be passed to the callback function
  *
  *	@return	NM_OK if successfully sent, error otherwise
  */
@@ -264,6 +297,41 @@
 NMERR_T nm_send_reject_conference(NMUser * user, NMConference * conference,
 								  nm_response_cb callback, gpointer data);
 
+
+/**
+ *	Send a conference invitation to the server.
+ *
+ *	The response data sent to the callback will be NULL.
+ *
+ *  @param	user		The logged in User
+ *	@param	conference	Conference the user is rejecting
+ *  @param  user_record The user to invite
+ *  @param  message		The invite message if there is one, NULL otherwise
+ *	@param	callback	Function to call when we get the response from the server
+ *	@param	data		User defined data to be passed to the callback function
+ *
+ *
+ *	@return	NM_OK if successfully sent, error otherwise
+ */
+NMERR_T nm_send_conference_invite(NMUser *user, NMConference *conference, NMUserRecord *user_record,
+								  const char *message, nm_response_cb callback, gpointer data);
+
+/**
+ *	Get details for a more than one user from the server.
+ *
+ *	The response data sent to the callback will be an NMUserRecord which should be
+ *  freed with nm_release_user_record
+ *
+ *  @param	user		The logged in User
+ *	@param	names		Link list of user id's or dn's
+ *	@param	callback	Function to call when we get the response from the server
+ *	@param	data		User defined data to be passed to the callback function
+ *
+ *	@return	NM_OK if successfully sent, error otherwise
+ */
+NMERR_T nm_send_multiple_get_details(NMUser * user, GSList *names,
+									 nm_response_cb callback, gpointer data);
+
 /**
  *	Get details for a user from the server.
  *
@@ -281,23 +349,6 @@
 							nm_response_cb callback, gpointer data);
 
 /**
- *	Get details for multiple users from the server.
- *
- *	The response data to the callback will be a list of NMUserRecord, which should be
- *	freed (each user record should be released with nm_release_user_record and the
- *  list should be freed)
- *
- *  @param	user		The logged in User
- *	@param	name		Userid or DN of the user to look up
- *	@param	callback	Function to call when we get the response from the server
- *	@param	data		User defined data to be passed to the callback function
- *
- *	@return	NM_OK if successfully sent, error otherwise
- */
-NMERR_T nm_send_multiple_get_details(NMUser *user, GSList *names,
-									 nm_response_cb callback, gpointer data);
-
-/**
  *	Send a message.
  *
  *  The response data sent to the callback will be NULL.
@@ -464,6 +515,50 @@
 						   nm_response_cb callback, gpointer data);
 
 /**
+ *	Send a request to add an item to the allow or deny list.
+ *
+ *  @param	user		The logged in User
+ *	@param	who			The userid or DN of the user to add to list
+ *  @param	allow_list	TRUE if adding to allow list, FALSE if adding to deny list
+ *	@param	callback	Function to call when we get the response from the server
+ *  @param	data		User defined data
+ *
+ *	@return	NM_OK if successfully sent, error otherwise
+ */
+NMERR_T
+nm_send_create_privacy_item(NMUser *user, const char *who, gboolean is_allowed,
+							nm_response_cb callback, gpointer data);
+
+/**
+ *	Send a request to remove an item from the allow or deny list.
+ *
+ *  @param	user		The logged in User
+ *	@param	who			The userid or DN of the user to add to list
+ *  @param	allow_list	TRUE if removing from allow list, FALSE if removing from deny list
+ *	@param	callback	Function to call when we get the response from the server
+ *  @param	data		User defined data
+ *
+ *	@return	NM_OK if successfully sent, error otherwise
+ */
+NMERR_T
+nm_send_remove_privacy_item(NMUser *user, const char *dn, gboolean allow_list,
+							nm_response_cb callback, gpointer data);
+
+/**
+ *	Send a request to change the default privacy setting to deny all or allow all
+ *
+ *  @param	user			The logged in User
+ *	@param	default_deny	TRUE if default should be changed to deny all
+ *	@param	callback		Function to call when we get the response from the server
+ *  @param	data			User defined data
+ *
+ *	@return	NM_OK if successfully sent, error otherwise
+ */
+NMERR_T
+nm_send_set_privacy_default(NMUser *user, gboolean default_deny,
+							nm_response_cb callback, gpointer data);
+
+/**
  *	Reads a response/event from the server and processes it.
  *
  *  @param	user	The logged in User
@@ -519,6 +614,8 @@
 
 NMConn *nm_user_get_conn(NMUser * user);
 
+gboolean nm_user_is_privacy_locked(NMUser *user);
+
 /** Some utility functions **/
 
 /**
@@ -566,4 +663,13 @@
  */
 char *nm_typed_to_dotted(const char *typed);
 
+/**
+ *      Return a string representation of the error code.
+ *
+ *      @param  error           NMERR_T to convert to string
+ *
+ *      @return String representation.
+ */
+const char *nm_error_to_string (NMERR_T err);
+
 #endif
--- a/src/protocols/novell/nmuserrecord.c	Sat May 15 06:24:52 2004 +0000
+++ b/src/protocols/novell/nmuserrecord.c	Sat May 15 14:00:31 2004 +0000
@@ -1,22 +1,20 @@
 /*
  * nmuserrecord.c
  *
- * Copyright © 2004 Unpublished Work of Novell, Inc. All Rights Reserved.
+ * Copyright (c) 2004 Novell, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
  *
- * THIS WORK IS AN UNPUBLISHED WORK OF NOVELL, INC. NO PART OF THIS WORK MAY BE
- * USED, PRACTICED, PERFORMED, COPIED, DISTRIBUTED, REVISED, MODIFIED,
- * TRANSLATED, ABRIDGED, CONDENSED, EXPANDED, COLLECTED, COMPILED, LINKED,
- * RECAST, TRANSFORMED OR ADAPTED WITHOUT THE PRIOR WRITTEN CONSENT OF NOVELL,
- * INC. ANY USE OR EXPLOITATION OF THIS WORK WITHOUT AUTHORIZATION COULD SUBJECT
- * THE PERPETRATOR TO CRIMINAL AND CIVIL LIABILITY.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
  *
- * AS BETWEEN [GAIM] AND NOVELL, NOVELL GRANTS [GAIM] THE RIGHT TO REPUBLISH
- * THIS WORK UNDER THE GPL (GNU GENERAL PUBLIC LICENSE) WITH ALL RIGHTS AND
- * LICENSES THEREUNDER.  IF YOU HAVE RECEIVED THIS WORK DIRECTLY OR INDIRECTLY
- * FROM [GAIM] AS PART OF SUCH A REPUBLICATION, YOU HAVE ALL RIGHTS AND LICENSES
- * GRANTED BY [GAIM] UNDER THE GPL.  IN CONNECTION WITH SUCH A REPUBLICATION, IF
- * ANYTHING IN THIS NOTICE CONFLICTS WITH THE TERMS OF THE GPL, SUCH TERMS
- * PREVAIL.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA	02111-1307	USA
  *
  */
 
@@ -70,24 +68,24 @@
 {
 	char *value = NULL;
 
-	if (field->value == 0)
+	if (field->ptr_value == NULL)
 		return NULL;
 
 	if (field->type == NMFIELD_TYPE_UTF8 || field->type == NMFIELD_TYPE_DN) {
 
-		value = (char *)field->value;
+		value = (char *)field->ptr_value;
 
 	} else if (field->type == NMFIELD_TYPE_MV) {
 
 		/* Need to handle multi-valued returns, for now
 		 * just pick the first value and return it
 		 */
-		NMField *tmp = (NMField *)field->value;
+		NMField *tmp = (NMField *)field->ptr_value;
 		if ((tmp != NULL) &&
 			((tmp->type == NMFIELD_TYPE_UTF8) ||
 			(tmp->type == NMFIELD_TYPE_DN))) {
 
-			value = (char *)tmp->value;
+			value = (char *)tmp->ptr_value;
 
 		} else {
 			return NULL;
@@ -115,16 +113,16 @@
 	}
 
 	if (details->type == NMFIELD_TYPE_ARRAY) {
-		if (details->value == 0)
+		if (details->ptr_value == NULL)
 			return NULL;
-		fields = (NMField *) details->value;
+		fields = (NMField *) details->ptr_value;
 	}
 
 	user_record = nm_create_user_record();
 
 	if ((field = nm_locate_field(NM_A_SZ_AUTH_ATTRIBUTE, fields))) {
 
-		if (field->value) {
+		if (field->ptr_value) {
 			user_record->display_id = _get_attribute_value(field);
 			user_record->auth_attr = TRUE;
 		}
@@ -132,50 +130,50 @@
 
 	if ((field = nm_locate_field(NM_A_SZ_DN, fields))) {
 
-		if (field->value) {
+		if (field->ptr_value) {
 			user_record->dn = _get_attribute_value(field);
 		}
 	}
 
 	if ((field = nm_locate_field("CN", fields))) {
 
-		if (field->value) {
+		if (field->ptr_value) {
 			user_record->cn = _get_attribute_value(field);
 		}
 	}
 
 	if ((field = nm_locate_field("Given Name", fields))) {
 
-		if (field->value) {
+		if (field->ptr_value) {
 			user_record->fname = _get_attribute_value(field);
 		}
 	}
 
 	if ((field = nm_locate_field("Surname", fields))) {
 
-		if (field->value) {
+		if (field->ptr_value) {
 			user_record->lname = _get_attribute_value(field);
 		}
 	}
 
 	if ((field = nm_locate_field("Full Name", fields))) {
 
-		if (field->value) {
+		if (field->ptr_value) {
 			user_record->full_name = _get_attribute_value(field);
 		}
 	}
 
 	if ((field = nm_locate_field(NM_A_SZ_STATUS, fields))) {
 
-		if (field->value)
-			user_record->status = atoi((char *) field->value);
+		if (field->ptr_value)
+			user_record->status = atoi((char *) field->ptr_value);
 
 	}
 
 	if ((field = nm_locate_field(NM_A_SZ_MESSAGE_BODY, fields))) {
 
-		if (field->value)
-			user_record->status_text = g_strdup((char *) field->value);
+		if (field->ptr_value)
+			user_record->status_text = g_strdup((char *) field->ptr_value);
 
 	}
 
@@ -495,7 +493,7 @@
 	if (user_record && user_record->fields) {
 		locate = nm_locate_field(NM_A_FA_INFO_DISPLAY_ARRAY,
 								 (NMField *) user_record->fields);
-		if (locate && (fields = (NMField *) (locate->value))) {
+		if (locate && (fields = (NMField *) (locate->ptr_value))) {
 			count = (int) nm_count_fields(fields);
 		}
 	}
@@ -511,13 +509,13 @@
 	if (user_record && user_record->fields) {
 		locate = nm_locate_field(NM_A_FA_INFO_DISPLAY_ARRAY,
 								 (NMField *) user_record->fields);
-		if (locate && (fields = (NMField *) (locate->value))) {
+		if (locate && (fields = (NMField *) (locate->ptr_value))) {
 			int max = nm_count_fields(fields);
 
 			if (index < max) {
 				if (user_record) {
 					field = &fields[index];
-					if (field && field->tag && field->value) {
+					if (field && field->tag && field->ptr_value) {
 						property = g_new0(NMProperty, 1);
 						property->tag = g_strdup(field->tag);
 						property->value = _get_attribute_value(field);
--- a/src/protocols/novell/nmuserrecord.h	Sat May 15 06:24:52 2004 +0000
+++ b/src/protocols/novell/nmuserrecord.h	Sat May 15 14:00:31 2004 +0000
@@ -1,22 +1,20 @@
 /*
  * nmuserrecord.h
  *
- * Copyright © 2004 Unpublished Work of Novell, Inc. All Rights Reserved.
+ * Copyright (c) 2004 Novell, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
  *
- * THIS WORK IS AN UNPUBLISHED WORK OF NOVELL, INC. NO PART OF THIS WORK MAY BE
- * USED, PRACTICED, PERFORMED, COPIED, DISTRIBUTED, REVISED, MODIFIED,
- * TRANSLATED, ABRIDGED, CONDENSED, EXPANDED, COLLECTED, COMPILED, LINKED,
- * RECAST, TRANSFORMED OR ADAPTED WITHOUT THE PRIOR WRITTEN CONSENT OF NOVELL,
- * INC. ANY USE OR EXPLOITATION OF THIS WORK WITHOUT AUTHORIZATION COULD SUBJECT
- * THE PERPETRATOR TO CRIMINAL AND CIVIL LIABILITY.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
  *
- * AS BETWEEN [GAIM] AND NOVELL, NOVELL GRANTS [GAIM] THE RIGHT TO REPUBLISH
- * THIS WORK UNDER THE GPL (GNU GENERAL PUBLIC LICENSE) WITH ALL RIGHTS AND
- * LICENSES THEREUNDER.  IF YOU HAVE RECEIVED THIS WORK DIRECTLY OR INDIRECTLY
- * FROM [GAIM] AS PART OF SUCH A REPUBLICATION, YOU HAVE ALL RIGHTS AND LICENSES
- * GRANTED BY [GAIM] UNDER THE GPL.  IN CONNECTION WITH SUCH A REPUBLICATION, IF
- * ANYTHING IN THIS NOTICE CONFLICTS WITH THE TERMS OF THE GPL, SUCH TERMS
- * PREVAIL.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA	02111-1307	USA
  *
  */
 
--- a/src/protocols/novell/novell.c	Sat May 15 06:24:52 2004 +0000
+++ b/src/protocols/novell/novell.c	Sat May 15 14:00:31 2004 +0000
@@ -1,22 +1,20 @@
 /*
  * novell.c
  *
- * Copyright © 2004 Unpublished Work of Novell, Inc. All Rights Reserved.
+ * Copyright (c) 2004 Novell, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
  *
- * THIS WORK IS AN UNPUBLISHED WORK OF NOVELL, INC. NO PART OF THIS WORK MAY BE
- * USED, PRACTICED, PERFORMED, COPIED, DISTRIBUTED, REVISED, MODIFIED,
- * TRANSLATED, ABRIDGED, CONDENSED, EXPANDED, COLLECTED, COMPILED, LINKED,
- * RECAST, TRANSFORMED OR ADAPTED WITHOUT THE PRIOR WRITTEN CONSENT OF NOVELL,
- * INC. ANY USE OR EXPLOITATION OF THIS WORK WITHOUT AUTHORIZATION COULD SUBJECT
- * THE PERPETRATOR TO CRIMINAL AND CIVIL LIABILITY.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
  *
- * AS BETWEEN [GAIM] AND NOVELL, NOVELL GRANTS [GAIM] THE RIGHT TO REPUBLISH
- * THIS WORK UNDER THE GPL (GNU GENERAL PUBLIC LICENSE) WITH ALL RIGHTS AND
- * LICENSES THEREUNDER.  IF YOU HAVE RECEIVED THIS WORK DIRECTLY OR INDIRECTLY
- * FROM [GAIM] AS PART OF SUCH A REPUBLICATION, YOU HAVE ALL RIGHTS AND LICENSES
- * GRANTED BY [GAIM] UNDER THE GPL.  IN CONNECTION WITH SUCH A REPUBLICATION, IF
- * ANYTHING IN THIS NOTICE CONFLICTS WITH THE TERMS OF THE GPL, SUCH TERMS
- * PREVAIL.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA	02111-1307	USA
  *
  */
 
@@ -31,12 +29,16 @@
 #include "sslconn.h"
 #include "request.h"
 #include "network.h"
+#include "privacy.h"
+#include "multi.h"
 
 #define DEFAULT_PORT			8300
 #define NOVELL_CONNECT_STEPS	4
 
 static GaimPlugin *my_protocol = NULL;
 
+static gboolean set_permit = FALSE;
+
 static gboolean
 _is_disconnect_error(NMERR_T err);
 
@@ -59,8 +61,17 @@
 _add_gaim_buddies(NMUser * user);
 
 static void
+_sync_contact_list(NMUser *user);
+
+static void
+_sync_privacy_lists(NMUser *user);
+
+static void
 _show_info(GaimConnection * gc, NMUserRecord * user_record);
 
+const char *
+_get_conference_name(int id);
+
 /*******************************************************************************
  * Response callbacks
  *******************************************************************************/
@@ -92,25 +103,21 @@
 				gaim_account_set_alias(user->client_data, alias);
 		}
 
+		_sync_contact_list(user);
+		_sync_privacy_lists(user);
+
 		/* Tell Gaim that we are connected */
 		gaim_connection_set_state(gc, GAIM_CONNECTED);
 		serv_finish_login(gc);
 
-		/* Sync the contact list. This is pretty simplistic right now,
-		 * we just remove all of the GaimBuddy from the client side list
-		 * for this account and then add in all of the contacts from the
-		 * server side list.
-		 */
-		_remove_gaim_buddies(user);
-		_add_gaim_buddies(user);
-
 		rc = nm_send_set_status(user, NM_STATUS_AVAILABLE, NULL, NULL, NULL,
 								NULL);
 		_check_for_disconnect(user, rc);
 
 	} else {
 
-		char *err = g_strdup_printf(_("Login failed (0x%X)."), ret_code);
+		char *err = g_strdup_printf(_("Login failed (%s)."),
+					    nm_error_to_string (ret_code));
 
 		gaim_connection_error(gc, err);
 		g_free(err);
@@ -223,8 +230,8 @@
 		gc = gaim_account_get_connection(user->client_data);
 		if (gc != NULL) {
 			char *err = g_strdup_printf(_("Unable to send message."
-										  " Could not get details for user (0x%X)."),
-										ret_code);
+										  " Could not get details for user (%s)."),
+						    nm_error_to_string (ret_code));
 
 			gaim_notify_error(gc, NULL, err, NULL);
 			g_free(err);
@@ -368,8 +375,8 @@
 		char *err;
 
 		err =
-			g_strdup_printf(_("Unable to add %s to your buddy list (0x%X)."),
-							name, ret_code);
+			g_strdup_printf(_("Unable to add %s to your buddy list (%s)."),
+					name, nm_error_to_string (ret_code));
 		gaim_notify_error(gc, NULL, err, NULL);
 		g_free(err);
 
@@ -394,8 +401,8 @@
 		gc = gaim_account_get_connection(user->client_data);
 
 		/* TODO: Improve this! message to who or for what conference? */
-		err = g_strdup_printf(_("Unable to send message (0x%X)."),
-							  ret_code);
+		err = g_strdup_printf(_("Unable to send message (%s)."),
+				      nm_error_to_string (ret_code));
 		gaim_notify_error(gc, NULL, err, NULL);
 		g_free(err);
 	}
@@ -453,6 +460,28 @@
 	}
 }
 
+static void
+_sendinvite_resp_cb(NMUser *user, NMERR_T ret_code,
+					gpointer resp_data, gpointer user_data)
+{
+	char *err;
+	GaimConnection *gc;
+
+	if (user == NULL)
+		return;
+
+	if (ret_code != NM_OK) {
+		gc = gaim_account_get_connection(user->client_data);
+		err = g_strdup_printf(_("Unable to invite user (%s)."), nm_error_to_string(ret_code));
+		gaim_notify_error(gc, NULL, err, NULL);
+		g_free(err);
+
+		gaim_debug(GAIM_DEBUG_INFO, "novell",
+				   "_sendinvite_resp_cb(): rc = 0x%x\n", ret_code);
+	}
+
+}
+
 /* If the createconf was successful attempt to send the message,
  * otherwise display an error message to the user.
  */
@@ -483,12 +512,13 @@
 
 			if (name)
 				err = g_strdup_printf(_("Unable to send message to %s."
-										" Could not create the conference (0x%X)."),
-									  name, ret_code);
+										" Could not create the conference (%s)."),
+						      name,
+						      nm_error_to_string (ret_code));
 			else
 				err = g_strdup_printf(_("Unable to send message."
-										" Could not create the conference (0x%X)."),
-									  ret_code);
+										" Could not create the conference (%s)."),
+						      nm_error_to_string (ret_code));
 
 			gaim_notify_error(gc, NULL, err, NULL);
 			g_free(err);
@@ -517,7 +547,7 @@
 		return;
 	}
 
-	if (ret_code == NM_OK || ret_code == 0xD126) {
+	if (ret_code == NM_OK || ret_code == NMERR_DUPLICATE_FOLDER) {
 		new_folder = nm_find_folder(user, folder_name);
 		if (new_folder) {
 
@@ -535,10 +565,10 @@
 		GaimConnection *gc = gaim_account_get_connection(user->client_data);
 		char *err = g_strdup_printf(_("Unable to move user %s"
 									  " to folder %s in the server side list."
-									  " Error while creating folder (0x%X)."),
-									nm_contact_get_dn(contact),
-									folder_name,
-									ret_code);
+									  " Error while creating folder (%s)."),
+					    nm_contact_get_dn(contact),
+					    folder_name,
+					    nm_error_to_string (ret_code));
 
 		gaim_notify_error(gc, NULL, err, NULL);
 		g_free(err);
@@ -569,7 +599,7 @@
 		return;
 	}
 
-	if (ret_code == NM_OK || ret_code == 0xD126) {
+	if (ret_code == NM_OK || ret_code == NMERR_DUPLICATE_FOLDER) {
 		folder = nm_find_folder(user, folder_name);
 		if (folder) {
 
@@ -582,8 +612,8 @@
 		const char *name = nm_contact_get_dn(contact);
 		char *err =
 			g_strdup_printf(_("Unable to add %s to your buddy list."
-							 " Error creating folder in server side list (0x%X)."),
-							name, ret_code);
+					  " Error creating folder in server side list (%s)."),
+					name, nm_error_to_string (ret_code));
 
 		gaim_notify_error(gc, NULL, err, NULL);
 
@@ -602,8 +632,7 @@
 	GaimConnection *gc;
 	NMUserRecord *ur;
 	NMConference *conference = user_data;
-	const char *name;
-	char *conf_name;
+	const char *name, *conf_name;
 	int i, count;
 
 	if (user == NULL || conference == NULL)
@@ -612,8 +641,7 @@
 	gc = gaim_account_get_connection(user->client_data);
 
 	if (ret_code == NM_OK) {
-		conf_name = g_strdup_printf(_("GroupWise Conference %d"),
-									++user->conference_count);
+		conf_name = _get_conference_name(++user->conference_count);
 		chat = serv_got_joined_chat(gc, user->conference_count, conf_name);
 		if (chat) {
 
@@ -628,7 +656,6 @@
 				}
 			}
 		}
-		g_free(conf_name);
 	}
 }
 
@@ -656,8 +683,8 @@
 	} else {
 		gc = gaim_account_get_connection(user->client_data);
 		err =
-			g_strdup_printf(_("Could not get details for user %s (0x%X)."), name,
-							ret_code);
+			g_strdup_printf(_("Could not get details for user %s (%s)."),
+					name, nm_error_to_string (ret_code));
 		gaim_notify_error(gc, NULL, err, NULL);
 		g_free(err);
 	}
@@ -666,6 +693,312 @@
 		g_free(name);
 }
 
+/* Handle get details response add to privacy list */
+static void
+_get_details_resp_add_privacy_item(NMUser *user, NMERR_T ret_code,
+								   gpointer resp_data, gpointer user_data)
+{
+	GaimConnection *gc;
+	NMUserRecord *user_record = resp_data;
+	char *err;
+	gboolean allowed = (gboolean)user_data;
+	const char *display_id;
+
+	if (user == NULL)
+		return;
+
+	gc = gaim_account_get_connection(user->client_data);
+	display_id = nm_user_record_get_display_id(user_record);
+
+	if (ret_code == NM_OK) {
+
+		if (allowed) {
+
+			if (!g_slist_find_custom(gc->account->permit,
+									 display_id, (GCompareFunc)nm_utf8_strcasecmp)) {
+				gaim_privacy_permit_add(gc->account, display_id, TRUE);
+			}
+
+		} else {
+
+			if (!g_slist_find_custom(gc->account->permit,
+									 display_id, (GCompareFunc)nm_utf8_strcasecmp)) {
+				gaim_privacy_deny_add(gc->account, display_id, TRUE);
+			}
+		}
+
+	} else {
+
+		err = g_strdup_printf(_("Unable to add user to privacy list (%s)."),
+							  nm_error_to_string(ret_code));
+		gaim_notify_error(gc, NULL, err, NULL);
+		g_free(err);
+
+	}
+}
+
+/* Handle response to create privacy item request */
+static void
+_create_privacy_item_deny_resp_cb(NMUser *user, NMERR_T ret_code,
+								  gpointer resp_data, gpointer user_data)
+{
+	GaimConnection *gc;
+	NMUserRecord *user_record;
+	char *who = user_data;
+	char *err;
+	NMERR_T rc = NM_OK;
+	const char *display_id = NULL;
+
+	if (user == NULL)
+		return;
+
+	gc = gaim_account_get_connection(user->client_data);
+
+	if (ret_code == NM_OK) {
+
+		user_record = nm_find_user_record(user, who);
+		if (user_record)
+			display_id = nm_user_record_get_display_id(user_record);
+
+		if (display_id) {
+
+			if (!g_slist_find_custom(gc->account->deny,
+									 display_id, (GCompareFunc)nm_utf8_strcasecmp)) {
+
+				gaim_privacy_deny_add(gc->account, display_id, TRUE);
+			}
+
+		} else {
+			rc = nm_send_get_details(user, who,
+									 _get_details_resp_add_privacy_item,
+									 (gpointer)FALSE);
+			_check_for_disconnect(user, rc);
+		}
+	} else {
+
+		err = g_strdup_printf(_("Unable to add %s to deny list (%s)."),
+							  who, nm_error_to_string(ret_code));
+		gaim_notify_error(gc, NULL, err, NULL);
+		g_free(err);
+
+	}
+
+	if (who)
+		g_free(who);
+
+}
+
+/* Handle response to create privacy item request */
+static void
+_create_privacy_item_permit_resp_cb(NMUser *user, NMERR_T ret_code,
+									gpointer resp_data, gpointer user_data)
+{
+	GaimConnection *gc;
+	NMUserRecord *user_record;
+	char *who = user_data;
+	char *err;
+	NMERR_T rc = NM_OK;
+	const char *display_id = NULL;
+
+	if (user == NULL)
+		return;
+
+	gc = gaim_account_get_connection(user->client_data);
+
+	if (ret_code == NM_OK) {
+
+		user_record = nm_find_user_record(user, who);
+		if (user_record)
+			display_id = nm_user_record_get_display_id(user_record);
+
+		if (display_id) {
+
+			if (!g_slist_find_custom(gc->account->permit,
+									 display_id,
+									 (GCompareFunc)nm_utf8_strcasecmp)) {
+
+				gaim_privacy_permit_add(gc->account, display_id, TRUE);
+			}
+
+		} else {
+			rc = nm_send_get_details(user, who,
+									 _get_details_resp_add_privacy_item,
+									 (gpointer)TRUE);
+			_check_for_disconnect(user, rc);
+		}
+
+	} else {
+
+		err = g_strdup_printf(_("Unable to add %s to permit list (%s)."), who,
+							  nm_error_to_string(ret_code));
+		gaim_notify_error(gc, NULL, err, NULL);
+		g_free(err);
+
+	}
+
+	if (who)
+		g_free(who);
+}
+
+static void
+_get_details_send_privacy_create(NMUser *user, NMERR_T ret_code,
+								 gpointer resp_data, gpointer user_data)
+{
+	NMERR_T rc = NM_OK;
+	GaimConnection *gc;
+	NMUserRecord *user_record = resp_data;
+	char *err;
+	gboolean allowed = (gboolean)user_data;
+	const char *dn, *display_id;
+
+	if (user == NULL)
+		return;
+
+	gc = gaim_account_get_connection(user->client_data);
+	dn = nm_user_record_get_dn(user_record);
+	display_id = nm_user_record_get_display_id(user_record);
+
+	if (ret_code == NM_OK) {
+
+		if (allowed) {
+			rc = nm_send_create_privacy_item(user, dn, TRUE,
+											 _create_privacy_item_permit_resp_cb,
+											 g_strdup(display_id));
+			_check_for_disconnect(user, rc);
+
+		} else {
+			rc = nm_send_create_privacy_item(user, dn, FALSE,
+											 _create_privacy_item_deny_resp_cb,
+											 g_strdup(display_id));
+			_check_for_disconnect(user, rc);
+		}
+
+	} else {
+
+		err = g_strdup_printf(_("Unable to add user to privacy list (%s)."),
+							  nm_error_to_string(ret_code));
+		gaim_notify_error(gc, NULL, err, NULL);
+		g_free(err);
+
+	}
+}
+
+static void
+_remove_privacy_item_resp_cb(NMUser *user, NMERR_T ret_code,
+									gpointer resp_data, gpointer user_data)
+{
+	GaimConnection *gc;
+	char *who = user_data;
+	char *err;
+
+	if (user == NULL)
+		return;
+
+	if (ret_code != NM_OK) {
+
+		gc = gaim_account_get_connection(user->client_data);
+		err = g_strdup_printf(_("Unable to remove %s from privacy list (%s)."), who,
+							  nm_error_to_string(ret_code));
+		gaim_notify_error(gc, NULL, err, NULL);
+		g_free(err);
+	}
+
+	if (who)
+		g_free(who);
+}
+
+static void
+_set_privacy_default_resp_cb(NMUser *user, NMERR_T ret_code,
+									gpointer resp_data, gpointer user_data)
+{
+	GaimConnection *gc;
+	char *err;
+
+	if (user == NULL)
+		return;
+
+	if (ret_code != NM_OK) {
+
+		gc = gaim_account_get_connection(user->client_data);
+		err = g_strdup_printf(_("Unable to change server side privacy settings (%s)."),
+							  nm_error_to_string(ret_code));
+		gaim_notify_error(gc, NULL, err, NULL);
+		g_free(err);
+
+	}
+}
+
+/* Handle get details response add to privacy list */
+static void
+_get_details_resp_send_invite(NMUser *user, NMERR_T ret_code,
+							  gpointer resp_data, gpointer user_data)
+{
+	NMERR_T rc = NM_OK;
+	GaimConnection *gc;
+	NMUserRecord *user_record = resp_data;
+	char *err;
+	const char *display_id;
+	GSList *cnode;
+	NMConference *conference;
+	gpointer chat;
+	long id = (long) user_data;
+
+	if (user == NULL)
+		return;
+
+	gc = gaim_account_get_connection(user->client_data);
+	display_id = nm_user_record_get_display_id(user_record);
+
+	if (ret_code == NM_OK) {
+
+		for (cnode = user->conferences; cnode != NULL; cnode = cnode->next) {
+			conference = cnode->data;
+			if (conference && (chat = nm_conference_get_data(conference))) {
+				if (gaim_conv_chat_get_id(GAIM_CONV_CHAT(chat)) == id) {
+					rc = nm_send_conference_invite(user, conference, user_record,
+												   NULL, _sendinvite_resp_cb, NULL);
+					_check_for_disconnect(user, rc);
+					break;
+				}
+			}
+		}
+
+	} else {
+
+		err = g_strdup_printf(_("Unable to invite user (%s)."), nm_error_to_string(ret_code));
+		gaim_notify_error(gc, NULL, err, NULL);
+		g_free(err);
+
+	}
+}
+
+static void
+_createconf_resp_send_invite(NMUser * user, NMERR_T ret_code,
+							  gpointer resp_data, gpointer user_data)
+{
+	NMERR_T rc = NM_OK;
+	NMConference *conference = resp_data;
+	NMUserRecord *user_record = user_data;
+	GaimConnection *gc;
+	char *err;
+
+	if (user == NULL)
+		return;
+
+
+
+	if (ret_code == NM_OK) {
+		rc = nm_send_conference_invite(user, conference, user_record,
+									   NULL, _sendinvite_resp_cb, NULL);
+		_check_for_disconnect(user, rc);
+	} else {
+		err = g_strdup_printf(_("Unable to create conference (%s)."), nm_error_to_string(ret_code));
+		gc = gaim_account_get_connection(user->client_data);
+		gaim_notify_error(gc, NULL, err, NULL);
+		g_free(err);
+	}
+}
+
 /*******************************************************************************
  * Helper functions
  ******************************************************************************/
@@ -802,8 +1135,7 @@
 			nm_release_message(message);
 
 		} else {
-			rc = nm_send_create_conference(user, conf,
-										   _createconf_resp_send_msg, message);
+			rc = nm_send_create_conference(user, conf, _createconf_resp_send_msg, message);
 			_check_for_disconnect(user, rc);
 		}
 	}
@@ -843,11 +1175,11 @@
 	serv_got_update(gc, buddy->name, loggedin, 0, 0, idle, gstatus);
 }
 
-/* Iterate through the cached Gaim buddy list and remove all buddies
- * for this account.
+/* Iterate through the cached Gaim buddy list and remove buddies
+ * that are not in the server side list.
  */
 static void
-_remove_gaim_buddies(NMUser * user)
+_remove_gaim_buddies(NMUser *user)
 {
 	GaimBlistNode *gnode;
 	GaimBlistNode *cnode;
@@ -857,6 +1189,7 @@
 	GaimBuddyList *blist;
 	GSList *rem_list = NULL;
 	GSList *l;
+	NMFolder *folder = NULL;
 
 	if ((blist = gaim_get_blist())) {
 		for (gnode = blist->root; gnode; gnode = gnode->next) {
@@ -871,7 +1204,11 @@
 						continue;
 					buddy = (GaimBuddy *) bnode;
 					if (buddy->account == user->client_data) {
-						rem_list = g_slist_append(rem_list, buddy);
+						folder = nm_find_folder(user, group->name);
+						if (folder == NULL ||
+							!nm_folder_find_contact_by_display_id(folder, buddy->name)) {
+							rem_list = g_slist_append(rem_list, buddy);
+						}
 					}
 				}
 			}
@@ -899,6 +1236,14 @@
 	const char *name = NULL;
 	int status = 0;
 
+	/* Does the Gaim group exist already? */
+	group = gaim_find_group(nm_folder_get_name(folder));
+
+	if (group == NULL) {
+		group = gaim_group_new(nm_folder_get_name(folder));
+		gaim_blist_add_group(group, NULL);
+	}
+
 	/* Get each contact for this folder */
 	cnt = nm_folder_get_contact_count(folder);
 	for (i = 0; i < cnt; i++) {
@@ -907,17 +1252,15 @@
 
 			name = nm_contact_get_display_id(contact);
 			if (name) {
-				/* Add it to the gaim buddy list */
-				buddy = gaim_buddy_new(user->client_data,
-									   name,
-									   nm_contact_get_display_name(contact));
-
-				/* Does the Gaim group exist already? */
-				group = gaim_find_group(nm_folder_get_name(folder));
-
-				if (group == NULL) {
-					group = gaim_group_new(nm_folder_get_name(folder));
-					gaim_blist_add_group(group, NULL);
+
+				buddy = gaim_find_buddy_in_group(user->client_data, name, group);
+				if (buddy == NULL) {
+					/* Add it to the gaim buddy list */
+					buddy = gaim_buddy_new(user->client_data,
+										   name,
+										   nm_contact_get_display_name(contact));
+
+					gaim_blist_add_buddy(buddy, NULL, group, NULL);
 				}
 
 				/* Set the initial status for the buddy */
@@ -926,8 +1269,6 @@
 					status = nm_user_record_get_status(user_record);
 					text = nm_user_record_get_status_text(user_record);
 				}
-
-				gaim_blist_add_buddy(buddy, NULL, group, NULL);
 				_update_buddy_status(buddy, status, time(0));
 
 				/* Save the new buddy as part of the contact object */
@@ -941,7 +1282,6 @@
 			break;
 		}
 	}
-
 }
 
 /* Add all of the server side contacts to the Gaim buddy list. */
@@ -969,6 +1309,111 @@
 	}
 }
 
+static void
+_sync_contact_list(NMUser *user)
+{
+	/* Remove all buddies from the local list that are
+	 * not in the server side list and add all buddies
+	 * from the server side list that are not in
+	 * the local list
+	 */
+	_remove_gaim_buddies(user);
+	_add_gaim_buddies(user);
+}
+
+static void
+_sync_privacy_lists(NMUser *user)
+{
+	GSList *node = NULL, *rem_list = NULL;
+	GaimConnection *gc;
+	const char *name, *dn;
+	NMUserRecord *user_record;
+
+	if (user == NULL)
+		return;
+
+	gc = gaim_account_get_connection(user->client_data);
+	if (gc == NULL)
+		return;
+
+	/* Set the Gaim privacy setting */
+	if (user->default_deny) {
+		if (user->allow_list == NULL) {
+			gc->account->perm_deny = GAIM_PRIVACY_DENY_ALL;
+		} else {
+			gc->account->perm_deny = GAIM_PRIVACY_ALLOW_USERS;
+		}
+	} else {
+		if (user->deny_list == NULL) {
+			gc->account->perm_deny = GAIM_PRIVACY_ALLOW_ALL;
+		} else {
+			gc->account->perm_deny = GAIM_PRIVACY_DENY_USERS;
+		}
+	}
+
+	/* Add stuff */
+	for (node = user->allow_list; node; node = node->next) {
+		user_record = nm_find_user_record(user, (char *)node->data);
+		if (user_record)
+			name = nm_user_record_get_display_id(user_record);
+		else
+			name =(char *)node->data;
+
+		if (!g_slist_find_custom(gc->account->permit,
+								 name, (GCompareFunc)nm_utf8_strcasecmp)) {
+			gaim_privacy_permit_add(gc->account, name , TRUE);
+		}
+	}
+
+	for (node = user->deny_list; node; node = node->next) {
+		user_record = nm_find_user_record(user, (char *)node->data);
+		if (user_record)
+			name = nm_user_record_get_display_id(user_record);
+		else
+			name =(char *)node->data;
+
+		if (!g_slist_find_custom(gc->account->deny,
+								 name, (GCompareFunc)nm_utf8_strcasecmp)) {
+			gaim_privacy_deny_add(gc->account, name, TRUE);
+		}
+	}
+
+
+	/*  Remove stuff */
+	for (node = gc->account->permit; node; node = node->next) {
+		dn = nm_lookup_dn(user, (char *)node->data);
+		if (dn != NULL &&
+			!g_slist_find_custom(user->allow_list,
+								 dn, (GCompareFunc)nm_utf8_strcasecmp)) {
+			rem_list = g_slist_append(rem_list, node->data);
+		}
+	}
+
+	if (rem_list) {
+		for (node = rem_list; node; node = node->next) {
+			gaim_privacy_permit_remove(gc->account, (char *)node->data, TRUE);
+		}
+		g_free(rem_list);
+		rem_list = NULL;
+	}
+
+	for (node = gc->account->deny; node; node = node->next) {
+		dn = nm_lookup_dn(user, (char *)node->data);
+		if (dn != NULL &&
+			!g_slist_find_custom(user->deny_list,
+								 dn, (GCompareFunc)nm_utf8_strcasecmp)) {
+			rem_list = g_slist_append(rem_list, node->data);
+		}
+	}
+
+	if (rem_list) {
+		for (node = rem_list; node; node = node->next) {
+			gaim_privacy_deny_remove(gc->account, (char *)node->data, TRUE);
+		}
+		g_slist_free(rem_list);
+	}
+}
+
 /* Display a dialog box showing the properties for the given user record */
 static void
 _show_info(GaimConnection * gc, NMUserRecord * user_record)
@@ -1073,6 +1518,59 @@
 	g_slist_free(parms);
 }
 
+static void
+_initiate_conference_cb(GaimConnection *gc, const char *who)
+{
+	NMUser *user;
+	const char *conf_name;
+	GaimConversation *chat = NULL;
+	NMUserRecord *user_record;
+	NMConference *conference;
+
+	user = gc->proto_data;
+	if (user == NULL)
+		return;
+
+	/* We should already have a userrecord for the buddy */
+	user_record = nm_find_user_record(user, who);
+	if (user_record == NULL)
+		return;
+
+	conf_name = _get_conference_name(++user->conference_count);
+	chat = serv_got_joined_chat(gc, user->conference_count, conf_name);
+	if (chat) {
+
+		conference = nm_create_conference(NULL);
+		nm_conference_set_data(conference, (gpointer) chat);
+		nm_send_create_conference(user, conference, _createconf_resp_send_invite, user_record);
+		nm_release_conference(conference);
+	}
+}
+
+const char *
+_get_conference_name(int id)
+{
+	static char *name = NULL;
+
+	if (name)
+		g_free(name);
+
+	name = g_strdup_printf(_("GroupWise Conference %d"), id);
+
+	return name;
+}
+
+void
+_show_privacy_locked_error(GaimConnection *gc, NMUser *user)
+{
+	char *err;
+
+	err = g_strdup_printf(_("Unable to change server side privacy settings (%s)."),
+						  nm_error_to_string(NMERR_ADMIN_LOCKED));
+	gaim_notify_error(gc, NULL, err, NULL);
+	g_free(err);
+}
+
 /*******************************************************************************
  * Connect and recv callbacks
  ******************************************************************************/
@@ -1104,6 +1602,7 @@
 	if (rc != NM_OK) {
 
 		if (_is_disconnect_error(rc)) {
+
 			gaim_connection_error(gc,
 								  _("Error communicating with server."
 									" Closing connection."));
@@ -1111,8 +1610,8 @@
 
 			char *error;
 
-			error = g_strdup_printf(_("Error processing event or response."
-									  " (0x%X)"), rc);
+			error = g_strdup_printf(_("Error processing event or response (%s)."),
+									nm_error_to_string (rc));
 			gaim_notify_error(gc, NULL, error, NULL);
 			g_free(error);
 
@@ -1282,6 +1781,26 @@
 }
 
 static void
+_evt_conference_invite_notify(NMUser * user, NMEvent * event)
+{
+	GaimConversation *gconv;
+	NMConference *conference;
+	NMUserRecord *user_record = NULL;
+	char *str = NULL;
+
+	user_record = nm_find_user_record(user, nm_event_get_source(event));
+	conference = nm_event_get_conference(event);
+	if (user_record && conference) {
+		gconv = nm_conference_get_data(conference);
+		str = g_strdup_printf(_("%s has been invited to this conversation."),
+							  nm_user_record_get_display_id(user_record));
+		gaim_conversation_write(gconv, NULL, str,
+								GAIM_MESSAGE_SYSTEM, time(NULL));
+		g_free(str);
+	}
+}
+
+static void
 _evt_conference_invite(NMUser * user, NMEvent * event)
 {
 	NMUserRecord *ur;
@@ -1330,7 +1849,8 @@
 	NMConference *conference = NULL;
 	NMUserRecord *ur = NULL;
 	const char *name;
-	char *conf_name;
+	const char *conf_name;
+	GList *list = NULL;
 
 	gc = gaim_account_get_connection(user->client_data);
 	if (gc == NULL)
@@ -1342,11 +1862,9 @@
 		if (nm_conference_get_participant_count(conference) == 2 && chat == NULL) {
 			ur = nm_conference_get_participant(conference, 0);
 			if (ur) {
-				conf_name = g_strdup_printf(_("GroupWise Conference %d"),
-											++user->conference_count);
+				conf_name = _get_conference_name(++user->conference_count);
 				chat =
 					serv_got_joined_chat(gc, user->conference_count, conf_name);
-				g_free(conf_name);
 				if (chat) {
 
 					nm_conference_set_data(conference, (gpointer) chat);
@@ -1362,7 +1880,10 @@
 			ur = nm_find_user_record(user, nm_event_get_source(event));
 			if (ur) {
 				name = nm_user_record_get_display_id(ur);
-				gaim_conv_chat_add_user(GAIM_CONV_CHAT(chat), name, NULL);
+				list = gaim_conv_chat_get_users(GAIM_CONV_CHAT(chat));
+				if (!g_list_find_custom(list, name, (GCompareFunc)nm_utf8_strcasecmp)) {
+					gaim_conv_chat_add_user(GAIM_CONV_CHAT(chat), name, NULL);
+				}
 			}
 		}
 	}
@@ -1504,7 +2025,7 @@
 			/* Someone else has been invited to join a
 			 * conference that we are currently a part of
 			 */
-			/* TODO: show the invite notify in chat window */
+			_evt_conference_invite_notify(user, event);
 			break;
 		case NMEVT_CONFERENCE_INVITE:
 			/* We have been invited to join a conference */
@@ -1661,8 +2182,7 @@
 			 * have to finish sending the message when we
 			 * get the response with the new conference guid.
 			 */
-			rc = nm_send_create_conference(user, conf,
-										   _createconf_resp_send_msg, message);
+			rc = nm_send_create_conference(user, conf, _createconf_resp_send_msg, message);
 			_check_for_disconnect(user, rc);
 
 			done = FALSE;
@@ -1786,6 +2306,44 @@
 	serv_got_chat_left(gc, id);
 }
 
+void
+novell_chat_invite(GaimConnection *gc, int id,
+				   const char *message, const char *who)
+{
+	NMConference *conference;
+	NMUser *user;
+	GaimConversation *chat;
+	GSList *cnode;
+	NMERR_T rc = NM_OK;
+	NMUserRecord *user_record = NULL;
+
+	if (gc == NULL)
+		return;
+
+	user = gc->proto_data;
+	if (user == NULL)
+		return;
+
+	user_record = nm_find_user_record(user, who);
+	if (user_record == NULL) {
+		rc = nm_send_get_details(user, who, _get_details_resp_send_invite, (gpointer)id);
+		_check_for_disconnect(user, rc);
+		return;
+	}
+
+	for (cnode = user->conferences; cnode != NULL; cnode = cnode->next) {
+		conference = cnode->data;
+		if (conference && (chat = nm_conference_get_data(conference))) {
+			if (gaim_conv_chat_get_id(GAIM_CONV_CHAT(chat)) == id) {
+				rc = nm_send_conference_invite(user, conference, user_record,
+											   message, _sendinvite_resp_cb, NULL);
+				_check_for_disconnect(user, rc);
+				break;
+			}
+		}
+	}
+}
+
 static int
 novell_chat_send(GaimConnection * gc, int id, const char *text)
 {
@@ -1814,7 +2372,14 @@
 
 				nm_message_set_conference(message, conference);
 
-				rc = nm_send_message(user, message, _send_message_resp_cb);
+				/* check to see if the conference is instatiated yet */
+				if (!nm_conference_is_instantiated(conference)) {
+					nm_message_add_ref(message);
+					nm_send_create_conference(user, conference, _createconf_resp_send_msg, message);
+				} else {
+					rc = nm_send_message(user, message, _send_message_resp_cb);
+				}
+
 				nm_release_message(message);
 
 				if (!_check_for_disconnect(user, rc)) {
@@ -1841,6 +2406,7 @@
 		}
 	}
 
+
 	/* The conference was not found, must be closed */
 	chat = gaim_find_chat(gc, id);
 	if (chat) {
@@ -2342,6 +2908,386 @@
 		g_free(text);
 }
 
+static void
+novell_add_permit(GaimConnection *gc, const char *who)
+{
+	NMUser *user;
+	NMERR_T rc = NM_OK;
+	const char *name = who;
+
+	if (gc == NULL || who == NULL)
+		return;
+
+	user = gc->proto_data;
+	if (user == NULL)
+		return;
+
+	/* Remove first -- we will add it back in when we get
+	 * the okay from the server
+	 */
+	gaim_privacy_permit_remove(gc->account, who, TRUE);
+
+	if (nm_user_is_privacy_locked(user)) {
+		_show_privacy_locked_error(gc, user);
+		_sync_privacy_lists(user);
+		return;
+	}
+
+	/* Work around for problem with un-typed, dotted contexts */
+	if (strchr(who, '.')) {
+		const char *dn = nm_lookup_dn(user, who);
+		if (dn == NULL) {
+			rc = nm_send_get_details(user, who, _get_details_send_privacy_create,
+									 (gpointer)TRUE);
+			_check_for_disconnect(user, rc);
+			return;
+		} else {
+			name = dn;
+		}
+	}
+
+	rc = nm_send_create_privacy_item(user, name, TRUE,
+									 _create_privacy_item_permit_resp_cb,
+									 g_strdup(who));
+	_check_for_disconnect(user, rc);
+}
+
+static void
+novell_add_deny(GaimConnection *gc, const char *who)
+{
+	NMUser *user;
+	NMERR_T rc = NM_OK;
+	const char *name = who;
+
+	if (gc == NULL || who == NULL)
+		return;
+
+	user = gc->proto_data;
+	if (user == NULL)
+		return;
+
+	/* Remove first -- we will add it back in when we get
+	 * the okay from the server
+	 */
+	gaim_privacy_deny_remove(gc->account, who, TRUE);
+
+	if (nm_user_is_privacy_locked(user)) {
+		_show_privacy_locked_error(gc, user);
+		_sync_privacy_lists(user);
+		return;
+	}
+
+	/* Work around for problem with un-typed, dotted contexts */
+	if (strchr(who, '.')) {
+		const char *dn = nm_lookup_dn(user, who);
+		if (dn == NULL) {
+			rc = nm_send_get_details(user, who, _get_details_send_privacy_create,
+									 (gpointer)FALSE);
+			_check_for_disconnect(user, rc);
+			return;
+		} else {
+			name = dn;
+		}
+	}
+
+	rc = nm_send_create_privacy_item(user, name, FALSE,
+									 _create_privacy_item_deny_resp_cb,
+									 g_strdup(who));
+	_check_for_disconnect(user, rc);
+}
+
+static void
+novell_rem_permit(GaimConnection *gc, const char *who)
+{
+	NMUser *user;
+	NMERR_T rc = NM_OK;
+	const char *dn = NULL;
+
+	if (gc == NULL || who == NULL)
+		return;
+
+	user = gc->proto_data;
+	if (user == NULL)
+		return;
+
+	if (nm_user_is_privacy_locked(user)) {
+		_show_privacy_locked_error(gc, user);
+		_sync_privacy_lists(user);
+		return;
+	}
+
+	dn = nm_lookup_dn(user, who);
+	if (dn == NULL)
+		dn = who;
+
+	rc = nm_send_remove_privacy_item(user, dn, TRUE,
+									 _remove_privacy_item_resp_cb,
+									 g_strdup(who));
+	_check_for_disconnect(user, rc);
+}
+
+static void
+novell_rem_deny(GaimConnection *gc, const char *who)
+{
+	NMUser *user;
+	NMERR_T rc = NM_OK;
+	const char *dn = NULL;
+
+	if (gc == NULL || who == NULL)
+		return;
+
+	user = gc->proto_data;
+	if (user == NULL)
+		return;
+
+	if (nm_user_is_privacy_locked(user)) {
+		_show_privacy_locked_error(gc, user);
+		_sync_privacy_lists(user);
+		return;
+	}
+
+	dn = nm_lookup_dn(user, who);
+	if (dn == NULL)
+		dn = who;
+
+	rc = nm_send_remove_privacy_item(user, dn, FALSE,
+									 _remove_privacy_item_resp_cb,
+									 g_strdup(who));
+	_check_for_disconnect(user, rc);
+}
+
+static void
+novell_set_permit_deny(GaimConnection *gc)
+{
+	NMERR_T rc = NM_OK;
+	const char *dn, *name = NULL;
+	NMUserRecord *user_record = NULL;
+	GSList *node = NULL, *copy = NULL;
+	NMUser *user;
+	int i, j, num_contacts, num_folders;
+	NMContact *contact;
+	NMFolder *folder = NULL;
+
+	if (gc == NULL)
+		return;
+
+	user = gc->proto_data;
+	if (user == NULL)
+		return;
+
+	if (set_permit == FALSE) {
+		set_permit = TRUE;
+		return;
+	}
+
+	if (nm_user_is_privacy_locked(user)) {
+		_show_privacy_locked_error(gc, user);
+		_sync_privacy_lists(user);
+		return;
+	}
+
+	switch (gc->account->perm_deny) {
+
+		case GAIM_PRIVACY_ALLOW_ALL:
+			rc = nm_send_set_privacy_default(user, FALSE,
+											 _set_privacy_default_resp_cb, NULL);
+			_check_for_disconnect(user, rc);
+
+			/* clear server side deny list */
+			if (rc == NM_OK) {
+				copy = g_slist_copy(user->deny_list);
+				for (node = copy; node && node->data; node = node->next) {
+					rc = nm_send_remove_privacy_item(user, (const char *)node->data,
+													 FALSE, NULL, NULL);
+					if (_check_for_disconnect(user, rc))
+						break;
+				}
+				g_slist_free(copy);
+				g_slist_free(user->deny_list);
+				user->deny_list = NULL;
+			}
+			break;
+
+		case GAIM_PRIVACY_DENY_ALL:
+			rc = nm_send_set_privacy_default(user, TRUE,
+											 _set_privacy_default_resp_cb, NULL);
+			_check_for_disconnect(user, rc);
+
+			/* clear server side allow list */
+			if (rc == NM_OK) {
+				copy = g_slist_copy(user->allow_list);
+				for (node = copy; node && node->data; node = node->next) {
+					rc = nm_send_remove_privacy_item(user, (const char *)node->data,
+													 TRUE, NULL, NULL);
+					if (_check_for_disconnect(user, rc))
+						break;
+				}
+				g_slist_free(copy);
+				g_slist_free(user->allow_list);
+				user->allow_list = NULL;
+			}
+			break;
+
+		case GAIM_PRIVACY_ALLOW_USERS:
+
+			rc = nm_send_set_privacy_default(user, TRUE,
+											 _set_privacy_default_resp_cb, NULL);
+			_check_for_disconnect(user, rc);
+
+			/* sync allow lists */
+			if (rc == NM_OK) {
+
+				for (node = user->allow_list; node; node = node->next) {
+					user_record = nm_find_user_record(user, (char *)node->data);
+					if (user_record) {
+						name = nm_user_record_get_display_id(user_record);
+
+						if (!g_slist_find_custom(gc->account->permit,
+												 name, (GCompareFunc)nm_utf8_strcasecmp)) {
+							gaim_privacy_permit_add(gc->account, name , TRUE);
+						}
+					}
+				}
+
+				for (node = gc->account->permit; node; node = node->next) {
+					name = NULL;
+					dn = nm_lookup_dn(user, (char *)node->data);
+					if (dn) {
+						user_record = nm_find_user_record(user, dn);
+						name = nm_user_record_get_display_id(user_record);
+
+						if (!g_slist_find_custom(user->allow_list,
+												 dn, (GCompareFunc)nm_utf8_strcasecmp)) {
+							rc = nm_send_create_privacy_item(user, dn, TRUE,
+															 _create_privacy_item_deny_resp_cb,
+															 g_strdup(dn));
+						}
+					} else {
+						gaim_privacy_permit_remove(gc->account, (char *)node->data, TRUE);
+					}
+				}
+			}
+			break;
+
+		case GAIM_PRIVACY_DENY_USERS:
+
+			/* set to default allow */
+			rc = nm_send_set_privacy_default(user, FALSE,
+											 _set_privacy_default_resp_cb, NULL);
+			_check_for_disconnect(user, rc);
+
+			/* sync deny lists */
+			if (rc == NM_OK) {
+
+				for (node = user->deny_list; node; node = node->next) {
+					user_record = nm_find_user_record(user, (char *)node->data);
+					if (user_record) {
+						name = nm_user_record_get_display_id(user_record);
+
+						if (!g_slist_find_custom(gc->account->deny,
+												 name, (GCompareFunc)nm_utf8_strcasecmp)) {
+							gaim_privacy_deny_add(gc->account, name , TRUE);
+						}
+					}
+				}
+
+				for (node = gc->account->deny; node; node = node->next) {
+
+					name = NULL;
+					dn = nm_lookup_dn(user, (char *)node->data);
+					if (dn) {
+						user_record = nm_find_user_record(user, dn);
+						name = nm_user_record_get_display_id(user_record);
+
+						if (!g_slist_find_custom(user->deny_list,
+												 dn, (GCompareFunc)nm_utf8_strcasecmp)) {
+							rc = nm_send_create_privacy_item(user, dn, FALSE,
+															 _create_privacy_item_deny_resp_cb,
+															 g_strdup(name));
+						}
+					} else {
+						gaim_privacy_deny_remove(gc->account, (char *)node->data, TRUE);
+					}
+				}
+
+			}
+			break;
+
+		case GAIM_PRIVACY_ALLOW_BUDDYLIST:
+
+			/* remove users from allow list that are not in buddy list */
+			copy = g_slist_copy(user->allow_list);
+			for (node = copy; node && node->data; node = node->next) {
+				if (!nm_find_contacts(user, node->data)) {
+					rc = nm_send_remove_privacy_item(user, (const char *)node->data,
+													 TRUE, NULL, NULL);
+					if (_check_for_disconnect(user, rc))
+						return;
+				}
+			}
+			g_slist_free(copy);
+
+			/* add all buddies to allow list */
+			num_contacts = nm_folder_get_contact_count(user->root_folder);
+			for (i = 0; i < num_contacts; i++) {
+				contact = nm_folder_get_contact(user->root_folder, i);
+				dn = nm_contact_get_dn(contact);
+				if (dn && !g_slist_find_custom(user->allow_list,
+											   dn, (GCompareFunc)nm_utf8_strcasecmp))
+				{
+					rc = nm_send_create_privacy_item(user, dn, TRUE,
+													 _create_privacy_item_deny_resp_cb,
+													 g_strdup(dn));
+					if (_check_for_disconnect(user, rc))
+						return;
+				}
+
+			}
+
+			num_folders = nm_folder_get_subfolder_count(user->root_folder);
+			for (i = 0; i < num_folders; i++) {
+				folder = nm_folder_get_subfolder(user->root_folder, i);
+				num_contacts = nm_folder_get_contact_count(folder);
+				for (j = 0; j < num_contacts; j++) {
+					contact = nm_folder_get_contact(folder, j);
+					dn = nm_contact_get_dn(contact);
+					if (dn && !g_slist_find_custom(user->allow_list,
+												   dn, (GCompareFunc)nm_utf8_strcasecmp))
+					{
+						rc = nm_send_create_privacy_item(user, dn, TRUE,
+														 _create_privacy_item_deny_resp_cb,
+														 g_strdup(dn));
+						if (_check_for_disconnect(user, rc))
+							return;
+					}
+				}
+			}
+
+			/* set to default deny */
+			rc = nm_send_set_privacy_default(user, TRUE,
+											 _set_privacy_default_resp_cb, NULL);
+			if (_check_for_disconnect(user, rc))
+				break;
+
+			break;
+	}
+}
+
+static GList *
+novell_buddy_menu(GaimConnection *gc, const char *who)
+{
+	GList *list = NULL;
+	struct proto_buddy_menu *pbm;
+
+	pbm = g_new0(struct proto_buddy_menu, 1);
+	pbm->label = _("Initiate _Chat");
+	pbm->callback = _initiate_conference_cb;
+	pbm->gc = gc;
+	list = g_list_append(list, pbm);
+
+	return list;
+}
+
 static GaimPluginProtocolInfo prpl_info = {
 	GAIM_PRPL_API_VERSION,
 	0,
@@ -2353,7 +3299,7 @@
 	novell_tooltip_text,
 	novell_away_states,
 	NULL,						/* prpl_actions */
-	NULL,						/* buddy_menu */
+	novell_buddy_menu,
 	NULL,						/* chat_info */
 	novell_login,
 	novell_close,
@@ -2371,15 +3317,15 @@
 	NULL,						/* add_buddies */
 	novell_remove_buddy,
 	NULL,						/* remove_buddies */
-	NULL,						/* add_permit */
-	NULL,						/* add_deny */
-	NULL,						/* rem_permit */
-	NULL,						/* rem_deny */
-	NULL,						/* set_permit_deny */
+	novell_add_permit,
+	novell_add_deny,
+	novell_rem_permit,
+	novell_rem_deny,
+	novell_set_permit_deny,
 	NULL,						/* warn */
 	NULL,						/* join_chat */
 	NULL,						/* reject_chat ?? */
-	NULL,						/* chat_invite */
+	novell_chat_invite,			/* chat_invite */
 	novell_chat_leave,
 	NULL,						/* chat_whisper */
 	novell_chat_send,