/** * Verify the peer's certificate, if successfully verified, * save the peer's certificate */ static gint ssl_verify_certs(SSL *ssl) { FILE *f; X509 *x; gchar *cert_path; gchar *cert_file; gchar buf[256]; gchar *pos; hybrid_debug_info("ssl", "verifying the peer's certificate"); if ((x = SSL_get_peer_certificate(ssl)) != NULL) { if (SSL_get_verify_result(ssl) == X509_V_OK) { X509_NAME_oneline(X509_get_subject_name(x), buf, 256); hybrid_debug_info("ssl", "client verification succeeded."); cert_path = hybrid_config_get_cert_path(); if ((pos = strstr(buf, "CN="))) { cert_file = g_strdup_printf("%s/%s", cert_path, pos + 3); } else { cert_file = g_strdup_printf("%s/%s", cert_path, buf); } g_free(cert_path); f = fopen(cert_file, "w+"); PEM_write_X509(f, x); fclose(f); g_free(cert_file); } else { hybrid_debug_error("ssl", "client verification failed."); return HYBRID_OK; } } else { hybrid_debug_error("ssl", "the peer certificate was not presented.\n"); } return HYBRID_OK; }
static gint invite_buddy_cb(fetion_account *account, const gchar *sipmsg, fetion_transaction *trans) { hybrid_debug_info("fetion", "invite buddy response:\n%s", sipmsg); if (trans->msg && *(trans->msg) != '\0') { fetion_message_send(account, trans->userid, trans->msg); } return HYBRID_OK; }
gint hybrid_ssl_read(HybridSslConnection *ssl, gchar *buf, gint len) { gint ret; hybrid_debug_info("ssl", "start ssl read."); ret = BIO_read(ssl->rbio, buf, len); switch (SSL_get_error(ssl->ssl, ret)) { case SSL_ERROR_NONE: hybrid_debug_info("ssl", "ssl read %d bytes, success!", ret); return ret; case SSL_ERROR_WANT_WRITE: case SSL_ERROR_WANT_READ: hybrid_debug_info("ssl", "ssl read WANT RW with ret %d.", ret); break; case SSL_ERROR_SYSCALL: hybrid_debug_info("ssl", "ssl read io error."); return -1; case SSL_ERROR_WANT_X509_LOOKUP: hybrid_debug_info("ssl", "ssl read X509."); return -1; case SSL_ERROR_ZERO_RETURN: hybrid_debug_info("ssl", "ssl connection permaturely closed."); return 0; case SSL_ERROR_SSL: default: hybrid_debug_error("ssl", "ssl read error:%s", ERR_reason_error_string(ERR_get_error())); return -1; } return -1; }
/** * Callback function to handle the pic-code download event. */ static gboolean pic_download_cb(gint sk, gpointer user_data) { gchar *cookie = NULL; gchar *http; fetion_account *ac = (fetion_account*)user_data; hybrid_debug_info("fetion", "start downloading pic-cocde."); if(ac->ssic) { cookie = g_strdup_printf("Cookie: ssic=%s\r\n", ac->ssic); } http = g_strdup_printf("GET /nav/GetPicCodeV4.aspx?algorithm=%s HTTP/1.1\r\n" "%sHost: %s\r\n" "User-Agent: IIC2.0/PC "PROTO_VERSION"\r\n" "Connection: close\r\n\r\n", ac->verification->algorithm == NULL ? "" : ac->verification->algorithm, ac->ssic == NULL ? "" : cookie, NAV_SERVER); hybrid_debug_info("fetion", "download pic request:\n%s", http); if (send(sk, http, strlen(http), 0) == -1) { g_free(cookie); g_free(http); return FALSE; } ac->buffer = (char*)0; ac->source = hybrid_event_add(sk, HYBRID_EVENT_READ, pic_read_cb, user_data); g_free(cookie); g_free(http); return FALSE; }
gint xmpp_message_send_typing(XmppStream *stream, const gchar *to, HybridInputState state) { xmlnode *root; xmlnode *node; gchar *xml_string; g_return_val_if_fail(stream != NULL, HYBRID_ERROR); g_return_val_if_fail(to != NULL, HYBRID_ERROR); root = xmlnode_create("message"); xmlnode_new_prop(root, "from", stream->jid); xmlnode_new_prop(root, "to", to); xmlnode_new_prop(root, "type", "chat"); switch (state) { case INPUT_STATE_TYPING: node = xmlnode_new_child(root, "composing"); break; case INPUT_STATE_ACTIVE: node = xmlnode_new_child(root, "active"); break; case INPUT_STATE_PAUSED: node = xmlnode_new_child(root, "paused"); break; default: node = NULL; break; } if (node) { xmlnode_new_namespace(node, NULL, NS_CHANGESTATES); } xml_string = xmlnode_to_string(root); xmlnode_free(root); hybrid_debug_info("xmpp", "send message to %s:\n%s", to, xml_string); if (hybrid_ssl_write(stream->ssl, xml_string, strlen(xml_string)) == -1) { hybrid_debug_error("xmpp", "send message to %s failed\n", to); g_free(xml_string); return HYBRID_ERROR; } g_free(xml_string); return HYBRID_OK; }
/** * 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; }
static gboolean fx_login(HybridAccount *imac) { HybridSslConnection *conn; hybrid_debug_info("fetion", "fetion is now logging in..."); ac = fetion_account_create(imac, imac->username, imac->password); hybrid_account_set_protocol_data(imac, ac); conn = hybrid_ssl_connect(SSI_SERVER, 443, ssi_auth_action, ac); return TRUE; }
/** * Callback function to handle the invite-connect event, when we * get this acknowledge message, we should start to invite the buddy * to the conversation. * * The message received is: * * SIP-C/4.0 200 OK * I: 5 * Q: 2 R * XI: 3d2ef745db9741a8946a57c40b0eb4d5 * X: 1200 * K: text/plain * K: text/html-fragment * K: multiparty * K: nudge * * then we send out invite-buddy request: */ static gint chat_reg_cb(fetion_account *account, const gchar *sipmsg, fetion_transaction *trans) { fetion_sip *sip; sip_header *eheader; gchar *body; gchar *sip_text; fetion_transaction *new_trans; fetion_buddy *buddy; sip = account->sip; fetion_sip_set_type(sip, SIP_SERVICE); if (!(buddy = fetion_buddy_find_by_userid(account, trans->userid))) { hybrid_debug_error("fetion", "invite new buddy failed"); return HYBRID_ERROR; } eheader = sip_event_header_create(SIP_EVENT_INVITEBUDDY); fetion_sip_add_header(sip, eheader); body = generate_invite_buddy_body(buddy->sipuri); new_trans = transaction_clone(trans); transaction_set_callid(new_trans, sip->callid); transaction_set_callback(new_trans, invite_buddy_cb); transaction_add(account, new_trans); sip_text = fetion_sip_to_string(sip, body); g_free(body); hybrid_debug_info("fetion", "invite new buddy,send:\n%s", sip_text); if (send(account->sk, sip_text, strlen(sip_text), 0) == -1) { hybrid_debug_error("fetion", "invite new buddy failed"); return HYBRID_ERROR; } g_free(sip_text); return HYBRID_OK; }
/** * Process the synchronization message, when the contact list or the personal info * changed, the server will push this message to tell the client to update its * local cache file, well, we will not update the local cache file, we keep the * old version numbers, and reload it after the next logining. */ static void process_sync_info(fetion_account *ac, const gchar *sipmsg) { GSList *list; gchar *sid; fetion_buddy *buddy; HybridBuddy *hb; hybrid_debug_info("fetion", "sync info,recv:\n%s", sipmsg); if (!(list = sip_parse_sync(ac, sipmsg))) { return; } while (list) { buddy = (fetion_buddy*)list->data; list = g_slist_remove(list, buddy); if (buddy->status == 0) { continue; } if (!(hb = hybrid_blist_find_buddy(ac->account, buddy->userid))) { continue; } if (buddy->status == 1) { hybrid_blist_set_buddy_status(hb, TRUE); } else { hybrid_blist_set_buddy_status(hb, FALSE); } sid = get_sid_from_sipuri(buddy->sipuri); hybrid_message_box_show(HYBRID_MESSAGE_INFO, _("Buddy <b>%s</b> has %s your add-buddy request."), buddy->localname && *(buddy->localname) != '\0' ? buddy->localname : sid, buddy->status == 1 ? _("accepted") : _("declined")); } }
static void pic_code_ok_cb(HybridAccount *account, const gchar *code, gpointer user_data) { fetion_account *ac = (fetion_account*)user_data; hybrid_debug_info("fetion", "pic code %s inputed.", code); g_free(ac->verification->code); ac->verification->code = g_strdup(code); if (VERIFY_TYPE_SSI == verify_data.type) { hybrid_ssl_connect(SSI_SERVER, 443, ssi_auth_action, ac); } else { printf("%s\n", verify_data.response); sipc_aut_action(verify_data.sipc_conn, ac, verify_data.response); } }
gboolean hybrid_pref_get_boolean(const gchar *name) { xmlnode *node; gchar *type; gchar *value; g_return_val_if_fail(hybrid_pref != NULL, FALSE); g_return_val_if_fail(hybrid_pref->root != NULL, FALSE); if (!(node = xmlnode_find(hybrid_pref->root, name))) { return FALSE; } if (!xmlnode_has_prop(node, "type")) { hybrid_debug_info("pref", "invalid pref node."); return FALSE; } type = xmlnode_prop(node, "type"); if (g_strcmp0(type, "bool") != 0) { hybrid_debug_error("pref", "bool pref node with a type which is not bool."); return FALSE; } value = xmlnode_content(node); if (g_strcmp0(value, "0") == 0) { g_free(value); return FALSE; } else { g_free(value); return TRUE; } }
gint fetion_message_send_to_me(fetion_account *account, const gchar *text) { sip_header *toheader; sip_header *eheader; gchar *sip_text; fetion_sip *sip; fetion_transaction *trans; g_return_val_if_fail(account != NULL, HYBRID_ERROR); g_return_val_if_fail(text != NULL, HYBRID_ERROR); sip = account->sip; fetion_sip_set_type(sip, SIP_MESSAGE); toheader = sip_header_create("T", account->sipuri); eheader = sip_event_header_create(SIP_EVENT_SENDCATMESSAGE); fetion_sip_add_header(sip, toheader); fetion_sip_add_header(sip, eheader); trans = transaction_create(); transaction_set_callid(trans, sip->callid); transaction_set_callback(trans, sms_to_me_cb); transaction_add(account, trans); sip_text = fetion_sip_to_string(sip, text); hybrid_debug_info("fetion", "send sms to youself,send:\n%s", sip_text); if (send(account->sk, sip_text, strlen(sip_text), 0) == -1) { hybrid_debug_error("fetion", "send message to yourself error."); return HYBRID_ERROR; } g_free(sip_text); return HYBRID_OK; }
gint fetion_buddy_add(fetion_account *account, const gchar *groupid, const gchar *no, const gchar *alias) { fetion_sip *sip; sip_header *eheader; fetion_transaction *trans; gchar *body; gchar *sip_text; g_return_val_if_fail(account != NULL, HYBRID_ERROR); g_return_val_if_fail(groupid != NULL, HYBRID_ERROR); g_return_val_if_fail(no != NULL, HYBRID_ERROR); sip = account->sip; fetion_sip_set_type(sip, SIP_SERVICE); eheader = sip_event_header_create(SIP_EVENT_ADDBUDDY); fetion_sip_add_header(sip, eheader); trans = transaction_create(); transaction_set_callid(trans, sip->callid); transaction_set_callback(trans, buddy_add_cb); transaction_add(account, trans); body = generate_buddy_add_body(no, groupid, alias, account->nickname); sip_text = fetion_sip_to_string(sip, body); g_free(body); hybrid_debug_info("fetion", "add buddy,send:\n%s", sip_text); if (send(account->sk, sip_text, strlen(sip_text), 0) == -1) { hybrid_debug_error("fetion", "add buddy failed"); return HYBRID_ERROR; } g_free(sip_text); return HYBRID_OK; }
static void process_add_buddy(fetion_account *ac, const gchar *sipmsg) { gchar *sipuri; gchar *userid; gchar *desc; HybridBuddyReqWindow *req; hybrid_debug_info("fetion", "received add-buddy request:\n%s", sipmsg); if (sip_parse_appbuddy(sipmsg, &userid, &sipuri, &desc) != HYBRID_OK) { return; } req = hybrid_buddy_request_window_create(ac->account, userid, desc); hybrid_buddy_request_set_user_data(req, sipuri, g_free); g_free(userid); g_free(desc); }
gint fetion_message_new_chat(fetion_account *account, const gchar *userid, const gchar *text) { fetion_sip *sip; sip_header *eheader; fetion_transaction *trans; gchar *sip_text; g_return_val_if_fail(account != NULL, HYBRID_ERROR); g_return_val_if_fail(userid != NULL, HYBRID_ERROR); sip = account->sip; /*start chat*/ fetion_sip_set_type(sip, SIP_SERVICE); eheader = sip_event_header_create(SIP_EVENT_STARTCHAT); fetion_sip_add_header(sip, eheader); trans = transaction_create(); transaction_set_callid(trans, sip->callid); transaction_set_userid(trans, userid); transaction_set_msg(trans, text); transaction_set_callback(trans, new_chat_cb); transaction_add(account, trans); sip_text = fetion_sip_to_string(sip, NULL); hybrid_debug_info("fetion", "new chat,send:\n%s", sip_text); if (send(account->sk, sip_text, strlen(sip_text), 0) == -1) { hybrid_debug_error("fetion", "new chat failed"); return HYBRID_ERROR; } g_free(sip_text); return HYBRID_OK; }
gint fetion_buddy_get_info(fetion_account *ac, const gchar *userid, TransCallback callback, gpointer data) { fetion_transaction *trans; fetion_sip *sip; sip_header *eheader; gchar *body; gchar *res; g_return_val_if_fail(ac != NULL, HYBRID_ERROR); g_return_val_if_fail(userid != NULL, HYBRID_ERROR); sip = ac->sip; fetion_sip_set_type(sip , SIP_SERVICE); eheader = sip_event_header_create(SIP_EVENT_GETCONTACTINFO); trans = transaction_create(); transaction_set_callid(trans, sip->callid); transaction_set_userid(trans, userid); transaction_set_callback(trans, callback); transaction_set_data(trans, data); transaction_add(ac, trans); fetion_sip_add_header(sip, eheader); body = generate_get_info_body(userid); res = fetion_sip_to_string(sip, body); g_free(body); hybrid_debug_info("fetion", "send:\n%s", res); if (send(ac->sk, res, strlen(res), 0) == -1) { g_free(res); return HYBRID_ERROR; } g_free(res); return HYBRID_OK; }
static gint sms_response_cb(fetion_account *account, const gchar *sipmsg, fetion_transaction *trans) { gint code; g_source_remove(trans->timer); code = fetion_sip_get_code(sipmsg); hybrid_debug_info("fetion", "send message response:\n%s", sipmsg); if (code != 200 && code != 280) { return HYBRID_ERROR; } /* TODO add error message to textview */ return HYBRID_OK; }
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; }
gint hybrid_pref_get_int(const gchar *name) { xmlnode *node; gchar *type; gchar *value; gint value_int; g_return_val_if_fail(hybrid_pref != NULL, FALSE); g_return_val_if_fail(hybrid_pref->root != NULL, FALSE); if (!(node = xmlnode_find(hybrid_pref->root, name))) { return -1; } if (!xmlnode_has_prop(node, "type")) { hybrid_debug_info("pref", "invalid pref node."); return -1; } type = xmlnode_prop(node, "type"); if (g_strcmp0(type, "int") != 0) { hybrid_debug_error("pref", "integer pref node with a type which is not int."); return -1; } value = xmlnode_content(node); value_int = atoi(value); g_free(value); return value_int; }
/** * set the socket to be nonblock */ static gint nonblock(gint sk) { gint flag; g_return_val_if_fail(sk != 0, HYBRID_ERROR); hybrid_debug_info("option", "set socket to be nonblock"); if ((flag = fcntl(sk, F_GETFL, 0)) == -1) { hybrid_debug_error("socket", "set socket to be nonblock:%s", strerror(errno)); return HYBRID_ERROR; } if ((flag = fcntl(sk, F_SETFL, flag | O_NONBLOCK)) == -1) { hybrid_debug_error("socket", "set socket to be nonblock:%s", strerror(errno)); return HYBRID_ERROR; } 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); }
/** * 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; }
gint resolve_host(const gchar *hostname, gchar *ip) { g_return_val_if_fail(hostname != NULL, HYBRID_ERROR); struct addrinfo *result; struct addrinfo *rp; struct sockaddr_in *addr; gchar *hash_value; gchar buf[32]; hybrid_debug_info("dns", "resolve host \'%s\'", hostname); if (host_hash && (hash_value = g_hash_table_lookup(host_hash, hostname))) { strcpy(ip, (gchar*)hash_value); hybrid_debug_info("dns", "ip of \'%s\' is \'%s\'[cached]", hostname, ip); return HYBRID_OK; } if (getaddrinfo(hostname, NULL, NULL, &result) != 0) { hybrid_debug_error("resolve_host", "resolve host \'%s\' failed", hostname); return HYBRID_ERROR; } for (rp = result; rp != NULL; rp = rp->ai_next) { addr = (struct sockaddr_in*)rp->ai_addr; memset(buf, 0, sizeof(buf)); if (!inet_ntop(AF_INET, (void*)&addr->sin_addr, buf, 16)) { hybrid_debug_error("dns", "reslove host \'%s\' failed when" " transforming binary ip address to doted ip address", hostname); continue; } if (g_strcmp0(buf, "0.0.0.0") == 0 || g_strcmp0(buf, "127.0.0.1") == 0) { continue; } strncpy(ip, buf, strlen(buf)); goto addr_success; } return HYBRID_ERROR; addr_success: if (!host_hash) { host_hash = g_hash_table_new(g_str_hash, g_str_equal); } hash_value = g_strdup(ip); g_hash_table_insert(host_hash, (gchar*)hostname, hash_value); hybrid_debug_info("dns", "ip of \'%s\' is \'%s\'[new]", hostname, 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; }
/** * 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); }
/** * Start sipc authencation with the response string. * * @param response It is generated by generate_response(). */ static gint sipc_aut_action(gint sk, fetion_account *ac, const gchar *response) { gchar *sipmsg; gchar *body; sip_header *aheader; sip_header *akheader; sip_header *ackheader; fetion_transaction *trans; fetion_sip *sip = ac->sip; ac->sk = sk; hybrid_debug_info("fetion", "sipc authencation action"); hybrid_account_set_connection_string(ac->account, _("start sipc authentication...")); body = generate_auth_body(ac); fetion_sip_set_type(sip, SIP_REGISTER); aheader = sip_authentication_header_create(response); akheader = sip_header_create("AK", "ak-value"); trans = transaction_create(); transaction_set_callid(trans, sip->callid); transaction_set_callback(trans, sipc_auth_cb); transaction_add(ac, trans); fetion_sip_add_header(sip, aheader); fetion_sip_add_header(sip, akheader); if(ac->verification != NULL && ac->verification->algorithm != NULL) { ackheader = sip_ack_header_create(ac->verification->code, ac->verification->algorithm, ac->verification->type, ac->verification->guid); fetion_sip_add_header(sip , ackheader); } fetion_verification_destroy(ac->verification); ac->verification = NULL; sipmsg = fetion_sip_to_string(sip, body); g_free(body); hybrid_debug_info("fetion", "Start sipc authentication , with ak-value"); hybrid_debug_info("fetion", "send:\n%s", sipmsg); if(send(sk, sipmsg, strlen(sipmsg), 0) == -1) { hybrid_debug_error("fetion", "send sipc auth request:%s\n", strerror(errno)); g_free(sipmsg); return HYBRID_ERROR; } g_free(sipmsg); return 0; }
gint fetion_message_send(fetion_account *account, const gchar *userid, const gchar *text) { fetion_sip *sip; sip_header *toheader; sip_header *cheader; sip_header *kheader; sip_header *nheader; gchar *sip_text; fetion_buddy *buddy; g_return_val_if_fail(account != NULL, HYBRID_ERROR); g_return_val_if_fail(userid != NULL && *userid != '\0', HYBRID_ERROR); g_return_val_if_fail(text != NULL, HYBRID_ERROR); sip = account->sip; if (!(buddy = fetion_buddy_find_by_userid(account, userid))) { hybrid_debug_error("fetion", "FATAL, can't find specified buddy"); return HYBRID_ERROR; } fetion_transaction *trans = transaction_create(); transaction_set_userid(trans, userid); transaction_set_msg(trans, text); if (!account->channel_ready) { /* If the channel is not ready, make the transaction to wait * until the transaction is ready */ transaction_wait(account, trans); hybrid_debug_info("fetion", "channel not ready, transaction sleep."); return HYBRID_OK; } fetion_sip_set_type(sip, SIP_MESSAGE); nheader = sip_event_header_create(SIP_EVENT_CATMESSAGE); toheader = sip_header_create("T", buddy->sipuri); cheader = sip_header_create("C", "text/plain"); kheader = sip_header_create("K", "SaveHistory"); fetion_sip_add_header(sip, toheader); fetion_sip_add_header(sip, cheader); fetion_sip_add_header(sip, kheader); fetion_sip_add_header(sip, nheader); transaction_set_callid(trans, sip->callid); transaction_set_callback(trans, sms_response_cb); transaction_set_data(trans, account); transaction_set_timeout(trans, (GSourceFunc)sms_timeout_cb, trans); transaction_add(account, trans); sip_text = fetion_sip_to_string(sip, text); hybrid_debug_info("fetion", "send message, send:\n%s", sip_text); if (send(account->sk, sip_text, strlen(sip_text), 0) == -1) { g_free(sip_text); return HYBRID_ERROR; } g_free(sip_text); return HYBRID_OK; }
gint fetion_process_message(fetion_account *account, const gchar *sipmsg) { gchar *from; gchar *sid; gchar *callid; gchar *sequence; gchar *sendtime; gchar *text; gchar *sip_text; fetion_buddy *buddy; g_return_val_if_fail(account != NULL, HYBRID_ERROR); g_return_val_if_fail(sipmsg != NULL, HYBRID_ERROR); if (!(text = strstr(sipmsg, "\r\n\r\n"))) { hybrid_debug_error("fetion", "invalid message received\n"); return HYBRID_ERROR; } text += 4; from = sip_header_get_attr(sipmsg, "F"); callid = sip_header_get_attr(sipmsg, "I"); sendtime = sip_header_get_attr(sipmsg, "D"); sequence = sip_header_get_attr(sipmsg, "Q"); sip_text = g_strdup_printf( "SIP-C/4.0 200 OK\r\n" "I: %s\r\n" "Q: %s\r\n" "F: %s\r\n\r\n", callid, sequence, from); g_free(callid); g_free(sendtime); g_free(sequence); hybrid_debug_info("fetion", "message response, send:\n%s", sip_text); if (send(account->sk, sip_text, strlen(sip_text), 0) == -1) { g_free(sip_text); g_free(from); return HYBRID_ERROR; } g_free(sip_text); sid = get_sid_from_sipuri(from); g_free(from); if (!(buddy = fetion_buddy_find_by_sid(account, sid))) { hybrid_debug_error("fetion", "invalid message received\n"); g_free(sid); return HYBRID_ERROR; } hybrid_conv_got_message(account->account, buddy->userid, text, time(NULL)); g_free(sid); return HYBRID_OK; }
static gint process_invite_conn_cb(gint sk, gpointer user_data) { invite_conn_data *data; fetion_account *account; fetion_sip *sip; gchar *credential; gchar *sip_text; sip_header *aheader; sip_header *theader; sip_header *mheader; sip_header *nheader; data = (invite_conn_data*)user_data; account = data->account; credential = data->credential; g_free(data); account->sk = sk; sip = account->sip; account->source = hybrid_event_add(sk, HYBRID_EVENT_READ, hybrid_push_cb, account); if (account->source == 0) { hybrid_debug_error("fetion", "add read event error"); return HYBRID_ERROR; } fetion_sip_set_type(sip, SIP_REGISTER); aheader = sip_credential_header_create(credential); theader = sip_header_create("K", "text/html-fragment"); mheader = sip_header_create("K", "multiparty"); nheader = sip_header_create("K", "nudge"); g_free(credential); fetion_sip_add_header(sip, aheader); fetion_sip_add_header(sip, theader); fetion_sip_add_header(sip, mheader); fetion_sip_add_header(sip, nheader); sip_text = fetion_sip_to_string(sip, NULL); hybrid_debug_info("feiton", "register to a new channel:\n%s", sip_text); if (send(sk, sip_text, strlen(sip_text), 0) == -1) { hybrid_debug_error("fetion", "register to new channel error."); g_free(sip_text); return HYBRID_ERROR; } g_free(sip_text); return HYBRID_OK; }
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; }