/** * Callback function for the resource bind request to process the response. */ static gboolean resource_bind_cb(XmppStream *stream, xmlnode *root, gpointer user_data) { gchar *type; gchar *jid; xmlnode *node; type = xmlnode_prop(root, "type"); if (g_strcmp0(type, "result")) { hybrid_account_error_reason(stream->account->account, _("resource bind error.")); return FALSE; } if (!(node = xmlnode_find(root, "jid"))) { hybrid_account_error_reason(stream->account->account, _("resource bind error: no jabber id returned.")); return FALSE; } jid = xmlnode_content(node); xmpp_stream_set_jid(stream, jid); g_free(jid); /* request to start a session. */ IqRequest *iq; iq = iq_request_create(stream, IQ_TYPE_SET); node = xmlnode_new_child(iq->node, "session"); xmlnode_new_namespace(node, NULL, NS_XMPP_SESSION); iq_request_set_callback(iq, start_session_cb, NULL); if (iq_request_send(iq) != HYBRID_OK) { hybrid_account_error_reason(stream->account->account, _("start session error.")); iq_request_destroy(iq); return TRUE; } iq_request_destroy(iq); return TRUE; }
/** * Callback function to handle the cfg connect event. */ static gboolean cfg_connect_cb(gint sk, gpointer user_data) { gchar *http; gchar *body; fetion_account *ac = (fetion_account*)user_data; hybrid_account_set_connection_string(ac->account, _("Downloading configure file...")); body = generate_configuration_body(ac); http = g_strdup_printf("POST /nav/getsystemconfig.aspx HTTP/1.1\r\n" "User-Agent: IIC2.0/PC "PROTO_VERSION"\r\n" "Host: %s\r\n" "Connection: Close\r\n" "Content-Length: %lu\r\n\r\n%s", NAV_SERVER, strlen(body), body); g_free(body); hybrid_debug_info("fetion", "send:\n%s", http); if (send(sk, http, strlen(http), 0) == -1) { hybrid_account_error_reason(ac->account, _("downloading cfg error")); g_free(http); return FALSE; } g_free(http); ac->source = hybrid_event_add(sk, HYBRID_EVENT_READ, cfg_read_cb, ac); return FALSE; }
gboolean imap_auth_cb(hybrid_imap *imap, const gchar *msg, gpointer user_data) { hybrid_debug_info("imap", "recv:\n%s", msg); if (HYBRID_OK == check_resp_ok(msg)) { hybrid_account_set_connection_string(imap->account, _("IMAP OK.")); hybrid_account_set_connection_status(imap->account, HYBRID_CONNECTION_CONNECTED); hybrid_account_set_state(imap->account, HYBRID_STATE_ONLINE); imap->mail_check_source = g_timeout_add_seconds( imap->mail_check_interval, check_mail, imap); return FALSE; } hybrid_account_error_reason(imap->account, _("IMAP Authenticate Failed." " Check your username and password.")); return FALSE; }
/** * Process deregister message. When the same account logins * at somewhere else, this message will be received. */ static void process_dereg_cb(fetion_account *ac, const gchar *sipmsg) { hybrid_account_error_reason(ac->account, _("Your account has logined elsewhere." "You are forced to quit.")); }
/** * Request the roster from the server. */ static void xmpp_stream_get_roster(XmppStream *stream) { xmlnode *node; IqRequest *iq; g_return_if_fail(stream != NULL); xmpp_stream_iqid_increase(stream); iq = iq_request_create(stream, IQ_TYPE_GET); iq_request_set_callback(iq, request_roster_cb, NULL); node = xmlnode_new_child(iq->node, "query"); xmlnode_new_namespace(node, NULL, NS_IQ_ROSTER); #if 0 xmlnode_new_namespace(node, "gr", NS_GOOGLE_ROSTER); xmlnode_new_prop(node, "gr:ext", "2"); #endif if (iq_request_send(iq) != HYBRID_OK) { hybrid_account_error_reason( stream->account->account, "request roster error."); iq_request_destroy(iq); return; } iq_request_destroy(iq); }
/** * Client binds a resource. */ static void xmpp_stream_bind(XmppStream *stream) { xmlnode *node; IqRequest *iq; g_return_if_fail(stream != NULL); iq = iq_request_create(stream, IQ_TYPE_SET); node = xmlnode_new_child(iq->node, "bind"); xmlnode_new_namespace(node, NULL, NS_XMPP_BIND); node = xmlnode_new_child(node, "resource"); xmlnode_set_content(node, "Hybrid."); iq_request_set_callback(iq, resource_bind_cb, NULL); if (iq_request_send(iq) != HYBRID_OK) { hybrid_account_error_reason( stream->account->account, "binds a resource error."); iq_request_destroy(iq); return; } iq_request_destroy(iq); }
/** * Request the vcard from the server. */ static void xmpp_stream_get_vcard(XmppStream *stream) { xmlnode *node; IqRequest *iq; g_return_if_fail(stream != NULL); xmpp_stream_iqid_increase(stream); iq = iq_request_create(stream, IQ_TYPE_GET); //iq_request_set_callback(iq, request_roster_cb, NULL); node = xmlnode_new_child(iq->node, "vCard"); xmlnode_new_namespace(node, NULL, "vcard-temp"); if (iq_request_send(iq) != HYBRID_OK) { hybrid_account_error_reason( stream->account->account, "request vcard error."); iq_request_destroy(iq); return; } iq_request_destroy(iq); }
static gboolean check_mail(gpointer user_data) { hybrid_imap *imap; gchar *cmd; imap = (hybrid_imap*)user_data; cmd = g_strdup_printf("A%d STATUS INBOX (UNSEEN)\r\n", imap->current_tag); hybrid_debug_info("imap", "send:\n%s", cmd); imap_trans_create(imap, check_mail_cb, NULL); if (hybrid_ssl_write(imap->ssl, cmd, strlen(cmd)) <= 0) { hybrid_account_error_reason(imap->account, _("IMAP Connection Closed.")); } g_free(cmd); if (imap->mail_check_source > 0) { g_source_remove(imap->mail_check_source); imap->mail_check_source = 0; } return FALSE; }
/** * Ok, TLS handshake success, we will continue the authtication * through the established TLS channel. */ static gboolean tls_conn_cb(HybridSslConnection *ssl, XmppStream *stream) { gchar *msg; hybrid_account_set_connection_string(stream->account->account, "TLS connection established."); msg = create_initiate_stream(stream); /* * Reset the stream id, we will start a new stream through * the TLS channel, whether stream id is NULL is the flag * of a new stream. */ xmpp_stream_set_id(stream, NULL); xmpp_stream_set_state(stream, XMPP_STATE_TLS_STREAM_STARTING); hybrid_debug_info("stream", "send start stream request:\n%s", msg); if (hybrid_ssl_write(ssl, msg, strlen(msg)) == -1) { hybrid_account_error_reason(stream->account->account, "send initial jabber request failed"); g_free(msg); return FALSE; } g_free(msg); return FALSE; }
/** * Parse the ssi authentication response string. then we can * get the following information: sipuri/mobileno/sid/ssic. */ static gint parse_ssi_response(fetion_account *ac, const gchar *response) { gchar *prop; xmlnode *node; xmlnode *root = xmlnode_root(response, strlen(response)); if (!root) { goto ssi_term; } prop = xmlnode_prop(root, "status-code"); if (g_strcmp0(prop, "200") != 0) { g_free(prop); goto ssi_term; } g_free(prop); node = xmlnode_find(root, "user"); prop = xmlnode_prop(node, "uri"); fetion_account_set_sipuri(ac, prop); g_free(prop); if (!ac->sid || *(ac->sid) == '\0') { g_free(ac->sid); ac->sid = get_sid_from_sipuri(ac->sipuri); fetion_sip_set_from(ac->sip, ac->sid); } prop = xmlnode_prop(node, "mobile-no"); fetion_account_set_mobileno(ac, prop); g_free(prop); prop = xmlnode_prop(node, "user-id"); fetion_account_set_userid(ac, prop); g_free(prop); #if 0 node = xmlnode_find(root, "credential"); prop = xmlnode_prop(node, "c"); fetion_account_set_ssic(ac, prop); g_free(prop); #endif return HYBRID_OK; ssi_term: hybrid_account_error_reason(ac->account, _("ssi authencation")); xmlnode_free(root); return HYBRID_ERROR; }
gboolean xmpp_stream_init(gint sk, XmppStream *stream) { gchar *msg; stream->sk = sk; /* send version. */ msg = "<?xml version='1.0' ?>"; if (send(sk, msg, strlen(msg), 0) == -1) { hybrid_account_error_reason(stream->account->account, "send initial jabber request failed"); return FALSE; } /* send initiate stream request. */ msg = create_initiate_stream(stream); hybrid_debug_info("xmpp", "send initite jabber stream:\n%s", msg); if (send(sk, msg, strlen(msg), 0) == -1) { hybrid_account_error_reason(stream->account->account, "send initial jabber request failed"); g_free(msg); return FALSE; } g_free(msg); stream->source = hybrid_event_add(sk, HYBRID_EVENT_READ, (input_func)stream_recv_cb, stream); return FALSE; }
static void xmpp_stream_process_failure(XmppStream *stream, xmlnode *root) { xmlnode *node; HybridAccount *account; account = stream->account->account; if ((node = xmlnode_find(root, "not-authorized"))) { hybrid_account_error_reason(account, _("Account not authorized." " Check Username and Password.")); } }
/** * Callback function to handle the sipc reg response. */ static gboolean sipc_reg_cb(gint sk, gpointer user_data) { gchar buf[BUF_LENGTH]; gchar *digest; gchar *nonce, *key, *aeskey; gchar *response; gint n; fetion_account *ac = (fetion_account*)user_data; if ((n = recv(sk, buf, sizeof(buf), 0)) == -1) { hybrid_account_error_reason(ac->account, _("sipc reg error.")); return FALSE; } buf[n] = '\0'; hybrid_debug_info("fetion", "recv:\n%s", buf); /* parse response, we need the key and nouce */ digest = sip_header_get_attr(buf, "W"); if (parse_sipc_reg_response(digest, &nonce, &key) != HYBRID_OK) { g_free(digest); return FALSE; } aeskey = generate_aes_key(); response = generate_response(nonce, ac->userid, ac->password, key, aeskey); /* fill verify_data for pic confirm */ strncpy(verify_data.response, response, sizeof(verify_data.response)); /* now we start to handle the pushed messages */ ac->source = hybrid_event_add(sk, HYBRID_EVENT_READ, hybrid_push_cb, ac); /* start sipc authencation action. */ sipc_aut_action(sk, ac, response); g_free(digest); g_free(nonce); g_free(key); g_free(aeskey); g_free(response); return FALSE; }
/** * Start the TLS handshake, if success, jump to the * tls_conn_cb() callback function to send the * stream start request through the TLS channel. */ static void xmpp_stream_performtls(XmppStream *stream) { g_return_if_fail(stream != NULL); hybrid_account_set_connection_string(stream->account->account, "Start performing tls"); if (!(stream->ssl = hybrid_ssl_connect_with_fd(stream->sk, (ssl_callback)tls_conn_cb, stream))) { hybrid_account_error_reason(stream->account->account, _("TLS hand-shake failed.")); return; } }
/** * This function starts to register to the sipc server, since we have * got the ip address and port from the cfg string in the last step. */ static gboolean sipc_reg_action(gint sk, gpointer user_data) { gchar *sipmsg; gchar *cnouce = generate_cnouce(); fetion_account *ac = (fetion_account*)user_data; fetion_sip *sip = ac->sip; hybrid_debug_info("fetion", "sipc registeration action"); hybrid_account_set_connection_string(ac->account, _("start registering to the sipc server.")); /* Now we start to register to the sipc server. */ fetion_sip_set_type(sip, SIP_REGISTER); sip_header *cheader = sip_header_create("CN", cnouce); sip_header *client = sip_header_create("CL", "type=\"pc\"" " ,version=\""PROTO_VERSION"\""); fetion_sip_add_header(sip, cheader); fetion_sip_add_header(sip, client); g_free(cnouce); sipmsg = fetion_sip_to_string(sip, NULL); hybrid_debug_info("fetion", "start registering to sip server(%s:%d)", ac->sipc_proxy_ip, ac->sipc_proxy_port); hybrid_debug_info("fetion", "send:\n%s", sipmsg); if (send(sk, sipmsg, strlen(sipmsg), 0) == -1) { hybrid_account_error_reason(ac->account, _("sipc reg error")); g_free(sipmsg); return FALSE; } hybrid_event_add(sk, HYBRID_EVENT_READ, sipc_reg_cb, ac); g_free(sipmsg); return FALSE; }
gint xmpp_stream_ping(XmppStream *stream) { IqRequest *iq; xmlnode *node; g_return_val_if_fail(stream != NULL, HYBRID_ERROR); iq = iq_request_create(stream, IQ_TYPE_GET); node = xmlnode_new_child(iq->node, "ping"); xmlnode_new_namespace(node, NULL, NS_XMPP_PING); iq_request_set_callback(iq, ping_cb, NULL); if (stream->keepalive_source) { g_source_remove(stream->keepalive_source); } stream->keepalive_source = g_timeout_add_seconds(60, (GSourceFunc)ping_timeout_cb, stream); if (iq_request_send(iq) != HYBRID_OK) { hybrid_debug_error("xmpp", "ping xmpp server failed."); iq_request_destroy(iq); hybrid_account_error_reason(stream->account->account, _("Connection Closed.")); return HYBRID_ERROR; } iq_request_destroy(iq); return HYBRID_OK; }
/** * Start a new stream on the sasl layer. */ static void xmpp_stream_new_on_sasl(XmppStream *stream) { gchar *msg; g_return_if_fail(stream != NULL); msg = create_initiate_stream(stream); xmpp_stream_set_id(stream, NULL); xmpp_stream_set_state(stream, XMPP_STATE_SASL_STREAM_STARTING); hybrid_debug_info("xmpp", "new stream on sasl,send:\n%s", msg); if (hybrid_ssl_write(stream->ssl, msg, strlen(msg)) == -1) { hybrid_account_error_reason(stream->account->account, "start new stream on sasl layer error."); return; } g_free(msg); }
static gboolean ping_cb(XmppStream *stream, xmlnode *node, gpointer user_data) { gchar *value; if (xmlnode_has_prop(node, "type")) { value = xmlnode_prop(node, "type"); if (g_strcmp0(value, "result") != 0) { hybrid_debug_error("xmpp", "ping xmpp server refused."); hybrid_account_error_reason(stream->account->account, _("Connection Closed.")); } } if (stream->keepalive_source) { g_source_remove(stream->keepalive_source); stream->keepalive_source = 0; } return FALSE; }
/** * Callback function to handle the ssi read event. We get the response * string from the ssi server here. */ static gboolean ssi_auth_cb(HybridSslConnection *ssl, gpointer user_data) { gchar buf[BUF_LENGTH]; gchar *pos; gchar *pos1; gint ret; gint code; fetion_account *ac = (fetion_account*)user_data; ret = hybrid_ssl_read(ssl, buf, sizeof(buf)); if (ret == -1 || ret == 0) { hybrid_debug_error("ssi", "ssi server response error"); return FALSE; } buf[ret] = '\0'; hybrid_ssl_connection_destory(ssl); hybrid_debug_info("fetion", "recv:\n%s", buf); code = hybrid_get_http_code(buf); if (421 == code || 420 == code) { /* confirm code needed. */ if (HYBRID_ERROR == parse_ssi_fail_resp(ac, buf)) { goto ssi_auth_err; } verify_data.ssl = ssl; verify_data.type = VERIFY_TYPE_SSI; hybrid_proxy_connect(NAV_SERVER, 80, pic_download_cb, ac); return FALSE; } if (200 != code) { goto ssi_auth_err; } if (!(pos = strstr(buf, "ssic="))) { goto ssi_auth_err; } pos += 5; for (pos1 = pos; *pos1 && *pos1 != ';'; pos1 ++); ac->ssic = g_strndup(pos, pos1 - pos); if (!(pos = g_strrstr(buf, "\r\n\r\n"))) { goto ssi_auth_err; } pos += 4; if (strlen(pos) != hybrid_get_http_length(buf)) { goto ssi_auth_err; } if (parse_ssi_response(ac, pos) != HYBRID_OK) { goto ssi_auth_err; } /* * First of all, we load the account's version information from the disk, * so that we can use it for authenticating, if the server find the versions * are up-to-date, it would return a brief response message in stead of the * full version, so that we can use the information store locally. This method * makes account logining more faster. */ fetion_config_load_account(ac); /* now we will download the configuration */ hybrid_proxy_connect(NAV_SERVER, 80, cfg_connect_cb, ac); return FALSE; ssi_auth_err: hybrid_account_error_reason(ac->account, _("ssi authentication failed")); return FALSE; }
/** * Callback function to handle the pushed message. */ gboolean hybrid_push_cb(gint sk, gpointer user_data) { gchar sipmsg[BUF_LENGTH]; gchar *pos; gchar *h; gchar *msg; fetion_account *ac = (fetion_account*)user_data; gint n; guint len, data_len; if ((n = recv(sk, sipmsg, sizeof(sipmsg), 0)) == -1) { hybrid_account_error_reason(ac->account, _("connection terminated")); return FALSE; } else if (0 == n) { hybrid_debug_info("fetion", "hybrid_push_cb in fetion received 0 bytes," "connection closed."); channel_list = g_slist_remove(channel_list, ac); fetion_account_destroy(ac); close(sk); return FALSE; } sipmsg[n] = '\0'; data_len = ac->buffer ? strlen(ac->buffer) : 0; ac->buffer = (gchar*)realloc(ac->buffer, data_len + n + 1); memcpy(ac->buffer + data_len, sipmsg, n + 1); recheck: data_len = ac->buffer ? strlen(ac->buffer) : 0; if ((pos = strstr(ac->buffer, "\r\n\r\n"))) { pos += 4; h = (gchar*)g_malloc0(data_len - strlen(pos) + 1); memcpy(h, ac->buffer, data_len - strlen(pos)); h[data_len - strlen(pos)] = '\0'; if (strstr(h, "L: ")) { len = fetion_sip_get_length(ac->buffer); if (len <= strlen(pos)) { msg = (gchar*)g_malloc0(strlen(h) + len + 1); memcpy(msg, ac->buffer, strlen(h) + len); msg[strlen(h) + len] = '\0'; /* A message is complete, process it. */ process_pushed(ac, msg); memmove(ac->buffer, ac->buffer + strlen(msg), data_len - strlen(msg)); ac->buffer = (gchar*)realloc(ac->buffer, data_len - strlen(msg) + 1); ac->buffer[data_len - strlen(msg)] = '\0'; g_free(msg); g_free(h); msg = NULL; h = NULL; goto recheck; } } else { /* A message is complete, process it. */ process_pushed(ac, h); memmove(ac->buffer, ac->buffer + strlen(h), data_len - strlen(h)); ac->buffer = (gchar*)realloc(ac->buffer, data_len - strlen(h) + 1); ac->buffer[data_len - strlen(h)] = '\0'; g_free(h); h = NULL; goto recheck; } g_free(h); } return TRUE; }
/** * Callback function to handle the read event after * rendered sipc authentication. */ static gint sipc_auth_cb(fetion_account *ac, const gchar *sipmsg, fetion_transaction *trans) { gint code; gint length; gchar *pos; code = fetion_sip_get_code(sipmsg); hybrid_debug_info("fetion", "sipc recv:\n%s", sipmsg); if (code == FETION_SIP_OK) { /**< ok, we got the contact list */ /* update the portrait. */ fetion_account_update_portrait(ac); length = fetion_sip_get_length(sipmsg); pos = strstr(ac->buffer, "\r\n\r\n") + 4; parse_sipc_resp(ac, pos, length); /* set the nickname of the hybrid account. */ hybrid_account_set_nickname(ac->account, ac->nickname); /* set the mood phrase of the hybrid account. */ hybrid_account_set_status_text(ac->account, ac->mood_phrase); hybrid_account_set_state(ac->account, HYBRID_STATE_INVISIBLE); /* set the connection status. */ hybrid_account_set_connection_status(ac->account, HYBRID_CONNECTION_CONNECTED); /* init group list */ fetion_groups_init(ac); /* init buddy list */ fetion_buddies_init(ac); /* start scribe the pushed msg */ fetion_buddy_scribe(ac); } else if (420 == code || 421 == code) { if (HYBRID_ERROR == parse_sipc_verification(ac, sipmsg)) { hybrid_account_error_reason(ac->account, _("Fetion Protocol ERROR.")); return FALSE; } hybrid_debug_error("fetion", "sipc authentication need Verification."); verify_data.sipc_conn = ac->sk; verify_data.type = VERIFY_TYPE_SIP; hybrid_proxy_connect(NAV_SERVER, 80, pic_download_cb, ac); g_free(ac->buffer); ac->buffer = NULL; return HYBRID_OK; } else { g_free(ac->buffer); ac->buffer = NULL; return HYBRID_ERROR; } return HYBRID_ERROR; }
/** * Start sasl authentication. */ static void xmpp_stream_startsasl(XmppStream *stream) { guchar *auth; gchar *auth_encoded; gchar *xml_string; gint username_len; gint password_len; xmlnode *node; g_return_if_fail(stream != NULL); hybrid_debug_info("xmpp", "start sasl authentication."); hybrid_account_set_connection_string(stream->account->account, "Start sasl authentication."); xmpp_stream_set_state(stream, XMPP_STATE_SASL_AUTHENTICATING); /* * construct the authentication string to be base64 encoded, * which is in form of '\0 + username + \0 + password ' */ username_len = strlen(stream->account->username); password_len = strlen(stream->account->password); auth = g_malloc0(username_len + password_len + 2); auth[0] = '\0'; memcpy(auth + 1, stream->account->username, username_len); auth[username_len + 1] = '\0'; memcpy(auth + 2 + username_len, stream->account->password, password_len); auth_encoded = hybrid_base64_encode(auth, username_len + password_len + 2); g_free(auth); /* construct the xml string, which is in form of: * * <auth xmlns="urn:ietf:params:xml:ns:xmpp-sasl" * mechanism="PLAIN">encoded sasl string</auth> */ node = xmlnode_create("auth"); xmlnode_new_namespace(node, NULL, NS_XMPP_SASL); xmlnode_new_namespace(node, "ga", "http://www.google.com/talk/protocol/auth"); xmlnode_new_prop(node, "ga:client-uses-full-bind-result", "true"); xmlnode_new_prop(node, "mechanism", "PLAIN"); xmlnode_set_content(node, auth_encoded); g_free(auth_encoded); xml_string = xmlnode_to_string(node); xmlnode_free(node); hybrid_debug_info("xmpp", "sasl send:\n%s", xml_string); if (hybrid_ssl_write(stream->ssl, xml_string, strlen(xml_string)) == -1) { hybrid_account_error_reason(stream->account->account, "SASL authentication error."); return; } g_free(xml_string); }
/** * Callback function to handle the cfg read event. */ static gboolean cfg_read_cb(gint sk, gpointer user_data) { gchar buf[BUF_LENGTH]; gint n; gint length = 0; gchar *pos; fetion_account *ac = (fetion_account*)user_data; if ((n = recv(sk, buf, sizeof(buf), 0)) == -1) { hybrid_account_error_reason(ac->account, _("read cfg failed")); return FALSE; } buf[n] = '\0'; if (n != 0) { /* larger the recv buffer, and copy the new * received bytes to the buffer */ length = ac->buffer ? strlen(ac->buffer) : 0; ac->buffer = g_realloc(ac->buffer, length + n + 1); memcpy(ac->buffer + length, buf, n + 1); return TRUE; } else { /* receive complete, start process */ if (hybrid_get_http_code(ac->buffer) != 200) { goto error; } hybrid_debug_info("fetion", "cfg recv:\n%s", ac->buffer); if (!(pos = g_strrstr(ac->buffer, "\r\n\r\n"))) { goto error; } pos += 4; if (strlen(pos) != hybrid_get_http_length(ac->buffer)) { goto error; } if (parse_configuration(ac, pos) != HYBRID_OK) { g_free(ac->buffer); ac->buffer = NULL; goto error; } g_free(ac->buffer); ac->buffer = NULL; /* now we start sipc register */ hybrid_proxy_connect(ac->sipc_proxy_ip, ac->sipc_proxy_port, sipc_reg_action, ac); } return FALSE; error: hybrid_account_error_reason(ac->account, _("read cfg failed")); return FALSE; }
static gboolean pic_read_cb(gint sk, gpointer user_data) { gint n, len; gchar sipmsg[BUF_LENGTH]; gchar *code, *pos; guchar *pic; gint piclen; xmlnode *root; xmlnode *node; fetion_account *ac = (fetion_account*)user_data; len = ac->buffer ? strlen(ac->buffer) : 0; if((n = recv(sk, sipmsg, strlen(sipmsg), 0)) == -1) { return -1; } sipmsg[n] = 0; if(n == 0) { g_source_remove(ac->source); ac->source = 0; close(sk); if(! ac->buffer) { return 0; } hybrid_debug_info("fetion", "read message resp:\n%s", ac->buffer); if (200 != hybrid_get_http_code(ac->buffer)) { goto read_pic_err; } if(!(pos = strstr(ac->buffer, "\r\n\r\n"))) { goto read_pic_err; } pos += 4; if (!(root = xmlnode_root(pos, strlen(pos)))) { goto read_pic_err; } if (!(node = xmlnode_find(root, "pic-certificate"))) { xmlnode_free(root); goto read_pic_err; } if (!xmlnode_has_prop(node, "id") || !xmlnode_has_prop(node, "pic")) { xmlnode_free(root); goto read_pic_err; } ac->verification->guid = xmlnode_prop(node, "id"); code = xmlnode_prop(node, "pic"); pic = hybrid_base64_decode(code, &piclen); hybrid_confirm_window_create(ac->account, pic, piclen, pic_code_ok_cb, pic_code_cancel_cb, ac); g_free(code); g_free(pic); xmlnode_free(root); g_free(ac->buffer); ac->buffer = (gchar*)0; return FALSE; } ac->buffer = (gchar*)realloc(ac->buffer, len + n + 1); memcpy(ac->buffer + len, sipmsg, n + 1); return TRUE; read_pic_err: hybrid_debug_error("fetion", "read pic code error."); g_free(ac->buffer); ac->buffer = (gchar *)0; hybrid_account_error_reason(ac->account, _("read pic code error.")); return FALSE; }