static gint hybrid_blist_cache_init(HybridConfig *config) { gchar *cache_file_name; HybridBlistCache *cache; xmlnode *root; gint err; g_return_val_if_fail(config != NULL, HYBRID_ERROR); cache_file_name = g_strdup_printf("%s/blist.xml", config->config_path); hybrid_debug_info("config", "init the blist cache from %s", cache_file_name); cache = g_new0(HybridBlistCache, 1); cache->cache_file_name = cache_file_name; config->blist_cache = cache; if (!(root = xmlnode_root_from_file(cache_file_name))) { const gchar *root_string = "<blist></blist>"; root = xmlnode_root(root_string, strlen(root_string)); cache->root = root; goto blist_cache_init_null; } if (!root) { hybrid_debug_error("config", "FATAL, init blist cache"); return HYBRID_ERROR; } cache->root = root; /* Load the cached buddy list */ goto blist_cache_init_fin; blist_cache_init_null: /* initialize the xml context since we don't have local cache */ xmlnode_new_child(root, "accounts"); xmlnode_save_file(root, cache->cache_file_name); blist_cache_init_fin: /* initialize the icon path. */ config->icon_path = g_strdup_printf("%s/icons", config->config_path); err = mkdir(config->icon_path, S_IRWXU|S_IRWXO|S_IRWXG); if (err && access(config->icon_path, R_OK|W_OK)) { hybrid_debug_error("config", "%s,cannot create, read or write", config->icon_path); g_free(config->icon_path); return HYBRID_ERROR; } return HYBRID_OK; }
static gboolean stream_recv_cb(gint sk, XmppStream *stream) { gchar buf[BUF_LENGTH]; gint n; if (!stream->ssl) { if ((n = recv(sk, buf, sizeof(buf) - 1, 0)) == -1) { hybrid_debug_error("xmpp", "init stream error."); return FALSE; } } else { if ((n = hybrid_ssl_read(stream->ssl, buf, sizeof(buf) - 1)) == -1) { hybrid_debug_error("xmpp", "stream read io error."); return TRUE; } else if (0 == n) { hybrid_debug_error("xmpp", "connection closed by server."); return FALSE; } } buf[n] = '\0'; if (n > 0) { xmpp_process_pushed(stream, buf, n); } return TRUE; }
HybridConnection* hybrid_proxy_connect(const gchar *hostname, gint port, connect_callback func, gpointer user_data) { gint sk; struct sockaddr addr; HybridConnection *conn; g_return_val_if_fail(port != 0, NULL); g_return_val_if_fail(hostname != NULL, NULL); hybrid_debug_info("connect", "connecting to %s:%d", hostname, port); conn = g_new0(HybridConnection, 1); if ((sk = socket(AF_INET, SOCK_STREAM, 0)) == -1) { hybrid_debug_error("connect", "create socket: %s", strerror(errno)); hybrid_connection_destroy(conn); return NULL; } if (nonblock(sk) != HYBRID_OK) { hybrid_connection_destroy(conn); return NULL; } if (addr_init(hostname, port, &addr) != HYBRID_OK) { hybrid_connection_destroy(conn); return NULL; } if (connect(sk, &addr, sizeof(addr)) != 0) { if (errno != EINPROGRESS) { hybrid_debug_error("connect", "connect to \'%s:%d\':%s", hostname, port, strerror(errno)); hybrid_connection_destroy(conn); return NULL; } hybrid_debug_info("connect", "connect in progress"); hybrid_event_add(sk, HYBRID_EVENT_WRITE, func, user_data); } else { /* connection establish imediately */ func(sk, user_data); } conn->sk = sk; conn->host = g_strdup(hostname); conn->port = port; return conn; }
/** * 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; }
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); }
gint fetion_buddy_rename(fetion_account *ac, const gchar *userid, const gchar *newname) { fetion_sip *sip; sip_header *eheader; gchar *res; gchar *body; g_return_val_if_fail(ac != NULL, HYBRID_ERROR); g_return_val_if_fail(userid != NULL, HYBRID_ERROR); g_return_val_if_fail(newname != NULL, HYBRID_ERROR); sip = ac->sip; fetion_sip_set_type(sip, SIP_SERVICE); eheader = sip_event_header_create(SIP_EVENT_SETCONTACTINFO); fetion_sip_add_header(sip , eheader); body = generate_rename_buddy_body(userid, newname); res = fetion_sip_to_string(sip, body); g_free(body); if (send(ac->sk, res, strlen(res), 0) == -1) { hybrid_debug_error("fetion", "rename buddy %s", userid); return HYBRID_ERROR; } g_free(res); return HYBRID_OK; }
gint hybrid_get_http_length(const gchar *http_response) { gchar *pos, *stop; gchar *temp; gint length; const gchar *cur = "Content-Length: "; g_return_val_if_fail(http_response != NULL, 0); if (!(pos = g_strrstr(http_response, cur))) { hybrid_debug_error("http", "no Content-length in response header."); return 0; } pos += strlen(cur); for (stop = pos; *stop && *stop != '\r'; stop ++); temp = g_strndup(pos, stop - pos); length = atoi(temp); g_free(temp); return length; }
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; }
/** * Create a new SSL struct with certificates loaded. */ static SSL* ssl_new_with_certs(SSL_CTX *ctx) { SSL *ssl; g_return_val_if_fail(ctx != NULL, NULL); if(SSL_CTX_use_certificate_file(ctx, CCERT_DIR"/client_cert", SSL_FILETYPE_PEM) <= 0) { ERR_print_errors_fp(stderr); } if(SSL_CTX_use_PrivateKey_file(ctx, CCERT_DIR"/client_key", SSL_FILETYPE_PEM) <= 0) { ERR_print_errors_fp(stderr); } if (!SSL_CTX_load_verify_locations(ctx, NULL, CERTS_DIR)) { ERR_print_errors_fp(stderr); } if (!(ssl = SSL_new(ctx))) { hybrid_debug_error("ssl", "create SSl:%s", ERR_reason_error_string(ERR_get_error())); return NULL; } return ssl; }
gint hybrid_logs_init(void) { const gchar *config_path; gchar *log_path; gint e; config_path = hybrid_config_get_path(); log_path = g_strdup_printf("%s/logs/", config_path); e = mkdir(log_path, S_IRWXU|S_IRWXO|S_IRWXG); if (e && access(log_path, R_OK|W_OK)) { hybrid_debug_error("logs", "%s,cannot create, read or write", log_path); g_free(log_path); return HYBRID_ERROR; } g_free(log_path); return HYBRID_OK; }
gint xmpp_message_send(XmppStream *stream, const gchar *text, const gchar *to) { xmlnode *root; xmlnode *node; gchar *xml_string; g_return_val_if_fail(stream != NULL, HYBRID_ERROR); g_return_val_if_fail(text != 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"); node = xmlnode_new_child(root, "body"); xmlnode_set_content(node, text); 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 new-chat connecting event. * The message is: * * R fetion.com.cn SIP-C/4.0 * F: 547264589 * I: 5 * Q: 2 R * A: TICKS auth="2051600954.830102111" * K: text/html-fragment * K: multiparty * K: nudge */ static gint invite_connect_cb(gint sk, gpointer user_data) { fetion_transaction *trans; fetion_account *account; fetion_sip *sip; invite_data *data; gchar *credential; gchar *sip_text; sip_header *aheader; sip_header *theader; sip_header *mheader; sip_header *nheader; data = (invite_data*)user_data; trans = data->trans; credential = data->credential; account = trans->data; g_free(data); sip = account->sip; account->sk = sk; /* listen for this thread */ account->source = hybrid_event_add(sk, HYBRID_EVENT_READ, hybrid_push_cb, account); 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"); transaction_set_callid(trans, sip->callid); transaction_set_callback(trans, chat_reg_cb); transaction_add(account, trans); 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("fetion", "register, send:\n%s", sip_text); if (send(sk, sip_text, strlen(sip_text), 0) == -1) { hybrid_debug_error("fetion", "register to the new chat channel failed"); return HYBRID_ERROR; } g_free(sip_text); g_free(credential); return HYBRID_OK; }
gint hybrid_imap_auth(hybrid_imap *imap) { gchar *cmd; HybridSslConnection *ssl; ssl = imap->ssl; cmd = g_strdup_printf("A%d LOGIN %s %s\r\n", imap->current_tag, imap->username, imap->password); hybrid_debug_info("imap", "send:\n%s", cmd); imap_trans_create(imap, imap_auth_cb, NULL); if (hybrid_ssl_write(ssl, cmd, strlen(cmd)) <= 0) { hybrid_debug_error("imap", "write to IMAP ssl connection error."); g_free(cmd); return HYBRID_ERROR; } g_free(cmd); return HYBRID_OK; }
void hybrid_conv_got_status(HybridAccount *account, const gchar *buddy_id, const gchar *text, gint type) { HybridChatWindow *chat; HybridBuddy *buddy; g_return_if_fail(account != NULL); g_return_if_fail(buddy_id != NULL); if (!(buddy = hybrid_blist_find_buddy(account, buddy_id))) { hybrid_debug_error("conv", "buddy doesn't exist."); return; } if (!(chat = hybrid_conv_find_chat(buddy_id))) { /* * Well, we haven't find an existing chat panel so far, check the type * to determine whether to create a new one. */ if (type == MSG_NOTIFICATION_INPUT) { return; } else { chat = hybrid_chat_window_create(account, buddy->id, HYBRID_CHAT_PANEL_SYSTEM); } } if (type == MSG_NOTIFICATION_INPUT) { text_ops->notify(chat->textview, text, MSG_NOTIFICATION_INPUT); } }
static gboolean ping_timeout_cb(XmppStream *stream) { hybrid_debug_error("xmpp", "ping timeout"); return FALSE; }
void hybrid_conv_clear_input(HybridAccount *account, const gchar *buddy_id) { HybridBuddy *buddy; HybridChatWindow *chat; g_return_if_fail(account != NULL); g_return_if_fail(buddy_id != NULL); if (!(buddy = hybrid_blist_find_buddy(account, buddy_id))) { hybrid_debug_error("conv", "buddy doesn't exist."); return; } if (!(chat = hybrid_conv_find_chat(buddy_id))) { return; } if (chat->input_source) { g_source_remove(chat->input_source); } text_ops->notify(chat->textview, "" , MSG_NOTIFICATION_INPUT); }
gboolean check_mail_cb(hybrid_imap *imap, const gchar *msg, gpointer user_data) { const gchar *pos; const gchar *cur; gchar *count_str; gint count_int; hybrid_debug_info("imap", "recv:\n%s", msg); if (HYBRID_OK == check_resp_ok(msg)) { if ((pos = strstr(msg, "UNSEEN "))) { pos += 7; for (cur = pos; '\0' != *cur && ')' != *cur; cur ++); if ('\0' != *cur) { count_str = g_strndup(pos, cur - pos); count_int = atoi(count_str); g_free(count_str); process_unread_mails(imap, count_int); } } } else { hybrid_debug_error("imap", "check unread mail error."); } imap->mail_check_source = g_timeout_add_seconds(imap->mail_check_interval, check_mail, imap); return FALSE; }
gint hybrid_pref_init(void) { const gchar *body; gchar *config_path; hybrid_pref = g_new0(HybridPref, 1); if (!(config_path = hybrid_config_get_path())) { hybrid_debug_error("pref", "get config path error."); return HYBRID_ERROR; } hybrid_pref->filename = g_strdup_printf("%s/pref.xml", config_path); g_free(config_path); if (!(hybrid_pref->root = xmlnode_root_from_file(hybrid_pref->filename))) { body = "<pref></pref>"; hybrid_pref->root = xmlnode_root(body, strlen(body)); hybrid_pref_save(); } return HYBRID_OK; }
gchar* hybrid_pref_get_string(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 NULL; } if (!xmlnode_has_prop(node, "type")) { hybrid_debug_info("pref", "invalid pref node."); return NULL; } type = xmlnode_prop(node, "type"); if (g_strcmp0(type, "string") != 0) { hybrid_debug_error("pref", "string pref node with a type which is not string."); return NULL; } value = xmlnode_content(node); return value; }
/** * Process the user left message, we close the current channel, * and remove the session from the session list. */ static void process_left_cb(fetion_account *ac, const gchar *sipmsg) { extern GSList *channel_list; GSList *pos; g_return_if_fail(ac != NULL); g_return_if_fail(sipmsg != NULL); hybrid_debug_info("fetion", "buddy left, recv:\n%s", sipmsg); for (pos = channel_list; pos; pos = pos->next) { if (pos->data == ac) { channel_list = g_slist_remove(channel_list, ac); goto channel_removed; } } hybrid_debug_error("fetion", "FATAL, can't find channel"); return; channel_removed: /* remove the read event source. */ g_source_remove(ac->source); /* close the channel. */ close(ac->sk); /* destroy the account. */ fetion_account_destroy(ac); }
static void create_account_menus(GtkUIManager *ui) { GtkWidget *account_shell; GtkWidget *seperator; HybridAccount *account; GSList *pos; if (!(account_shell = gtk_ui_manager_get_widget(ui, "/MenuBar/Account"))) { hybrid_debug_error("core", "account menu init err"); return; } account_shell = gtk_menu_item_get_submenu(GTK_MENU_ITEM(account_shell)); if (account_list) { seperator = gtk_separator_menu_item_new(); gtk_menu_shell_insert(GTK_MENU_SHELL(account_shell), seperator, 2); } for (pos = account_list; pos; pos = pos->next) { /* set the name of the account menu. */ account = (HybridAccount*)pos->data; hybrid_account_create_menu(account); } }
/** * 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; }
gchar* hybrid_config_get_path(void) { gchar *home; static gchar *config_path = NULL; static gchar *hybrid_path = NULL; gint e; if (hybrid_path) goto check_hybrid; if (config_path) goto check_conf; if (!(config_path = getenv("XDG_CONFIG_HOME"))) { if (!(home = getenv("HOME"))) { hybrid_debug_error("config", "No environment variable " "named HOME\n"); return NULL; } config_path = g_strdup_printf("%s/.config", home); } else { config_path = g_strdup_printf("%s", config_path); } check_conf: e = mkdir(config_path, S_IRWXU|S_IRWXO|S_IRWXG); if (e && access(config_path, R_OK|W_OK)) { hybrid_debug_error("config", "cannot create, read from or write to %s", config_path); g_free(config_path); config_path = NULL; return NULL; } hybrid_path = g_strdup_printf("%s/hybrid", config_path); check_hybrid: e = mkdir(hybrid_path, S_IRWXU|S_IRWXO|S_IRWXG); if (e && access(hybrid_path, R_OK|W_OK)) { hybrid_debug_error("config", "cannot create, read from or write to %s", hybrid_path); g_free(hybrid_path); hybrid_path = NULL; return NULL; } return hybrid_path; }
/** * 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; }
/** * Callback function of the save button click signal. */ static void save_cb(GtkWidget *widget, HybridGroupAddWindow *window) { GtkTreeModel *model; GtkTreeIter iter; HybridAccount *account; HybridModule *proto; HybridIMOps *ops; const gchar *name; model = gtk_combo_box_get_model(GTK_COMBO_BOX(window->account_combo)); if (!gtk_combo_box_get_active_iter( GTK_COMBO_BOX(window->account_combo), &iter)) { hybrid_debug_error("groupadd", "no account was choosed."); return; } gtk_tree_model_get(model, &iter, GROUPADD_ACCOUNT_COLUMN, &account, -1); name = gtk_entry_get_text(GTK_ENTRY(window->name_entry)); if (!name || *name == '\0') { hybrid_debug_error("groupadd", "no group name was specified."); return; } proto = account->proto; ops = proto->info->im_ops; /* call the protocol hook function. */ if (ops->group_add) { ops->group_add(account, name); } /* destroy the groupadd window. */ gtk_widget_destroy(window->window); }
gint resolve_host(const gchar *hostname, gchar *ip) { g_return_val_if_fail(hostname != NULL, HYBRID_ERROR); struct addrinfo *result; struct sockaddr_in *addr; gchar *hash_value; 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\'", 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; } addr = (struct sockaddr_in*)result->ai_addr; if (!inet_ntop(AF_INET, (void*)&addr->sin_addr, ip, 16)) { hybrid_debug_error("dns", "reslove host \'%s\' failed when" " transforming binary ip address to doted ip address", hostname); return HYBRID_ERROR; } 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\'", hostname, ip); return HYBRID_OK; }
gchar* hybrid_config_get_path(void) { gchar *home; gchar *config_path; gchar *hybrid_path; gint e; if (!(home = getenv("HOME"))) { hybrid_debug_error("config", "No environment variable named HOME\n"); return NULL; } config_path = g_strdup_printf("%s/.config", home); e = mkdir(config_path, S_IRWXU|S_IRWXO|S_IRWXG); if (e && access(config_path, R_OK|W_OK)) { hybrid_debug_error("config", "%s,cannot create, read or write", config_path); g_free(config_path); return NULL; } hybrid_path = g_strdup_printf("%s/hybrid", config_path); e = mkdir(hybrid_path, S_IRWXU|S_IRWXO|S_IRWXG); if (e && access(hybrid_path, R_OK|W_OK)) { hybrid_debug_error("config", "%s,cannot create, read or write", hybrid_path); g_free(config_path); g_free(hybrid_path); return NULL; } g_free(config_path); return hybrid_path; }
gboolean portrait_conn_cb(gint sk, gpointer user_data) { portrait_data *data = (portrait_data*)user_data; portrait_trans *trans; gchar *http_string; gchar *encoded_sipuri; gchar *encoded_ssic; gchar *uri; trans = g_new0(portrait_trans, 1); trans->buddy = data->buddy; trans->ac = data->ac; trans->portrait_type = data->portrait_type; g_free(data); if (trans->portrait_type == PORTRAIT_TYPE_BUDDY) { encoded_sipuri = g_uri_escape_string(trans->buddy->sipuri, NULL, TRUE); } else { encoded_sipuri = g_uri_escape_string(trans->ac->sipuri, NULL, TRUE); } encoded_ssic = g_uri_escape_string(trans->ac->ssic, NULL, TRUE); uri = g_strdup_printf("/%s/getportrait.aspx", trans->ac->portrait_host_path); http_string = g_strdup_printf("GET %s?Uri=%s" "&Size=120&c=%s HTTP/1.1\r\n" "User-Agent: IIC2.0/PC "PROTO_VERSION"\r\n" "Accept: image/pjpeg;image/jpeg;image/bmp;" "image/x-windows-bmp;image/png;image/gif\r\n" "Host: %s\r\nConnection: Close\r\n\r\n", uri, encoded_sipuri, encoded_ssic, trans->ac->portrait_host_name); g_free(encoded_sipuri); g_free(encoded_ssic); g_free(uri); if (send(sk, http_string, strlen(http_string), 0) == -1) { hybrid_debug_error("fetion", "download portrait for \'%s\':%s", trans->buddy->sid, strerror(errno)); g_free(http_string); return FALSE; } g_free(http_string); hybrid_event_add(sk, HYBRID_EVENT_READ, portrait_recv_cb, trans); return FALSE; }
/** * Process the iq messages. */ static void xmpp_stream_process_iq(XmppStream *stream, xmlnode *node) { gchar *id; gint id_int; GSList *pos; IqTransaction *trans; gchar *value; g_return_if_fail(stream != NULL); g_return_if_fail(node != NULL); if (!xmlnode_has_prop(node, "type") || !xmlnode_has_prop(node, "id")) { hybrid_debug_error("xmpp", "invalid iq message."); return; } value = xmlnode_prop(node, "type"); /* response to a get or set request. */ if (g_strcmp0(value, "result") == 0 || g_strcmp0(value, "error") == 0) { id = xmlnode_prop(node, "id"); id_int = atoi(id); g_free(id); for (pos = stream->pending_trans; pos; pos = pos->next) { trans = (IqTransaction*)pos->data; if (trans->iq_id == id_int) { if (trans->callback) { trans->callback(stream, node, trans->user_data); } iq_transaction_remove(stream, trans); } } /* * An entity that receives an IQ request of type "get" or "set" MUST reply with an IQ response of type "result" or "error". */ } else if (g_strcmp0(value, "get") == 0) { /* process later. */ } else if (g_strcmp0(value, "set") == 0) { xmpp_stream_process_iq_set(stream, node); } g_free(value); }
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; }