changeset 9360:d77537e8bfe5

[gaim-migrate @ 10168] " This patch fixes contact list sync problem, fixes a memory leak, and includes some code cleanup." --Mike Stoddard of Novell committer: Tailor Script <tailor@pidgin.im>
author Luke Schierer <lschiere@pidgin.im>
date Wed, 23 Jun 2004 17:27:56 +0000
parents 43741d8f76f7
children 0f4d49677f84
files ChangeLog src/protocols/novell/nmconn.c src/protocols/novell/nmconn.h src/protocols/novell/nmrequest.c src/protocols/novell/nmrequest.h src/protocols/novell/nmuser.c src/protocols/novell/nmuser.h src/protocols/novell/novell.c
diffstat 8 files changed, 170 insertions(+), 269 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Wed Jun 23 16:58:22 2004 +0000
+++ b/ChangeLog	Wed Jun 23 17:27:56 2004 +0000
@@ -33,6 +33,7 @@
 	  support the URGENT hint (Etan Reisner)
 	* Better handling of character sets in RTF for Novell (Mike Stoddard of
 	  Novell)
+	* Contact list sync problems in Novell fixed (Mike Stoddard of Novell)
 	* Fixed a crash in SILC that sometimes happened when resolving
 	  the buddy list (Pekka Riikonen)
 	* Parallel compiles of the perl plugin should work better
--- a/src/protocols/novell/nmconn.c	Wed Jun 23 16:58:22 2004 +0000
+++ b/src/protocols/novell/nmconn.c	Wed Jun 23 17:27:56 2004 +0000
@@ -168,6 +168,35 @@
 	return str;
 }
 
+NMConn *
+nm_create_conn(const char *addr, int port)
+{
+	NMConn *conn = 	g_new0(NMConn, 1);
+	conn->addr = g_strdup(addr);
+	conn->port = port;
+	return conn;
+}
+
+void nm_release_conn(NMConn *conn)
+{
+	if (conn) {
+		GSList *node;
+		for (node = conn->requests; node; node = node->next) {
+			if (node->data)
+				nm_release_request(node->data);
+		}
+		g_slist_free(conn->requests);
+		conn->requests = NULL;
+		if (conn->ssl_conn) {
+			g_free(conn->ssl_conn);
+			conn->ssl_conn = NULL;
+		}
+		g_free(conn->addr);
+		conn->addr = NULL;
+		g_free(conn);
+	}
+}
+
 int
 nm_tcp_write(NMConn * conn, const void *buff, int len)
 {
@@ -376,13 +405,14 @@
 }
 
 NMERR_T
-nm_send_request(NMConn * conn, char *cmd, NMField * fields, NMRequest ** req)
+nm_send_request(NMConn *conn, char *cmd, NMField *fields,
+				nm_response_cb cb, gpointer data, NMRequest **request)
 {
 	NMERR_T rc = NM_OK;
 	char buffer[512];
 	int bytes_to_send;
 	int ret;
-	NMField *request = NULL;
+	NMField *request_fields = NULL;
 	char *str = NULL;
 
 	if (conn == NULL || cmd == NULL)
@@ -417,17 +447,17 @@
 	/* Add the transaction id to the request fields */
 	if (rc == NM_OK) {
 		if (fields)
-			request = nm_copy_field_array(fields);
+			request_fields = nm_copy_field_array(fields);
 
 		str = g_strdup_printf("%d", ++(conn->trans_id));
-		request = nm_field_add_pointer(request, NM_A_SZ_TRANSACTION_ID, 0,
-									   NMFIELD_METHOD_VALID, 0,
-									   str, NMFIELD_TYPE_UTF8);
+		request_fields = nm_field_add_pointer(request_fields, NM_A_SZ_TRANSACTION_ID, 0,
+											  NMFIELD_METHOD_VALID, 0,
+											  str, NMFIELD_TYPE_UTF8);
 	}
 
 	/* Send the request to the server */
 	if (rc == NM_OK) {
-		rc = nm_write_fields(conn, request);
+		rc = nm_write_fields(conn, request_fields);
 	}
 
 	/* Write the CRLF to terminate the data */
@@ -438,14 +468,21 @@
 		}
 	}
 
-	/* Create a request struct and return it */
+	/* Create a request struct, add it to our queue, and return it */
 	if (rc == NM_OK) {
-		*req = nm_create_request(cmd, conn->trans_id, time(0));
+		NMRequest *new_request = nm_create_request(cmd, conn->trans_id,
+												   time(0), cb, NULL, data);
+		nm_conn_add_request_item(conn, new_request);
+
+		/* Set the out param if it was sent in, otherwise release the request */
+		if (request)
+			*request = new_request;
+		else
+			nm_release_request(new_request);
 	}
 
-	if (request != NULL) {
-		nm_free_fields(&request);
-	}
+	if (request_fields != NULL)
+		nm_free_fields(&request_fields);
 
 	return rc;
 }
--- a/src/protocols/novell/nmconn.h	Wed Jun 23 16:58:22 2004 +0000
+++ b/src/protocols/novell/nmconn.h	Wed Jun 23 17:27:56 2004 +0000
@@ -75,6 +75,25 @@
 };
 
 /**
+ * Allocate a new NMConn struct
+ *
+ * @param 	The address of the server that we are connecting to.
+ * @param 	The port that we are connecting to.
+ *
+ * @return		A pointer to a newly allocated NMConn struct, should
+ *				be freed by calling nm_release_conn()
+ */
+NMConn *nm_create_conn(const char *addr, int port);
+
+/**
+ * Release an NMConn
+ *
+ * @param 	Pointer to the NMConn to release.
+ *
+ */
+void nm_release_conn(NMConn *conn);
+
+/**
  * Write len bytes from the given buffer.
  *
  * @param conn	The connection to write to.
@@ -135,12 +154,15 @@
  * @param conn		The connection.
  * @param cmd		The request to dispatch.
  * @param fields	The field list for the request.
+ * @param cb		The response callback for the new request object.
+ * @param data		The user defined data for the request (to be passed to the resp cb).
  * @param req		The request. Should be freed with nm_release_request.
  *
  * @return			NM_OK on success.
  */
-NMERR_T nm_send_request(NMConn * conn, char *cmd, NMField * fields,
-						NMRequest ** req);
+NMERR_T
+nm_send_request(NMConn *conn, char *cmd, NMField *fields,
+				nm_response_cb cb, gpointer data, NMRequest **request);
 
 /**
  * Write out the given field list.
--- a/src/protocols/novell/nmrequest.c	Wed Jun 23 16:58:22 2004 +0000
+++ b/src/protocols/novell/nmrequest.c	Wed Jun 23 17:27:56 2004 +0000
@@ -20,6 +20,8 @@
 
 #include "nmrequest.h"
 
+static int count = 0;
+
 struct _NMRequest
 {
 	int trans_id;
@@ -32,9 +34,8 @@
 	NMERR_T ret_code;
 };
 
-
-NMRequest *
-nm_create_request(const char *cmd, int trans_id, int gmt)
+NMRequest *nm_create_request(const char *cmd, int trans_id, int gmt, nm_response_cb cb,
+							 gpointer resp_data, gpointer user_define)
 {
 	NMRequest *req;
 
@@ -45,8 +46,13 @@
 	req->cmd = g_strdup(cmd);
 	req->trans_id = trans_id;
 	req->gmt = gmt;
+	req->callback = cb;
+	req->data = resp_data;
+	req->user_define = user_define;
 	req->ref_count = 1;
 
+	gaim_debug_info("novell", "Creating NMRequest instance, total=%d\n", ++count);
+
 	return req;
 }
 
@@ -57,7 +63,11 @@
 		if (req->cmd)
 			g_free(req->cmd);
 		g_free(req);
+
+		gaim_debug_info("novell",
+						"Releasing NMRequest instance, total=%d\n", --count);
 	}
+
 }
 
 void
--- a/src/protocols/novell/nmrequest.h	Wed Jun 23 16:58:22 2004 +0000
+++ b/src/protocols/novell/nmrequest.h	Wed Jun 23 17:27:56 2004 +0000
@@ -34,7 +34,8 @@
  *
  *	@return The new request object
  */
-NMRequest *nm_create_request(const char *cmd, int trans_id, int gmt);
+NMRequest *nm_create_request(const char *cmd, int trans_id, int gmt, nm_response_cb cb,
+							 gpointer resp_data, gpointer user_define);
 
 /**
  *	Release a request object.
--- a/src/protocols/novell/nmuser.c	Wed Jun 23 16:58:22 2004 +0000
+++ b/src/protocols/novell/nmuser.c	Wed Jun 23 17:27:56 2004 +0000
@@ -57,7 +57,7 @@
 
 	user = g_new0(NMUser, 1);
 
-	user->conn = g_new0(NMConn, 1);
+
 
 	user->contacts =
 		g_hash_table_new_full(g_str_hash, nm_utf8_str_equal,
@@ -71,6 +71,7 @@
 												   g_free, g_free);
 
 	user->name = g_strdup(name);
+	user->conn = nm_create_conn(server_addr, port);
 	user->conn->addr = g_strdup(server_addr);
 	user->conn->port = port;
 	user->evt_callback = event_callback;
@@ -83,10 +84,7 @@
 void
 nm_deinitialize_user(NMUser * user)
 {
-	NMConn *conn = user->conn;
-
-	g_free(conn->addr);
-	g_free(conn);
+	nm_release_conn(user->conn);
 
 	if (user->contacts) {
 		g_hash_table_destroy(user->contacts);
@@ -120,7 +118,6 @@
 {
 	NMERR_T rc = NM_OK;
 	NMField *fields = NULL;
-	NMRequest *req = NULL;
 
 	if (user == NULL || pwd == NULL || user_agent == NULL) {
 		return NMERR_BAD_PARM;
@@ -143,21 +140,9 @@
 	}
 
 	/* Send the login */
-	rc = nm_send_request(user->conn, "login", fields, &req);
-	if (rc == NM_OK && req != NULL) {
-		nm_request_set_callback(req, callback);
-		nm_request_set_user_define(req, data);
-		nm_conn_add_request_item(user->conn, req);
-	}
+	rc = nm_send_request(user->conn, "login", fields, callback, data, NULL);
 
-	if (fields) {
-		nm_free_fields(&fields);
-	}
-
-	if (req) {
-		nm_release_request(req);
-	}
-
+	nm_free_fields(&fields);
 	return rc;
 }
 
@@ -167,7 +152,6 @@
 {
 	NMERR_T rc = NM_OK;
 	NMField *fields = NULL;
-	NMRequest *req = NULL;
 
 	if (user == NULL)
 		return NMERR_BAD_PARM;
@@ -189,21 +173,9 @@
 									  NMFIELD_TYPE_UTF8);
 	}
 
-	rc = nm_send_request(user->conn, "setstatus", 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);
-	}
+	rc = nm_send_request(user->conn, "setstatus", fields, callback, data, NULL);
 
-	if (fields) {
-		nm_free_fields(&fields);
-	}
-
-	if (req) {
-		nm_release_request(req);
-	}
-
+	nm_free_fields(&fields);
 	return rc;
 }
 
@@ -213,7 +185,6 @@
 {
 	NMERR_T rc = NM_OK;
 	NMField *fields = NULL;
-	NMRequest *req = NULL;
 	GSList *node;
 
 	if (user == NULL || names == NULL)
@@ -225,19 +196,9 @@
 									  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);
-	}
+	rc = nm_send_request(user->conn, "getdetails", fields, callback, data, NULL);
 
-	if (fields)
-		nm_free_fields(&fields);
-
-	if (req)
-		nm_release_request(req);
-
+	nm_free_fields(&fields);
 	return rc;
 }
 
@@ -247,7 +208,6 @@
 {
 	NMERR_T rc = NM_OK;
 	NMField *fields = NULL;
-	NMRequest *req = NULL;
 
 	if (user == NULL || name == NULL)
 		return NMERR_BAD_PARM;
@@ -259,7 +219,6 @@
 	} else {
 
 		const char *dn = nm_lookup_dn(user, name);
-
 		if (dn) {
 			fields = nm_field_add_pointer(fields, NM_A_SZ_DN, 0, NMFIELD_METHOD_VALID, 0,
 										  g_strdup(name), NMFIELD_TYPE_DN);
@@ -271,25 +230,15 @@
 
 	}
 
-	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);
-	}
+	rc = nm_send_request(user->conn, "getdetails", fields, callback, data, NULL);
 
-	if (fields)
-		nm_free_fields(&fields);
-
-	if (req)
-		nm_release_request(req);
-
+	nm_free_fields(&fields);
 	return rc;
 }
 
 NMERR_T
 nm_send_create_conference(NMUser * user, NMConference * conference,
-						  nm_response_cb callback, gpointer message)
+						  nm_response_cb callback, gpointer data)
 {
 	NMERR_T rc = NM_OK;
 	NMField *fields = NULL;
@@ -333,29 +282,23 @@
 									  NMFIELD_TYPE_DN);
 	}
 
-	rc = nm_send_request(user->conn, "createconf", fields, &req);
+	rc = nm_send_request(user->conn, "createconf", fields, callback, data, &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);
 	}
 
 	if (req)
 		nm_release_request(req);
 
-	if (fields)
-		nm_free_fields(&fields);
-
+	nm_free_fields(&fields);
 	return rc;
 }
 
 NMERR_T
 nm_send_leave_conference(NMUser * user, NMConference * conference,
-						 nm_response_cb callback, gpointer message)
+						 nm_response_cb callback, gpointer data)
 {
-
 	NMERR_T rc = NM_OK;
 	NMField *fields = NULL;
 	NMField *tmp = NULL;
@@ -375,20 +318,14 @@
 	tmp = NULL;
 
 	/* Send the request to the server */
-	rc = nm_send_request(user->conn, "leaveconf", fields, &req);
-	if (rc == NM_OK && req) {
-		nm_request_set_callback(req, callback);
+	rc = nm_send_request(user->conn, "leaveconf", fields, callback, data, &req);
+	if (rc == NM_OK && req)
 		nm_request_set_data(req, conference);
-		nm_request_set_user_define(req, message);
-		nm_conn_add_request_item(user->conn, req);
-	}
 
 	if (req)
 		nm_release_request(req);
 
-	if (fields)
-		nm_free_fields(&fields);
-
+	nm_free_fields(&fields);
 	return rc;
 }
 
@@ -414,24 +351,14 @@
 	tmp = NULL;
 
 	/* Send the request to the server */
-	rc = nm_send_request(user->conn, "joinconf", 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);
+	rc = nm_send_request(user->conn, "joinconf", fields, callback, data, &req);
+	if (rc == NM_OK && req)
 		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);
-
+	nm_free_fields(&fields);
 	return rc;
 }
 
@@ -458,24 +385,14 @@
 	tmp = NULL;
 
 	/* Send the request to the server */
-	rc = nm_send_request(user->conn, "rejectconf", 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);
+	rc = nm_send_request(user->conn, "rejectconf", fields, callback, data, &req);
+	if (rc == NM_OK && req)
 		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);
-
+	nm_free_fields(&fields);
 	return rc;
 }
 
@@ -512,24 +429,14 @@
 									  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);
+	rc = nm_send_request(user->conn, "sendinvite", fields, callback, data, &req);
+	if (rc == NM_OK && req)
 		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);
-
+	nm_free_fields(&fields);
 	return rc;
 }
 
@@ -539,7 +446,6 @@
 	NMERR_T rc = NM_OK;
 	char *text, *rtfized;
 	NMField *fields = NULL, *tmp = NULL;
-	NMRequest *req = NULL;
 	NMConference *conf;
 	NMUserRecord *user_record;
 	int count, i;
@@ -600,21 +506,10 @@
 		}
 
 		/* Send the request */
-		rc = nm_send_request(user->conn, "sendmessage", fields, &req);
-		if (rc == NM_OK && req) {
-			nm_request_set_callback(req, callback);
-			nm_conn_add_request_item(user->conn, req);
-		}
+		rc = nm_send_request(user->conn, "sendmessage", fields, callback, NULL, NULL);
 	}
 
-	if (fields) {
-		nm_free_fields(&fields);
-	}
-
-	if (req) {
-		nm_release_request(req);
-	}
-
+	nm_free_fields(&fields);
 	return rc;
 }
 
@@ -625,7 +520,6 @@
 	NMERR_T rc = NM_OK;
 	char *str = NULL;
 	NMField *fields = NULL, *tmp = NULL;
-	NMRequest *req = NULL;
 
 	if (user == NULL || conf == NULL) {
 		return NMERR_BAD_PARM;
@@ -652,19 +546,10 @@
 								 tmp, NMFIELD_TYPE_ARRAY);
 		tmp = NULL;
 
-		rc = nm_send_request(user->conn, "sendtyping", fields, &req);
-		if (rc == NM_OK && req) {
-			nm_request_set_callback(req, callback);
-			nm_conn_add_request_item(user->conn, req);
-		}
+		rc = nm_send_request(user->conn, "sendtyping", fields, callback, NULL, NULL);
 	}
 
-	if (req)
-		nm_release_request(req);
-
-	if (fields)
-		nm_free_fields(&fields);
-
+	nm_free_fields(&fields);
 	return rc;
 }
 
@@ -712,20 +597,14 @@
 									  g_strdup(display_name), NMFIELD_TYPE_UTF8);
 
 	/* Dispatch the request */
-	rc = nm_send_request(user->conn, "createcontact", fields, &req);
-	if (rc == NM_OK && req) {
-		nm_request_set_callback(req, callback);
+	rc = nm_send_request(user->conn, "createcontact", fields, callback, data, &req);
+	if (rc == NM_OK && req)
 		nm_request_set_data(req, contact);
-		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);
 
+	nm_free_fields(&fields);
 	return rc;
 }
 
@@ -753,20 +632,14 @@
 								  NMFIELD_TYPE_UTF8);
 
 	/* Dispatch the request */
-	rc = nm_send_request(user->conn, "deletecontact", fields, &req);
-	if (rc == NM_OK && req) {
-		nm_request_set_callback(req, callback);
+	rc = nm_send_request(user->conn, "deletecontact", fields, callback, data, &req);
+	if (rc == NM_OK && req)
 		nm_request_set_data(req, contact);
-		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);
 
+	nm_free_fields(&fields);
 	return rc;
 }
 
@@ -797,20 +670,14 @@
 							 g_strdup("-1"), NMFIELD_TYPE_UTF8);
 
 	/* Dispatch the request */
-	rc = nm_send_request(user->conn, "createfolder", fields, &req);
-	if (rc == NM_OK && req) {
-		nm_request_set_callback(req, callback);
+	rc = nm_send_request(user->conn, "createfolder", fields, callback, data, &req);
+	if (rc == NM_OK && req)
 		nm_request_set_data(req, g_strdup(name));
-		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);
 
+	nm_free_fields(&fields);
 	return rc;
 }
 
@@ -832,20 +699,14 @@
 								  NMFIELD_TYPE_UTF8);
 
 	/* Dispatch the request */
-	rc = nm_send_request(user->conn, "deletecontact", fields, &req);
-	if (rc == NM_OK && req) {
-		nm_request_set_callback(req, callback);
+	rc = nm_send_request(user->conn, "deletecontact", fields, callback, data, &req);
+	if (rc == NM_OK && req)
 		nm_request_set_data(req, folder);
-		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);
 
+	nm_free_fields(&fields);
 	return rc;
 }
 
@@ -870,20 +731,14 @@
 								  g_strdup(dn), NMFIELD_TYPE_UTF8);
 
 	/* Dispatch the request */
-	rc = nm_send_request(user->conn, "getstatus", fields, &req);
-	if (rc == NM_OK && req) {
-		nm_request_set_callback(req, callback);
+	rc = nm_send_request(user->conn, "getstatus", fields, callback, data, &req);
+	if (rc == NM_OK && req)
 		nm_request_set_data(req, user_record);
-		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);
 
+	nm_free_fields(&fields);
 	return rc;
 }
 
@@ -925,16 +780,15 @@
 									 0, fields, NMFIELD_TYPE_ARRAY);
 			fields = NULL;
 
-			rc = nm_send_request(user->conn, "updateitem", list, &req);
-			if (rc == NM_OK && req) {
-				nm_request_set_callback(req, callback);
+			rc = nm_send_request(user->conn, "updateitem", list, callback, data, &req);
+			if (rc == NM_OK && req)
 				nm_request_set_data(req, contact);
-				nm_request_set_user_define(req, data);
-				nm_conn_add_request_item(user->conn, req);
-			}
 		}
 	}
 
+	if (req)
+		nm_release_request(req);
+
 	if (list)
 		nm_free_fields(&list);
 
@@ -979,16 +833,15 @@
 										0, fields, NMFIELD_TYPE_ARRAY);
 			fields = NULL;
 
-			rc = nm_send_request(user->conn, "updateitem", list, &req);
-			if (rc == NM_OK && req) {
-				nm_request_set_callback(req, callback);
+			rc = nm_send_request(user->conn, "updateitem", list, callback, data, &req);
+			if (rc == NM_OK && req)
 				nm_request_set_data(req, folder);
-				nm_request_set_user_define(req, data);
-				nm_conn_add_request_item(user->conn, req);
-			}
 		}
 	}
 
+	if (req)
+		nm_release_request(req);
+
 	if (list)
 		nm_free_fields(&list);
 
@@ -1029,15 +882,14 @@
 									NMFIELD_TYPE_UTF8);
 
 		/* Dispatch the request */
-		rc = nm_send_request(user->conn, "movecontact", list, &req);
-		if (rc == NM_OK && req) {
-			nm_request_set_callback(req, callback);
+		rc = nm_send_request(user->conn, "movecontact", list, callback, data, &req);
+		if (rc == NM_OK && req)
 			nm_request_set_data(req, contact);
-			nm_request_set_user_define(req, data);
-			nm_conn_add_request_item(user->conn, req);
+
+	}
 
-		}
-	}
+	if (req)
+		nm_release_request(req);
 
 	if (list)
 		nm_free_fields(&list);
@@ -1052,7 +904,6 @@
 {
 	NMERR_T rc = NM_OK;
 	NMField *fields = NULL;
-	NMRequest *req = NULL;
 	const char *tag;
 
 	if (user == NULL || who == NULL)
@@ -1066,16 +917,9 @@
     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);
-	}
+	rc = nm_send_request(user->conn, "createblock", fields, callback, data, NULL);
 
-	if (fields)
-		nm_free_fields(&fields);
-
+	nm_free_fields(&fields);
 	return rc;
 }
 
@@ -1085,7 +929,6 @@
 {
 	NMERR_T rc = NM_OK;
 	NMField *fields = NULL;
-	NMRequest *req = NULL;
 	const char *tag;
 	GSList **list_ptr, *node;
 
@@ -1109,16 +952,9 @@
     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);
-	}
+	rc = nm_send_request(user->conn, "updateblocks", fields, callback, data, NULL);
 
-	if (fields)
-		nm_free_fields(&fields);
-
+	nm_free_fields(&fields);
 	return rc;
 
 }
@@ -1129,7 +965,6 @@
 {
 	NMERR_T rc = NM_OK;
 	NMField *fields = NULL;
-	NMRequest *req = NULL;
 
 	if (user == NULL)
 		return NMERR_BAD_PARM;
@@ -1138,16 +973,9 @@
 								  (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);
-	}
+	rc = nm_send_request(user->conn, "updateblocks", fields, callback, data, NULL);
 
-	if (fields)
-		nm_free_fields(&fields);
-
+	nm_free_fields(&fields);
 	return rc;
 }
 
@@ -1155,17 +983,11 @@
 nm_send_keepalive(NMUser *user, nm_response_cb callback, gpointer data)
 {
 	NMERR_T rc = NM_OK;
-	NMRequest *req = NULL;
 
 	if (user == NULL)
 		return NMERR_BAD_PARM;
 
-	rc = nm_send_request(user->conn, "ping", NULL, &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);
-	}
+	rc = nm_send_request(user->conn, "ping", NULL, callback, data, NULL);
 
 	return rc;
 }
--- a/src/protocols/novell/nmuser.h	Wed Jun 23 16:58:22 2004 +0000
+++ b/src/protocols/novell/nmuser.h	Wed Jun 23 17:27:56 2004 +0000
@@ -127,6 +127,8 @@
 	/* Have the privacy lists been synched yet */
 	gboolean privacy_synched;
 
+	/* Has the contact list been synched */
+	gboolean clist_synched;
 };
 
 #define	NM_STATUS_UNKNOWN			0
--- a/src/protocols/novell/novell.c	Wed Jun 23 16:58:22 2004 +0000
+++ b/src/protocols/novell/novell.c	Wed Jun 23 17:27:56 2004 +0000
@@ -101,12 +101,12 @@
 				gaim_account_set_alias(user->client_data, alias);
 		}
 
-		_sync_contact_list(user);
-
 		/* Tell Gaim that we are connected */
 		gaim_connection_set_state(gc, GAIM_CONNECTED);
 		serv_finish_login(gc);
 
+		_sync_contact_list(user);
+
 		rc = nm_send_set_status(user, NM_STATUS_AVAILABLE, NULL, NULL, NULL,
 								NULL);
 		_check_for_disconnect(user, rc);
@@ -1316,6 +1316,7 @@
 	 */
 	_remove_gaim_buddies(user);
 	_add_gaim_buddies(user);
+	user->clist_synched = TRUE;
 }
 
 static void
@@ -2445,6 +2446,12 @@
 	if (user == NULL)
 		return;
 
+	/* If we haven't synched the contact list yet, ignore
+	 * the add_buddy calls. Server side list is the master.
+	 */
+	if (!user->clist_synched)
+		return;
+
 	contact = nm_create_contact();
 	nm_contact_set_dn(contact, buddy->name);
 
@@ -2477,7 +2484,7 @@
 }
 
 static void
-novell_remove_buddy(GaimConnection * gc, GaimBuddy *buddy, GaimGroup *group)
+novell_remove_buddy(GaimConnection *gc, GaimBuddy *buddy, GaimGroup *group)
 {
 	NMContact *contact;
 	NMFolder *folder;
@@ -2490,7 +2497,6 @@
 
 	user = (NMUser *) gc->proto_data;
 	if (user && (dn = nm_lookup_dn(user, buddy->name))) {
-
 		folder = nm_find_folder(user, group->name);
 		if (folder) {
 			contact = nm_folder_find_contact(folder, dn);