MsnSession * msn_session_new (const gchar *username, const gchar *password, gboolean http_method) { MsnSession *session; session = g_new0 (MsnSession, 1); session->username = pn_normalize (username); session->password = g_strndup (password, 16); #ifdef INTERNAL_MAINLOOP session->g_main_loop = g_main_loop_new (NULL, FALSE); session->g_main_loop_timer = purple_timeout_add (1000, g_main_context_iteration_timer, NULL); #endif session->config = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); /** @todo sb and ns need this here but should be updated on-the-fly. */ msn_session_set_bool (session, "use_http_method", http_method); #if 0 if (session->http_method) { PnNode *foo; foo = PN_NODE (pn_http_server_new ("foo server")); foo->session = session; session->http_conn = foo; } #endif session->dp_manager = pn_dp_manager_new (session); session->notification = msn_notification_new (session); pn_node_set_id(session->notification->cmdproc->conn, session->conn_count++, "ns"); session->contactlist = pn_contactlist_new (session); session->user = pn_contact_new (NULL); pn_contact_set_passport (session->user, session->username); session->conv_seq = 1; session->oim_session = pn_oim_session_new (session); session->conversations = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) msn_switchboard_unref); session->chats = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, (GDestroyNotify) msn_switchboard_unref); #if defined(PECAN_CVR) session->links = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) pn_peer_link_unref); #endif /* defined(PECAN_CVR) */ purple_signal_connect (purple_conversations_get_handle(), "conversation-created", session, PURPLE_CALLBACK (conversation_created_cb), session); return session; }
static void finalize (GObject *obj) { PnNode *conn = PN_NODE (obj); pn_node_close (conn); g_free (conn->name); parent_class->finalize (obj); }
static void connect_cb(GObject *source, GAsyncResult *res, gpointer user_data) { GSocketConnection *socket_conn; PnNode *conn; GError *error = NULL; conn = PN_NODE(user_data); socket_conn = g_socket_client_connect_to_host_finish(G_SOCKET_CLIENT(source), res, &error); g_object_unref(source); if (error) { g_error_free(error); return; } g_object_ref(conn); if (socket_conn) { GSocket *socket; GInputStream *input; conn->socket_conn = socket_conn; socket = g_socket_connection_get_socket(socket_conn); conn->status = PN_NODE_STATUS_OPEN; input = g_io_stream_get_input_stream (G_IO_STREAM (conn->socket_conn)); g_object_ref (conn); g_input_stream_read_async (input, conn->input_buffer, PN_BUF_LEN, G_PRIORITY_DEFAULT, NULL, read_cb, conn); } else { conn->error = g_error_new_literal(PN_NODE_ERROR, PN_NODE_ERROR_OPEN, "Unable to connect"); pn_node_error(conn); } { PnNodeClass *class; class = g_type_class_peek(PN_NODE_TYPE); g_signal_emit(G_OBJECT(conn), class->open_sig, 0, conn); } g_object_unref(conn); }
static void connect_cb (gpointer data, gint source, const gchar *error_message) { PnNode *conn; pn_log ("begin"); conn = PN_NODE (data); conn->connect_data = NULL; g_object_ref (conn); if (source >= 0) { GIOChannel *channel; conn->stream = pn_stream_new (source); channel = conn->stream->channel; PN_NODE_GET_CLASS (conn)->channel_setup (conn, channel); conn->status = PN_NODE_STATUS_OPEN; pn_info ("connected: conn=%p,channel=%p", conn, channel); conn->read_watch = g_io_add_watch (channel, G_IO_IN, read_cb, conn); #if 0 g_io_add_watch (channel, G_IO_ERR | G_IO_HUP | G_IO_NVAL, close_cb, conn); #endif } else { /* pn_error ("connection error: conn=%p,msg=[%s]", conn, error_message); */ conn->error = g_error_new_literal (PN_NODE_ERROR, PN_NODE_ERROR_OPEN, error_message ? error_message : "Unable to connect"); pn_node_error (conn); } { PnNodeClass *class; class = g_type_class_peek (PN_NODE_TYPE); g_signal_emit (G_OBJECT (conn), class->open_sig, 0, conn); } g_object_unref (conn); pn_log ("end"); }
static void read_cb (GObject *source, GAsyncResult *result, gpointer user_data) { PnNode *conn; gssize size; GError *error = NULL; conn = PN_NODE(user_data); size = g_input_stream_read_finish (G_INPUT_STREAM (source), result, &error); conn = PN_NODE(user_data); if (G_UNLIKELY (size == 0)) error = g_error_new_literal(PN_NODE_ERROR, PN_NODE_ERROR_OPEN, "End of stream"); if (error) goto nok; pn_node_parse (conn, (char *) conn->input_buffer, size); if (conn->status == PN_NODE_STATUS_OPEN) g_input_stream_read_async (G_INPUT_STREAM (source), conn->input_buffer, PN_BUF_LEN, G_PRIORITY_DEFAULT, NULL, read_cb, conn); else g_object_unref (conn); return; nok: conn->error = error; pn_node_error (conn); g_object_unref (conn); }
static gboolean read_cb (GIOChannel *source, GIOCondition condition, gpointer data) { PnNode *conn; gchar buf[PN_BUF_LEN + 1]; gsize bytes_read; pn_log ("begin"); conn = PN_NODE (data); pn_debug ("conn=%p,name=%s", conn, conn->name); g_object_ref (conn); { GIOStatus status = G_IO_STATUS_NORMAL; status = pn_node_read (conn, buf, PN_BUF_LEN, &bytes_read, NULL); if (status == G_IO_STATUS_AGAIN) { g_object_unref (conn); return TRUE; } if (status == G_IO_STATUS_EOF) { conn->error = g_error_new (PN_NODE_ERROR, PN_NODE_ERROR_OPEN, "End of stream"); } if (conn->error) { pn_node_error (conn); g_object_unref (conn); return FALSE; } } pn_node_parse (conn, buf, bytes_read); g_object_unref (conn); pn_log ("end"); return TRUE; }
static void connect_cb(GObject *source, GAsyncResult *res, gpointer user_data) { GSocketConnection *socket_conn; PnNode *conn; conn = PN_NODE(user_data); socket_conn = g_socket_client_connect_to_host_finish(G_SOCKET_CLIENT(source), res, NULL); g_object_unref(source); g_object_ref(conn); if (socket_conn) { GIOChannel *channel; GSocket *socket; conn->socket_conn = socket_conn; socket = g_socket_connection_get_socket(socket_conn); conn->stream = pn_stream_new(g_socket_get_fd(socket)); channel = conn->stream->channel; PN_NODE_GET_CLASS (conn)->channel_setup (conn, channel); conn->status = PN_NODE_STATUS_OPEN; pn_info("connected: conn=%p,channel=%p", conn, channel); conn->read_watch = g_io_add_watch(channel, G_IO_IN, read_cb, conn); #if 0 g_io_add_watch (channel, G_IO_ERR | G_IO_HUP | G_IO_NVAL, close_cb, conn); #endif } else { conn->error = g_error_new_literal(PN_NODE_ERROR, PN_NODE_ERROR_OPEN, "Unable to connect"); pn_node_error(conn); } { PnNodeClass *class; class = g_type_class_peek(PN_NODE_TYPE); g_signal_emit(G_OBJECT(conn), class->open_sig, 0, conn); } g_object_unref(conn); }
static gboolean write_cb (GIOChannel *source, GIOCondition condition, gpointer data) { PnHttpServer *http_conn = data; if (http_conn->last_flush == G_IO_STATUS_AGAIN) { http_conn->last_flush = pn_stream_flush(PN_NODE(http_conn)->stream, NULL); if (http_conn->last_flush == G_IO_STATUS_AGAIN) return TRUE; } http_conn->write_watch = 0; return FALSE; }
PnNode * pn_node_new (gchar *name, PnNodeType type) { PnNode *conn; pn_log ("begin"); conn = PN_NODE (g_type_create_instance (PN_NODE_TYPE)); conn->name = g_strdup (name); conn->type = type; pn_log ("end"); return conn; }
PnHttpServer * pn_http_server_new (const gchar *name) { PnHttpServer *http_conn; pn_log ("begin"); http_conn = PN_HTTP_SERVER (g_type_create_instance (PN_HTTP_SERVER_TYPE)); { PnNode *tmp = PN_NODE (http_conn); tmp->name = g_strdup (name); tmp->type = PN_NODE_HTTP; } pn_log ("end"); return http_conn; }
static void close_cb (PnNode *next, gpointer data) { PnNode *conn; conn = PN_NODE (data); pn_log ("begin"); pn_node_close (conn); { PnNodeClass *class; class = g_type_class_peek (PN_NODE_TYPE); g_signal_emit (G_OBJECT (conn), class->close_sig, 0, conn); } pn_log ("end"); }
void msn_nexus_connect(MsnNexus *nexus) { PnSslConn *ssl_conn; PnNode *conn; ssl_conn = pn_ssl_conn_new("nexus", PN_NODE_NULL); conn = PN_NODE(ssl_conn); conn->session = nexus->session; nexus->parser = pn_parser_new(conn); pn_ssl_conn_set_read_cb(ssl_conn, nexus_read_cb, nexus); nexus->conn = conn; nexus->open_handler = g_signal_connect(conn, "open", G_CALLBACK(nexus_open_cb), nexus); nexus->error_handler = g_signal_connect(conn, "error", G_CALLBACK(close_cb), nexus); pn_node_connect(conn, "nexus.passport.com", 443); }
static void dispose (GObject *obj) { PnNode *conn = PN_NODE (obj); pn_log ("begin"); if (conn->next) { g_signal_handler_disconnect (conn->next, conn->open_sig_handler); g_signal_handler_disconnect (conn->next, conn->close_sig_handler); g_signal_handler_disconnect (conn->next, conn->error_sig_handler); pn_node_free (conn->next); conn->next = NULL; } parent_class->dispose (obj); pn_log ("end"); }
static void process_queue (PnHttpServer *http_conn, GError **error) { HttpQueueData *queue_data; queue_data = g_queue_pop_head (http_conn->write_queue); if (queue_data) { foo_write (PN_NODE (http_conn), queue_data->conn, queue_data->body, queue_data->body_len, NULL, error); g_object_unref (queue_data->conn); g_free (queue_data->body); g_free (queue_data); } }
static void auth_cb (PnAuth *auth, void *data) { PnSslConn *ssl_conn; PnNode *conn; RoamingRequest *roaming_request = data; ssl_conn = pn_ssl_conn_new ("ab_roaming", PN_NODE_NULL); conn = PN_NODE (ssl_conn); conn->session = roaming_request->roaming_session->session; roaming_request->parser = pn_parser_new (conn); pn_ssl_conn_set_read_cb (ssl_conn, read_cb, roaming_request); if (!roaming_request->roaming_session->hostname) pn_node_connect (conn, "tkrdr.storage.msn.com", 443); else pn_node_connect (conn, roaming_request->roaming_session->hostname, 443); roaming_request->conn = conn; roaming_request->open_sig_handler = g_signal_connect (conn, "open", G_CALLBACK (open_cb), roaming_request); }
static void open_cb (PnNode *next, gpointer data) { PnNode *conn; conn = PN_NODE (data); pn_log ("begin"); conn->status = PN_NODE_STATUS_OPEN; { PnNodeClass *class; class = g_type_class_peek (PN_NODE_TYPE); g_signal_emit (G_OBJECT (conn), class->open_sig, 0, conn); } g_signal_handler_disconnect (next, conn->open_sig_handler); conn->open_sig_handler = 0; pn_log ("end"); }
static void error_cb (PnNode *next, gpointer data) { PnNode *conn; conn = PN_NODE (data); pn_log ("begin"); if (next->error) { g_propagate_error (&conn->error, next->error); next->error = NULL; } { PnNodeClass *class; class = g_type_class_peek (PN_NODE_TYPE); g_signal_emit (G_OBJECT (conn), class->error_sig, 0, conn); } pn_log ("end"); }
static gboolean http_poll (gpointer data) { PnNode *conn; PnHttpServer *http_conn; GIOStatus status = G_IO_STATUS_NORMAL; GError *tmp_error = NULL; gsize bytes_written = 0; static guint count = 0; gchar *header; gchar *params; gchar *auth = NULL; g_return_val_if_fail (data != NULL, FALSE); conn = PN_NODE (data); http_conn = PN_HTTP_SERVER (data); pn_debug ("stream=%p", conn->stream); if (!http_conn->cur) return TRUE; g_return_val_if_fail (http_conn->cur, FALSE); count++; /* Don't poll if we already sent something, unless we have been waiting for * too long; a disconnection might have happened. */ if (http_conn->waiting_response && count < 10) { /* There's no need to poll if we're already waiting for a response */ pn_debug ("waiting for response"); return TRUE; } #ifdef HAVE_LIBPURPLE auth = get_auth(conn); #endif /* HAVE_LIBPURPLE */ params = g_strdup_printf ("Action=poll&SessionID=%s", (gchar *) http_conn->cur->foo_data); header = g_strdup_printf ("POST http://%s/gateway/gateway.dll?%s HTTP/1.1\r\n" "Accept: */*\r\n" "User-Agent: MSMSGS\r\n" "Host: %s\r\n" "%s" /* Proxy auth */ "Proxy-Connection: Keep-Alive\r\n" "Connection: Keep-Alive\r\n" "Pragma: no-cache\r\n" "Cache-Control: no-cache\r\n" "Content-Type: application/x-msn-messenger\r\n" "Content-Length: 0\r\n\r\n", http_conn->gateway, params, http_conn->gateway, auth ? auth : ""); #ifdef PECAN_DEBUG_HTTP pn_debug ("header=[%s]", header); #endif g_free (params); status = pn_stream_write_full (conn->stream, header, strlen (header), &bytes_written, &tmp_error); g_free (header); http_conn->waiting_response = TRUE; pn_timer_stop (http_conn->timer); if (status == G_IO_STATUS_NORMAL) { status = pn_stream_flush (conn->stream, &tmp_error); if (status == G_IO_STATUS_AGAIN) { http_conn->last_flush = status; http_conn->write_watch = g_io_add_watch(conn->stream->channel, G_IO_OUT, write_cb, http_conn); /* fake status */ status = G_IO_STATUS_NORMAL; } if (status == G_IO_STATUS_NORMAL) pn_log ("bytes_written=%zu", bytes_written); } if (status != G_IO_STATUS_NORMAL) { PnNodeClass *class; pn_error ("not normal: status=%d", status); class = g_type_class_peek (PN_NODE_TYPE); g_signal_emit (G_OBJECT (conn), class->error_sig, 0, conn); return FALSE; }
MsnSession * msn_session_new (const gchar *username, const gchar *password, gboolean http_method) { MsnSession *session; PnClientCaps caps; session = g_new0 (MsnSession, 1); session->username = pn_normalize (username); session->password = g_strndup (password, 16); #ifdef INTERNAL_MAINLOOP session->g_main_loop = g_main_loop_new (NULL, FALSE); session->g_main_loop_timer = purple_timeout_add (1000, g_main_context_iteration_timer, NULL); #endif session->config = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); /** @todo sb and ns need this here but should be updated on-the-fly. */ msn_session_set_bool (session, "use_http_method", http_method); #if 0 if (session->http_method) { PnNode *foo; foo = PN_NODE (pn_http_server_new ("foo server")); foo->session = session; session->http_conn = foo; } #endif session->dp_manager = pn_dp_manager_new (session); session->notification = msn_notification_new (session); pn_node_set_id(session->notification->cmdproc->conn, session->conn_count++, "ns"); session->contactlist = pn_contactlist_new (session); session->user = pn_contact_new (NULL); pn_contact_set_passport (session->user, session->username); session->conv_seq = 1; session->machineguid = pn_rand_guid (); session->oim_session = pn_oim_session_new (session); session->service_session = pn_service_session_new (session); session->roaming_session = pn_roaming_session_new (session); session->conversations = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) msn_switchboard_unref); session->chats = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, (GDestroyNotify) msn_switchboard_unref); #if defined(PECAN_CVR) session->links = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) pn_peer_link_unref); #endif /* defined(PECAN_CVR) */ caps = PN_CLIENT_CAP_BASE; #if defined(PECAN_CVR) caps |= PN_CLIENT_CAP_INK_GIF; #if defined(PECAN_LIBSIREN) caps |= PN_CLIENT_CAP_VOICE_CLIP; #endif #if defined(PECAN_LIBMSPACK) caps |= PN_CLIENT_CAP_WINKS; #endif #endif session->client_id = caps | PN_CLIENT_VER_2009; return session; }
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; } } } }
static gboolean read_cb (GIOChannel *source, GIOCondition condition, gpointer data) { PnNode *conn; gchar buf[PN_BUF_LEN + 1]; gsize bytes_read; pn_log ("begin"); conn = PN_NODE (data); pn_debug ("conn=%p,source=%p", conn, source); g_object_ref (conn); { GIOStatus status = G_IO_STATUS_NORMAL; status = pn_node_read (conn, buf, PN_BUF_LEN, &bytes_read, &conn->error); if (status == G_IO_STATUS_AGAIN) { g_object_unref (conn); return TRUE; } if (conn->error) { pn_node_error (conn); g_object_unref (conn); return FALSE; } if (status != G_IO_STATUS_NORMAL) { pn_warning ("not normal, status=%d", status); g_object_unref (conn); return TRUE; } } if (!conn->error) { PnHttpServer *http_conn; http_conn = PN_HTTP_SERVER (conn); if (http_conn->cur) { /* make sure the server is not sending the same buffer again */ /** @todo find out why this happens */ if (!(http_conn->old_buffer && strncmp (buf, http_conn->old_buffer, bytes_read) == 0)) { pn_node_parse (http_conn->cur, buf, bytes_read); g_free (http_conn->old_buffer); http_conn->old_buffer = g_strndup (buf, bytes_read); } } if (conn->error) { pn_node_error (conn); g_object_unref (conn); return FALSE; } } g_object_unref (conn); pn_log ("end"); return TRUE; }