Beispiel #1
0
static void
nexus_got_response_cb(MsnSoapMessage *req, MsnSoapMessage *resp, gpointer data)
{
	MsnNexus *nexus = data;
	MsnSession *session = nexus->session;
	const char *ticket;
	char *response;

	if (resp == NULL) {
		msn_session_set_error(session, MSN_ERROR_SERVCONN, _("Windows Live ID authentication:Unable to connect"));
		return;
	}

	if (!nexus_parse_collection(nexus, -1,
	                            xmlnode_get_child(resp->xml,
	                                              "Body/RequestSecurityTokenResponseCollection"))) {
		msn_session_set_error(session, MSN_ERROR_SERVCONN, _("Windows Live ID authentication:Invalid response"));
		return;
	}

	ticket = msn_nexus_get_token_str(nexus, MSN_AUTH_MESSENGER);
	response = msn_rps_encrypt(nexus);
	msn_got_login_params(session, ticket, response);
	g_free(response);
}
Beispiel #2
0
static void
out_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
{
    if (!g_ascii_strcasecmp(cmd->params[0], "OTH"))
        msn_session_set_error(cmdproc->session, MSN_ERROR_SIGN_OTHER,
                              NULL);
    else if (!g_ascii_strcasecmp(cmd->params[0], "SSD"))
        msn_session_set_error(cmdproc->session, MSN_ERROR_SERV_DOWN, NULL);
}
Beispiel #3
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);
}
Beispiel #4
0
static void
ver_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
{
    MsnSession *session;
    gboolean protocol_supported = FALSE;
    const gchar *proto_str;
    guint i;

    session = cmdproc->session;

    proto_str = "MSNP12";

    for (i = 1; i < cmd->param_count; i++)
    {
        if (!strcmp(cmd->params[i], proto_str))
        {
            protocol_supported = TRUE;
            break;
        }
    }

    if (!protocol_supported)
    {
        msn_session_set_error(session, MSN_ERROR_UNSUPPORTED_PROTOCOL,
                              NULL);
        return;
    }

    msn_cmdproc_send(cmdproc, "CVR",
                     "0x0409 winnt 5.1 i386 MSNMSGR 6.0.0602 MSMSGS %s",
                     msn_session_get_username(session));
}
Beispiel #5
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);
}
Beispiel #6
0
static void
login_open_cb(PnNode *conn,
              gpointer data)
{
    MsnNexus *nexus = data;
    MsnSession *session;
    const char *username, *password;
    char *req, *head, *tail;
    guint32 ctint;
    GIOStatus status = G_IO_STATUS_NORMAL;

    g_return_if_fail(conn);

    g_signal_handler_disconnect(conn, nexus->open_handler);
    nexus->open_handler = 0;

    session = nexus->session;

    username = msn_session_get_username(session);
    password = msn_session_get_password(session);

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

    head = g_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"),
                           purple_url_encode(username));

    tail = g_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",
                           get_key(nexus->challenge_data, "lc"),
                           get_key(nexus->challenge_data, "id"),
                           get_key(nexus->challenge_data, "tw"),
                           get_key(nexus->challenge_data, "fs"),
                           get_key(nexus->challenge_data, "ru"),
                           ctint,
                           get_key(nexus->challenge_data, "kpp"),
                           get_key(nexus->challenge_data, "kv"),
                           get_key(nexus->challenge_data, "ver"),
                           get_key(nexus->challenge_data, "tpf"),
                           nexus->login_host);

    req = g_strdup_printf("%s,pwd=%s,%s\r\n", head, purple_url_encode(password), tail);

    g_free(head);
    g_free(tail);

    status = pn_node_write(conn, req, strlen(req), NULL, NULL);

    if (status != G_IO_STATUS_NORMAL) {
        msn_session_set_error(nexus->session, MSN_ERROR_AUTH,
                              _("nexus stream error"));
    }

    g_free(req);
}
Beispiel #7
0
static void
ver_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
{
	MsnSession *session;
	GaimAccount *account;
	gboolean protocol_supported = FALSE;
	char proto_str[8];
	size_t i;

	session = cmdproc->session;
	account = session->account;

	g_snprintf(proto_str, sizeof(proto_str), "MSNP%d", session->protocol_ver);

	for (i = 1; i < cmd->param_count; i++)
	{
		if (!strcmp(cmd->params[i], proto_str))
		{
			protocol_supported = TRUE;
			break;
		}
	}

	if (!protocol_supported)
	{
		msn_session_set_error(session, MSN_ERROR_UNSUPPORTED_PROTOCOL,
							  NULL);
		return;
	}

	msn_cmdproc_send(cmdproc, "CVR",
					 "0x0409 winnt 5.1 i386 MSNMSGR 6.0.0602 MSMSGS %s",
					 gaim_account_get_username(account));
}
Beispiel #8
0
static gboolean
msn_soap_handle_body(MsnSoapConnection *conn, MsnSoapMessage *response)
{
	xmlnode *body = xmlnode_get_child(response->xml, "Body");
	xmlnode *fault = xmlnode_get_child(response->xml, "Fault");

	if (fault) {
		xmlnode *faultcode = xmlnode_get_child(fault, "faultcode");

		if (faultcode != NULL) {
			char *faultdata = xmlnode_get_data(faultcode);

			if (faultdata && g_str_equal(faultdata, "psf:Redirect")) {
				xmlnode *url = xmlnode_get_child(fault, "redirectUrl");

				if (url) {
					char *urldata = xmlnode_get_data(url);
					if (urldata)
						msn_soap_handle_redirect(conn, urldata);
					g_free(urldata);
				}

				g_free(faultdata);
				msn_soap_message_destroy(response);
				return TRUE;
			} else if (faultdata && g_str_equal(faultdata, "wsse:FailedAuthentication")) {
				xmlnode *reason = xmlnode_get_child(fault, "faultstring");
				char *reasondata = NULL;

				if (reason)
					reasondata = xmlnode_get_data(reason);

				msn_soap_connection_sanitize(conn, TRUE);
				msn_session_set_error(conn->session, MSN_ERROR_AUTH,
					reasondata);

				g_free(reasondata);
				g_free(faultdata);
				msn_soap_message_destroy(response);
				return FALSE;
			}

			g_free(faultdata);
		}
	}

	if (fault || body) {
		if (conn->current_request) {
			MsnSoapRequest *request = conn->current_request;
			conn->current_request = NULL;
			request->cb(request->message, response,
				request->cb_data);
			msn_soap_request_destroy(request, FALSE);
		}
		msn_soap_message_destroy(response);
	}

	return TRUE;
}
Beispiel #9
0
static void
login_read_cb(PnNode *conn,
              gpointer data)
{
    MsnNexus *nexus = data;
    GIOStatus status = G_IO_STATUS_NORMAL;
    gchar *str = NULL;

    if (!nexus->header)
        nexus->header = g_string_new(NULL);

    g_object_ref (conn);

    while (nexus->parser_state == 0) {
        gsize terminator_pos;

        status = pn_parser_read_line(nexus->parser, &str, NULL, &terminator_pos, NULL);

        if (status == G_IO_STATUS_AGAIN)
            goto leave;

        if (status != G_IO_STATUS_NORMAL) {
            msn_session_set_error(nexus->session, MSN_ERROR_AUTH,
                                  _("nexus stream error"));
            goto leave;
        }

        if (str) {
            str[terminator_pos] = '\0';

            nexus->header = g_string_append(nexus->header, str);

            if (str[0] == '\0') {
                gchar *tmp;
                nexus->parser_state++;
                tmp = g_string_free(nexus->header, FALSE);
                nexus->header = NULL;
                got_header(nexus, tmp);
                g_free(tmp);
                g_free(str);
                break;
            }

            g_free(str);
        }
    }

leave:
    g_object_unref(conn);
}
Beispiel #10
0
void
msn_servconn_got_error(MsnServConn *servconn, MsnServConnError error,
                       const char *reason)
{
	MsnSession *session = servconn->session;
	MsnServConnType type = servconn->type;

	const char *names[] = { "Notification", "Switchboard" };
	const char *name;

	name = names[type];

	if (reason == NULL) {
		switch (error)
		{
			case MSN_SERVCONN_ERROR_CONNECT:
				reason = _("Unable to connect"); break;
			case MSN_SERVCONN_ERROR_WRITE:
				reason = _("Writing error"); break;
			case MSN_SERVCONN_ERROR_READ:
				reason = _("Reading error"); break;
			default:
				reason = _("Unknown error"); break;
		}
	}

	purple_debug_error("msn", "Connection error from %s server (%s): %s\n",
					 name, servconn->host, reason);

	if (type == MSN_SERVCONN_SB)
	{
		MsnSwitchBoard *swboard;
		swboard = servconn->cmdproc->data;
		if (swboard != NULL)
			swboard->error = MSN_SB_ERROR_CONNECTION;
	}

	/* servconn->disconnect_cb may destroy servconn, so don't use it again */
	msn_servconn_disconnect(servconn);

	if (type == MSN_SERVCONN_NS)
	{
		char *tmp = g_strdup_printf(_("Connection error from %s server:\n%s"),
		                            name, reason);
		msn_session_set_error(session, MSN_ERROR_SERVCONN, tmp);
		g_free(tmp);
	}
}
Beispiel #11
0
static void
login_error_cb(PurpleSslConnection *gsc, PurpleSslErrorType error, void *data)
{
	MsnNexus *nexus;
	MsnSession *session;

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

	nexus->gsc = NULL;

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

	msn_session_set_error(session, MSN_ERROR_AUTH, _("Unable to connect"));
	/* the above line will result in nexus being destroyed, so we don't want
	 * to destroy it here, or we'd crash */
}
Beispiel #12
0
static void
close_cb(PnNode *conn,
         MsnNexus *nexus)
{
    char *tmp;

    if (conn->error) {
        const char *reason;
        reason = conn->error->message;
        tmp = g_strdup_printf(_("error on nexus server: %s"), reason);
        g_clear_error(&conn->error);
    }
    else {
        tmp = g_strdup_printf(_("error on nexus server"));
    }

    msn_session_set_error(nexus->session, MSN_ERROR_AUTH, tmp);

    g_free(tmp);
}
Beispiel #13
0
static void
syn_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
{
	MsnSession *session;
	int total_users;

	session = cmdproc->session;

	if (cmd->param_count == 2)
	{
		/*
		 * This can happen if we sent a SYN with an up-to-date
		 * buddy list revision, but we send 0 to get a full list.
		 * So, error out.
		 */

		msn_session_set_error(cmdproc->session, MSN_ERROR_BAD_BLIST, NULL);
		return;
	}

	total_users  = atoi(cmd->params[2]);

	if (total_users == 0)
	{
		msn_session_finish_login(session);
	}
	else
	{
		/* syn_table */
		MsnSync *sync;

		sync = msn_sync_new(session);
		sync->total_users = total_users;
		sync->old_cbs_table = cmdproc->cbs_table;

		session->sync = sync;
		cmdproc->cbs_table = sync->cbs_table;
	}
}
Beispiel #14
0
static void
nexus_open_cb(PnNode *conn,
              gpointer data)
{
    MsnNexus *nexus = data;
    const gchar *req = "GET /rdr/pprdr.asp\r\n\r\n";
    GIOStatus status = G_IO_STATUS_NORMAL;

    g_return_if_fail(conn);

    g_signal_handler_disconnect(conn, nexus->open_handler);
    nexus->open_handler = 0;
    g_signal_handler_disconnect(conn, nexus->error_handler);
    nexus->error_handler = 0;

    pn_node_write(conn, req, strlen(req), NULL, NULL);

    if (status != G_IO_STATUS_NORMAL) {
        msn_session_set_error(nexus->session, MSN_ERROR_AUTH,
                              _("nexus stream error"));
    }
}
Beispiel #15
0
static void
usr_error(MsnCmdProc *cmdproc, MsnTransaction *trans, int error)
{
    MsnErrorType msnerr = 0;

    switch (error)
    {
        case 500:
        case 601:
        case 910:
        case 921:
            msnerr = MSN_ERROR_SERV_UNAVAILABLE;
            break;
        case 911:
            msnerr = MSN_ERROR_AUTH;
            break;
        default:
            return;
            break;
    }

    msn_session_set_error(cmdproc->session, msnerr, NULL);
}
Beispiel #16
0
static void
got_header(MsnNexus *nexus,
           const gchar *header)
{
    MsnSession *session = nexus->session;

    if (strstr(header, "HTTP/1.1 200 OK")) {
        char *base, *c;
        char *login_params;

        base  = strstr(header, "Authentication-Info: ");

        if (!base)
            goto parse_error;

        base = strstr(base, "from-PP='");
        base += strlen("from-PP='");
        c = strchr(base, '\'');

        login_params = g_strndup(base, c - base);

        msn_got_login_params(session, login_params);

        g_free(login_params);

        msn_nexus_destroy(nexus);
        session->nexus = NULL;
        return;
    }
    else if (strstr(header, "HTTP/1.1 302")) {
        /* Redirect. */
        char *location, *c;

        location = strstr(header, "Location: ");
        if (!location)
            goto parse_error;
        location = strchr(location, ' ') + 1;

        if ((c = strchr(location, '\r')))
            *c = '\0';

        /* Skip the http:// */
        if ((c = strchr(location, '/')))
            location = c + 2;

        if ((c = strchr(location, '/'))) {
            g_free(nexus->login_path);
            nexus->login_path = g_strdup(c);

            *c = '\0';
        }

        g_free(nexus->login_host);
        nexus->login_host = g_strdup(location);

        pn_info("reconnecting to '%s'", nexus->login_host);
        pn_parser_reset(nexus->parser);
        nexus->parser_state = 0;

        nexus->open_handler = g_signal_connect(nexus->conn, "open", G_CALLBACK(login_open_cb), nexus);
        pn_node_connect(nexus->conn, nexus->login_host, 443);
        return;
    }
    else if (strstr(header, "HTTP/1.1 401 Unauthorized")) {
        const char *tmp;
        gchar *error = NULL;

        if ((tmp = strstr(header, "WWW-Authenticate"))) {
            if ((tmp = strstr(tmp, "cbtxt="))) {
                const char *c;
                char *tmp2;

                tmp += strlen("cbtxt=");

                c = strchr(tmp, '\n');
                if (!c)
                    c = tmp + strlen(tmp);

                tmp2 = g_strndup(tmp, c - tmp);
                error = pn_url_decode(tmp2);
                g_free(tmp2);
                if ((tmp2 = strstr(error, " Do one of the following or try again:")) != NULL)
                    *tmp2 = '\0';
            }
        }

        msn_session_set_error(session, MSN_ERROR_AUTH, error);
        g_free(error);
        return;
    }
    else if (strstr(header, "HTTP/1.1 503 Service Unavailable")) {
        msn_session_set_error(session, MSN_ERROR_SERV_UNAVAILABLE, NULL);
        return;
    }

parse_error:
    msn_session_set_error(session, MSN_ERROR_AUTH, _("nexus parse error"));
}
Beispiel #17
0
static void
nexus_login_written_cb(gpointer data, gint source, PurpleInputCondition cond)
{
	MsnNexus *nexus = data;
	MsnSession *session;
	int len;

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

	if (nexus->input_handler == 0)
		/* TODO: Use purple_ssl_input_add()? */
		nexus->input_handler = purple_input_add(nexus->gsc->fd,
			PURPLE_INPUT_READ, nexus_login_written_cb, nexus);


	len = msn_ssl_read(nexus);

	if (len < 0 && errno == EAGAIN)
		return;
	else if (len < 0) {
		purple_input_remove(nexus->input_handler);
		nexus->input_handler = 0;
		g_free(nexus->read_buf);
		nexus->read_buf = NULL;
		nexus->read_len = 0;
		/* TODO: error handling */
		return;
	}

	if (g_strstr_len(nexus->read_buf, nexus->read_len,
			"\r\n\r\n") == NULL)
		return;

	purple_input_remove(nexus->input_handler);
	nexus->input_handler = 0;

	purple_ssl_close(nexus->gsc);
	nexus->gsc = NULL;

	pecan_log ("ssl buffer: [%s]", nexus->read_buf);

	if (strstr(nexus->read_buf, "HTTP/1.1 302") != NULL)
	{
		/* Redirect. */
		char *location, *c;

		location = strstr(nexus->read_buf, "Location: ");
		if (location == NULL)
		{
			g_free(nexus->read_buf);
			nexus->read_buf = NULL;
			nexus->read_len = 0;

			return;
		}
		location = strchr(location, ' ') + 1;

		if ((c = strchr(location, '\r')) != NULL)
			*c = '\0';

		/* Skip the http:// */
		if ((c = strchr(location, '/')) != NULL)
			location = c + 2;

		if ((c = strchr(location, '/')) != NULL)
		{
			g_free(nexus->login_path);
			nexus->login_path = g_strdup(c);

			*c = '\0';
		}

		g_free(nexus->login_host);
		nexus->login_host = g_strdup(location);

		nexus->gsc = purple_ssl_connect(session->account,
				nexus->login_host, PURPLE_SSL_DEFAULT_PORT,
				login_connect_cb, login_error_cb, nexus);
	}
	else if (strstr(nexus->read_buf, "HTTP/1.1 401 Unauthorized") != NULL)
	{
		const char *error;

		if ((error = strstr(nexus->read_buf, "WWW-Authenticate")) != NULL)
		{
			if ((error = strstr(error, "cbtxt=")) != NULL)
			{
				const char *c;
				char *temp;

				error += strlen("cbtxt=");

				if ((c = strchr(error, '\n')) == NULL)
					c = error + strlen(error);

				temp = g_strndup(error, c - error);
				error = purple_url_decode(temp);
				g_free(temp);
				if ((temp = strstr(error, " Do one of the following or try again:")) != NULL)
					*temp = '\0';
			}
		}

		msn_session_set_error(session, MSN_ERROR_AUTH, error);
	}
	else if (strstr(nexus->read_buf, "HTTP/1.1 503 Service Unavailable"))
	{
		msn_session_set_error(session, MSN_ERROR_SERV_UNAVAILABLE, NULL);
	}
	else if (strstr(nexus->read_buf, "HTTP/1.1 200 OK"))
	{
		char *base, *c;
		char *login_params;

#if 0
		/* All your base are belong to us. */
		base = buffer;

		/* For great cookie! */
		while ((base = strstr(base, "Set-Cookie: ")) != NULL)
		{
			base += strlen("Set-Cookie: ");

			c = strchr(base, ';');

			session->login_cookies =
				g_list_append(session->login_cookies,
							  g_strndup(base, c - base));
		}
#endif

		base  = strstr(nexus->read_buf, "Authentication-Info: ");

		g_return_if_fail(base != NULL);

		base  = strstr(base, "from-PP='");
		base += strlen("from-PP='");
		c     = strchr(base, '\'');

		login_params = g_strndup(base, c - base);

		msn_got_login_params(session, login_params);

		g_free(login_params);

		msn_nexus_destroy(nexus);
		session->nexus = NULL;
		return;
	}

	g_free(nexus->read_buf);
	nexus->read_buf = NULL;
	nexus->read_len = 0;

}
Beispiel #18
0
static void
nexus_read_cb(PnNode *conn,
              gpointer data)
{
    MsnNexus *nexus = data;
    GIOStatus status = G_IO_STATUS_NORMAL;
    gchar *str = NULL;

    while (nexus->parser_state == 0) {
        gsize terminator_pos;

        status = pn_parser_read_line(nexus->parser, &str, NULL, &terminator_pos, NULL);

        if (status == G_IO_STATUS_AGAIN)
            return;

        if (status != G_IO_STATUS_NORMAL) {
            msn_session_set_error(nexus->session, MSN_ERROR_AUTH,
                                  _("nexus stream error"));
            return;
        }

        if (str) {
            char *field;
            str[terminator_pos] = '\0';

            if ((field = get_field(str, "PassportURLs: "))) {
                char *da_login;

                da_login = strstr(field, "DALogin="******"DALogin="******"msnia.login.live.com");
#endif
                }
            }

            g_free(str);

            if (nexus->login_host) {
                PnSslConn *ssl_conn;
                PnNode *conn;

                ssl_conn = pn_ssl_conn_new("login", PN_NODE_NULL);

                conn = PN_NODE(ssl_conn);
                conn->session = nexus->session;

                if (nexus->error_handler)
                    g_signal_handler_disconnect(nexus->conn, nexus->error_handler);
                if (nexus->open_handler)
                    g_signal_handler_disconnect(nexus->conn, nexus->open_handler);
                g_object_unref(nexus->conn);
                pn_parser_free(nexus->parser);
                nexus->parser_state = 0;

                nexus->parser = pn_parser_new(conn);
                pn_ssl_conn_set_read_cb(ssl_conn, login_read_cb, nexus);

                nexus->conn = conn;
                nexus->open_handler = g_signal_connect(conn, "open", G_CALLBACK(login_open_cb), nexus);
                nexus->error_handler = g_signal_connect(conn, "error", G_CALLBACK(close_cb), nexus);

                pn_node_connect(conn, nexus->login_host, 443);

                return;
            }
        }
    }
}
Beispiel #19
0
static gboolean
msn_httpconn_parse_data(MsnHttpConn *httpconn, const char *buf,
						size_t size, char **ret_buf, size_t *ret_size,
						gboolean *error)
{
	const char *s, *c;
	char *header, *body;
	const char *body_start;
	char *tmp;
	size_t body_len = 0;

	g_return_val_if_fail(httpconn != NULL, FALSE);
	g_return_val_if_fail(buf      != NULL, FALSE);
	g_return_val_if_fail(size      > 0,    FALSE);
	g_return_val_if_fail(ret_buf  != NULL, FALSE);
	g_return_val_if_fail(ret_size != NULL, FALSE);
	g_return_val_if_fail(error    != NULL, FALSE);

#if 0
	purple_debug_info("msn", "HTTP: parsing data {%s}\n", buf);
#endif

	/* Healthy defaults. */
	body = NULL;

	*ret_buf  = NULL;
	*ret_size = 0;
	*error    = FALSE;

	/* First, some tests to see if we have a full block of stuff. */
	if (((strncmp(buf, "HTTP/1.1 200 OK\r\n", 17) != 0) &&
		 (strncmp(buf, "HTTP/1.1 100 Continue\r\n", 23) != 0)) &&
		((strncmp(buf, "HTTP/1.0 200 OK\r\n", 17) != 0) &&
		 (strncmp(buf, "HTTP/1.0 100 Continue\r\n", 23) != 0)))
	{
		*error = TRUE;

		return FALSE;
	}

	if (strncmp(buf, "HTTP/1.1 100 Continue\r\n", 23) == 0)
	{
		if ((s = strstr(buf, "\r\n\r\n")) == NULL)
			return FALSE;

		s += 4;

		if (*s == '\0')
		{
			*ret_buf = g_strdup("");
			*ret_size = 0;

			msn_httpconn_process_queue(httpconn);

			return TRUE;
		}

		buf = s;
		size -= (s - buf);
	}

	if ((s = strstr(buf, "\r\n\r\n")) == NULL)
		/* Need to wait for the full HTTP header to arrive */
		return FALSE;

	s += 4; /* Skip \r\n\r\n */
	header = g_strndup(buf, s - buf);
	body_start = s;
	body_len = size - (body_start - buf);

	if ((s = purple_strcasestr(header, "Content-Length: ")) != NULL)
	{
		int tmp_len;

		s += strlen("Content-Length: ");

		if ((c = strchr(s, '\r')) == NULL)
		{
			g_free(header);

			return FALSE;
		}

		tmp = g_strndup(s, c - s);
		tmp_len = atoi(tmp);
		g_free(tmp);

		if (body_len != tmp_len)
		{
			/* Need to wait for the full packet to arrive */

			g_free(header);

#if 0
			purple_debug_warning("msn",
							   "body length (%d) != content length (%d)\n",
							   body_len, tmp_len);
#endif

			return FALSE;
		}
	}

	body = g_malloc(body_len + 1);
	memcpy(body, body_start, body_len);
	body[body_len] = '\0';

#ifdef MSN_DEBUG_HTTP
	purple_debug_misc("msn", "Incoming HTTP buffer (header): {%s}\n",
					header);
#endif

	/* Now we should be able to process the data. */
	if ((s = purple_strcasestr(header, "X-MSN-Messenger: ")) != NULL)
	{
		gchar *full_session_id = NULL, *gw_ip = NULL, *session_action = NULL;
		char *t, *session_id;
		char **elems, **cur, **tokens;

		full_session_id = gw_ip = session_action = NULL;

		s += strlen("X-MSN-Messenger: ");

		if ((c = strchr(s, '\r')) == NULL)
		{
			msn_session_set_error(httpconn->session,
								  MSN_ERROR_HTTP_MALFORMED, NULL);
			purple_debug_error("msn", "Malformed X-MSN-Messenger field.\n{%s}\n",
							 buf);

			g_free(header);
			g_free(body);
			return FALSE;
		}

		tmp = g_strndup(s, c - s);

		elems = g_strsplit(tmp, "; ", 0);

		for (cur = elems; *cur != NULL; cur++)
		{
			tokens = g_strsplit(*cur, "=", 2);

			if (strcmp(tokens[0], "SessionID") == 0) {
				g_free(full_session_id);
				full_session_id = tokens[1];
			} else if (strcmp(tokens[0], "GW-IP") == 0) {
				g_free(gw_ip);
				gw_ip = tokens[1];
			} else if (strcmp(tokens[0], "Session") == 0) {
				g_free(session_action);
				session_action = tokens[1];
			} else
				g_free(tokens[1]);

			g_free(tokens[0]);
			/* Don't free each of the tokens, only the array. */
			g_free(tokens);
		}

		g_strfreev(elems);

		g_free(tmp);

		t = strchr(full_session_id, '.');
		if (t != NULL)
			session_id = g_strndup(full_session_id, t - full_session_id);
		else {
			purple_debug_error("msn", "Malformed full_session_id[%s]\n",
					   full_session_id ? full_session_id : NULL);
			session_id = g_strdup(full_session_id);
		}

		if (session_action == NULL || strcmp(session_action, "close") != 0)
		{
			g_free(httpconn->full_session_id);
			httpconn->full_session_id = full_session_id;

			g_free(httpconn->session_id);
			httpconn->session_id = session_id;

			g_free(httpconn->host);
			httpconn->host = gw_ip;
		}
		else
		{
			MsnServConn *servconn;

			/* It's going to die. */
			/* poor thing */

			servconn = httpconn->servconn;

			/* I'll be honest, I don't fully understand all this, but this
			 * causes crashes, Stu. */
			/* if (servconn != NULL)
				servconn->wasted = TRUE; */

			g_free(full_session_id);
			g_free(session_id);
			g_free(gw_ip);
		}

		g_free(session_action);
	}

	g_free(header);

	*ret_buf  = body;
	*ret_size = body_len;

	msn_httpconn_process_queue(httpconn);

	return TRUE;
}
Beispiel #20
0
static void
msn_soap_process(MsnSoapConnection *conn)
{
	gboolean handled = FALSE;
	char *cursor;
	char *linebreak;

	cursor = conn->buf->str + conn->handled_len;

	if (!conn->headers_done) {
		while ((linebreak = strstr(cursor, "\r\n"))	!= NULL) {
			conn->handled_len = linebreak - conn->buf->str + 2;

			if (conn->response_code == 0) {
				if (sscanf(cursor, "HTTP/1.1 %d", &conn->response_code) != 1) {
					/* something horribly wrong */
					purple_ssl_close(conn->ssl);
					conn->ssl = NULL;
					handled = TRUE;
					break;
				} else if (conn->response_code == 503 && conn->session->login_step < MSN_LOGIN_STEP_END) {
					msn_soap_connection_sanitize(conn, TRUE);
					msn_session_set_error(conn->session, MSN_ERROR_SERV_UNAVAILABLE, NULL);
					return;
				}
			} else if (cursor == linebreak) {
				/* blank line */
				conn->headers_done = TRUE;
				cursor = conn->buf->str + conn->handled_len;
				break;
			} else {
				char *line = g_strndup(cursor, linebreak - cursor);
				char *sep = strstr(line, ": ");
				char *key = line;
				char *value;

				if (sep == NULL) {
					purple_debug_info("soap", "ignoring malformed line: %s\n", line);
					g_free(line);
					goto loop_end;
				}

				value = sep + 2;
				*sep = '\0';
				msn_soap_message_add_header(conn->message, key, value);

				if ((conn->response_code == 301 || conn->response_code == 300)
					&& strcmp(key, "Location") == 0) {

					msn_soap_handle_redirect(conn, value);

					handled = TRUE;
					g_free(line);
					break;
				} else if (conn->response_code == 401 &&
					strcmp(key, "WWW-Authenticate") == 0) {
					char *error = strstr(value, "cbtxt=");

					if (error) {
						error += strlen("cbtxt=");
					}

					msn_soap_connection_sanitize(conn, TRUE);
					msn_session_set_error(conn->session, MSN_ERROR_AUTH,
						error ? purple_url_decode(error) : NULL);

					g_free(line);
					return;
				} else if (strcmp(key, "Content-Length") == 0) {
					if (sscanf(value, "%" G_GSIZE_FORMAT, &(conn->body_len)) != 1)
						purple_debug_error("soap", "Unable to parse Content-Length\n");
				} else if (strcmp(key, "Connection") == 0) {
					if (strcmp(value, "close") == 0) {
						conn->close_when_done = TRUE;
					}
				}
				g_free(line);
			}

		loop_end:
			cursor = conn->buf->str + conn->handled_len;
		}
	}

	if (!handled && conn->headers_done) {
		if (conn->buf->len - conn->handled_len >=
			conn->body_len) {
			xmlnode *node = xmlnode_from_str(cursor, conn->body_len);

			if (node == NULL) {
				purple_debug_info("soap", "Malformed SOAP response: %s\n",
					cursor);
			} else {
				MsnSoapMessage *message = conn->message;
				conn->message = NULL;
				message->xml = node;

				if (!msn_soap_handle_body(conn, message)) {
					return;
				}
			}

			msn_soap_connection_handle_next(conn);
		}

		return;
	}

	if (handled) {
		msn_soap_connection_handle_next(conn);
	}
}