--- telepathy-idle-0.1.3.orig/src/idle-connection-manager.c +++ telepathy-idle-0.1.3/src/idle-connection-manager.c @@ -38,6 +38,7 @@ gchar *fullname; gchar *charset; gchar *quit_message; + gchar *local_ip_address; gboolean use_ssl; }; @@ -56,6 +57,7 @@ g_free(params->fullname); g_free(params->charset); g_free(params->quit_message); + g_free(params->local_ip_address); g_slice_free(Params, params); } @@ -95,6 +97,7 @@ {"fullname", DBUS_TYPE_STRING_AS_STRING, G_TYPE_STRING, 0, NULL, G_STRUCT_OFFSET(Params, fullname)}, {"charset", DBUS_TYPE_STRING_AS_STRING, G_TYPE_STRING, TP_CONN_MGR_PARAM_FLAG_HAS_DEFAULT, "UTF-8", G_STRUCT_OFFSET(Params, charset)}, {"quit-message", DBUS_TYPE_STRING_AS_STRING, G_TYPE_STRING, TP_CONN_MGR_PARAM_FLAG_HAS_DEFAULT, "So long and thanks for all the IRC - telepathy-idle IRC Connection Manager for Telepathy - http://telepathy.freedesktop.org", G_STRUCT_OFFSET(Params, quit_message)}, + {"local-ip-address", DBUS_TYPE_STRING_AS_STRING, G_TYPE_STRING, 0, NULL, G_STRUCT_OFFSET(Params, local_ip_address)}, {"use-ssl", DBUS_TYPE_BOOLEAN_AS_STRING, G_TYPE_BOOLEAN, TP_CONN_MGR_PARAM_FLAG_HAS_DEFAULT, GINT_TO_POINTER(FALSE), G_STRUCT_OFFSET(Params, use_ssl)}, {NULL, NULL, 0, 0, NULL, 0} }; @@ -128,6 +131,7 @@ "nickname", params->account, "server", params->server, "port", params->port, + "local-ip-address", params->local_ip_address, "password", params->password, "realname", params->fullname, "charset", params->charset, --- telepathy-idle-0.1.3.orig/src/idle-dns-resolver.c +++ telepathy-idle-0.1.3/src/idle-dns-resolver.c @@ -112,7 +112,7 @@ IdleDNSResultReal *results = NULL, *tail = NULL; IdleDNSResultCallback cb; gpointer user_data; - gchar *service = g_strdup_printf("%u", data->port); + gchar *service = data->port != 0 ? g_strdup_printf("%u", data->port) : NULL; cb = data->cb; user_data = data->user_data; @@ -164,7 +164,6 @@ g_assert (res != NULL); g_assert (name != NULL); - g_assert (port != 0); g_assert (cb != NULL); ret = res->serial++; --- telepathy-idle-0.1.3.orig/src/idle-server-connection.c +++ telepathy-idle-0.1.3/src/idle-server-connection.c @@ -49,7 +49,8 @@ enum { PROP_HOST = 1, - PROP_PORT + PROP_PORT, + PROP_LOCAL }; struct _AsyncConnectData { @@ -89,6 +90,7 @@ struct _IdleServerConnectionPrivate { gchar *host; guint port; + gchar *local; GIOChannel *io_chan; IdleServerConnectionState state; @@ -98,6 +100,7 @@ gboolean dispose_has_run; IdleDNSResolver *resolver; + IdleDNSResult *loc; struct _AsyncConnectData *connect_data; }; @@ -161,6 +164,11 @@ IdleServerConnection *conn = IDLE_SERVER_CONNECTION(obj); IdleServerConnectionPrivate *priv = IDLE_SERVER_CONNECTION_GET_PRIVATE(conn); + if (priv->loc) { + idle_dns_result_destroy(priv->loc); + priv->loc = NULL; + } + g_free(priv->host); } @@ -177,6 +185,10 @@ g_value_set_uint(value, priv->port); break; + case PROP_LOCAL: + g_value_set_string(value, priv->local); + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, prop_id, pspec); break; @@ -200,6 +212,11 @@ priv->port = g_value_get_uint(value); break; + case PROP_LOCAL: + g_free(priv->local); + priv->local = g_value_dup_string(value); + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, prop_id, pspec); break; @@ -237,7 +254,17 @@ G_PARAM_STATIC_NICK| G_PARAM_STATIC_BLURB); + g_object_class_install_property(object_class, PROP_PORT, pspec); + + pspec = g_param_spec_string("local", "Local host", + "Hostname of the local address to bind to.", + NULL, + G_PARAM_READABLE| + G_PARAM_WRITABLE| + G_PARAM_STATIC_NICK| + G_PARAM_STATIC_BLURB); + g_object_class_install_property(object_class, PROP_LOCAL, pspec); } static void change_state(IdleServerConnection *conn, IdleServerConnectionState state, guint reason) { @@ -344,6 +371,7 @@ IdleDNSResult *cur = connect_data->cur; IdleDNSResult *next = cur->ai_next; + IdleDNSResult *loc_i; fd = g_io_channel_unix_get_fd(connect_data->io_chan); g_assert(getsockopt(fd, SOL_SOCKET, SO_ERROR, &optval, &optlen) == 0); @@ -440,6 +468,15 @@ return FALSE; } + for (loc_i = priv->loc; loc_i != NULL; loc_i = loc_i->ai_next) { + if (loc_i->ai_family == cur->ai_family) { + if (bind(fd, loc_i->ai_addr, loc_i->ai_addrlen) == -1) + IDLE_DEBUG("Bind failed: %s.", g_strerror(errno)); + else + break; + } + } + io_chan = g_io_channel_unix_new(fd); g_io_channel_set_encoding(io_chan, NULL, NULL); g_io_channel_set_buffered(io_chan, FALSE); @@ -481,6 +518,7 @@ int fd = -1; int rc = -1; GIOChannel *io_chan; + IdleDNSResult *loc_i; if (!results) { IDLE_DEBUG("no DNS results received"); @@ -517,6 +555,17 @@ return; } + for (loc_i = priv->loc; loc_i != NULL; loc_i = loc_i->ai_next) { + if (loc_i->ai_family == cur->ai_family) { + if (bind(fd, loc_i->ai_addr, loc_i->ai_addrlen) == -1) + IDLE_DEBUG("Bind failed: %s.", g_strerror(errno)); + else + break; + break; + } + } + + rc = connect(fd, cur->ai_addr, cur->ai_addrlen); g_assert(rc == -1); @@ -544,10 +593,26 @@ priv->connect_data->watch_id = g_io_add_watch(io_chan, G_IO_OUT | G_IO_ERR, connect_io_func, conn); } -static gboolean do_connect(IdleServerConnection *conn) { +static void dns_local_callback(guint unused, IdleDNSResult *results, gpointer user_data) { + IdleServerConnection *conn = IDLE_SERVER_CONNECTION(user_data); IdleServerConnectionPrivate *priv = IDLE_SERVER_CONNECTION_GET_PRIVATE(conn); + if (priv->loc) { + idle_dns_result_destroy(priv->loc); + } + priv->loc = results; + idle_dns_resolver_query(priv->resolver, priv->host, priv->port, dns_result_callback, conn); +} + +static gboolean do_connect(IdleServerConnection *conn) { + IdleServerConnectionPrivate *priv = IDLE_SERVER_CONNECTION_GET_PRIVATE(conn); + + if (priv->local) { + idle_dns_resolver_query(priv->resolver, priv->local, 0, dns_local_callback, conn); + } else { + idle_dns_resolver_query(priv->resolver, priv->host, priv->port, dns_result_callback, conn); + } return TRUE; } --- telepathy-idle-0.1.3.orig/src/idle-connection.c +++ telepathy-idle-0.1.3/src/idle-connection.c @@ -122,6 +122,7 @@ PROP_REALNAME, PROP_CHARSET, PROP_QUITMESSAGE, + PROP_LOCALIPADDRESS, PROP_USE_SSL, LAST_PROPERTY_ENUM }; @@ -144,6 +145,7 @@ char *realname; char *charset; char *quit_message; + char *local_ip_address; gboolean use_ssl; /* the string used by the a server as a prefix to any messages we send that @@ -253,6 +255,11 @@ priv->quit_message = g_value_dup_string(value); break; + case PROP_LOCALIPADDRESS: + g_free(priv->local_ip_address); + priv->local_ip_address = g_value_dup_string(value); + break; + case PROP_USE_SSL: priv->use_ssl = g_value_get_boolean(value); break; @@ -295,6 +302,10 @@ g_value_set_string(value, priv->quit_message); break; + case PROP_LOCALIPADDRESS: + g_value_set_string(value, priv->local_ip_address); + break; + case PROP_USE_SSL: g_value_set_boolean(value, priv->use_ssl); break; @@ -402,6 +413,9 @@ param_spec = g_param_spec_string("quit-message", "Quit message", "The quit message to send to the server when leaving IRC", NULL, G_PARAM_READWRITE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_BLURB | G_PARAM_CONSTRUCT); g_object_class_install_property(object_class, PROP_QUITMESSAGE, param_spec); + param_spec = g_param_spec_string("local-ip-address", "Local IP address", "The IP the outgoing socket should be bound to.", NULL, G_PARAM_READWRITE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_BLURB | G_PARAM_CONSTRUCT); + g_object_class_install_property(object_class, PROP_LOCALIPADDRESS, param_spec); + param_spec = g_param_spec_boolean("use-ssl", "Use SSL", "If the connection should use a SSL tunneled socket connection", FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_BLURB | G_PARAM_CONSTRUCT); g_object_class_install_property(object_class, PROP_USE_SSL, param_spec); } @@ -506,7 +520,7 @@ priv->realname = g_strdup(priv->nickname); } - sconn = IDLE_SERVER_CONNECTION_IFACE(g_object_new(connection_type, "host", priv->server, "port", priv->port, NULL)); + sconn = IDLE_SERVER_CONNECTION_IFACE(g_object_new(connection_type, "host", priv->server, "port", priv->port, "local", priv->local_ip_address, NULL)); g_signal_connect(sconn, "status-changed", (GCallback)(sconn_status_changed_cb), conn);