Beispiel #1
0
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);
	}
}
Beispiel #2
0
void *ssl_starttls(int fd, char *hostname, gboolean verify,
		   ssl_input_function func, gpointer data)
{
	struct scd *conn = g_new0(struct scd, 1);

	conn->fd = fd;
	conn->func = func;
	conn->data = data;
	conn->hostname = hostname;

	/* For now, SSL verification is globally enabled by setting the cafile
	   setting in bitlbee.conf. Commented out by default because probably
	   not everyone has this file in the same place and plenty of folks
	   may not have the cert of their private Jabber server in it. */
	conn->verify = verify && global.conf->cafile;

	/* This function should be called via a (short) timeout instead of
	   directly from here, because these SSL calls are *supposed* to be
	   *completely* asynchronous and not ready yet when this function
	   (or *_connect, for examle) returns. Also, errors are reported via
	   the callback function, not via this function's return value.

	   In short, doing things like this makes the rest of the code a lot
	   simpler. */

	b_timeout_add(1, ssl_starttls_real, conn);

	return conn;
}
Beispiel #3
0
static void prplcb_xfer_new( PurpleXfer *xfer )
{
	if( purple_xfer_get_type( xfer ) == PURPLE_XFER_RECEIVE )
	{
		/* This should suppress the stupid file dialog. */
		purple_xfer_set_local_filename( xfer, "/tmp/wtf123" );
		
		/* Sadly the xfer struct is still empty ATM so come back after
		   the caller is done. */
		b_timeout_add( 0, prplcb_xfer_new_send_cb, xfer );
	}
	else
	{
		struct prpl_xfer_data *px = g_new0( struct prpl_xfer_data, 1 );
		
		px->ft = next_ft;
		px->ft->data = px;
		px->xfer = xfer;
		px->xfer->ui_data = px;
		
		purple_xfer_set_filename( xfer, px->ft->file_name );
		purple_xfer_set_size( xfer, px->ft->file_size );
		
		next_ft = NULL;
	}
}
Beispiel #4
0
/**
 * Sends a PING after #FB_MQTT_KA seconds. This clears any timeout which
 * currently exists.
 *
 * @param mqtt The #fb_mqtt.
 **/
static void fb_mqtt_ping(fb_mqtt_t *mqtt)
{
    g_return_if_fail(mqtt != NULL);

    fb_mqtt_timeout_clear(mqtt);
    mqtt->tev = b_timeout_add(FB_MQTT_TIMEOUT_PING, fb_mqtt_cb_ping, mqtt);
}
Beispiel #5
0
/* immed=1 makes this function pretty much equal to irc_free(), except that
   this one will "log". In case the connection is already broken and we
   shouldn't try to write to it. */
void irc_abort(irc_t *irc, int immed, char *format, ...)
{
	char *reason = NULL;

	if (format != NULL) {
		va_list params;

		va_start(params, format);
		reason = g_strdup_vprintf(format, params);
		va_end(params);
	}

	if (reason) {
		irc_write(irc, "ERROR :Closing link: %s", reason);
	}

	ipc_to_master_str("OPERMSG :Client exiting: %s@%s [%s]\r\n",
	                  irc->user->nick ? irc->user->nick : "(NONE)",
	                  irc->user->host, reason ? : "");

	g_free(reason);

	irc_flush(irc);
	if (immed) {
		irc_free(irc);
	} else {
		b_event_remove(irc->ping_source_id);
		irc->ping_source_id = b_timeout_add(1, (b_event_handler) irc_free, irc);
	}
}
Beispiel #6
0
/* Free the channel, but via the event loop, so after finishing whatever event
   we're currently handling. */
void irc_channel_free_soon(irc_channel_t *ic)
{
	struct irc_channel_free_data *d = g_new0(struct irc_channel_free_data, 1);

	d->irc = ic->irc;
	d->ic = ic;
	d->name = g_strdup(ic->name);

	b_timeout_add(0, irc_channel_free_callback, d);
}
Beispiel #7
0
void jabber_si_transfer_request(struct im_connection *ic, file_transfer_t *ft, char *who)
{
	struct jabber_transfer *tf;
	struct jabber_data *jd = ic->proto_data;
	struct jabber_buddy *bud;
	char *server = jd->server, *s;

	if ((s = strchr(who, '=')) && jabber_chat_by_jid(ic, s + 1)) {
		bud = jabber_buddy_by_ext_jid(ic, who, 0);
	} else {
		bud = jabber_buddy_by_jid(ic, who, 0);
	}

	if (bud == NULL) {
		imcb_file_canceled(ic, ft, "Couldn't find buddy (BUG?)");
		return;
	}

	imcb_log(ic, "Trying to send %s(%zd bytes) to %s", ft->file_name, ft->file_size, who);

	tf = g_new0(struct jabber_transfer, 1);

	tf->ic = ic;
	tf->ft = ft;
	tf->fd = -1;
	tf->ft->data = tf;
	tf->ft->free = jabber_si_free_transfer;
	tf->bud = bud;
	ft->write = jabber_bs_send_write;

	jd->filetransfers = g_slist_prepend(jd->filetransfers, tf);

	/* query buddy's features and server's streaming proxies if necessary */

	if (!tf->bud->features) {
		jabber_iq_query_features(ic, bud->full_jid);
	}

	/* If <auto> is not set don't check for proxies */
	if ((jd->have_streamhosts != 1) && (jd->streamhosts == NULL) &&
	    (strstr(set_getstr(&ic->acc->set, "proxy"), "<auto>") != NULL)) {
		jd->have_streamhosts = 0;
		jabber_iq_query_server(ic, server, XMLNS_DISCO_ITEMS);
	} else if (jd->streamhosts != NULL) {
		jd->have_streamhosts = 1;
	}

	/* if we had to do a query, wait for the result.
	 * Otherwise fire away. */
	if (!tf->bud->features || jd->have_streamhosts != 1) {
		tf->disco_timeout = b_timeout_add(500, jabber_si_waitfor_disco, tf);
	} else {
		jabber_si_transfer_start(tf);
	}
}
Beispiel #8
0
static gboolean prpl_xfer_write( struct file_transfer *ft, char *buffer, unsigned int len )
{
	struct prpl_xfer_data *px = ft->data;
	
	px->buf = g_memdup( buffer, len );
	px->buf_len = len;

	//purple_xfer_ui_ready( px->xfer );
	px->ready_timer = b_timeout_add( 0, prplcb_xfer_write_request_cb, px );
	
	return TRUE;
}
Beispiel #9
0
void account_on( bee_t *bee, account_t *a )
{
    if( a->ic )
    {
        /* Trying to enable an already-enabled account */
        return;
    }

    cancel_auto_reconnect( a );

    a->reconnect = 0;
    a->prpl->login( a );

    if( a->ic && !( a->ic->flags & ( OPT_SLOW_LOGIN | OPT_LOGGED_IN ) ) )
        a->ic->keepalive = b_timeout_add( 120000, account_on_timeout, a->ic );
}
Beispiel #10
0
static void sighandler( int signal )
{
	/* FIXME: Calling log_message() here is not a very good idea! */
	
	if( signal == SIGTERM || signal == SIGQUIT || signal == SIGINT )
	{
		static int first = 1;
		
		if( first )
		{
			/* We don't know what we were doing when this signal came in. It's not safe to touch
			   the user data now (not to mention writing them to disk), so add a timer. */
			
			log_message( LOGLVL_ERROR, "SIGTERM received, cleaning up process." );
			b_timeout_add( 1, (b_event_handler) bitlbee_shutdown, NULL );
			
			first = 0;
		}
		else
		{
			/* Well, actually, for now we'll never need this part because this signal handler
			   will never be called more than once in a session for a non-SIGPIPE signal...
			   But just in case we decide to change that: */
			
			log_message( LOGLVL_ERROR, "SIGTERM received twice, so long for a clean shutdown." );
			raise( signal );
		}
	}
	else if( signal == SIGCHLD )
	{
		pid_t pid;
		int st;
		
		while( ( pid = waitpid( 0, &st, WNOHANG ) ) > 0 )
		{
			if( WIFSIGNALED( st ) )
				log_message( LOGLVL_INFO, "Client %d terminated normally. (status = %d)", (int) pid, WEXITSTATUS( st ) );
			else if( WIFEXITED( st ) )
				log_message( LOGLVL_INFO, "Client %d killed by signal %d.", (int) pid, WTERMSIG( st ) );
		}
	}
	else if( signal != SIGPIPE )
	{
		log_message( LOGLVL_ERROR, "Fatal signal received: %d. That's probably a bug.", signal );
		raise( signal );
	}
}
Beispiel #11
0
static void prplcb_xfer_new(PurpleXfer *xfer)
{
	if (purple_xfer_get_type(xfer) == PURPLE_XFER_RECEIVE) {
		struct prpl_xfer_data *px = g_new0(struct prpl_xfer_data, 1);

		xfer->ui_data = px;
		px->xfer = xfer;
		px->fn = mktemp(g_strdup("/tmp/bitlbee-purple-ft.XXXXXX"));
		px->fd = -1;
		px->ic = purple_ic_by_pa(xfer->account);

		purple_xfer_set_local_filename(xfer, px->fn);

		/* Sadly the xfer struct is still empty ATM so come back after
		   the caller is done. */
		b_timeout_add(0, prplcb_xfer_new_send_cb, xfer);
	} else {
Beispiel #12
0
void purple_transfer_request( struct im_connection *ic, file_transfer_t *ft, char *handle )
{
	PurpleAccount *pa = ic->proto_data;
	struct prpl_xfer_data *px;
	
	/* xfer_new() will pick up this variable. It's a hack but we're not
	   multi-threaded anyway. */
	next_ft = ft;
	serv_send_file( purple_account_get_connection( pa ), handle, ft->file_name );
	
	ft->write = prpl_xfer_write;
	
	px = ft->data;
	imcb_file_recv_start( ft );
	
	px->ready_timer = b_timeout_add( 100, prplcb_xfer_send_cb, px );
}
Beispiel #13
0
int sasl_oauth2_get_refresh_token( struct im_connection *ic, const char *msg )
{
	struct jabber_data *jd = ic->proto_data;
	char *code;
	int ret;
	
	imcb_log( ic, "Requesting OAuth access token" );
	
	/* Don't do it here because the caller may get confused if the contact
	   we're currently sending a message to is deleted. */
	b_timeout_add( 1, sasl_oauth2_remove_contact, ic );
	
	code = g_strdup( msg );
	g_strstrip( code );
	ret = oauth2_access_token( jd->oauth2_service, OAUTH2_AUTH_CODE,
	                           code, sasl_oauth2_got_token, ic );
	
	g_free( code );
	return ret;
}
Beispiel #14
0
/**
 * Sends a #SteamHttpReq.
 *
 * @param req The #SteamHttpReq.
 **/
void steam_http_req_send(SteamHttpReq *req)
{
    gchar *str;
    gchar *hs;
    gchar *ps;

    g_return_if_fail(req != NULL);

    steam_http_req_asm(req, &hs, &ps, &str);

#ifdef DEBUG_STEAM
    steam_http_req_debug(req, FALSE, hs, ps);
#endif /* DEBUG_STEAM */

    req->request = http_dorequest(req->host, req->port,
                                  (req->flags & STEAM_HTTP_REQ_FLAG_SSL),
                                  str, steam_http_req_cb, req);
    g_hash_table_add(req->http->reqs, req);

    g_free(hs);
    g_free(ps);
    g_free(str);

    if (G_UNLIKELY(req->request == NULL)) {
        g_set_error(&req->err, STEAM_HTTP_ERROR, STEAM_HTTP_ERROR_INIT,
                    "Failed to init request");
        steam_http_req_done(req);
        return;
    }

    /* Prevent automatic redirection */
    req->request->redir_ttl = 0;

    if (req->timeout > 0) {
        req->toid = b_timeout_add(req->timeout, steam_http_req_send_timeout,
                                  req);
    }
}
Beispiel #15
0
void *ssl_starttls(int fd, char *hostname, gboolean verify, ssl_input_function func, gpointer data)
{
    struct scd *conn = g_new0(struct scd, 1);

    conn->fd = fd;
    conn->func = func;
    conn->data = data;
    conn->inpa = -1;
    conn->verify = verify && global.conf->cafile;
    conn->hostname = g_strdup(hostname);

    /* This function should be called via a (short) timeout instead of
       directly from here, because these SSL calls are *supposed* to be
       *completely* asynchronous and not ready yet when this function
       (or *_connect, for examle) returns. Also, errors are reported via
       the callback function, not via this function's return value.

       In short, doing things like this makes the rest of the code a lot
       simpler. */

    b_timeout_add(1, ssl_starttls_real, conn);

    return conn;
}
Beispiel #16
0
/**
 * Processes all #SteamHttpReq by resending, queuing, and freeing.
 *
 * @param req The #SteamHttpReq.
 **/
static void steam_http_req_done(SteamHttpReq *req)
{
#ifdef DEBUG_STEAM
    steam_http_req_debug(req, TRUE, req->header, req->body);
#endif /* DEBUG_STEAM */

    if (req->err != NULL) {
        if (req->rsc < STEAM_HTTP_RESEND_MAX) {
            steam_http_req_close(req, FALSE);
            g_error_free(req->err);
            req->err = NULL;

            req->toid = b_timeout_add(STEAM_HTTP_RESEND_TIMEOUT,
                                      steam_http_req_done_error, req);
            req->rsc++;
            return;
        }

        g_prefix_error(&req->err, "HTTP: ");
    }

    g_hash_table_remove(req->http->reqs, req);
    steam_http_req_free(req);
}
Beispiel #17
0
static gboolean prpl_xfer_write_request( struct file_transfer *ft )
{
	struct prpl_xfer_data *px = ft->data;
	px->ready_timer = b_timeout_add( 100, prplcb_xfer_write_request_cb, px );
	return TRUE;
}
Beispiel #18
0
static guint prplcb_ev_timeout_add( guint interval, GSourceFunc func, gpointer udata )
{
	return b_timeout_add( interval, (b_event_handler) func, udata );
}
Beispiel #19
0
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;
	}
}
Beispiel #20
0
irc_t *irc_new(int fd)
{
	irc_t *irc;
	struct sockaddr_storage sock;
	socklen_t socklen = sizeof(sock);
	char *host = NULL, *myhost = NULL;
	irc_user_t *iu;
	GSList *l;
	set_t *s;
	bee_t *b;

	irc = g_new0(irc_t, 1);

	irc->fd = fd;
	sock_make_nonblocking(irc->fd);

	irc->r_watch_source_id = b_input_add(irc->fd, B_EV_IO_READ, bitlbee_io_current_client_read, irc);

	irc->status = USTATUS_OFFLINE;
	irc->last_pong = gettime();

	irc->nick_user_hash = g_hash_table_new(g_str_hash, g_str_equal);
	irc->watches = g_hash_table_new(g_str_hash, g_str_equal);

	irc->iconv = (GIConv) - 1;
	irc->oconv = (GIConv) - 1;

	if (global.conf->hostname) {
		myhost = g_strdup(global.conf->hostname);
	} else if (getsockname(irc->fd, (struct sockaddr*) &sock, &socklen) == 0) {
		char buf[NI_MAXHOST + 1];

		if (getnameinfo((struct sockaddr *) &sock, socklen, buf,
		                NI_MAXHOST, NULL, 0, 0) == 0) {
			myhost = g_strdup(ipv6_unwrap(buf));
		}
	}

	if (getpeername(irc->fd, (struct sockaddr*) &sock, &socklen) == 0) {
		char buf[NI_MAXHOST + 1];

		if (getnameinfo((struct sockaddr *) &sock, socklen, buf,
		                NI_MAXHOST, NULL, 0, 0) == 0) {
			host = g_strdup(ipv6_unwrap(buf));
		}
	}

	if (host == NULL) {
		host = g_strdup("localhost.localdomain");
	}
	if (myhost == NULL) {
		myhost = g_strdup("localhost.localdomain");
	}

	if (global.conf->ping_interval > 0 && global.conf->ping_timeout > 0) {
		irc->ping_source_id = b_timeout_add(global.conf->ping_interval * 1000, irc_userping, irc);
	}

	irc_connection_list = g_slist_append(irc_connection_list, irc);

	b = irc->b = bee_new();
	b->ui_data = irc;
	b->ui = &irc_ui_funcs;

	s = set_add(&b->set, "allow_takeover", "true", set_eval_bool, irc);
	s = set_add(&b->set, "away_devoice", "true", set_eval_bw_compat, irc);
	s->flags |= SET_HIDDEN;
	s = set_add(&b->set, "away_reply_timeout", "3600", set_eval_int, irc);
	s = set_add(&b->set, "charset", "utf-8", set_eval_charset, irc);
	s = set_add(&b->set, "default_target", "root", NULL, irc);
	s = set_add(&b->set, "display_namechanges", "false", set_eval_bool, irc);
	s = set_add(&b->set, "display_timestamps", "true", set_eval_bool, irc);
	s = set_add(&b->set, "handle_unknown", "add_channel", NULL, irc);
	s = set_add(&b->set, "last_version", "0", NULL, irc);
	s->flags |= SET_HIDDEN;
	s = set_add(&b->set, "nick_format", "%-@nick", NULL, irc);
	s = set_add(&b->set, "nick_lowercase", "false", set_eval_bool, irc);
	s = set_add(&b->set, "nick_underscores", "false", set_eval_bool, irc);
	s = set_add(&b->set, "offline_user_quits", "true", set_eval_bool, irc);
	s = set_add(&b->set, "ops", "both", set_eval_irc_channel_ops, irc);
	s = set_add(&b->set, "paste_buffer", "false", set_eval_bool, irc);
	s->old_key = g_strdup("buddy_sendbuffer");
	s = set_add(&b->set, "paste_buffer_delay", "200", set_eval_int, irc);
	s->old_key = g_strdup("buddy_sendbuffer_delay");
	s = set_add(&b->set, "password", NULL, set_eval_password, irc);
	s->flags |= SET_NULL_OK | SET_PASSWORD;
	s = set_add(&b->set, "private", "true", set_eval_bool, irc);
	s = set_add(&b->set, "query_order", "lifo", NULL, irc);
	s = set_add(&b->set, "root_nick", ROOT_NICK, set_eval_root_nick, irc);
	s->flags |= SET_HIDDEN;
	s = set_add(&b->set, "show_offline", "false", set_eval_bw_compat, irc);
	s->flags |= SET_HIDDEN;
	s = set_add(&b->set, "self_messages", "true", set_eval_self_messages, irc);
	s = set_add(&b->set, "simulate_netsplit", "true", set_eval_bool, irc);
	s = set_add(&b->set, "timezone", "local", set_eval_timezone, irc);
	s = set_add(&b->set, "to_char", ": ", set_eval_to_char, irc);
	s = set_add(&b->set, "typing_notice", "false", set_eval_bool, irc);
	s = set_add(&b->set, "utf8_nicks", "false", set_eval_utf8_nicks, irc);

	irc->root = iu = irc_user_new(irc, ROOT_NICK);
	iu->host = g_strdup(myhost);
	iu->fullname = g_strdup(ROOT_FN);
	iu->f = &irc_user_root_funcs;

	iu = irc_user_new(irc, NS_NICK);
	iu->host = g_strdup(myhost);
	iu->fullname = g_strdup(ROOT_FN);
	iu->f = &irc_user_root_funcs;

	irc->user = g_new0(irc_user_t, 1);
	irc->user->host = g_strdup(host);

	conf_loaddefaults(irc);

	/* Evaluator sets the iconv/oconv structures. */
	set_eval_charset(set_find(&b->set, "charset"), set_getstr(&b->set, "charset"));

	irc_write(irc, ":%s NOTICE * :%s", irc->root->host, "BitlBee-IRCd initialized, please go on");
	if (isatty(irc->fd)) {
		irc_write(irc, ":%s NOTICE * :%s", irc->root->host,
		          "If you read this, you most likely accidentally "
		          "started BitlBee in inetd mode on the command line. "
		          "You probably want to run it in (Fork)Daemon mode. "
		          "See doc/README for more information.");
	}

	g_free(myhost);
	g_free(host);

	/* libpurple doesn't like fork()s after initializing itself, so this
	   is the right moment to initialize it. */
#ifdef WITH_PURPLE
	nogaim_init();
#endif

	/* SSL library initialization also should be done after the fork, to
	   avoid shared CSPRNG state. This is required by NSS, which refuses to
	   work if a fork is detected */
	ssl_init();

	for (l = irc_plugins; l; l = l->next) {
		irc_plugin_t *p = l->data;
		if (p->irc_new) {
			p->irc_new(irc);
		}
	}

	return irc;
}