void fetion_update_portrait(fetion_account *ac, fetion_buddy *buddy) { portrait_data *data; HybridBuddy *hybrid_buddy; const gchar *checksum; g_return_if_fail(ac != NULL); g_return_if_fail(buddy != NULL); data = g_new0(portrait_data, 1); data->buddy = buddy; data->ac = ac; data->portrait_type = PORTRAIT_TYPE_BUDDY; if (!(hybrid_buddy = hybrid_blist_find_buddy(ac->account, buddy->userid))) { hybrid_debug_error("fetion", "FATAL, update portrait," " unable to find a buddy."); return; } checksum = hybrid_blist_get_buddy_checksum(hybrid_buddy); if (checksum != NULL && g_strcmp0(checksum, buddy->portrait_crc) == 0) { hybrid_debug_info("fetion", "portrait for %s(%s) up to date", buddy->nickname && *(buddy->nickname) != '\0' ? buddy->nickname : buddy->userid, buddy->portrait_crc); return; } hybrid_proxy_connect(ac->portrait_host_name, 80, portrait_conn_cb, data); }
/** * Callback function to handle the new_chat response message, if success * we would get the following message: * * SIP-C/4.0 200 OK * I: 4 * Q: 2 S * A: CS address="221.176.31.128:8080;221.176.31.128:443",credential="439333922.916967705" * * Now we should start a new socket connect to 221.176.31.128:8080 with port 443 as * a back port if 8080 failed to connect. */ gint new_chat_cb(fetion_account *account, const gchar *sipmsg, fetion_transaction *trans) { gchar *auth; gchar *ip; gint port; gchar *credential; invite_data *data; fetion_transaction *new_trans; fetion_account *new_account; printf("%s\n", sipmsg); if (!(auth = sip_header_get_attr(sipmsg, "A"))) { hybrid_debug_error("fetion", "invalid invitation response."); return HYBRID_ERROR; } if (sip_header_get_auth(auth, &ip, &port, &credential) != HYBRID_OK) { hybrid_debug_error("fetion", "invalid invitation response."); return HYBRID_ERROR; } g_free(auth); new_trans = transaction_clone(trans); new_account = fetion_account_clone(account); fetion_account_set_who(new_account, trans->userid); transaction_set_data(new_trans, new_account); data = g_new0(invite_data, 1); data->trans = new_trans; data->credential = credential; hybrid_proxy_connect(ip, port, invite_connect_cb, data); g_free(ip); return HYBRID_OK; }
HybridSslConnection* hybrid_ssl_connect(const gchar *hostname, gint port, ssl_callback func, gpointer user_data) { BIO *buf_io; BIO *ssl_bio; HybridSslConnection *conn; g_return_val_if_fail(hostname != NULL, NULL); g_return_val_if_fail(port != 0, NULL); g_return_val_if_fail(func != NULL, NULL); SSLeay_add_all_algorithms(); SSL_load_error_strings(); SSL_library_init(); conn = g_new0(HybridSslConnection, 1); if (!(conn->ssl_ctx = SSL_CTX_new(SSLv23_client_method()))) { hybrid_debug_error("ssl", "initialize SSL CTX: %s", ERR_reason_error_string(ERR_get_error())); hybrid_ssl_connection_destory(conn); return NULL; } if (!(conn->ssl = ssl_new_with_certs(conn->ssl_ctx))) { hybrid_ssl_connection_destory(conn); return NULL; } SSL_set_mode(conn->ssl, SSL_MODE_AUTO_RETRY); buf_io = BIO_new(BIO_f_buffer()); ssl_bio = BIO_new(BIO_f_ssl()); BIO_set_ssl(ssl_bio, conn->ssl, BIO_NOCLOSE); BIO_push(buf_io, ssl_bio); conn->conn_cb = func; conn->conn_data = user_data; conn->rbio = buf_io; conn->conn = hybrid_proxy_connect(hostname, port, ssl_connect_cb, conn); return conn; }
gint fetion_process_invite(fetion_account *account, const gchar *sipmsg) { gchar *from; gchar *auth; gchar *ip; gchar *credential; gchar *sid; gint port; gchar *sip_text; fetion_account *new_account; fetion_buddy *buddy; invite_conn_data *data; g_return_val_if_fail(account != NULL, HYBRID_ERROR); g_return_val_if_fail(sipmsg != NULL, HYBRID_ERROR); from = sip_header_get_attr(sipmsg, "F"); auth = sip_header_get_attr(sipmsg, "A"); sip_header_get_auth(auth, &ip, &port, &credential); g_free(auth); sip_text = g_strdup_printf("SIP-C/4.0 200 OK\r\n" "F: %s\r\n" "I: 61\r\n" "Q: 200002 I\r\n\r\n", from); hybrid_debug_info("fetion", "invite, send back:\n%s", sip_text); if (send(account->sk, sip_text, strlen(sip_text), 0) == -1) { hybrid_debug_error("fetion", "process an invitation error."); g_free(from); g_free(ip); g_free(credential); g_free(sip_text); return HYBRID_ERROR; } g_free(sip_text); sid = get_sid_from_sipuri(from); if (!(buddy = fetion_buddy_find_by_sid(account, sid))) { hybrid_debug_error("fetion", "can't find buddy %s", from); g_free(from); g_free(ip); g_free(credential); g_free(sid); return HYBRID_ERROR; } g_free(sid); new_account = fetion_account_clone(account); fetion_account_set_who(new_account, buddy->userid); data = g_new0(invite_conn_data, 1); data->account = new_account; data->credential = credential; hybrid_proxy_connect(ip, port, process_invite_conn_cb, data); g_free(from); g_free(ip); return HYBRID_OK; }
/** * 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; }
/** * 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 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; }