void Skype_login (account_t* account) { im_connection* connection = imcb_new(account); SkypeData* skype = g_new0(struct SkypeData, 1); connection->proto_data = skype; imcb_log(connection, "Connecting"); skype->ssl = ssl_connect( set_getstr(&account->set, "server"), set_getint(&account->set, "port"), Skype_connected, connection ); skype->fd = skype->ssl ? ssl_getfd(skype->ssl) : -1; skype->username = g_strdup(account->user); skype->connection = connection; if (set_getbool(&account->set, "skypeconsole")) { imcb_add_buddy(connection, "skypeconsole", NULL); } }
static void twitter_main_loop_start(struct im_connection *ic) { struct twitter_data *td = ic->proto_data; /* Create the room now that we "logged in". */ if (td->flags & TWITTER_MODE_CHAT) twitter_groupchat_init(ic); imcb_log(ic, "Getting initial statuses"); // Run this once. After this queue the main loop function (or open the // stream if available). twitter_main_loop(ic, -1, 0); if (set_getbool(&ic->acc->set, "stream")) { /* That fetch was just to get backlog, the stream will give us the rest. \o/ */ twitter_open_stream(ic); /* Stream sends keepalives (empty lines) or actual data at least twice a minute. Disconnect if this stops. */ ic->flags |= OPT_PONGS; } else { /* Not using the streaming API, so keep polling the old- fashioned way. :-( */ td->main_loop_id = b_timeout_add(set_getint(&ic->acc->set, "fetch_interval") * 1000, twitter_main_loop, ic); } }
static void purple_login(account_t *acc) { struct im_connection *ic = imcb_new(acc); struct purple_data *pd; if ((local_bee != NULL && local_bee != acc->bee) || (global.conf->runmode == RUNMODE_DAEMON && !getenv("BITLBEE_DEBUG"))) { imcb_error(ic, "Daemon mode detected. Do *not* try to use libpurple in daemon mode! " "Please use inetd or ForkDaemon mode instead."); imc_logout(ic, FALSE); return; } local_bee = acc->bee; /* For now this is needed in the _connected() handlers if using GLib event handling, to make sure we're not handling events on dead connections. */ purple_connections = g_slist_prepend(purple_connections, ic); ic->proto_data = pd = g_new0(struct purple_data, 1); pd->account = purple_account_new(acc->user, (char *) acc->prpl->data); pd->input_requests = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, g_free); pd->next_request_id = 0; purple_account_set_password(pd->account, acc->pass); purple_sync_settings(acc, pd->account); purple_account_set_enabled(pd->account, "BitlBee", TRUE); if (set_getbool(&acc->set, "mail_notifications") && set_getstr(&acc->set, "mail_notifications_handle")) { imcb_add_buddy(ic, set_getstr(&acc->set, "mail_notifications_handle"), NULL); } }
/* * In AIM 3.5 protocol, the first stage of login is to request login from the * Authorizer, passing it the screen name for verification. If the name is * invalid, a 0017/0003 is spit back, with the standard error contents. If * valid, a 0017/0007 comes back, which is the signal to send it the main * login command (0017/0002). * */ int aim_request_login(aim_session_t *sess, aim_conn_t *conn, const char *sn) { aim_frame_t *fr; aim_snacid_t snacid; aim_tlvlist_t *tl = NULL; struct im_connection *ic = sess->aux_data; if (!sess || !conn || !sn) { return -EINVAL; } if (g_ascii_isdigit(sn[0]) && set_getbool(&ic->acc->set, "old_icq_auth")) { return goddamnicq(sess, conn, sn); } sess->flags |= AIM_SESS_FLAGS_SNACLOGIN; aim_sendflapver(sess, conn); if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10 + 2 + 2 + strlen(sn)))) { return -ENOMEM; } snacid = aim_cachesnac(sess, 0x0017, 0x0006, 0x0000, NULL, 0); aim_putsnac(&fr->data, 0x0017, 0x0006, 0x0000, snacid); aim_addtlvtochain_raw(&tl, 0x0001, strlen(sn), (guint8 *) sn); aim_writetlvchain(&fr->data, &tl); aim_freetlvchain(&tl); aim_tx_enqueue(sess, fr); return 0; }
void imcb_notify_email(struct im_connection *ic, char *format, ...) { const char *handle; va_list params; char *msg; if (!set_getbool(&ic->acc->set, "mail_notifications")) { return; } va_start(params, format); msg = g_strdup_vprintf(format, params); va_end(params); /* up to the protocol to set_add this if they want to use this */ handle = set_getstr(&ic->acc->set, "mail_notifications_handle"); if (handle != NULL) { imcb_buddy_msg(ic, handle, msg, 0, 0); } else { imcb_log(ic, "%s", msg); } g_free(msg); }
static int twitter_buddy_msg(struct im_connection *ic, char *who, char *message, int away) { struct twitter_data *td = ic->proto_data; int plen = strlen(td->prefix); if (g_strncasecmp(who, td->prefix, plen) == 0 && who[plen] == '_' && g_strcasecmp(who + plen + 1, ic->acc->user) == 0) { if (set_getbool(&ic->acc->set, "oauth") && td->oauth_info && td->oauth_info->token == NULL) { char pin[strlen(message) + 1], *s; strcpy(pin, message); for (s = pin + sizeof(pin) - 2; s > pin && isspace(*s); s--) *s = '\0'; for (s = pin; *s && isspace(*s); s++) { } if (!oauth_access_token(s, td->oauth_info)) { imcb_error(ic, "OAuth error: %s", "Failed to send access token request"); imc_logout(ic, TRUE); return FALSE; } } else twitter_handle_command(ic, message); } else { twitter_direct_messages_new(ic, who, message); } return (0); }
gboolean Skype_begin (im_connection* connection) { SkypeData* skype = connection->proto_data; int result; if (!skype) { return FALSE; } skype->bfd = b_input_add(skype->fd, B_EV_IO_READ, Skype_loop, connection); /* Identifying */ Skype_printf(connection, "USERNAME %s\n", connection->acc->user); Skype_printf(connection, "PASSWORD %s\n", connection->acc->pass); result = Skype_printf(connection, "SEARCH FRIENDS\n"); Skype_printf(connection, "SET USERSTATUS ONLINE\n"); if (set_getbool(&connection->acc->set, "auto_join")) { Skype_printf(connection, "SEARCH BOOKMRKEDCHATS\n"); } return result; }
static gboolean bee_irc_user_new(bee_t *bee, bee_user_t *bu) { irc_user_t *iu; irc_t *irc = (irc_t *) bee->ui_data; char nick[MAX_NICK_LENGTH + 1], *s; memset(nick, 0, MAX_NICK_LENGTH + 1); strncpy(nick, nick_get(bu), MAX_NICK_LENGTH); bu->ui_data = iu = irc_user_new(irc, nick); iu->bu = bu; if (set_getbool(&irc->b->set, "private")) { iu->last_channel = NULL; } else { iu->last_channel = irc_channel_with_user(irc, iu); } if ((s = strchr(bu->handle, '@'))) { iu->host = g_strdup(s + 1); iu->user = g_strndup(bu->handle, s - bu->handle); } else { iu->user = g_strdup(bu->handle); if (bu->ic->acc->server) { iu->host = g_strdup(bu->ic->acc->server); } else { char *s; for (s = bu->ic->acc->tag; g_ascii_isalnum(*s); s++) { ; } /* Only use the tag if we got to the end of the string. (So allow alphanumerics only. Hopefully not too restrictive.) */ if (*s) { iu->host = g_strdup(bu->ic->acc->prpl->name); } else { iu->host = g_strdup(bu->ic->acc->tag); } } } while ((s = strchr(iu->user, ' '))) { *s = '_'; } if (bu->flags & BEE_USER_LOCAL) { char *s = set_getstr(&bee->set, "handle_unknown"); if (strcmp(s, "add_private") == 0) { iu->last_channel = NULL; } else if (strcmp(s, "add_channel") == 0) { iu->last_channel = irc->default_channel; } } iu->f = &irc_user_im_funcs; return TRUE; }
static gboolean bee_irc_user_msg(bee_t *bee, bee_user_t *bu, const char *msg_, guint32 flags, time_t sent_at) { irc_t *irc = bee->ui_data; irc_user_t *iu = (irc_user_t *) bu->ui_data; irc_user_t *src_iu = iu; irc_user_t *dst_iu = irc->user; const char *dst; char *prefix = NULL; char *wrapped, *ts = NULL; char *msg = g_strdup(msg_); char *message_type = "PRIVMSG"; GSList *l; if (sent_at > 0 && set_getbool(&irc->b->set, "display_timestamps")) { ts = irc_format_timestamp(irc, sent_at); } dst = irc_user_msgdest(iu); if (flags & OPT_SELFMESSAGE) { char *setting = set_getstr(&irc->b->set, "self_messages"); if (is_bool(setting)) { if (bool2int(setting)) { /* set to true, send it with src/dst flipped */ dst_iu = iu; src_iu = irc->user; if (dst == irc->user->nick) { dst = dst_iu->nick; } } else { /* set to false, skip the message completely */ goto cleanup; } } else if (g_strncasecmp(setting, "prefix", 6) == 0) { /* third state, prefix, loosely imitates the znc privmsg_prefix module */ g_free(msg); if (g_strncasecmp(msg_, "/me ", 4) == 0) { msg = g_strdup_printf("/me -> %s", msg_ + 4); } else { msg = g_strdup_printf("-> %s", msg_); } if (g_strcasecmp(setting, "prefix_notice") == 0) { message_type = "NOTICE"; } } } if (dst != dst_iu->nick) { /* if not messaging directly (control channel), call user by name */ prefix = g_strdup_printf("%s%s%s", dst_iu->nick, set_getstr(&bee->set, "to_char"), ts ? : ""); } else {
int irc_user_free( irc_t *irc, irc_user_t *iu ) { static struct im_connection *last_ic; static char *msg; if( !iu ) return 0; if( iu->bu && ( iu->bu->ic->flags & OPT_LOGGING_OUT ) && iu->bu->ic != last_ic ) { char host_prefix[] = "bitlbee."; char *s; /* Irssi recognises netsplits by quitmsgs with two hostnames, where a hostname is a "word" with one of more dots. Mangle no-dot hostnames a bit. */ if( strchr( irc->root->host, '.' ) ) *host_prefix = '\0'; last_ic = iu->bu->ic; g_free( msg ); if( !set_getbool( &irc->b->set, "simulate_netsplit" ) ) msg = g_strdup( "Account off-line" ); else if( ( s = strchr( iu->bu->ic->acc->user, '@' ) ) ) msg = g_strdup_printf( "%s%s %s", host_prefix, irc->root->host, s + 1 ); else msg = g_strdup_printf( "%s%s %s.%s", host_prefix, irc->root->host, iu->bu->ic->acc->prpl->name, irc->root->host ); } else if( !iu->bu || !( iu->bu->ic->flags & OPT_LOGGING_OUT ) ) { g_free( msg ); msg = g_strdup( "Removed" ); last_ic = NULL; } irc_user_quit( iu, msg ); irc->users = g_slist_remove( irc->users, iu ); g_hash_table_remove( irc->nick_user_hash, iu->key ); g_free( iu->nick ); if( iu->nick != iu->user ) g_free( iu->user ); if( iu->nick != iu->host ) g_free( iu->host ); if( iu->nick != iu->fullname ) g_free( iu->fullname ); g_free( iu->pastebuf ); if( iu->pastebuf_timer ) b_event_remove( iu->pastebuf_timer ); g_free( iu->key ); g_free( iu ); return 1; }
static gboolean bee_irc_user_status(bee_t *bee, bee_user_t *bu, bee_user_t *old) { irc_t *irc = bee->ui_data; irc_user_t *iu = bu->ui_data; /* Do this outside the if below since away state can change without the online state changing. */ iu->flags &= ~IRC_USER_AWAY; if (bu->flags & BEE_USER_AWAY || !(bu->flags & BEE_USER_ONLINE)) { iu->flags |= IRC_USER_AWAY; } if ((bu->flags & BEE_USER_ONLINE) != (old->flags & BEE_USER_ONLINE)) { if (bu->flags & BEE_USER_ONLINE) { if (g_hash_table_lookup(irc->watches, iu->key)) { irc_send_num(irc, 600, "%s %s %s %d :%s", iu->nick, iu->user, iu->host, (int) time(NULL), "logged online"); } } else { if (g_hash_table_lookup(irc->watches, iu->key)) { irc_send_num(irc, 601, "%s %s %s %d :%s", iu->nick, iu->user, iu->host, (int) time(NULL), "logged offline"); } /* Send a QUIT since those will also show up in any query windows the user may have, plus it's only one QUIT instead of possibly many (in case of multiple control chans). If there's a channel that shows offline people, a JOIN will follow. */ if (set_getbool(&bee->set, "offline_user_quits")) { irc_user_quit(iu, "Leaving..."); } } } /* Reset this one since the info may have changed. */ iu->away_reply_timeout = 0; bee_irc_channel_update(irc, NULL, iu); /* If away-notify enabled, send status updates when: * Away or Online state changes * Status changes (e.g. "Away" to "Mobile") * Status message changes */ if ((irc->caps & CAP_AWAY_NOTIFY) && ((bu->flags & BEE_USER_AWAY) != (old->flags & BEE_USER_AWAY) || (bu->flags & BEE_USER_ONLINE) != (old->flags & BEE_USER_ONLINE) || (g_strcmp0(bu->status, old->status) != 0) || (g_strcmp0(bu->status_msg, old->status_msg) != 0))) { irc_send_away_notify(iu); } return TRUE; }
gboolean ipc_child_identify( irc_t *irc ) { if( global.conf->runmode == RUNMODE_FORKDAEMON ) { #ifndef NO_FD_PASSING if( !ipc_send_fd( global.listen_socket, irc->fd ) ) ipc_child_disable(); ipc_to_master_str( "IDENTIFY %s :%s\r\n", irc->user->nick, irc->password ); #endif return TRUE; } else if( global.conf->runmode == RUNMODE_DAEMON ) { GSList *l; irc_t *old = NULL; char *to_init[] = { "TAKEOVER", "INIT", NULL }; for( l = irc_connection_list; l; l = l->next ) { old = l->data; if( irc != old && irc->user->nick && old->user->nick && irc->password && old->password && strcmp( irc->user->nick, old->user->nick ) == 0 && strcmp( irc->password, old->password ) == 0 ) break; } if( l == NULL || old == NULL || !set_getbool( &irc->b->set, "allow_takeover" ) || !set_getbool( &old->b->set, "allow_takeover" ) ) return FALSE; ipc_child_cmd_takeover( irc, to_init ); return TRUE; } else return FALSE; }
static void purple_sync_settings( account_t *acc, PurpleAccount *pa ) { PurplePlugin *prpl = purple_plugins_find_with_id( pa->protocol_id ); PurplePluginProtocolInfo *pi = prpl->info->extra_info; GList *i; for( i = pi->protocol_options; i; i = i->next ) { PurpleAccountOption *o = i->data; const char *name; set_t *s; name = purple_account_option_get_setting( o ); s = set_find( &acc->set, name ); if( s->value == NULL ) continue; switch( purple_account_option_get_type( o ) ) { case PURPLE_PREF_STRING: case PURPLE_PREF_STRING_LIST: purple_account_set_string( pa, name, set_getstr( &acc->set, name ) ); break; case PURPLE_PREF_INT: purple_account_set_int( pa, name, set_getint( &acc->set, name ) ); break; case PURPLE_PREF_BOOLEAN: purple_account_set_bool( pa, name, set_getbool( &acc->set, name ) ); break; default: break; } } if( pi->options & OPT_PROTO_MAIL_CHECK ) purple_account_set_check_mail( pa, set_getbool( &acc->set, "mail_notifications" ) ); }
gboolean cmd_identify_finish(gpointer data, gint fd, b_input_condition cond) { char *account_on[] = { "account", "on", NULL }; irc_t *irc = data; if (set_getbool(&irc->b->set, "auto_connect")) { cmd_account(irc, account_on); } b_event_remove(irc->login_source_id); irc->login_source_id = -1; return FALSE; }
void twitter_login_finish(struct im_connection *ic) { struct twitter_data *td = ic->proto_data; td->flags &= ~TWITTER_DOING_TIMELINE; if (set_getbool(&ic->acc->set, "oauth") && !td->oauth_info) twitter_oauth_start(ic); else if (!(td->flags & TWITTER_MODE_ONE) && !(td->flags & TWITTER_HAVE_FRIENDS)) { imcb_log(ic, "Getting contact list"); twitter_get_friends_ids(ic, -1); } else twitter_main_loop_start(ic); }
static gboolean bee_irc_user_new( bee_t *bee, bee_user_t *bu ) { irc_user_t *iu; irc_t *irc = (irc_t*) bee->ui_data; char nick[MAX_NICK_LENGTH+1], *s; memset( nick, 0, MAX_NICK_LENGTH + 1 ); strcpy( nick, nick_get( bu ) ); bu->ui_data = iu = irc_user_new( irc, nick ); iu->bu = bu; if( set_getbool( &irc->b->set, "private" ) ) iu->last_channel = NULL; else iu->last_channel = irc_channel_with_user( irc, iu ); if( ( s = strchr( bu->handle, '@' ) ) ) { iu->host = g_strdup( s + 1 ); iu->user = g_strndup( bu->handle, s - bu->handle ); } else { iu->user = g_strdup( bu->handle ); if( bu->ic->acc->server ) iu->host = g_strdup( bu->ic->acc->server ); else iu->host = g_strdup( bu->ic->acc->prpl->name ); } while( ( s = strchr( iu->user, ' ' ) ) ) *s = '_'; if( bu->flags & BEE_USER_LOCAL ) { char *s = set_getstr( &bee->set, "handle_unknown" ); if( strcmp( s, "add_private" ) == 0 ) iu->last_channel = NULL; else if( strcmp( s, "add_channel" ) == 0 ) iu->last_channel = irc->default_channel; } iu->f = &irc_user_im_funcs; return TRUE; }
/* IM->UI callbacks */ void imcb_buddy_status(struct im_connection *ic, const char *handle, int flags, const char *state, const char *message) { bee_t *bee = ic->bee; bee_user_t *bu, *old; if (!(bu = bee_user_by_handle(bee, ic, handle))) { if (g_strcasecmp(set_getstr(&ic->bee->set, "handle_unknown"), "add") == 0) { bu = bee_user_new(bee, ic, handle, BEE_USER_LOCAL); } else { if (g_strcasecmp(set_getstr(&ic->bee->set, "handle_unknown"), "ignore") != 0) { imcb_log(ic, "imcb_buddy_status() for unknown handle %s:\n" "flags = %d, state = %s, message = %s", handle, flags, state ? state : "NULL", message ? message : "NULL"); } return; } } /* May be nice to give the UI something to compare against. */ old = g_memdup(bu, sizeof(bee_user_t)); /* TODO(wilmer): OPT_AWAY, or just state == NULL ? */ bu->flags = flags; bu->status_msg = g_strdup(message); if (state && *state) { bu->status = g_strdup(state); } else if (flags & OPT_AWAY) { bu->status = g_strdup("Away"); } else { bu->status = NULL; } if (bu->status == NULL && (flags & OPT_MOBILE) && set_getbool(&bee->set, "mobile_is_away")) { bu->flags |= BEE_USER_AWAY; bu->status = g_strdup("Mobile"); } if (bee->ui->user_status) { bee->ui->user_status(bee, bu, old); } g_free(old->status_msg); g_free(old->status); g_free(old); }
static gboolean bee_irc_user_msg( bee_t *bee, bee_user_t *bu, const char *msg_, time_t sent_at ) { irc_t *irc = bee->ui_data; irc_user_t *iu = (irc_user_t *) bu->ui_data; const char *dst; char *prefix = NULL; char *wrapped, *ts = NULL; char *msg = g_strdup( msg_ ); GSList *l; if( sent_at > 0 && set_getbool( &irc->b->set, "display_timestamps" ) ) ts = irc_format_timestamp( irc, sent_at ); dst = irc_user_msgdest( iu ); if( dst != irc->user->nick ) { /* if not messaging directly, call user by name */ prefix = g_strdup_printf( "%s%s%s", irc->user->nick, set_getstr( &bee->set, "to_char" ), ts ? : "" ); }
static gboolean bee_irc_user_status( bee_t *bee, bee_user_t *bu, bee_user_t *old ) { irc_t *irc = bee->ui_data; irc_user_t *iu = bu->ui_data; /* Do this outside the if below since away state can change without the online state changing. */ iu->flags &= ~IRC_USER_AWAY; if( bu->flags & BEE_USER_AWAY || !( bu->flags & BEE_USER_ONLINE ) ) iu->flags |= IRC_USER_AWAY; if( ( bu->flags & BEE_USER_ONLINE ) != ( old->flags & BEE_USER_ONLINE ) ) { if( bu->flags & BEE_USER_ONLINE ) { if( g_hash_table_lookup( irc->watches, iu->key ) ) irc_send_num( irc, 600, "%s %s %s %d :%s", iu->nick, iu->user, iu->host, (int) time( NULL ), "logged online" ); } else { if( g_hash_table_lookup( irc->watches, iu->key ) ) irc_send_num( irc, 601, "%s %s %s %d :%s", iu->nick, iu->user, iu->host, (int) time( NULL ), "logged offline" ); /* Send a QUIT since those will also show up in any query windows the user may have, plus it's only one QUIT instead of possibly many (in case of multiple control chans). If there's a channel that shows offline people, a JOIN will follow. */ if( set_getbool( &bee->set, "offline_user_quits" ) ) irc_user_quit( iu, "Leaving..." ); } } /* Reset this one since the info may have changed. */ iu->away_reply_timeout = 0; bee_irc_channel_update( irc, NULL, iu ); return TRUE; }
/** * Creates a new #SteamData with an #account_t. The returned #SteamData * should be freed with #steam_data_free() when no longer needed. * * @param acc The #account_t. * * @return The #SteamData or NULL on error. **/ SteamData *steam_data_new(account_t *acc) { SteamData *sata; g_return_val_if_fail(acc != NULL, NULL); sata = g_new0(SteamData, 1); sata->api = steam_api_new(); sata->ic = imcb_new(acc); sata->ic->proto_data = sata; sata->api->umqid = g_strdup(set_getstr(&acc->set, "umqid")); sata->api->token = g_strdup(set_getstr(&acc->set, "token")); sata->api->sessid = g_strdup(set_getstr(&acc->set, "sessid")); sata->game_status = set_getbool(&acc->set, "game_status"); steam_api_rehash(sata->api); return sata; }
char *nick_get(bee_user_t *bu) { static char nick[MAX_NICK_LENGTH + 1]; char *store_handle, *found_nick; irc_t *irc = (irc_t *) bu->bee->ui_data; memset(nick, 0, MAX_NICK_LENGTH + 1); store_handle = clean_handle(bu->handle); /* Find out if we stored a nick for this person already. If not, try to generate a sane nick automatically. */ if ((found_nick = g_hash_table_lookup(bu->ic->acc->nicks, store_handle))) { strncpy(nick, found_nick, MAX_NICK_LENGTH); } else if ((found_nick = nick_gen(bu))) { strncpy(nick, found_nick, MAX_NICK_LENGTH); g_free(found_nick); } else { /* Keep this fallback since nick_gen() can return NULL in some cases. */ char *s; g_snprintf(nick, MAX_NICK_LENGTH, "%s", bu->handle); if ((s = strchr(nick, '@'))) { while (*s) { *(s++) = 0; } } nick_strip(irc, nick); if (set_getbool(&bu->bee->set, "lcnicks")) { nick_lc(irc, nick); } } g_free(store_handle); /* Make sure the nick doesn't collide with an existing one by adding underscores and that kind of stuff, if necessary. */ nick_dedupe(bu, nick); return nick; }
/* Separate this from jabber_login() so we can do OAuth first if necessary. Putting this in io.c would probably be more correct. */ void jabber_connect( struct im_connection *ic ) { account_t *acc = ic->acc; struct jabber_data *jd = ic->proto_data; int i; char *connect_to; struct ns_srv_reply **srvl = NULL, *srv = NULL; /* Figure out the hostname to connect to. */ if( acc->server && *acc->server ) connect_to = acc->server; else if( ( srvl = srv_lookup( "xmpp-client", "tcp", jd->server ) ) || ( srvl = srv_lookup( "jabber-client", "tcp", jd->server ) ) ) { /* Find the lowest-priority one. These usually come back in random/shuffled order. Not looking at weights etc for now. */ srv = *srvl; for( i = 1; srvl[i]; i ++ ) if( srvl[i]->prio < srv->prio ) srv = srvl[i]; connect_to = srv->name; } else connect_to = jd->server; imcb_log( ic, "Connecting" ); for( i = 0; jabber_port_list[i] > 0; i ++ ) if( set_getint( &acc->set, "port" ) == jabber_port_list[i] ) break; if( jabber_port_list[i] == 0 ) { imcb_log( ic, "Illegal port number" ); imc_logout( ic, FALSE ); return; } /* For non-SSL connections we can try to use the port # from the SRV reply, but let's not do that when using SSL, SSL usually runs on non-standard ports... */ if( set_getbool( &acc->set, "ssl" ) ) { jd->ssl = ssl_connect( connect_to, set_getint( &acc->set, "port" ), FALSE, jabber_connected_ssl, ic ); jd->fd = jd->ssl ? ssl_getfd( jd->ssl ) : -1; } else { jd->fd = proxy_connect( connect_to, srv ? srv->port : set_getint( &acc->set, "port" ), jabber_connected_plain, ic ); } srv_free( srvl ); if( jd->fd == -1 ) { imcb_error( ic, "Could not connect to server" ); imc_logout( ic, TRUE ); return; } if( set_getbool( &acc->set, "xmlconsole" ) ) { jd->flags |= JFLAG_XMLCONSOLE; /* Shouldn't really do this at this stage already, maybe. But I think this shouldn't break anything. */ imcb_add_buddy( ic, JABBER_XMLCONSOLE_HANDLE, NULL ); } jabber_generate_id_hash( jd ); }
static void cmd_identify(irc_t *irc, char **cmd) { storage_status_t status; gboolean load = TRUE; char *password = cmd[1]; if (irc->status & USTATUS_IDENTIFIED) { irc_rootmsg(irc, "You're already logged in."); return; } if (cmd[1] == NULL) { } else if (strncmp(cmd[1], "-no", 3) == 0) { load = FALSE; password = cmd[2]; if (password == NULL) { irc->status |= OPER_HACK_IDENTIFY_NOLOAD; } } else if (strncmp(cmd[1], "-force", 6) == 0) { password = cmd[2]; if (password == NULL) { irc->status |= OPER_HACK_IDENTIFY_FORCE; } } else if (irc->b->accounts != NULL) { irc_rootmsg(irc, "You're trying to identify yourself, but already have " "at least one IM account set up. " "Use \x02identify -noload\x02 or \x02identify -force\x02 " "instead (see \x02help identify\x02)."); return; } if (password == NULL) { irc_rootmsg(irc, "About to identify, use /OPER to enter the password"); irc->status |= OPER_HACK_IDENTIFY; return; } status = auth_check_pass(irc, irc->user->nick, password); if (load && (status == STORAGE_OK)) { status = storage_load(irc, password); } switch (status) { case STORAGE_INVALID_PASSWORD: irc_rootmsg(irc, "Incorrect password"); break; case STORAGE_NO_SUCH_USER: irc_rootmsg(irc, "The nick is (probably) not registered"); break; case STORAGE_OK: irc_rootmsg(irc, "Password accepted%s", load ? ", settings and accounts loaded" : ""); irc->status |= USTATUS_IDENTIFIED; irc_umode_set(irc, "+R", 1); if (irc->caps & CAP_SASL) { irc_user_t *iu = irc->user; irc_send_num(irc, 900, "%s!%s@%s %s :You are now logged in as %s", iu->nick, iu->user, iu->host, iu->nick, iu->nick); } bitlbee_whatsnew(irc); /* The following code is a bit hairy now. With takeover support, we shouldn't immediately auto_connect in case we're going to offer taking over an existing session. Do it in 200ms since that should give the parent process enough time to come back to us. */ if (load) { irc_channel_auto_joins(irc, NULL); if (!set_getbool(&irc->default_channel->set, "auto_join")) { irc_channel_del_user(irc->default_channel, irc->user, IRC_CDU_PART, "auto_join disabled " "for this channel."); } if (set_getbool(&irc->b->set, "auto_connect")) { irc->login_source_id = b_timeout_add(200, cmd_identify_finish, irc); } } /* If ipc_child_identify() returns FALSE, it means we're already sure that there's no takeover target (only possible in 1-process daemon mode). Start auto_connect immediately. */ if (!ipc_child_identify(irc) && load) { cmd_identify_finish(irc, 0, 0); } break; case STORAGE_OTHER_ERROR: default: irc_rootmsg(irc, "Unknown error while loading configuration"); break; } }
static xt_status jabber_pkt_features( struct xt_node *node, gpointer data ) { struct im_connection *ic = data; struct jabber_data *jd = ic->proto_data; struct xt_node *c, *reply; int trytls; trytls = g_strcasecmp( set_getstr( &ic->acc->set, "tls" ), "try" ) == 0; c = xt_find_node( node->children, "starttls" ); if( c && !jd->ssl ) { /* If the server advertises the STARTTLS feature and if we're not in a secure connection already: */ c = xt_find_node( c->children, "required" ); if( c && ( !trytls && !set_getbool( &ic->acc->set, "tls" ) ) ) { imcb_error( ic, "Server requires TLS connections, but TLS is turned off for this account" ); imc_logout( ic, FALSE ); return XT_ABORT; } /* Only run this if the tls setting is set to true or try: */ if( ( trytls || set_getbool( &ic->acc->set, "tls" ) ) ) { reply = xt_new_node( "starttls", NULL, NULL ); xt_add_attr( reply, "xmlns", XMLNS_TLS ); if( !jabber_write_packet( ic, reply ) ) { xt_free_node( reply ); return XT_ABORT; } xt_free_node( reply ); return XT_HANDLED; } } else if( !c && !jd->ssl ) { /* If the server does not advertise the STARTTLS feature and we're not in a secure connection already: (Servers have a habit of not advertising <starttls/> anymore when already using SSL/TLS. */ if( !trytls && set_getbool( &ic->acc->set, "tls" ) ) { imcb_error( ic, "TLS is turned on for this account, but is not supported by this server" ); imc_logout( ic, FALSE ); return XT_ABORT; } } /* This one used to be in jabber_handlers[], but it has to be done from here to make sure the TLS session will be initialized properly before we attempt SASL authentication. */ if( ( c = xt_find_node( node->children, "mechanisms" ) ) ) { if( sasl_pkt_mechanisms( c, data ) == XT_ABORT ) return XT_ABORT; } /* If the server *SEEMS* to support SASL authentication but doesn't support it after all, we should try to do authentication the other way. jabber.com doesn't seem to do SASL while it pretends to be XMPP 1.0 compliant! */ else if( !( jd->flags & JFLAG_AUTHENTICATED ) && sasl_supported( ic ) ) { if( !jabber_init_iq_auth( ic ) ) return XT_ABORT; } if( ( c = xt_find_node( node->children, "bind" ) ) ) { reply = xt_new_node( "bind", NULL, xt_new_node( "resource", set_getstr( &ic->acc->set, "resource" ), NULL ) ); xt_add_attr( reply, "xmlns", XMLNS_BIND ); reply = jabber_make_packet( "iq", "set", NULL, reply ); jabber_cache_add( ic, reply, jabber_pkt_bind_sess ); if( !jabber_write_packet( ic, reply ) ) return XT_ABORT; jd->flags |= JFLAG_WAIT_BIND; } if( ( c = xt_find_node( node->children, "session" ) ) ) { reply = xt_new_node( "session", NULL, NULL ); xt_add_attr( reply, "xmlns", XMLNS_SESSION ); reply = jabber_make_packet( "iq", "set", NULL, reply ); jabber_cache_add( ic, reply, jabber_pkt_bind_sess ); if( !jabber_write_packet( ic, reply ) ) return XT_ABORT; jd->flags |= JFLAG_WAIT_SESSION; } /* This flag is already set if we authenticated via SASL, so now we can resume the session in the new stream, if we don't have to bind/initialize the session. */ if( jd->flags & JFLAG_AUTHENTICATED && ( jd->flags & ( JFLAG_WAIT_BIND | JFLAG_WAIT_SESSION ) ) == 0 ) { if( !jabber_get_roster( ic ) ) return XT_ABORT; } return XT_HANDLED; }
static gboolean jabber_read_callback( gpointer data, gint fd, b_input_condition cond ) { struct im_connection *ic = data; struct jabber_data *jd = ic->proto_data; char buf[512]; int st; if( jd->fd == -1 ) return FALSE; if( jd->ssl ) st = ssl_read( jd->ssl, buf, sizeof( buf ) ); else st = read( jd->fd, buf, sizeof( buf ) ); if( st > 0 ) { /* Parse. */ if( xt_feed( jd->xt, buf, st ) < 0 ) { imcb_error( ic, "XML stream error" ); imc_logout( ic, TRUE ); return FALSE; } /* Execute all handlers. */ if( !xt_handle( jd->xt, NULL, 1 ) ) { /* Don't do anything, the handlers should have aborted the connection already. */ return FALSE; } if( jd->flags & JFLAG_STREAM_RESTART ) { jd->flags &= ~JFLAG_STREAM_RESTART; jabber_start_stream( ic ); } /* Garbage collection. */ xt_cleanup( jd->xt, NULL, 1 ); /* This is a bit hackish, unfortunately. Although xmltree has nifty event handler stuff, it only calls handlers when nodes are complete. Since the server should only send an opening <stream:stream> tag, we have to check this by hand. :-( */ if( !( jd->flags & JFLAG_STREAM_STARTED ) && jd->xt && jd->xt->root ) { if( g_strcasecmp( jd->xt->root->name, "stream:stream" ) == 0 ) { jd->flags |= JFLAG_STREAM_STARTED; /* If there's no version attribute, assume this is an old server that can't do SASL authentication. */ if( !sasl_supported( ic ) ) { /* If there's no version= tag, we suppose this server does NOT implement: XMPP 1.0, SASL and TLS. */ if( set_getbool( &ic->acc->set, "tls" ) ) { imcb_error( ic, "TLS is turned on for this " "account, but is not supported by this server" ); imc_logout( ic, FALSE ); return FALSE; } else { return jabber_init_iq_auth( ic ); } } } else { imcb_error( ic, "XML stream error" ); imc_logout( ic, TRUE ); return FALSE; } } } else if( st == 0 || ( st < 0 && !ssl_sockerr_again( jd->ssl ) ) ) { closesocket( jd->fd ); jd->fd = -1; imcb_error( ic, "Error while reading from server" ); imc_logout( ic, TRUE ); return FALSE; } if( ssl_pending( jd->ssl ) ) /* OpenSSL empties the TCP buffers completely but may keep some data in its internap buffers. select() won't see that, but ssl_pending() does. */ return jabber_read_callback( data, fd, cond ); else return TRUE; }
static void skype_parse_user(struct im_connection *ic, char *line) { int flags = 0; char *ptr; struct skype_data *sd = ic->proto_data; char *user = strchr(line, ' '); char *status = strrchr(line, ' '); status++; ptr = strchr(++user, ' '); if (!ptr) return; *ptr = '\0'; ptr++; if (!strncmp(ptr, "ONLINESTATUS ", 13)) { if (!strlen(user) || !strcmp(user, sd->username)) return; if (!set_getbool(&ic->acc->set, "test_join") && !strcmp(user, "echo123")) return; ptr = g_strdup_printf("*****@*****.**", user); imcb_add_buddy(ic, ptr, skype_group_by_username(ic, user)); if (strcmp(status, "OFFLINE") && (strcmp(status, "SKYPEOUT") || !set_getbool(&ic->acc->set, "skypeout_offline"))) flags |= OPT_LOGGED_IN; if (strcmp(status, "ONLINE") && strcmp(status, "SKYPEME")) flags |= OPT_AWAY; imcb_buddy_status(ic, ptr, flags, NULL, NULL); g_free(ptr); } else if (!strncmp(ptr, "RECEIVEDAUTHREQUEST ", 20)) { char *message = ptr + 20; if (strlen(message)) skype_buddy_ask(ic, user, message); } else if (!strncmp(ptr, "BUDDYSTATUS ", 12)) { char *st = ptr + 12; if (!strcmp(st, "3")) { char *buf = g_strdup_printf("*****@*****.**", user); imcb_add_buddy(ic, buf, skype_group_by_username(ic, user)); g_free(buf); } } else if (!strncmp(ptr, "MOOD_TEXT ", 10)) { char *buf = g_strdup_printf("*****@*****.**", user); bee_user_t *bu = bee_user_by_handle(ic->bee, ic, buf); g_free(buf); buf = ptr + 10; if (bu) imcb_buddy_status(ic, bu->handle, bu->flags, NULL, *buf ? buf : NULL); if (set_getbool(&ic->acc->set, "show_moods")) imcb_log(ic, "User `%s' changed mood text to `%s'", user, buf); } else if (!strncmp(ptr, "FULLNAME ", 9)) { char *name = ptr + 9; if (sd->is_info) { sd->is_info = FALSE; sd->info_fullname = g_strdup(name); } else { char *buf = g_strdup_printf("*****@*****.**", user); imcb_rename_buddy(ic, buf, name); g_free(buf); } } else if (!strncmp(ptr, "PHONE_HOME ", 11)) sd->info_phonehome = g_strdup(ptr + 11); else if (!strncmp(ptr, "PHONE_OFFICE ", 13)) sd->info_phoneoffice = g_strdup(ptr + 13); else if (!strncmp(ptr, "PHONE_MOBILE ", 13)) sd->info_phonemobile = g_strdup(ptr + 13); else if (!strncmp(ptr, "NROF_AUTHED_BUDDIES ", 20)) sd->info_nrbuddies = g_strdup(ptr + 20); else if (!strncmp(ptr, "TIMEZONE ", 9)) sd->info_tz = g_strdup(ptr + 9); else if (!strncmp(ptr, "LASTONLINETIMESTAMP ", 20)) sd->info_seen = g_strdup(ptr + 20); else if (!strncmp(ptr, "SEX ", 4)) sd->info_sex = g_strdup(ptr + 4); else if (!strncmp(ptr, "LANGUAGE ", 9)) sd->info_language = g_strdup(ptr + 9); else if (!strncmp(ptr, "COUNTRY ", 8)) sd->info_country = g_strdup(ptr + 8); else if (!strncmp(ptr, "PROVINCE ", 9)) sd->info_province = g_strdup(ptr + 9); else if (!strncmp(ptr, "CITY ", 5)) sd->info_city = g_strdup(ptr + 5); else if (!strncmp(ptr, "HOMEPAGE ", 9)) sd->info_homepage = g_strdup(ptr + 9); else if (!strncmp(ptr, "ABOUT ", 6)) { /* Support multiple about lines. */ if (!sd->info_about) sd->info_about = g_strdup(ptr + 6); else { GString *st = g_string_new(sd->info_about); g_string_append_printf(st, "\n%s", ptr + 6); g_free(sd->info_about); sd->info_about = g_strdup(st->str); g_string_free(st, TRUE); } } else if (!strncmp(ptr, "BIRTHDAY ", 9)) { sd->info_birthday = g_strdup(ptr + 9); GString *st = g_string_new("Contact Information\n"); g_string_append_printf(st, "Skype Name: %s\n", user); if (sd->info_fullname) { if (strlen(sd->info_fullname)) g_string_append_printf(st, "Full Name: %s\n", sd->info_fullname); g_free(sd->info_fullname); sd->info_fullname = NULL; } if (sd->info_phonehome) { if (strlen(sd->info_phonehome)) g_string_append_printf(st, "Home Phone: %s\n", sd->info_phonehome); g_free(sd->info_phonehome); sd->info_phonehome = NULL; } if (sd->info_phoneoffice) { if (strlen(sd->info_phoneoffice)) g_string_append_printf(st, "Office Phone: %s\n", sd->info_phoneoffice); g_free(sd->info_phoneoffice); sd->info_phoneoffice = NULL; } if (sd->info_phonemobile) { if (strlen(sd->info_phonemobile)) g_string_append_printf(st, "Mobile Phone: %s\n", sd->info_phonemobile); g_free(sd->info_phonemobile); sd->info_phonemobile = NULL; } g_string_append_printf(st, "Personal Information\n"); if (sd->info_nrbuddies) { if (strlen(sd->info_nrbuddies)) g_string_append_printf(st, "Contacts: %s\n", sd->info_nrbuddies); g_free(sd->info_nrbuddies); sd->info_nrbuddies = NULL; } if (sd->info_tz) { if (strlen(sd->info_tz)) { char ib[256]; time_t t = time(NULL); t += atoi(sd->info_tz)-(60*60*24); struct tm *gt = gmtime(&t); strftime(ib, 256, "%H:%M:%S", gt); g_string_append_printf(st, "Local Time: %s\n", ib); } g_free(sd->info_tz); sd->info_tz = NULL; } if (sd->info_seen) { if (strlen(sd->info_seen)) { char ib[256]; time_t it = atoi(sd->info_seen); struct tm *tm = localtime(&it); strftime(ib, 256, ("%Y. %m. %d. %H:%M"), tm); g_string_append_printf(st, "Last Seen: %s\n", ib); } g_free(sd->info_seen); sd->info_seen = NULL; } if (sd->info_birthday) { if (strlen(sd->info_birthday) && strcmp(sd->info_birthday, "0")) { char ib[256]; struct tm tm; strptime(sd->info_birthday, "%Y%m%d", &tm); strftime(ib, 256, "%B %d, %Y", &tm); g_string_append_printf(st, "Birthday: %s\n", ib); strftime(ib, 256, "%Y", &tm); int year = atoi(ib); time_t t = time(NULL); struct tm *lt = localtime(&t); g_string_append_printf(st, "Age: %d\n", lt->tm_year+1900-year); } g_free(sd->info_birthday); sd->info_birthday = NULL; } if (sd->info_sex) { if (strlen(sd->info_sex)) { char *iptr = sd->info_sex; while (*iptr++) *iptr = tolower(*iptr); g_string_append_printf(st, "Gender: %s\n", sd->info_sex); } g_free(sd->info_sex); sd->info_sex = NULL; } if (sd->info_language) { if (strlen(sd->info_language)) { char *iptr = strchr(sd->info_language, ' '); if (iptr) iptr++; else iptr = sd->info_language; g_string_append_printf(st, "Language: %s\n", iptr); } g_free(sd->info_language); sd->info_language = NULL; } if (sd->info_country) { if (strlen(sd->info_country)) { char *iptr = strchr(sd->info_country, ' '); if (iptr) iptr++; else iptr = sd->info_country; g_string_append_printf(st, "Country: %s\n", iptr); } g_free(sd->info_country); sd->info_country = NULL; } if (sd->info_province) { if (strlen(sd->info_province)) g_string_append_printf(st, "Region: %s\n", sd->info_province); g_free(sd->info_province); sd->info_province = NULL; } if (sd->info_city) { if (strlen(sd->info_city)) g_string_append_printf(st, "City: %s\n", sd->info_city); g_free(sd->info_city); sd->info_city = NULL; } if (sd->info_homepage) { if (strlen(sd->info_homepage)) g_string_append_printf(st, "Homepage: %s\n", sd->info_homepage); g_free(sd->info_homepage); sd->info_homepage = NULL; } if (sd->info_about) { if (strlen(sd->info_about)) g_string_append_printf(st, "%s\n", sd->info_about); g_free(sd->info_about); sd->info_about = NULL; } imcb_log(ic, "%s", st->str); g_string_free(st, TRUE); } }
static void ipc_child_cmd_takeover( irc_t *irc, char **cmd ) { if( strcmp( cmd[1], "NO" ) == 0 ) { /* Master->New connection */ /* No takeover, finish the login. */ } else if( strcmp( cmd[1], "INIT" ) == 0 ) { /* Master->New connection */ if( !set_getbool( &irc->b->set, "allow_takeover" ) ) { ipc_child_cmd_takeover_no( irc ); return; } /* Offer to take over the old session, unless for some reason we're already logging into IM connections. */ if( irc->login_source_id != -1 ) query_add( irc, NULL, "You're already connected to this server. " "Would you like to take over this session?", ipc_child_cmd_takeover_yes, ipc_child_cmd_takeover_no, NULL, irc ); /* This one's going to connect to accounts, avoid that. */ b_event_remove( irc->login_source_id ); irc->login_source_id = -1; } else if( strcmp( cmd[1], "AUTH" ) == 0 ) { /* Master->Old connection */ if( irc->password && cmd[2] && cmd[3] && ipc_child_recv_fd != -1 && strcmp( irc->user->nick, cmd[2] ) == 0 && strcmp( irc->password, cmd[3] ) == 0 && set_getbool( &irc->b->set, "allow_takeover" ) ) { irc_switch_fd( irc, ipc_child_recv_fd ); irc_sync( irc ); irc_rootmsg( irc, "You've successfully taken over your old session" ); ipc_child_recv_fd = -1; ipc_to_master_str( "TAKEOVER DONE\r\n" ); } else { ipc_to_master_str( "TAKEOVER FAIL\r\n" ); } } else if( strcmp( cmd[1], "DONE" ) == 0 ) { /* Master->New connection (now taken over by old process) */ irc_free( irc ); } else if( strcmp( cmd[1], "FAIL" ) == 0 ) { /* Master->New connection */ irc_rootmsg( irc, "Could not take over old session" ); } }
xt_status sasl_pkt_mechanisms( struct xt_node *node, gpointer data ) { struct im_connection *ic = data; struct jabber_data *jd = ic->proto_data; struct xt_node *c, *reply; char *s; int sup_plain = 0, sup_digest = 0, sup_gtalk = 0, sup_fb = 0; int want_oauth = FALSE; GString *mechs; if( !sasl_supported( ic ) ) { /* Should abort this now, since we should already be doing IQ authentication. Strange things happen when you try to do both... */ imcb_log( ic, "XMPP 1.0 non-compliant server seems to support SASL, please report this as a BitlBee bug!" ); return XT_HANDLED; } s = xt_find_attr( node, "xmlns" ); if( !s || strcmp( s, XMLNS_SASL ) != 0 ) { imcb_log( ic, "Stream error while authenticating" ); imc_logout( ic, FALSE ); return XT_ABORT; } want_oauth = set_getbool( &ic->acc->set, "oauth" ); mechs = g_string_new( "" ); c = node->children; while( ( c = xt_find_node( c, "mechanism" ) ) ) { if( c->text && g_strcasecmp( c->text, "PLAIN" ) == 0 ) sup_plain = 1; else if( c->text && g_strcasecmp( c->text, "DIGEST-MD5" ) == 0 ) sup_digest = 1; else if( c->text && g_strcasecmp( c->text, "X-OAUTH2" ) == 0 ) sup_gtalk = 1; else if( c->text && g_strcasecmp( c->text, "X-FACEBOOK-PLATFORM" ) == 0 ) sup_fb = 1; if( c->text ) g_string_append_printf( mechs, " %s", c->text ); c = c->next; } if( !want_oauth && !sup_plain && !sup_digest ) { if( !sup_gtalk && !sup_fb ) imcb_error( ic, "This server requires OAuth " "(supported schemes:%s)", mechs->str ); else imcb_error( ic, "BitlBee does not support any of the offered SASL " "authentication schemes:%s", mechs->str ); imc_logout( ic, FALSE ); g_string_free( mechs, TRUE ); return XT_ABORT; } g_string_free( mechs, TRUE ); reply = xt_new_node( "auth", NULL, NULL ); xt_add_attr( reply, "xmlns", XMLNS_SASL ); if( sup_gtalk && want_oauth ) { int len; /* X-OAUTH2 is, not *the* standard OAuth2 SASL/XMPP implementation. It's currently used by GTalk and vaguely documented on http://code.google.com/apis/cloudprint/docs/rawxmpp.html . */ xt_add_attr( reply, "mechanism", "X-OAUTH2" ); len = strlen( jd->username ) + strlen( jd->oauth2_access_token ) + 2; s = g_malloc( len + 1 ); s[0] = 0; strcpy( s + 1, jd->username ); strcpy( s + 2 + strlen( jd->username ), jd->oauth2_access_token ); reply->text = base64_encode( (unsigned char *)s, len ); reply->text_len = strlen( reply->text ); g_free( s ); } else if( sup_fb && want_oauth ) { xt_add_attr( reply, "mechanism", "X-FACEBOOK-PLATFORM" ); jd->flags |= JFLAG_SASL_FB; } else if( want_oauth ) { imcb_error( ic, "OAuth requested, but not supported by server" ); imc_logout( ic, FALSE ); xt_free_node( reply ); return XT_ABORT; } else if( sup_digest ) { xt_add_attr( reply, "mechanism", "DIGEST-MD5" ); /* The rest will be done later, when we receive a <challenge/>. */ } else if( sup_plain ) { int len; xt_add_attr( reply, "mechanism", "PLAIN" ); /* With SASL PLAIN in XMPP, the text should be b64(\0user\0pass) */ len = strlen( jd->username ) + strlen( ic->acc->pass ) + 2; s = g_malloc( len + 1 ); s[0] = 0; strcpy( s + 1, jd->username ); strcpy( s + 2 + strlen( jd->username ), ic->acc->pass ); reply->text = base64_encode( (unsigned char *)s, len ); reply->text_len = strlen( reply->text ); g_free( s ); } if( reply && !jabber_write_packet( ic, reply ) ) { xt_free_node( reply ); return XT_ABORT; } xt_free_node( reply ); /* To prevent classic authentication from happening. */ jd->flags |= JFLAG_STREAM_STARTED; return XT_HANDLED; }
static void jabber_login( account_t *acc ) { struct im_connection *ic = imcb_new( acc ); struct jabber_data *jd = g_new0( struct jabber_data, 1 ); char *s; /* For now this is needed in the _connected() handlers if using GLib event handling, to make sure we're not handling events on dead connections. */ jabber_connections = g_slist_prepend( jabber_connections, ic ); jd->ic = ic; ic->proto_data = jd; jabber_set_me( ic, acc->user ); jd->fd = jd->r_inpa = jd->w_inpa = -1; if( jd->server == NULL ) { imcb_error( ic, "Incomplete account name (format it like <*****@*****.**>)" ); imc_logout( ic, FALSE ); return; } if( ( s = strchr( jd->server, '/' ) ) ) { *s = 0; set_setstr( &acc->set, "resource", s + 1 ); /* Also remove the /resource from the original variable so we won't have to do this again every time. */ s = strchr( acc->user, '/' ); *s = 0; } jd->node_cache = g_hash_table_new_full( g_str_hash, g_str_equal, NULL, jabber_cache_entry_free ); jd->buddies = g_hash_table_new( g_str_hash, g_str_equal ); if( set_getbool( &acc->set, "oauth" ) ) { GSList *p_in = NULL; const char *tok; jd->fd = jd->r_inpa = jd->w_inpa = -1; if( strstr( jd->server, ".live.com" ) ) jd->oauth2_service = &oauth2_service_mslive; else if( strstr( jd->server, ".facebook.com" ) ) jd->oauth2_service = &oauth2_service_facebook; else jd->oauth2_service = &oauth2_service_google; oauth_params_parse( &p_in, ic->acc->pass ); /* First see if we have a refresh token, in which case any access token we *might* have has probably expired already anyway. */ if( ( tok = oauth_params_get( &p_in, "refresh_token" ) ) ) { sasl_oauth2_refresh( ic, tok ); } /* If we don't have a refresh token, let's hope the access token is still usable. */ else if( ( tok = oauth_params_get( &p_in, "access_token" ) ) ) { jd->oauth2_access_token = g_strdup( tok ); jabber_connect( ic ); } /* If we don't have any, start the OAuth process now. Don't even open an XMPP connection yet. */ else { sasl_oauth2_init( ic ); ic->flags |= OPT_SLOW_LOGIN; } oauth_params_free( &p_in ); } else jabber_connect( ic ); }
void irc_free(irc_t * irc) { GSList *l; irc->status |= USTATUS_SHUTDOWN; log_message(LOGLVL_INFO, "Destroying connection with fd %d", irc->fd); if (irc->status & USTATUS_IDENTIFIED && set_getbool(&irc->b->set, "save_on_quit")) { if (storage_save(irc, NULL, TRUE) != STORAGE_OK) { log_message(LOGLVL_WARNING, "Error while saving settings for user %s", irc->user->nick); } } for (l = irc_plugins; l; l = l->next) { irc_plugin_t *p = l->data; if (p->irc_free) { p->irc_free(irc); } } irc_connection_list = g_slist_remove(irc_connection_list, irc); while (irc->queries != NULL) { query_del(irc, irc->queries); } /* This is a little bit messy: bee_free() frees all b->users which calls us back to free the corresponding irc->users. So do this before we clear the remaining ones ourselves. */ bee_free(irc->b); while (irc->users) { irc_user_free(irc, (irc_user_t *) irc->users->data); } while (irc->channels) { irc_channel_free(irc->channels->data); } if (irc->ping_source_id > 0) { b_event_remove(irc->ping_source_id); } if (irc->r_watch_source_id > 0) { b_event_remove(irc->r_watch_source_id); } if (irc->w_watch_source_id > 0) { b_event_remove(irc->w_watch_source_id); } closesocket(irc->fd); irc->fd = -1; g_hash_table_foreach_remove(irc->nick_user_hash, irc_free_hashkey, NULL); g_hash_table_destroy(irc->nick_user_hash); g_hash_table_foreach_remove(irc->watches, irc_free_hashkey, NULL); g_hash_table_destroy(irc->watches); if (irc->iconv != (GIConv) - 1) { g_iconv_close(irc->iconv); } if (irc->oconv != (GIConv) - 1) { g_iconv_close(irc->oconv); } g_free(irc->sendbuffer); g_free(irc->readbuffer); g_free(irc->password); g_free(irc); if (global.conf->runmode == RUNMODE_INETD || global.conf->runmode == RUNMODE_FORKDAEMON || (global.conf->runmode == RUNMODE_DAEMON && global.listen_socket == -1 && irc_connection_list == NULL)) { b_main_quit(); } }