From c1bb27b04298b79cf83fb9a9edc996ca3d68e877 Mon Sep 17 00:00:00 2001 From: pier11 Date: Tue, 12 May 2009 20:31:13 +0100 Subject: [PATCH] Message delivery remake Back to original scheme plus new structure for unconfirmed messages. Should be no more duplicates. --- src/sipe.c | 134 +++++++++++++++++++++++++++++++++++++------------------------ src/sipe.h | 2 + 2 files changed, 84 insertions(+), 52 deletions(-) diff --git a/src/sipe.c b/src/sipe.c index 33884475..e8cb2d4e 100644 --- a/src/sipe.c +++ b/src/sipe.c @@ -2122,7 +2122,8 @@ static void sipe_process_registration_notify(struct sipe_account_data *sip, stru int error_id = 0; if (event && !g_ascii_strcasecmp(event, "unregistered")) { error_id = 4140; // [MS-SIPREGE] - reason = _("User logged out"); // [MS-OCER] + //reason = _("User logged out"); // [MS-OCER] + reason = _("You have been signed off because you've signed in at another location"); } else if (event && !g_ascii_strcasecmp(event, "rejected")) { error_id = 4141; reason = _("User disabled"); // [MS-OCER] @@ -2321,6 +2322,7 @@ static struct sip_im_session * find_or_create_im_session (struct sipe_account_da if (!session) { session = g_new0(struct sip_im_session, 1); session->with = g_strdup(who); + session->unconfirmed_messages = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); sip->im_sessions = g_slist_append(sip->im_sessions, session); } return session; @@ -2357,6 +2359,8 @@ static void im_session_destroy(struct sipe_account_data *sip, struct sip_im_sess g_free(entry->data); entry = g_slist_remove(entry, entry->data); } + + g_hash_table_destroy(session->unconfirmed_messages); g_free(session->with); g_free(session); @@ -2411,7 +2415,6 @@ static void sipe_present_message_undelivered_err(gchar *with, struct sipe_accoun g_free(msg_tmp); } -static void sipe_im_remove_first_from_queue (struct sip_im_session * session); static void sipe_im_process_queue (struct sipe_account_data * sip, struct sip_im_session * session); static gboolean @@ -2421,35 +2424,44 @@ process_message_response(struct sipe_account_data *sip, struct sipmsg *msg, stru gchar * with = parse_from(sipmsg_find_header(msg, "To")); struct sip_im_session * session = find_im_session(sip, with); struct sip_dialog *dialog; + gchar *cseq; + char *key; + gchar *message; if (!session) { purple_debug_info("sipe", "process_message_response: unable to find IM session\n"); g_free(with); return FALSE; } + + dialog = session->dialog; + if (!dialog) { + purple_debug_info("sipe", "process_message_response: session outgoing dialog is NULL\n"); + g_free(with); + return FALSE; + } + + cseq = sipmsg_find_part_of_header(sipmsg_find_header(msg, "CSeq"), NULL, " ", NULL); + key = g_strdup_printf("<%s><%d>", sipmsg_find_header(msg, "Call-ID"), atoi(cseq)); + g_free(cseq); + message = g_hash_table_lookup(session->unconfirmed_messages, key); if (msg->response != 200) { - gchar *queued_msg = NULL; purple_debug_info("sipe", "process_message_response: MESSAGE response not 200\n"); - if (session->outgoing_message_queue) { - queued_msg = session->outgoing_message_queue->data; - } - sipe_present_message_undelivered_err(with, sip, queued_msg); + sipe_present_message_undelivered_err(with, sip, message); im_session_destroy(sip, session); - g_free(with); - return FALSE; - } - - dialog = session->dialog; - if (!dialog) { - purple_debug_info("sipe", "process_message_response: session outgoing dialog is NULL\n"); ret = FALSE; + } else { + g_hash_table_remove(session->unconfirmed_messages, key); + purple_debug_info("sipe", "process_message_response: removed message %s from unconfirmed_messages(count=%d)\n", + key, g_hash_table_size(session->unconfirmed_messages)); } - - sipe_im_remove_first_from_queue(session); + + g_free(key); + g_free(with); + sipe_im_process_queue(sip, session); - g_free(with); return ret; } @@ -2501,19 +2513,18 @@ static void sipe_im_process_queue (struct sipe_account_data * sip, struct sip_im_session * session) { GSList *entry = session->outgoing_message_queue; - if (entry) { + + if (session->outgoing_invite) return; //do not send messages until INVITE responded. + + while (entry) { + char *key = g_strdup_printf("<%s><%d>", session->dialog->callid, (session->dialog->cseq) + 1); char *queued_msg = entry->data; + g_hash_table_insert(session->unconfirmed_messages, g_strdup(key), g_strdup(queued_msg)); + purple_debug_info("sipe", "sipe_im_process_queue: added message %s to unconfirmed_messages(count=%d)\n", + key, g_hash_table_size(session->unconfirmed_messages)); + g_free(key); sipe_send_message(sip, session, queued_msg); - } -} - -static void -sipe_im_remove_first_from_queue (struct sip_im_session * session) -{ - if (session && session->outgoing_message_queue) { - char *queued_msg = session->outgoing_message_queue->data; - // Remove from the queue and free the string - session->outgoing_message_queue = g_slist_remove(session->outgoing_message_queue, queued_msg); + entry = session->outgoing_message_queue = g_slist_remove(session->outgoing_message_queue, queued_msg); g_free(queued_msg); } } @@ -2593,9 +2604,12 @@ sipe_parse_dialog(struct sipmsg * msg, struct sip_dialog * dialog, gboolean outg static gboolean process_invite_response(struct sipe_account_data *sip, struct sipmsg *msg, struct transaction *trans) { - gchar * with = parse_from(sipmsg_find_header(msg, "To")); + gchar *with = parse_from(sipmsg_find_header(msg, "To")); struct sip_im_session * session = find_im_session(sip, with); struct sip_dialog *dialog; + char *cseq; + char *key; + gchar *message; if (!session) { purple_debug_info("sipe", "process_invite_response: unable to find IM session\n"); @@ -2603,38 +2617,48 @@ process_invite_response(struct sipe_account_data *sip, struct sipmsg *msg, struc return FALSE; } - if (msg->response != 200) { - gchar *queued_msg = NULL; - purple_debug_info("sipe", "process_invite_response: INVITE response not 200\n"); - - if (session->outgoing_message_queue) { - queued_msg = session->outgoing_message_queue->data; - } - sipe_present_message_undelivered_err(with, sip, queued_msg); - - im_session_destroy(sip, session); - g_free(with); - return FALSE; - } - dialog = session->dialog; if (!dialog) { purple_debug_info("sipe", "process_invite_response: session outgoing dialog is NULL\n"); g_free(with); return FALSE; } - + sipe_parse_dialog(msg, dialog, TRUE); - dialog->cseq = 0; + + cseq = sipmsg_find_part_of_header(sipmsg_find_header(msg, "CSeq"), NULL, " ", NULL); + key = g_strdup_printf("<%s><%d>", dialog->callid, atoi(cseq)); + g_free(cseq); + message = g_hash_table_lookup(session->unconfirmed_messages, key); + + if (msg->response != 200) { + purple_debug_info("sipe", "process_invite_response: INVITE response not 200\n"); + sipe_present_message_undelivered_err(with, sip, message); + im_session_destroy(sip, session); + g_free(with); + return FALSE; + } + + dialog->cseq = 0; send_sip_request(sip->gc, "ACK", session->with, session->with, NULL, NULL, dialog, NULL); session->outgoing_invite = NULL; if(g_slist_find_custom(dialog->supported, "ms-text-format", (GCompareFunc)strcmp)) { - sipe_im_remove_first_from_queue(session); - } else { - sipe_im_process_queue(sip, session); + purple_debug_info("sipe", "process_invite_response: remote system accepted message in INVITE\n"); + if (session->outgoing_message_queue) { + char *queued_msg = session->outgoing_message_queue->data; + session->outgoing_message_queue = g_slist_remove(session->outgoing_message_queue, queued_msg); + g_free(queued_msg); + } } - + + sipe_im_process_queue(sip, session); + + g_hash_table_remove(session->unconfirmed_messages, key); + purple_debug_info("sipe", "process_invite_response: removed message %s from unconfirmed_messages(count=%d)\n", + key, g_hash_table_size(session->unconfirmed_messages)); + + g_free(key); g_free(with); return TRUE; } @@ -2652,6 +2676,7 @@ static void sipe_invite(struct sipe_account_data *sip, struct sip_im_session *se char *ms_text_format; gchar *msgr_value; gchar *msgr; + char *key; if (session->dialog) { purple_debug_info("sipe", "session with %s already has a dialog open\n", session->with); @@ -2659,6 +2684,7 @@ static void sipe_invite(struct sipe_account_data *sip, struct sip_im_session *se } session->dialog = g_new0(struct sip_dialog, 1); + session->dialog->callid = gencallid(); if (strstr(session->with, "sip:")) { to = g_strdup(session->with); @@ -2682,6 +2708,12 @@ static void sipe_invite(struct sipe_account_data *sip, struct sip_im_session *se g_free(msgtext); g_free(msgr); g_free(base64_msg); + + key = g_strdup_printf("<%s><%d>", session->dialog->callid, (session->dialog->cseq) + 1); + g_hash_table_insert(session->unconfirmed_messages, g_strdup(key), g_strdup(msg_body)); + purple_debug_info("sipe", "sipe_im_send: added message %s to unconfirmed_messages(count=%d)\n", + key, g_hash_table_size(session->unconfirmed_messages)); + g_free(key); contact = get_contact(sip); hdr = g_strdup_printf( @@ -2765,7 +2797,6 @@ static int sipe_im_send(PurpleConnection *gc, const char *who, const char *what, return 1; } - /* End IM Session (INVITE and MESSAGE methods) */ static unsigned int @@ -2784,7 +2815,6 @@ sipe_send_typing(PurpleConnection *gc, const char *who, PurpleTypingState state) "Content-Type: application/xml\r\n", SIPE_SEND_TYPING, session->dialog, NULL); } - return SIPE_TYPING_SEND_TIMEOUT; } @@ -2970,7 +3000,7 @@ static void process_incoming_options(struct sipe_account_data *sip, struct sipms session->dialog->theirepid = sipmsg_find_part_of_header(sipmsg_find_header(msg, "From"), "epid=", NULL, NULL); } } else { - purple_debug_info("sipe", "process_incoming_invite, failed to find or create IM session\n"); + purple_debug_info("sipe", "process_incoming_options, failed to find or create IM session\n"); } g_free(from); diff --git a/src/sipe.h b/src/sipe.h index 309d1760..afefef2e 100644 --- a/src/sipe.h +++ b/src/sipe.h @@ -54,6 +54,8 @@ struct sip_im_session { struct transaction * outgoing_invite; GSList *outgoing_message_queue; + /** Key is */ + GHashTable *unconfirmed_messages; }; // dialog is the new term for call-leg -- 2.11.4.GIT