bool facebook_client::set_status(const std::string &status_text) { handle_entry( "set_status" ); std::string data = "post_form_id_source=AsyncRequest&post_form_id="; data += ( this->post_form_id_.length( ) ) ? this->post_form_id_ : "0"; data += "&fb_dtsg="; data += ( this->dtsg_.length( ) ) ? this->dtsg_ : "0"; data += "&target_id="; data += this->self_.user_id; if ( status_text.length( ) ) { data += "&action=PROFILE_UPDATE&app_id=&hey_kid_im_a_composer=true&display_context=profile&_log_display_context=profile&ajax_log=1&status="; data += utils::url::encode( status_text ); data += "&profile_id="; data += this->self_.user_id; } http::response resp = flap( FACEBOOK_REQUEST_STATUS_SET, &data ); validate_response(&resp); switch ( resp.code ) { case HTTP_CODE_OK: return handle_success( "set_status" ); case HTTP_CODE_FAKE_ERROR: case HTTP_CODE_FAKE_DISCONNECTED: default: return handle_error( "set_status" ); } }
bool facebook_client::feeds( ) { handle_entry( "feeds" ); // Get feeds http::response resp = flap( FACEBOOK_REQUEST_FEEDS ); // Process result data validate_response(&resp); switch ( resp.code ) { case HTTP_CODE_OK: if (resp.data.find("\"num_stories\":0") == std::string::npos) { std::string* response_data = new std::string( resp.data ); ForkThread( &FacebookProto::ProcessFeeds, this->parent, ( void* )response_data ); } return handle_success( "feeds" ); case HTTP_CODE_FAKE_ERROR: case HTTP_CODE_FAKE_DISCONNECTED: default: return handle_error( "feeds" ); } }
bool facebook_client::buddy_list( ) { handle_entry( "buddy_list" ); // Prepare update data std::string data = "user="******"&fetch_mobile=true&post_form_id=" + this->post_form_id_ + "&fb_dtsg=" + this->dtsg_ + "&lsd=&post_form_id_source=AsyncRequest&__user="******"&available_user_info_ids["; data += utils::conversion::to_string(&counter, UTILS_CONV_UNSIGNED_NUMBER); data += "]="; data += i->data->user_id; } } // Get buddy list http::response resp = flap( FACEBOOK_REQUEST_BUDDY_LIST, &data ); // Process result data validate_response(&resp); switch ( resp.code ) { case HTTP_CODE_OK: { std::string* response_data = new std::string( resp.data ); ForkThread( &FacebookProto::ProcessBuddyList, this->parent, ( void* )response_data ); return handle_success( "buddy_list" ); } case HTTP_CODE_FAKE_ERROR: case HTTP_CODE_FAKE_DISCONNECTED: default: return handle_error( "buddy_list" ); } }
bool facebook_client::reconnect( ) { handle_entry( "reconnect" ); // Request reconnect http::response resp = flap( FACEBOOK_REQUEST_RECONNECT ); // Process result data validate_response(&resp); switch ( resp.code ) { case HTTP_CODE_OK: { this->chat_channel_jslogger_ = utils::text::source_get_value( &resp.data, 2, "\"jslogger_suffix\":\"", "\"" ); parent->Log(" Got self channel jslogger: %s", this->chat_channel_jslogger_.c_str()); this->chat_channel_partition_ = utils::text::source_get_value2( &resp.data, "\"partition\":", ",}" ); parent->Log(" Got self channel partition: %s", this->chat_channel_partition_.c_str()); this->chat_channel_host_ = utils::text::source_get_value( &resp.data, 2, "\"host\":\"", "\"" ); parent->Log(" Got self channel host: %s", this->chat_channel_host_.c_str()); this->chat_sequence_num_ = utils::text::source_get_value2( &resp.data, "\"seq\":", ",}" ); parent->Log(" Got self sequence number: %s", this->chat_sequence_num_.c_str()); if (this->chat_channel_jslogger_.empty()) { if (!atoi(this->chat_channel_host_.substr(0, this->chat_channel_host_.find(".")).c_str())) { this->chat_channel_jslogger_ = "SOMETHING"; parent->Log(" Got no jslogger, changed."); } } return handle_success( "reconnect" ); } default: return handle_error( "reconnect", FORCE_DISCONNECT ); } }
bool facebook_client::load_friends( ) { handle_entry( "load_friends" ); // Get buddy list http::response resp = flap( FACEBOOK_REQUEST_LOAD_FRIENDS ); // Process result data validate_response(&resp); switch ( resp.code ) { case HTTP_CODE_OK: { std::string* response_data = new std::string( resp.data ); ForkThread( &FacebookProto::ProcessFriendList, this->parent, ( void* )response_data ); return handle_success( "load_friends" ); } case HTTP_CODE_FAKE_ERROR: case HTTP_CODE_FAKE_DISCONNECTED: default: return handle_error( "load_friends" ); } }
static void socket_readable(aeEventLoop *loop, int fd, void *data, int mask) { connection *c = data; thread *thread = c->thread; uint64_t now; ssize_t n; if ((n = read(fd, c->buf, sizeof(c->buf))) <= 0) goto error; c->buf[n] = '\0'; now = time_us(); if (!validate_response(c)) goto invalid; thread->bytes += n; thread->complete++; thread->requests++; stats_record(thread->latency, now - c->start); if (now >= thread->stop_at) { aeStop(thread->loop); close(c->fd); } else { reconnect_socket(c->thread, c); } return; invalid: c->thread->errors.validate++; reconnect_socket(c->thread, c); return; error: c->thread->errors.read++; reconnect_socket(c->thread, c); }
bool facebook_client::home( ) { handle_entry( "home" ); http::response resp = flap( FACEBOOK_REQUEST_HOME ); // Process result data validate_response(&resp); switch ( resp.code ) { case HTTP_CODE_OK: { if ( resp.data.find( "id=\"navAccountName\"" ) != std::string::npos ) { // Backup for old fb version // Get real_name this->self_.real_name = utils::text::remove_html( utils::text::special_expressions_decode( utils::text::source_get_value( &resp.data, 2, " id=\"navAccountName\">", "</a" ) ) ); DBWriteContactSettingUTF8String(NULL,parent->m_szModuleName,FACEBOOK_KEY_NAME,this->self_.real_name.c_str()); DBWriteContactSettingUTF8String(NULL,parent->m_szModuleName,FACEBOOK_KEY_NICK,this->self_.real_name.c_str()); parent->Log(" Got self real name: %s", this->self_.real_name.c_str()); } else if ( resp.data.find("id=\"pageNav\"") != std::string::npos ) { // Get real_name this->self_.real_name = utils::text::remove_html( utils::text::special_expressions_decode( utils::text::source_get_value( &resp.data, 3, " class=\"headerTinymanName\"", ">", "</a" ) ) ); DBWriteContactSettingUTF8String(NULL,parent->m_szModuleName,FACEBOOK_KEY_NAME,this->self_.real_name.c_str()); DBWriteContactSettingUTF8String(NULL,parent->m_szModuleName,FACEBOOK_KEY_NICK,this->self_.real_name.c_str()); parent->Log(" Got self real name: %s", this->self_.real_name.c_str()); } else { client_notify(TranslateT("Something happened to Facebook. Maybe there was some major update so you should wait for an update.")); return handle_error( "home", FORCE_DISCONNECT ); } // Get avatar std::string avatar = utils::text::source_get_value( &resp.data, 3, "class=\\\"fbxWelcomeBoxImg", "src=\\\"", "\\\"" ); if (avatar.empty()) avatar = utils::text::source_get_value( &resp.data, 3, "class=\"fbxWelcomeBoxImg", "src=\"", "\"" ); this->self_.image_url = utils::text::trim( utils::text::special_expressions_decode( avatar ) ); parent->Log(" Got self avatar: %s", this->self_.image_url.c_str()); parent->CheckAvatarChange(NULL, this->self_.image_url); // Get post_form_id this->post_form_id_ = utils::text::source_get_value( &resp.data, 3, "name=\"post_form_id\"", "value=\"", "\"" ); parent->Log(" Got self post form id: %s", this->post_form_id_.c_str()); // Get dtsg this->dtsg_ = utils::text::source_get_value( &resp.data, 3, "name=\"fb_dtsg\"", "value=\"", "\"" ); parent->Log(" Got self dtsg: %s", this->dtsg_.c_str()); // Get logout hash this->logout_hash_ = utils::text::source_get_value( &resp.data, 2, "<input type=\"hidden\" autocomplete=\"off\" name=\"h\" value=\"", "\"" ); parent->Log(" Got self logout hash: %s", this->logout_hash_.c_str()); // TODO: DIrectly get that friend requests // Get friend requests count and notify it std::string str_count = utils::text::source_get_value( &resp.data, 2, "<span id=\"requestsCountValue\">", "</span>" ); if ( str_count.length() && str_count != std::string( "0" ) ) { std::string message = Translate("Got new friend requests: ") + str_count; TCHAR* tmessage = mir_a2t(message.c_str()); parent->NotifyEvent( parent->m_tszUserName, tmessage, NULL, FACEBOOK_EVENT_OTHER, TEXT(FACEBOOK_URL_REQUESTS) ); mir_free( tmessage ); } if (!DBGetContactSettingByte(NULL,parent->m_szModuleName,FACEBOOK_KEY_PARSE_MESSAGES, DEFAULT_PARSE_MESSAGES)) { str_count = utils::text::source_get_value( &resp.data, 2, "<span id=\"messagesCountValue\">", "</span>" ); if ( str_count.length() && str_count != std::string( "0" ) ) { std::string message = Translate("Got new messages: ") + str_count; TCHAR* tmessage = mir_a2t(message.c_str()); parent->NotifyEvent( parent->m_tszUserName, tmessage, NULL, FACEBOOK_EVENT_OTHER, TEXT(FACEBOOK_URL_MESSAGES) ); mir_free( tmessage ); } } str_count = utils::text::source_get_value( &resp.data, 2, "<span id=\"notificationsCountValue\">", "</span>" ); if ( str_count.length() && str_count != std::string( "0" ) ) { // Parse notifications directly to popups ForkThread( &FacebookProto::ProcessNotifications, this->parent, NULL ); } if (DBGetContactSettingByte(NULL, parent->m_szModuleName, FACEBOOK_KEY_ENABLE_GROUPCHATS, DEFAULT_ENABLE_GROUPCHATS)) { // Get group chats std::string favorites = utils::text::source_get_value( &resp.data, 2, "<div id=\"leftCol\"", "<div id=\"contentCol\"" ); std::string::size_type pos = 0; while ((pos = favorites.find("href=\"/groups/",pos)) != std::string::npos) { pos += 14; std::string item = favorites.substr(pos, favorites.find("</a>", pos) - pos); std::string id = item.substr(0, item.find("/")); if (!id.empty()) { std::string name = utils::text::source_get_value( &item, 3, "class=\"linkWrap", ">", "</div>" ); name = utils::text::special_expressions_decode(utils::text::slashu_to_utf8( name ) ); parent->Log(" Got new group chat: %s (id: %s)", name.c_str(), id.c_str()); if (!name.empty()) parent->AddChat(id.c_str(), name.c_str()); } } } return handle_success( "home" ); } case HTTP_CODE_FOUND: // Work-around for replica_down, f**king hell what's that? parent->Log(" REPLICA_DOWN is back in force!"); return this->home(); default: return handle_error( "home", FORCE_DISCONNECT ); } }
bool facebook_client::login(const std::string &username,const std::string &password) { handle_entry( "login" ); username_ = username; password_ = password; // Access homepage to get initial cookies flap( FACEBOOK_REQUEST_HOME, NULL ); // Prepare login data std::string data = "charset_test=%e2%82%ac%2c%c2%b4%2c%e2%82%ac%2c%c2%b4%2c%e6%b0%b4%2c%d0%94%2c%d0%84&locale=en&email="; data += utils::url::encode( username ); data += "&pass="******"&pass_placeHolder=Password&login=Login&persistent=1"; // Send validation http::response resp = flap( FACEBOOK_REQUEST_LOGIN, &data ); // Process result data validate_response(&resp); if ( resp.code == HTTP_CODE_FOUND && resp.headers.find("Location") != resp.headers.end() ) { // Check whether some Facebook things are required if ( resp.headers["Location"].find("help.php") != std::string::npos ) { client_notify( TranslateT("Login error: Some Facebook things are required.") ); parent->Log(" ! ! Login error: Some Facebook things are required."); // return handle_error( "login", FORCE_DISCONNECT ); } // Check whether setting Machine name is required if ( resp.headers["Location"].find("/checkpoint/") != std::string::npos ) { resp = flap( FACEBOOK_REQUEST_SETUP_MACHINE ); std::string inner_data = "machine_name=MirandaIM&submit[Save%20Device]=Save%20Device"; inner_data += "&post_form_id="; inner_data += utils::text::source_get_value(&resp.data, 3, "name=\"post_form_id\"", "value=\"", "\"" ); inner_data += "&lsd="; inner_data += utils::text::source_get_value(&resp.data, 3, "name=\"lsd\"", "value=\"", "\"" ); inner_data += "&nh="; inner_data += utils::text::source_get_value(&resp.data, 3, "name=\"nh\"", "value=\"", "\"" ); resp = flap( FACEBOOK_REQUEST_SETUP_MACHINE, &inner_data ); validate_response(&resp); } } if ( resp.code == HTTP_CODE_FOUND && resp.headers.find("Location") != resp.headers.end() ) { // Check whether HTTPS connection is required and we don't have enabled it if (!this->https_) { if ( resp.headers["Location"].find("https://") != std::string::npos ) { client_notify(TranslateT("Your account requires HTTPS connection. Activating.")); DBWriteContactSettingByte(NULL, parent->m_szModuleName, FACEBOOK_KEY_FORCE_HTTPS, 1); this->https_ = true; } } } // Check for Device ID if ( cookies["datr"].length() ) DBWriteContactSettingString( NULL, parent->m_szModuleName, FACEBOOK_KEY_DEVICE_ID, cookies["datr"].c_str() ); switch ( resp.code ) { case HTTP_CODE_FAKE_DISCONNECTED: { // When is error only because timeout, try login once more if ( handle_error( "login" ) ) return login(username, password); else return false; } case HTTP_CODE_OK: // OK page returned, but that is regular login page we don't want in fact { // Check whether captcha code is required if ( resp.data.find("id=\"captcha\"") != std::string::npos ) { client_notify( TranslateT("Login error: Captcha code is required. Bad login credentials?") ); parent->Log(" ! ! Login error: Captcha code is required."); return handle_error( "login", FORCE_DISCONNECT ); } // Get error message std::string error_str = utils::text::trim( utils::text::special_expressions_decode( utils::text::remove_html( utils::text::edit_html( utils::text::source_get_value( &resp.data, 2, "id=\"standard_error\">", "</h2>" ) ) ) ) ); if ( !error_str.length() ) error_str = Translate("Unknown login error"); parent->Log(" ! ! Login error: %s", error_str.c_str()); std::string message = Translate("Login error: ") + error_str; TCHAR* tmessage = mir_a2t(message.c_str()); client_notify( tmessage ); mir_free( tmessage ); } case HTTP_CODE_FORBIDDEN: // Forbidden case HTTP_CODE_NOT_FOUND: // Not Found default: return handle_error( "login", FORCE_DISCONNECT ); case HTTP_CODE_FOUND: // Found and redirected to Home, Logged in, everything is OK if ( cookies.find("c_user") != cookies.end() ) { this->self_.user_id = cookies.find("c_user")->second; DBWriteContactSettingString(NULL,parent->m_szModuleName,FACEBOOK_KEY_ID,this->self_.user_id.c_str()); parent->Log(" Got self user id: %s", this->self_.user_id.c_str()); return handle_success( "login" ); } else { client_notify(TranslateT("Login error, probably bad login credentials.")); parent->Log(" ! ! Login error, probably bad login credentials."); return handle_error( "login", FORCE_DISCONNECT ); } } }
http::response facebook_client::flap( const int request_type, std::string* request_data, std::string* request_get_data ) { NETLIBHTTPREQUEST nlhr = {sizeof( NETLIBHTTPREQUEST )}; nlhr.requestType = choose_method( request_type ); std::string url = choose_request_url( request_type, request_data, request_get_data ); nlhr.szUrl = (char*)url.c_str( ); nlhr.flags = NLHRF_HTTP11 | NLHRF_NODUMP | choose_security_level( request_type ); nlhr.headers = get_request_headers( request_type, &nlhr.headersCount ); switch (request_type) { case FACEBOOK_REQUEST_MESSAGES_RECEIVE: nlhr.timeout = 1000 * 65; break; case FACEBOOK_REQUEST_MESSAGE_SEND: nlhr.timeout = 1000 * 10; break; default: nlhr.timeout = 1000 * 15; break; } if ( request_data != NULL ) { nlhr.pData = (char*)(*request_data).c_str(); nlhr.dataLength = (int)request_data->length( ); } parent->Log("@@@@@ Sending request to '%s'", nlhr.szUrl); switch ( request_type ) { case FACEBOOK_REQUEST_LOGIN: nlhr.nlc = NULL; break; case FACEBOOK_REQUEST_MESSAGES_RECEIVE: nlhr.nlc = hMsgCon; nlhr.flags |= NLHRF_PERSISTENT; break; default: WaitForSingleObject(fcb_conn_lock_, INFINITE); nlhr.nlc = hFcbCon; nlhr.flags |= NLHRF_PERSISTENT; break; } NETLIBHTTPREQUEST* pnlhr = ( NETLIBHTTPREQUEST* )CallService( MS_NETLIB_HTTPTRANSACTION, (WPARAM)handle_, (LPARAM)&nlhr ); utils::mem::detract(nlhr.headers[3].szValue); utils::mem::detract(nlhr.headers); http::response resp; switch ( request_type ) { case FACEBOOK_REQUEST_LOGIN: case FACEBOOK_REQUEST_SETUP_MACHINE: break; case FACEBOOK_REQUEST_MESSAGES_RECEIVE: hMsgCon = pnlhr ? pnlhr->nlc : NULL; break; default: ReleaseMutex(fcb_conn_lock_); hFcbCon = pnlhr ? pnlhr->nlc : NULL; break; } if ( pnlhr != NULL ) { parent->Log("@@@@@ Got response with code %d", pnlhr->resultCode); store_headers( &resp, pnlhr->headers, pnlhr->headersCount ); resp.code = pnlhr->resultCode; resp.data = pnlhr->pData ? pnlhr->pData : ""; CallService(MS_NETLIB_FREEHTTPREQUESTSTRUCT, 0, (LPARAM)pnlhr); } else { parent->Log("!!!!! No response from server (time-out)"); resp.code = HTTP_CODE_FAKE_DISCONNECTED; // Better to have something set explicitely as this value // is compaired in all communication requests } if (DBGetContactSettingByte( NULL, parent->m_szModuleName, FACEBOOK_KEY_VALIDATE_RESPONSE, 0 ) == 1) validate_response(&resp); return resp; }
bool facebook_client::send_message( std::string message_recipient, std::string message_text, std::string *error_text, bool use_inbox ) { handle_entry( "send_message" ); http::response resp; if (parent->isInvisible() || use_inbox) { // Use inbox send message when invisible std::string data = "action=send&body="; data += utils::url::encode( message_text ); data += "&recipients[0]="; data += message_recipient; data += "&lsd=&fb_dtsg="; data += ( dtsg_.length( ) ) ? dtsg_ : "0"; data += "&post_form_id="; data += ( post_form_id_.length( ) ) ? post_form_id_ : "0"; resp = flap( FACEBOOK_REQUEST_ASYNC, &data ); } else { // Use standard send message std::string data = "msg_text="; data += utils::url::encode( message_text ); data += "&msg_id="; data += utils::time::mili_timestamp( ); data += "%3A"; data += utils::time::unix_timestamp( ); data += "&to="; data += message_recipient; data += "&__user="******"&client_time="; data += utils::time::mili_timestamp( ); data += "&pvs_time&fb_dtsg="; data += ( dtsg_.length( ) ) ? dtsg_ : "0"; data += "&to_offline=false&to_idle=false&lsd&post_form_id_source=AsyncRequest&num_tabs=1"; data += "&window_id=0&sidebar_launched=false&sidebar_enabled=false&sidebar_capable=false&sidebar_should_show=false&sidebar_visible=false"; data += "&post_form_id="; data += ( post_form_id_.length( ) ) ? post_form_id_ : "0"; resp = flap( FACEBOOK_REQUEST_MESSAGE_SEND, &data ); } validate_response(&resp); *error_text = resp.error_text; switch ( resp.error_number ) { case 0: // Everything is OK break; //case 1356002: // You are offline - wtf?? case 1356003: // Contact is offline { HANDLE hContact = parent->ContactIDToHContact( message_recipient ); if (hContact != NULL) DBWriteContactSettingWord(hContact,parent->m_szModuleName,"Status",ID_STATUS_OFFLINE); return false; } break; case 1356026: // Contact has alternative client { client_notify(TranslateT("Need confirmation for sending messages to other clients.\nOpen facebook website and try to send message to this contact again!")); /* post na url http://www.facebook.com/ajax/chat/post_application_settings.php?__a=1 enable_and_send Povolit a odeslat to_send AQCoweMPeszBoKpd4iahcOyhmh0kiTYIhv1b5wCtuBiD0AaPVZIdEp3Pf5JMBmQ-9wf0ju-xdi-VRuk0ERk_I7XzI5dVJCs6-B0FExTZhspD-4-kTZLmZI-_M6fIuF2328yMyT3R3UEUmMV8P9MHcZwu-_pS3mOhsaHf6rIVcQ2rocSqLKi03wLKCfg0m8VsptPADWpOI-UNcIo-xl1PAoC1yVnL2wEXEtnF1qI_xFcmlJZ40AOONfIF_LS_lBrGYA-oCWLUK-GLHtQAHjO8aDeNXDU8Jk7Z_ES-_oAHee2PVLHcG_ACHXpasE7Iu3XFLMrdN2hjM96AjPRIf0Vk8gBZzfW_lUspakZmXxMI7iSNQE8lourK_6B3Z1s4UHxDZCNXYuc9gh70nm_xnaxnF9K1bR00s4MltnFjUT_3ypThzA __d 1 post_form_id c73ebd9d94b7449c40e6965410fcdcf6 fb_dtsg Tb-T9 lsd post_form_id_source AsyncRequest */ return false; } break; default: // Other error return false; } switch ( resp.code ) { case HTTP_CODE_OK: return handle_success( "send_message" ); case HTTP_CODE_FAKE_ERROR: case HTTP_CODE_FAKE_DISCONNECTED: default: *error_text = Translate("Timeout when sending message."); handle_error( "send_message" ); return false; } }
bool facebook_client::channel( ) { handle_entry( "channel" ); // Get update http::response resp = flap( FACEBOOK_REQUEST_MESSAGES_RECEIVE ); // Process result data validate_response(&resp); if ( resp.code != HTTP_CODE_OK ) { // Something went wrong } else if ( resp.data.find( "\"t\":\"continue\"" ) != std::string::npos ) { // Everything is OK, no new message received } else if ( resp.data.find( "\"t\":\"fullReload\"" ) != std::string::npos ) { // Something went wrong (server flooding?) parent->Log("! ! ! Requested full reload"); this->chat_sequence_num_ = utils::text::source_get_value2( &resp.data, "\"seq\":", ",}" ); parent->Log(" Got self sequence number: %s", this->chat_sequence_num_.c_str()); this->chat_reconnect_reason_ = utils::text::source_get_value2( &resp.data, "\"reason\":", ",}" ); parent->Log(" Reconnect reason: %s", this->chat_reconnect_reason_.c_str()); } else if ( resp.data.find( "\"t\":\"refresh\"" ) != std::string::npos ) { // Something went wrong (server flooding?) parent->Log("! ! ! Requested channel refresh"); this->chat_reconnect_reason_ = utils::text::source_get_value2( &resp.data, "\"reason\":", ",}" ); parent->Log(" Reconnect reason: %s", this->chat_reconnect_reason_.c_str()); this->chat_sequence_num_ = utils::text::source_get_value2( &resp.data, "\"seq\":", ",}" ); parent->Log(" Got self sequence number: %s", this->chat_sequence_num_.c_str()); return this->reconnect( ); } else { // Something has been received, throw to new thread to process std::string* response_data = new std::string( resp.data ); ForkThread( &FacebookProto::ProcessMessages, this->parent, ( void* )response_data ); // Increment sequence number this->chat_sequence_num_ = utils::text::source_get_value2( &resp.data, "\"seq\":", ",}" ); parent->Log(" Got self sequence number: %s", this->chat_sequence_num_.c_str()); } // Return switch ( resp.code ) { case HTTP_CODE_OK: return handle_success( "channel" ); case HTTP_CODE_FAKE_DISCONNECTED: case HTTP_CODE_FAKE_ERROR: default: // Testing workaround for channel change if (!this->chat_channel_jslogger_.empty()) this->chat_channel_jslogger_ = "_"; else this->chat_channel_jslogger_.clear(); return handle_error( "channel" ); } }