summaryrefslogtreecommitdiff
path: root/libpurple/protocols/msn/slplink.c
diff options
context:
space:
mode:
Diffstat (limited to 'libpurple/protocols/msn/slplink.c')
-rw-r--r--libpurple/protocols/msn/slplink.c230
1 files changed, 159 insertions, 71 deletions
diff --git a/libpurple/protocols/msn/slplink.c b/libpurple/protocols/msn/slplink.c
index eeeed3090d..ef70203bb1 100644
--- a/libpurple/protocols/msn/slplink.c
+++ b/libpurple/protocols/msn/slplink.c
@@ -78,7 +78,7 @@ msn_slplink_new(MsnSession *session, const char *username)
session->slplinks =
g_list_append(session->slplinks, slplink);
- return slplink;
+ return msn_slplink_ref(slplink);
}
void
@@ -91,15 +91,23 @@ msn_slplink_destroy(MsnSlpLink *slplink)
g_return_if_fail(slplink != NULL);
- if (slplink->swboard != NULL)
+ if (slplink->swboard != NULL) {
slplink->swboard->slplinks = g_list_remove(slplink->swboard->slplinks, slplink);
+ slplink->swboard = NULL;
+ }
+
+ if (slplink->refs > 1) {
+ slplink->refs--;
+ return;
+ }
session = slplink->session;
-#if 0
- if (slplink->directconn != NULL)
- msn_directconn_destroy(slplink->directconn);
-#endif
+ if (slplink->dc != NULL) {
+ slplink->dc->slplink = NULL;
+ msn_dc_destroy(slplink->dc);
+ slplink->dc = NULL;
+ }
while (slplink->slp_calls != NULL)
msn_slpcall_destroy(slplink->slp_calls->data);
@@ -115,6 +123,31 @@ msn_slplink_destroy(MsnSlpLink *slplink)
}
MsnSlpLink *
+msn_slplink_ref(MsnSlpLink *slplink)
+{
+ g_return_val_if_fail(slplink != NULL, NULL);
+
+ slplink->refs++;
+ if (purple_debug_is_verbose())
+ purple_debug_info("msn", "slplink ref (%p)[%d]\n", slplink, slplink->refs);
+
+ return slplink;
+}
+
+void
+msn_slplink_unref(MsnSlpLink *slplink)
+{
+ g_return_if_fail(slplink != NULL);
+
+ slplink->refs--;
+ if (purple_debug_is_verbose())
+ purple_debug_info("msn", "slplink unref (%p)[%d]\n", slplink, slplink->refs);
+
+ if (slplink->refs == 0)
+ msn_slplink_destroy(slplink);
+}
+
+MsnSlpLink *
msn_session_find_slplink(MsnSession *session, const char *who)
{
GList *l;
@@ -155,18 +188,43 @@ msn_slplink_add_slpcall(MsnSlpLink *slplink, MsnSlpCall *slpcall)
slplink->swboard->flag |= MSN_SB_FLAG_FT;
slplink->slp_calls = g_list_append(slplink->slp_calls, slpcall);
+
+ /*
+ if (slplink->dc != NULL && slplink->dc->state == DC_STATE_ESTABLISHED)
+ msn_dc_ref(slplink->dc);
+ */
}
void
msn_slplink_remove_slpcall(MsnSlpLink *slplink, MsnSlpCall *slpcall)
{
+ /*
+ if (slplink->dc != NULL && slplink->dc->state == DC_STATE_ESTABLISHED)
+ msn_dc_unref(slplink->dc);
+ */
+
slplink->slp_calls = g_list_remove(slplink->slp_calls, slpcall);
/* The slplink has no slpcalls in it, release it from MSN_SB_FLAG_FT.
* If nothing else is using it then this might cause swboard to be
* destroyed. */
- if (slplink->slp_calls == NULL && slplink->swboard != NULL)
+ if (slplink->slp_calls == NULL && slplink->swboard != NULL) {
+ slplink->swboard->slplinks = g_list_remove(slplink->swboard->slplinks, slplink);
msn_switchboard_release(slplink->swboard, MSN_SB_FLAG_FT);
+ slplink->swboard = NULL;
+ }
+
+ if (slplink->dc != NULL) {
+ if ((slplink->dc->state != DC_STATE_ESTABLISHED && slplink->dc->slpcall == slpcall)
+ || (slplink->slp_calls == NULL)) {
+ /* The DC is not established and its corresponding slpcall is dead,
+ * or the slplink has no slpcalls in it and no longer needs the DC.
+ */
+ slplink->dc->slplink = NULL;
+ msn_dc_destroy(slplink->dc);
+ slplink->dc = NULL;
+ }
+ }
}
MsnSlpCall *
@@ -206,16 +264,14 @@ msn_slplink_find_slp_call_with_session_id(MsnSlpLink *slplink, long id)
return NULL;
}
-static void
+void
msn_slplink_send_msg(MsnSlpLink *slplink, MsnMessage *msg)
{
-#if 0
- if (slplink->directconn != NULL)
+ if (slplink->dc != NULL && slplink->dc->state == DC_STATE_ESTABLISHED)
{
- msn_directconn_send_msg(slplink->directconn, msg);
+ msn_dc_enqueue_msg(slplink->dc, msg);
}
else
-#endif
{
if (slplink->swboard == NULL)
{
@@ -275,7 +331,7 @@ msn_slplink_send_msgpart(MsnSlpLink *slplink, MsnSlpMessage *slpmsg)
#endif
slpmsg->msgs =
- g_list_append(slpmsg->msgs, msg);
+ g_list_append(slpmsg->msgs, msn_message_ref(msg));
msn_slplink_send_msg(slplink, msg);
if ((slpmsg->flags == 0x20 || slpmsg->flags == 0x1000020 ||
@@ -314,6 +370,7 @@ msg_ack(MsnMessage *msg, void *data)
if (slpmsg->slpcall->xfer && purple_xfer_get_status(slpmsg->slpcall->xfer) == PURPLE_XFER_STATUS_STARTED)
{
slpmsg->slpcall->xfer_msg = slpmsg;
+ msn_message_ref(msg);
purple_xfer_prpl_ready(slpmsg->slpcall->xfer);
}
else
@@ -333,6 +390,8 @@ msg_ack(MsnMessage *msg, void *data)
}
}
}
+
+ msn_message_unref(msg);
}
/* We have received the message nak. */
@@ -346,12 +405,14 @@ msg_nak(MsnMessage *msg, void *data)
msn_slplink_send_msgpart(slpmsg->slplink, slpmsg);
slpmsg->msgs = g_list_remove(slpmsg->msgs, msg);
+ msn_message_unref(msg);
}
static void
msn_slplink_release_slpmsg(MsnSlpLink *slplink, MsnSlpMessage *slpmsg)
{
MsnMessage *msg;
+ const char *passport;
slpmsg->msg = msg = msn_message_new_msnslp();
@@ -390,7 +451,8 @@ msn_slplink_release_slpmsg(MsnSlpLink *slplink, MsnSlpMessage *slpmsg)
msg->msnslp_header.total_size = slpmsg->size;
- msn_message_set_attr(msg, "P2P-Dest", slplink->remote_user);
+ passport = purple_normalize(slplink->session->account, slplink->remote_user);
+ msn_message_set_attr(msg, "P2P-Dest", passport);
msg->ack_cb = msg_ack;
msg->nak_cb = msg_nak;
@@ -431,21 +493,29 @@ msn_slplink_send_queued_slpmsgs(MsnSlpLink *slplink)
}
}
-static void
-msn_slplink_send_ack(MsnSlpLink *slplink, MsnMessage *msg)
+static MsnSlpMessage *
+msn_slplink_create_ack(MsnSlpLink *slplink, MsnSlpHeader *header)
{
MsnSlpMessage *slpmsg;
slpmsg = msn_slpmsg_new(slplink);
- slpmsg->session_id = msg->msnslp_header.session_id;
- slpmsg->size = msg->msnslp_header.total_size;
+ slpmsg->session_id = header->session_id;
+ slpmsg->size = header->total_size;
slpmsg->flags = 0x02;
- slpmsg->ack_id = msg->msnslp_header.id;
- slpmsg->ack_sub_id = msg->msnslp_header.ack_id;
- slpmsg->ack_size = msg->msnslp_header.total_size;
+ slpmsg->ack_id = header->id;
+ slpmsg->ack_sub_id = header->ack_id;
+ slpmsg->ack_size = header->total_size;
slpmsg->info = "SLP ACK";
+ return slpmsg;
+}
+
+static void
+msn_slplink_send_ack(MsnSlpLink *slplink, MsnSlpHeader *header)
+{
+ MsnSlpMessage *slpmsg = msn_slplink_create_ack(slplink, header);
+
msn_slplink_send_slpmsg(slplink, slpmsg);
msn_slpmsg_destroy(slpmsg);
}
@@ -457,6 +527,9 @@ send_file_cb(MsnSlpCall *slpcall)
PurpleXfer *xfer;
xfer = (PurpleXfer *)slpcall->xfer;
+ if (purple_xfer_get_status(xfer) >= PURPLE_XFER_STATUS_STARTED)
+ return;
+
purple_xfer_ref(xfer);
purple_xfer_start(xfer, -1, NULL, 0);
if (purple_xfer_get_status(xfer) != PURPLE_XFER_STATUS_STARTED) {
@@ -491,38 +564,27 @@ msn_slplink_message_find(MsnSlpLink *slplink, long session_id, long id)
}
void
-msn_slplink_process_msg(MsnSlpLink *slplink, MsnMessage *msg)
+msn_slplink_process_msg(MsnSlpLink *slplink, MsnSlpHeader *header, const char *data, gsize len)
{
MsnSlpMessage *slpmsg;
- const char *data;
guint64 offset;
- gsize len;
PurpleXfer *xfer = NULL;
- if (purple_debug_is_verbose())
- msn_slpmsg_show(msg);
-
-#ifdef MSN_DEBUG_SLP_FILES
- debug_msg_to_file(msg, FALSE);
-#endif
-
- if (msg->msnslp_header.total_size < msg->msnslp_header.length)
+ if (header->total_size < header->length)
{
purple_debug_error("msn", "This can't be good\n");
g_return_if_reached();
}
- data = msn_message_get_bin_data(msg, &len);
-
- offset = msg->msnslp_header.offset;
+ offset = header->offset;
if (offset == 0)
{
slpmsg = msn_slpmsg_new(slplink);
- slpmsg->id = msg->msnslp_header.id;
- slpmsg->session_id = msg->msnslp_header.session_id;
- slpmsg->size = msg->msnslp_header.total_size;
- slpmsg->flags = msg->msnslp_header.flags;
+ slpmsg->id = header->id;
+ slpmsg->session_id = header->session_id;
+ slpmsg->size = header->total_size;
+ slpmsg->flags = header->flags;
if (slpmsg->session_id)
{
@@ -567,10 +629,10 @@ msn_slplink_process_msg(MsnSlpLink *slplink, MsnMessage *msg)
}
else
{
- slpmsg = msn_slplink_message_find(slplink, msg->msnslp_header.session_id, msg->msnslp_header.id);
+ slpmsg = msn_slplink_message_find(slplink, header->session_id, header->id);
if (slpmsg == NULL)
{
- /* Probably the transfer was canceled */
+ /* Probably the transfer was cancelled */
purple_debug_error("msn", "Couldn't find slpmsg\n");
return;
}
@@ -615,8 +677,7 @@ msn_slplink_process_msg(MsnSlpLink *slplink, MsnMessage *msg)
return;
#endif
- if (msg->msnslp_header.offset + msg->msnslp_header.length
- >= msg->msnslp_header.total_size)
+ if (header->offset + header->length >= header->total_size)
{
/* All the pieces of the slpmsg have been received */
MsnSlpCall *slpcall;
@@ -628,32 +689,45 @@ msn_slplink_process_msg(MsnSlpLink *slplink, MsnMessage *msg)
return;
}
- if (!slpcall->wasted) {
- if (slpmsg->flags == 0x100)
- {
- MsnDirectConn *directconn;
+ purple_debug_info("msn", "msn_slplink_process_msg: slpmsg complete\n");
- directconn = slplink->directconn;
+ if (/* !slpcall->wasted && */ slpmsg->flags == 0x100)
+ {
#if 0
- if (!directconn->acked)
- msn_directconn_send_handshake(directconn);
-#endif
- }
- else if (slpmsg->flags == 0x00 || slpmsg->flags == 0x1000000 ||
- slpmsg->flags == 0x20 || slpmsg->flags == 0x1000020 ||
- slpmsg->flags == 0x1000030)
- {
- /* Release all the messages and send the ACK */
+ MsnDirectConn *directconn;
- msn_slplink_send_ack(slplink, msg);
+ directconn = slplink->directconn;
+ if (!directconn->acked)
+ msn_directconn_send_handshake(directconn);
+#endif
+ }
+ else if (slpmsg->flags == 0x00 || slpmsg->flags == 0x1000000 ||
+ slpmsg->flags == 0x20 || slpmsg->flags == 0x1000020 ||
+ slpmsg->flags == 0x1000030)
+ {
+ /* Release all the messages and send the ACK */
+
+ if (slpcall->wait_for_socket) {
+ /*
+ * Save ack for later because we have to send
+ * a 200 OK message to the previous direct connect
+ * invitation before ACK but the listening socket isn't
+ * created yet.
+ */
+ purple_debug_info("msn", "msn_slplink_process_msg: save ACK\n");
+
+ slpcall->slplink->dc->prev_ack = msn_slplink_create_ack(slplink, header);
+ } else if (!slpcall->wasted) {
+ purple_debug_info("msn", "msn_slplink_process_msg: send ACK\n");
+
+ msn_slplink_send_ack(slplink, header);
msn_slplink_send_queued_slpmsgs(slplink);
}
-
}
msn_slpmsg_destroy(slpmsg);
- if (slpcall->wasted)
+ if (!slpcall->wait_for_socket && slpcall->wasted)
msn_slpcall_destroy(slpcall);
}
}
@@ -662,15 +736,19 @@ static gchar *
gen_context(PurpleXfer *xfer, const char *file_name, const char *file_path)
{
gsize size = 0;
- MsnFileContext header;
+ MsnFileContext *header;
gchar *u8 = NULL;
gchar *ret;
gunichar2 *uni = NULL;
glong currentChar = 0;
glong len = 0;
+ const char *preview;
+ gsize preview_len;
size = purple_xfer_get_size(xfer);
+ purple_xfer_prepare_thumbnail(xfer, "png");
+
if (!file_name) {
gchar *basename = g_path_get_basename(file_path);
u8 = purple_utf8_try_convert(basename);
@@ -686,23 +764,33 @@ gen_context(PurpleXfer *xfer, const char *file_name, const char *file_path)
u8 = NULL;
}
- header.length = GUINT32_TO_LE(sizeof(MsnFileContext) - 1);
- header.version = GUINT32_TO_LE(2); /* V.3 contains additional unnecessary data */
- header.file_size = GUINT64_TO_LE(size);
- header.type = GUINT32_TO_LE(1); /* No file preview */
+ preview = purple_xfer_get_thumbnail(xfer, &preview_len);
+ header = g_malloc(sizeof(MsnFileContext) + preview_len);
+
+ header->length = GUINT32_TO_LE(sizeof(MsnFileContext) - 1);
+ header->version = GUINT32_TO_LE(2); /* V.3 contains additional unnecessary data */
+ header->file_size = GUINT64_TO_LE(size);
+ if (preview)
+ header->type = GUINT32_TO_LE(0);
+ else
+ header->type = GUINT32_TO_LE(1);
len = MIN(len, MAX_FILE_NAME_LEN);
for (currentChar = 0; currentChar < len; currentChar++) {
- header.file_name[currentChar] = GUINT16_TO_LE(uni[currentChar]);
+ header->file_name[currentChar] = GUINT16_TO_LE(uni[currentChar]);
}
- memset(&header.file_name[currentChar], 0x00, (MAX_FILE_NAME_LEN - currentChar) * 2);
+ memset(&header->file_name[currentChar], 0x00, (MAX_FILE_NAME_LEN - currentChar) * 2);
- memset(&header.unknown1, 0, sizeof(header.unknown1));
- header.unknown2 = GUINT32_TO_LE(0xffffffff);
- header.preview[0] = '\0';
+ memset(&header->unknown1, 0, sizeof(header->unknown1));
+ header->unknown2 = GUINT32_TO_LE(0xffffffff);
+ if (preview) {
+ memcpy(&header->preview, preview, preview_len);
+ }
+ header->preview[preview_len] = '\0';
g_free(uni);
- ret = purple_base64_encode((const guchar *)&header, sizeof(MsnFileContext));
+ ret = purple_base64_encode((const guchar *)header, sizeof(MsnFileContext) + preview_len);
+ g_free(header);
return ret;
}