void sipe_core_user_feedback_typing(struct sipe_core_public *sipe_public, const gchar *to, gboolean typing) { struct sipe_core_private *sipe_private = SIPE_CORE_PRIVATE; struct sip_session *session = sipe_session_find_im(sipe_private, to); struct sip_dialog *dialog = sipe_dialog_find(session, to); /* only enable this debug output while testing SIPE_DEBUG_INFO("sipe_core_user_feedback_typing session %p (%s) dialog %p (%s) established %s", session, session ? session->callid : "N/A", dialog, dialog ? dialog->callid : "N/A", (dialog && dialog->is_established) ? "YES" : "NO"); */ if (session && dialog && dialog->is_established) { gchar *body = g_strdup_printf("<?xml version=\"1.0\"?>" "<KeyboardActivity>" " <status status=\"%s\" />" "</KeyboardActivity>", typing ? "type" : "idle"); sip_transport_info(sipe_private, "Content-Type: application/xml\r\n", body, dialog, process_info_typing_response); g_free(body); } }
struct sip_session * sipe_session_find_or_add_im(struct sipe_account_data *sip, const gchar *who) { struct sip_session *session = sipe_session_find_im(sip, who); if (!session) { purple_debug_info("sipe", "sipe_session_find_or_add_im: new session for %s\n", who); session = g_new0(struct sip_session, 1); session->is_multiparty = FALSE; session->with = g_strdup(who); session->unconfirmed_messages = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); sip->sessions = g_slist_append(sip->sessions, session); }
static gboolean process_info_typing_response(struct sipe_core_private *sipe_private, struct sipmsg *msg, SIPE_UNUSED_PARAMETER struct transaction *trans) { /* Indicates dangling IM session which needs to be dropped */ if (msg->response == 408 || /* Request timeout */ msg->response == 480 || /* Temporarily Unavailable */ msg->response == 481) { /* Call/Transaction Does Not Exist */ gchar *with = parse_from(sipmsg_find_header(msg, "To")); struct sip_session *session = sipe_session_find_im(sipe_private, with); struct sip_dialog *dialog = sipe_dialog_find(session, with); if (dialog) sipe_im_cancel_dangling(sipe_private, session, dialog, with, sipe_im_cancel_unconfirmed); g_free(with); } return(TRUE); }
/** Invite counterparty to join conference callback */ static gboolean process_invite_conf_response(struct sipe_core_private *sipe_private, struct sipmsg *msg, SIPE_UNUSED_PARAMETER struct transaction *trans) { struct sip_dialog *dialog = g_new0(struct sip_dialog, 1); dialog->callid = g_strdup(sipmsg_find_header(msg, "Call-ID")); dialog->cseq = sipmsg_parse_cseq(msg); dialog->with = parse_from(sipmsg_find_header(msg, "To")); sipe_dialog_parse(dialog, msg, TRUE); if (msg->response >= 200) { /* send ACK to counterparty */ dialog->cseq--; sip_transport_ack(sipe_private, dialog); dialog->outgoing_invite = NULL; dialog->is_established = TRUE; } if (msg->response >= 400) { SIPE_DEBUG_INFO("process_invite_conf_response: INVITE response is not 200. Failed to invite %s.", dialog->with); /* @TODO notify user of failure to invite counterparty */ sipe_dialog_free(dialog); return FALSE; } if (msg->response >= 200) { struct sip_session *session = sipe_session_find_im(sipe_private, dialog->with); struct sip_dialog *im_dialog = sipe_dialog_find(session, dialog->with); /* close IM session to counterparty */ if (im_dialog) { sip_transport_bye(sipe_private, im_dialog); sipe_dialog_remove(session, dialog->with); } } sipe_dialog_free(dialog); return TRUE; }