Example #1
0
static void
group_error_helper(MsnSession *session, const char *msg, const gchar *group_guid, int error)
{
    PurpleAccount *account;
    PurpleConnection *gc;
    char *reason = NULL;
    char *title = NULL;

    account = session->account;
    gc = purple_account_get_connection(account);

    if (error == 224)
    {
        const char *group_name;
        group_name = pecan_contactlist_find_group_name(session->contactlist, group_guid);
        reason = pecan_strdup_printf(_("%s is not a valid group."),
                                     group_name);
    }
    else
    {
        reason = g_strdup(_("Unknown error."));
    }

    title = pecan_strdup_printf(_("%s on %s (%s)"), msg,
                                purple_account_get_username(account),
                                purple_account_get_protocol_name(account));
    purple_notify_error(gc, NULL, title, reason);
    g_free(title);
    g_free(reason);
}
Example #2
0
static void
close_cb (PecanNode *conn,
          MsnNotification *notification)
{
    char *tmp;

    {
        const char *reason = NULL;

        if (conn->error)
        {
            reason = conn->error->message;

            pecan_error ("connection error: (NS):reason=[%s]", reason);
            tmp = pecan_strdup_printf (_("Error on notification server:\n%s"), reason);

            g_clear_error (&conn->error);
        }
        else
        {
            pecan_error ("connection error: (NS)");
            tmp = pecan_strdup_printf (_("Error on notification server:\nUnknown"));
        }
    }

    pecan_node_close (PECAN_NODE (notification->conn));
    notification->closed = TRUE;
    msn_session_set_error (notification->session, MSN_ERROR_SERVCONN, tmp);

    g_free (tmp);
}
Example #3
0
static void
adc_error(MsnCmdProc *cmdproc, MsnTransaction *trans, int error)
{
    MsnSession *session;
    PurpleAccount *account;
    PurpleConnection *gc;
    const char *list, *passport;
    const char *reason;
    char *msg = NULL;
    char **params;

    session = cmdproc->session;
    account = session->account;
    gc = purple_account_get_connection(account);
    params = g_strsplit(trans->params, " ", 0);

    list     = params[0];
    passport = params[1];

    if (!strcmp(list, "FL"))
        msg = pecan_strdup_printf(_("Unable to add user on %s (%s)"),
                                  purple_account_get_username(account),
                                  purple_account_get_protocol_name(account));
    else if (!strcmp(list, "BL"))
        msg = pecan_strdup_printf(_("Unable to block user on %s (%s)"),
                                  purple_account_get_username(account),
                                  purple_account_get_protocol_name(account));
    else if (!strcmp(list, "AL"))
        msg = pecan_strdup_printf(_("Unable to permit user on %s (%s)"),
                                  purple_account_get_username(account),
                                  purple_account_get_protocol_name(account));

    reason = pecan_error_to_string (error);

    if (msg != NULL)
    {
        purple_notify_error(gc, NULL, msg, reason);
        g_free(msg);
    }

    if (!strcmp(list, "FL"))
    {
        PurpleBuddy *buddy;

        buddy = purple_find_buddy(account, passport);

        if (buddy != NULL)
            purple_blist_remove_buddy(buddy);
    }

    g_strfreev(params);
}
Example #4
0
static void
error_handler (MsnCmdProc *cmdproc,
               MsnTransaction *trans,
               gint error)
{
    MsnNotification *notification;
    gchar *reason;

    notification = cmdproc->data;
    g_return_if_fail (notification);

    reason = pecan_error_to_string (error);
    pecan_error ("connection error: (NS):reason=[%s]", reason);

    switch (error)
    {
        case 913:
        case 208:
            /* non-fatal */
            break;
        default:
            {
                char *tmp;
                tmp = pecan_strdup_printf (_("Error on notification server:\n%s"), reason);
                msn_session_set_error (notification->session, MSN_ERROR_SERVCONN, tmp);
                g_free (tmp);
            }
    }

    g_free (reason);
}
Example #5
0
gchar *
msn_object_to_string(const MsnObject *obj)
{
    gchar *str;
    const gchar *sha1c;

    g_return_val_if_fail(obj != NULL, NULL);

    sha1c = msn_object_get_sha1c(obj);

    str = pecan_strdup_printf("<msnobj Creator=\"%s\" Size=\"%d\" Type=\"%d\" "
                              "Location=\"%s\" Friendly=\"%s\" SHA1D=\"%s\""
                              "%s%s%s/>",
                              msn_object_get_creator(obj),
                              msn_object_get_size(obj),
                              msn_object_get_type(obj),
                              msn_object_get_location(obj),
                              msn_object_get_friendly(obj),
                              msn_object_get_sha1d(obj),
                              sha1c ? " SHA1C=\"" : "",
                              sha1c ? sha1c : "",
                              sha1c ? "\"" : "");

    return str;
}
Example #6
0
void
send_bye(MsnSlpCall *slpcall, const char *type)
{
	MsnSlpLink *slplink;
	MsnSlpMessage *slpmsg;
	char *header;

	slplink = slpcall->slplink;

	g_return_if_fail(slplink != NULL);

        header = pecan_strdup_printf("BYE MSNMSGR:%s MSNSLP/1.0",
                                     slplink->local_user);

	slpmsg = msn_slpmsg_sip_new(slpcall, 0, header,
								"A0D624A6-6C0C-4283-A9E0-BC97B4B46D32",
								type,
								"\r\n");
	g_free(header);

#ifdef PECAN_DEBUG_SLP
	slpmsg->info = "SLP BYE";
	slpmsg->text_body = TRUE;
#endif

	msn_slplink_queue_slpmsg(slplink, slpmsg);
}
Example #7
0
void
msn_xfer_cancel(PurpleXfer *xfer)
{
	MsnSlpCall *slpcall;
	char *content;

	g_return_if_fail(xfer != NULL);
	g_return_if_fail(xfer->data != NULL);

	slpcall = xfer->data;

	if (purple_xfer_get_status(xfer) == PURPLE_XFER_STATUS_CANCEL_LOCAL)
	{
		if (slpcall->started)
		{
			msn_slp_call_close(slpcall);
		}
		else
		{
			content = pecan_strdup_printf("SessionID: %lu\r\n\r\n",
									  slpcall->session_id);

			send_decline(slpcall, slpcall->branch, "application/x-msnmsgr-sessionreqbody",
						 content);

			g_free(content);
			msn_slplink_unleash(slpcall->slplink);

			msn_slp_call_destroy(slpcall);
		}
	}
}
Example #8
0
MsnSlpMessage *
msn_slpmsg_sip_new(MsnSlpCall *slpcall, int cseq,
				   const char *header, const char *branch,
				   const char *content_type, const char *content)
{
	MsnSlpLink *slplink;
	MsnSlpMessage *slpmsg;
	gchar *body;
	gsize body_len;
	gsize content_len;

	g_return_val_if_fail(slpcall != NULL, NULL);
	g_return_val_if_fail(header  != NULL, NULL);

	slplink = slpcall->slplink;

	/* Let's remember that "content" should end with a 0x00 */

	content_len = (content != NULL) ? strlen(content) + 1 : 0;

        body = pecan_strdup_printf(
                                   "%s\r\n"
                                   "To: <msnmsgr:%s>\r\n"
                                   "From: <msnmsgr:%s>\r\n"
                                   "Via: MSNSLP/1.0/TLP ;branch={%s}\r\n"
                                   "CSeq: %d\r\n"
                                   "Call-ID: {%s}\r\n"
                                   "Max-Forwards: 0\r\n"
                                   "Content-Type: %s\r\n"
                                   "Content-Length: %" G_GSIZE_FORMAT "\r\n"
                                   "\r\n",
                                   header,
                                   slplink->remote_user,
                                   slplink->local_user,
                                   branch,
                                   cseq,
                                   slpcall->id,
                                   content_type,
                                   content_len);

	body_len = strlen(body);

	if (content_len > 0)
	{
		body_len += content_len;
		body = g_realloc(body, body_len);
		g_strlcat(body, content, body_len);
	}

	slpmsg = msn_slpmsg_new(slplink);
	msn_slpmsg_set_body(slpmsg, (gpointer) body, body_len);

	slpmsg->sip = TRUE;
	slpmsg->slpcall = slpcall;

	g_free(body);

	return slpmsg;
}
Example #9
0
static void
msn_xfer_init(PurpleXfer *xfer)
{
	MsnSlpCall *slpcall;
	/* MsnSlpLink *slplink; */
	char *content;

	pecan_info ("xfer_init");

	slpcall = xfer->data;

	/* Send Ok */
        content = pecan_strdup_printf("SessionID: %lu\r\n\r\n",
                                      slpcall->session_id);

	send_ok(slpcall, slpcall->branch, "application/x-msnmsgr-sessionreqbody",
			content);

	g_free(content);
	msn_slplink_unleash(slpcall->slplink);
}
Example #10
0
static void
debug_msg_to_file(MsnMessage *msg, gboolean send)
{
	char *tmp;
	char *dir;
	char *pload;
	FILE *tf;
	int c;
	gsize pload_size;

	dir = send ? "send" : "recv";
	c = send ? m_sc++ : m_rc++;
        tmp = pecan_strdup_printf("%s/msntest/%s/%03d", g_get_home_dir(), dir, c);
	tf = g_fopen(tmp, "wb");
	if (tf == NULL)
	{
		pecan_error ("could not open debug file");
		return;
	}
	pload = msn_message_gen_payload(msg, &pload_size);
	fwrite(pload, 1, pload_size, tf);
	fclose(tf);
	g_free(tmp);
}
Example #11
0
static void
url_cmd (MsnCmdProc *cmdproc,
         MsnCommand *cmd)
{
    MsnSession *session;
    PurpleConnection *connection;
    const gchar *rru;
    const gchar *url;
    gchar creds[64];
    glong tmp_timestamp;

    session = cmdproc->session;
    connection = purple_account_get_connection (session->account);

    rru = cmd->params[1];
    url = cmd->params[2];

    session->passport_info.mail_url_timestamp = time (NULL);
    tmp_timestamp = session->passport_info.mail_url_timestamp - session->passport_info.sl;

    {
        PurpleCipher *cipher;
        PurpleCipherContext *context;
        guchar digest[16];
        gchar *buf;

        buf = pecan_strdup_printf ("%s%ld%s",
                                   session->passport_info.mspauth ? session->passport_info.mspauth : "BOGUS",
                                   tmp_timestamp,
                                   purple_connection_get_password (connection));

        cipher = purple_ciphers_find_cipher ("md5");
        context = purple_cipher_context_new (cipher, NULL);

        purple_cipher_context_append (context, (const guchar *) buf, strlen (buf));
        purple_cipher_context_digest (context, sizeof (digest), digest, NULL);
        purple_cipher_context_destroy (context);

        g_free (buf);

        memset (creds, 0, sizeof (creds));

        {
            gchar buf2[3];
            gint i;

            for (i = 0; i < 16; i++)
            {
                g_snprintf (buf2, sizeof (buf2), "%02x", digest[i]);
                strcat (creds, buf2);
            }
        }
    }

    g_free (session->passport_info.mail_url);

    session->passport_info.mail_url = g_strdup_printf ("%s&auth=%s&creds=%s&sl=%ld&username=%s&mode=ttl&sid=%s&id=2&rru=%ssvc_mail&js=yes",
                                                       url,
                                                       session->passport_info.mspauth,
                                                       creds,
                                                       tmp_timestamp,
                                                       msn_session_get_username (session),
                                                       session->passport_info.sid,
                                                       rru);

    /* The user wants to check his email */
    if (cmd->trans && cmd->trans->data)
    {
        purple_notify_uri (connection, session->passport_info.mail_url);
        return;
    }

    if (purple_account_get_check_mail (session->account))
    {
        static gboolean is_initial = TRUE;

        if (!is_initial)
            return;

        if (session->inbox_unread_count > 0)
        {
            const gchar *passport;
            const gchar *main_url;

            passport = msn_session_get_username (session);
            main_url = session->passport_info.mail_url;

            purple_notify_emails (connection, session->inbox_unread_count, FALSE, NULL, NULL,
                                  &passport, &main_url, NULL, NULL);
        }

        is_initial = FALSE;
    }
}
Example #12
0
void
login_connect_cb(gpointer data, PurpleSslConnection *gsc,
				 PurpleInputCondition cond)
{
	MsnNexus *nexus;
	MsnSession *session;
	char *username, *password;
	char *request_str, *head, *tail;
	char *buffer = NULL;
	guint32 ctint;

	nexus = data;
	g_return_if_fail(nexus != NULL);

	session = nexus->session;
	g_return_if_fail(session != NULL);

	msn_session_set_login_step(session, PECAN_LOGIN_STEP_GET_COOKIE);

	username =
		g_strdup(purple_url_encode(msn_session_get_username(session)));

	password =
		g_strdup(purple_url_encode(msn_session_get_password(session)));

	ctint = strtoul((char *)g_hash_table_lookup(nexus->challenge_data, "ct"), NULL, 10) + 200;

        head = pecan_strdup_printf(
                                   "GET %s HTTP/1.1\r\n"
                                   "Authorization: Passport1.4 OrgVerb=GET,OrgURL=%s,sign-in=%s",
                                   nexus->login_path,
                                   (char *)g_hash_table_lookup(nexus->challenge_data, "ru"),
                                   username);

        tail = pecan_strdup_printf(
                                   "lc=%s,id=%s,tw=%s,fs=%s,ru=%s,ct=%" G_GUINT32_FORMAT ",kpp=%s,kv=%s,ver=%s,tpf=%s\r\n"
                                   "User-Agent: MSMSGS\r\n"
                                   "Host: %s\r\n"
                                   "Connection: Keep-Alive\r\n"
                                   "Cache-Control: no-cache\r\n",
                                   nexus_challenge_data_lookup(nexus->challenge_data, "lc"),
                                   nexus_challenge_data_lookup(nexus->challenge_data, "id"),
                                   nexus_challenge_data_lookup(nexus->challenge_data, "tw"),
                                   nexus_challenge_data_lookup(nexus->challenge_data, "fs"),
                                   nexus_challenge_data_lookup(nexus->challenge_data, "ru"),
                                   ctint,
                                   nexus_challenge_data_lookup(nexus->challenge_data, "kpp"),
                                   nexus_challenge_data_lookup(nexus->challenge_data, "kv"),
                                   nexus_challenge_data_lookup(nexus->challenge_data, "ver"),
                                   nexus_challenge_data_lookup(nexus->challenge_data, "tpf"),
                                   nexus->login_host);

	buffer = pecan_strdup_printf("%s,pwd=XXXXXXXX,%s\r\n", head, tail);
	request_str = pecan_strdup_printf("%s,pwd=%s,%s\r\n", head, password, tail);

	pecan_log ("sending: [%s]", buffer);

	g_free(buffer);
	g_free(head);
	g_free(tail);
	g_free(username);
	g_free(password);

	nexus->write_buf = request_str;
	nexus->written_len = 0;

	nexus->read_len = 0;

	nexus->written_cb = nexus_login_written_cb;

	nexus->input_handler = purple_input_add(gsc->fd, PURPLE_INPUT_WRITE,
		nexus_write_cb, nexus);

	nexus_write_cb(nexus, gsc->fd, PURPLE_INPUT_WRITE);

	return;


}
Example #13
0
static void
got_ok(MsnSlpCall *slpcall,
	   const char *type, const char *content)
{
	g_return_if_fail(slpcall != NULL);
	g_return_if_fail(type    != NULL);

        pecan_log ("type=%s", type);

	if (!strcmp(type, "application/x-msnmsgr-sessionreqbody"))
	{
#ifdef MSN_DIRECTCONN
		if (slpcall->slplink->session->use_directconn &&
                    slpcall->type == MSN_SLPCALL_DC)
		{
			/* First let's try a DirectConnection. */

			MsnSlpLink *slplink;
			MsnSlpMessage *slpmsg;
			char *header;
			gchar *new_content;
			char *branch;

			slplink = slpcall->slplink;

			branch = msn_rand_guid();

                        new_content = pecan_strdup_printf(
                                                          "Bridges: TRUDPv1 TCPv1\r\n"
                                                          "NetID: 0\r\n"
                                                          "Conn-Type: Direct-Connect\r\n"
                                                          "UPnPNat: false\r\n"
                                                          "ICF: false\r\n"
                                                         );

                        header = pecan_strdup_printf("INVITE MSNMSGR:%s MSNSLP/1.0",
                                                     slplink->remote_user);

			slpmsg = msn_slpmsg_sip_new(slpcall, 0, header, branch,
										"application/x-msnmsgr-transreqbody",
										new_content);

#ifdef PECAN_DEBUG_SLP
			slpmsg->info = "SLP INVITE";
			slpmsg->text_body = TRUE;
#endif
			msn_slplink_send_slpmsg(slplink, slpmsg);

			g_free(header);
			g_free(new_content);

			g_free(branch);
		}
		else
		{
			msn_slp_call_session_init(slpcall);
		}
#else
                msn_slp_call_session_init(slpcall);
#endif /* MSN_DIRECTCONN */
	}
	else if (!strcmp(type, "application/x-msnmsgr-transreqbody"))
	{
		/* Do we get this? */
		pecan_info ("OK with transreqbody");
	}
#ifdef MSN_DIRECTCONN
	else if (!strcmp(type, "application/x-msnmsgr-transrespbody"))
	{
		char *ip_addrs;
		char *temp;
		char *nonce;
		int port;

		{
			char *listening;
			listening = get_token(content, "Listening: ", "\r\n");
			if (strcmp (listening, "false") == 0)
			{
				/** @todo I'm not sure if this is OK. */
				msn_slp_call_session_init(slpcall);
				g_free (listening);
				return;
			}
			g_free (listening);
		}

		nonce = get_token(content, "Nonce: {", "}\r\n");
		ip_addrs = get_token(content, "IPv4Internal-Addrs: ", "\r\n");

		temp = get_token(content, "IPv4Internal-Port: ", "\r\n");
		if (temp != NULL)
			port = atoi(temp);
		else
			port = -1;
		g_free(temp);

		if (ip_addrs == NULL)
			return;

		if (port > 0)
			got_transresp(slpcall, nonce, ip_addrs, port);

		g_free(nonce);
		g_free(ip_addrs);
	}
#endif /* MSN_DIRECTCONN */
}
Example #14
0
static void
got_invite(MsnSlpCall *slpcall,
		   const char *branch, const char *type, const char *content)
{
	MsnSlpLink *slplink;

	slplink = slpcall->slplink;

        pecan_log ("type=%s", type);

	if (!strcmp(type, "application/x-msnmsgr-sessionreqbody"))
	{
		char *euf_guid, *context;
		char *temp;

		euf_guid = get_token(content, "EUF-GUID: {", "}\r\n");

		temp = get_token(content, "SessionID: ", "\r\n");
		if (temp != NULL)
			slpcall->session_id = atoi(temp);
		g_free(temp);

		temp = get_token(content, "AppID: ", "\r\n");
		if (temp != NULL)
			slpcall->app_id = atoi(temp);
		g_free(temp);

		context = get_token(content, "Context: ", "\r\n");

		if (context != NULL)
			got_sessionreq(slpcall, branch, euf_guid, context);

		g_free(context);
		g_free(euf_guid);
	}
	else if (!strcmp(type, "application/x-msnmsgr-transreqbody"))
	{
		/* A direct connection? */

		const gchar *listening;
		gchar *new_content, *nonce;

		if (FALSE)
		{
#if 0
			MsnDirectConn *directconn;
			/* const char *ip_addr; */
			char *ip_port;
			int port;

			/* ip_addr = purple_prefs_get_string("/purple/ft/public_ip"); */
			ip_port = "5190";
			listening = "true";
			nonce = msn_rand_guid();

			directconn = msn_directconn_new(slplink);

			/* msn_directconn_parse_nonce(directconn, nonce); */
			directconn->nonce = g_strdup(nonce);

			msn_directconn_listen(directconn);

			port = directconn->port;

                        new_content = pecan_strdup_printf(
                                                          "Bridge: TCPv1\r\n"
                                                          "Listening: %s\r\n"
                                                          "Nonce: {%s}\r\n"
                                                          "Ipv4Internal-Addrs: 192.168.0.82\r\n"
                                                          "Ipv4Internal-Port: %d\r\n"
                                                          "\r\n",
                                                          listening,
                                                          nonce,
                                                          port);
#endif
		}
		else
		{
			listening = "false";
			nonce = g_strdup("00000000-0000-0000-0000-000000000000");

                        new_content = pecan_strdup_printf(
                                                          "Bridge: TCPv1\r\n"
                                                          "Listening: %s\r\n"
                                                          "Nonce: {%s}\r\n"
                                                          "\r\n",
                                                          listening,
                                                          nonce);
		}

		send_ok(slpcall, branch,
				"application/x-msnmsgr-transrespbody", new_content);

		g_free(new_content);
		g_free(nonce);
	}
#ifdef MSN_DIRECTCONN
	else if (!strcmp(type, "application/x-msnmsgr-transrespbody"))
	{
		char *ip_addrs;
		char *temp;
		char *nonce;
		int port;

		nonce = get_token(content, "Nonce: {", "}\r\n");
		ip_addrs = get_token(content, "IPv4Internal-Addrs: ", "\r\n");

		temp = get_token(content, "IPv4Internal-Port: ", "\r\n");
		if (temp != NULL)
			port = atoi(temp);
		else
			port = -1;
		g_free(temp);

		if (ip_addrs == NULL)
			return;

		if (port > 0)
			got_transresp(slpcall, nonce, ip_addrs, port);

		g_free(nonce);
		g_free(ip_addrs);
	}
#endif /* MSN_DIRECTCONN */
}
Example #15
0
static void
got_sessionreq(MsnSlpCall *slpcall, const char *branch,
			   const char *euf_guid, const char *context)
{
	pecan_debug ("euf_guid=[%s]", euf_guid);

	if (!strcmp(euf_guid, "A4268EEC-FEC5-49E5-95C3-F126696BDBF6"))
	{
		/* Emoticon or UserDisplay */
		char *content;
		gsize len;
		MsnSlpSession *slpsession;
		MsnSlpLink *slplink;
		MsnSlpMessage *slpmsg;
		MsnObject *obj;
		char *msnobj_data;
		PecanBuffer *image;
		int type;

		/* Send Ok */
                content = pecan_strdup_printf("SessionID: %lu\r\n\r\n",
                                              slpcall->session_id);

		send_ok(slpcall, branch, "application/x-msnmsgr-sessionreqbody",
				content);

		g_free(content);

		slplink = slpcall->slplink;

		msnobj_data = (char *)purple_base64_decode(context, &len);
		obj = msn_object_new_from_string(msnobj_data);
		type = msn_object_get_type(obj);
		g_free(msnobj_data);

		if (type == MSN_OBJECT_USERTILE)
		{
			/* image is owned by a local object, not obj */
			image = msn_object_get_image(obj);
		}
#if PURPLE_VERSION_CHECK(2,5,0)
		else if (type == MSN_OBJECT_EMOTICON)
		{
			PurpleStoredImage *img;
			char *path;
			path = g_build_filename(purple_smileys_get_storing_dir(), msn_object_get_location(obj), NULL);
			img = purple_imgstore_new_from_file(path);
			image = pecan_buffer_new_memdup ((const gpointer) purple_imgstore_get_data (img),
							 purple_imgstore_get_size (img));
			purple_imgstore_unref(img);
			g_free(path);
		}
#endif /* PURPLE_VERSION_CHECK(2,5,0) */
		else
		{
			pecan_error ("Wrong object?");
			msn_object_destroy(obj);
			g_return_if_reached();
		}

		if (!image)
		{
                    pecan_error ("Wrong object");
                    msn_object_destroy (obj);
                    g_return_if_reached ();
		}

		msn_object_destroy(obj);

		{
			gchar *tmp;
			tmp = msn_object_to_string (obj);
			pecan_info ("object requested: %s", tmp);
			g_free (tmp);
		}

		slpsession = msn_slplink_find_slp_session(slplink,
												  slpcall->session_id);

		/* DATA PREP */
		slpmsg = msn_slpmsg_new(slplink);
		slpmsg->slpcall = slpcall;
		slpmsg->slpsession = slpsession;
		slpmsg->session_id = slpsession->id;
		msn_slpmsg_set_body(slpmsg, NULL, 4);
#ifdef PECAN_DEBUG_SLP
		slpmsg->info = "SLP DATA PREP";
#endif
		msn_slplink_queue_slpmsg(slplink, slpmsg);

		/* DATA */
		slpmsg = msn_slpmsg_new(slplink);
		slpmsg->slpcall = slpcall;
		slpmsg->slpsession = slpsession;
		slpmsg->flags = 0x20;
#ifdef PECAN_DEBUG_SLP
		slpmsg->info = "SLP DATA";
#endif
		msn_slpmsg_set_image (slpmsg, image);
		msn_slplink_queue_slpmsg(slplink, slpmsg);
	}
	else if (!strcmp(euf_guid, "5D3E02AB-6190-11D3-BBBB-00C04F795683"))
	{
		/* File Transfer */
		PurpleAccount *account;
		PurpleXfer *xfer;
		char *bin;
		gsize bin_len;
		guint32 file_size;
		char *file_name;
		gunichar2 *uni_name;

		account = slpcall->slplink->session->account;

		slpcall->cb = msn_xfer_completed_cb;
		slpcall->end_cb = msn_xfer_end_cb;
		slpcall->progress_cb = msn_xfer_progress_cb;
		slpcall->branch = g_strdup(branch);

		slpcall->pending = TRUE;

		xfer = purple_xfer_new(account, PURPLE_XFER_RECEIVE,
							   slpcall->slplink->remote_user);
		if (xfer)
		{
			bin = (char *)purple_base64_decode(context, &bin_len);
			file_size = GUINT32_FROM_LE(*(gsize *)(bin + 8));

			uni_name = (gunichar2 *)(bin + 20);
			while(*uni_name != 0 && ((char *)uni_name - (bin + 20)) < MAX_FILE_NAME_LEN) {
				*uni_name = GUINT16_FROM_LE(*uni_name);
				uni_name++;
			}

			file_name = g_utf16_to_utf8((const gunichar2 *)(bin + 20), -1,
										NULL, NULL, NULL);

			g_free(bin);

			purple_xfer_set_filename(xfer, file_name);
			purple_xfer_set_size(xfer, file_size);
			purple_xfer_set_init_fnc(xfer, msn_xfer_init);
			purple_xfer_set_request_denied_fnc(xfer, msn_xfer_cancel);
			purple_xfer_set_cancel_recv_fnc(xfer, msn_xfer_cancel);

			slpcall->xfer = xfer;
			purple_xfer_ref(slpcall->xfer);

			xfer->data = slpcall;

			purple_xfer_request(xfer);
		}
	}
}