changeset 10596:913ec44675c3

[gaim-migrate @ 12011] Get some rendezvous stuff out of my tree. No, you still can't get or send IMs. committer: Tailor Script <tailor@pidgin.im>
author Mark Doliner <mark@kingant.net>
date Mon, 14 Feb 2005 03:08:43 +0000
parents de34037a02c7
children 0e886a234d92
files src/protocols/rendezvous/direct.c src/protocols/rendezvous/direct.h src/protocols/rendezvous/mdns.c src/protocols/rendezvous/mdns.h src/protocols/rendezvous/rendezvous.c
diffstat 5 files changed, 275 insertions(+), 148 deletions(-) [+]
line wrap: on
line diff
--- a/src/protocols/rendezvous/direct.c	Mon Feb 14 03:07:06 2005 +0000
+++ b/src/protocols/rendezvous/direct.c	Mon Feb 14 03:08:43 2005 +0000
@@ -27,42 +27,33 @@
 #include "direct.h"
 #include "rendezvous.h"
 
-#if 0
-gchar *
-gaim_network_convert_ipv4_to_string(void *ip)
-{
-	gchar *ret;
-	unsigned char *ipv4 = (unsigned char *)ip;
-
-	ret = g_strdup_printf("::ffff:%02hhx%02hhx:%02hhx%02hhx", ipv4[0], ipv4[1], ipv4[2], ipv4[3]);
-
-	return ret;
-}
-
-gchar *
-gaim_network_convert_ipv6_to_string(void *ip)
-{
-	gchar *ret;
-
-	//ret = g_strdup_printf("%02hhx%02hhx:%02hhx%02hhx:%02hhx%02hhx:%02hhx%02hhx:%02hhx%02hhx:%02hhx%02hhx:%02hhx%02hhx:%02hhx%02hhx", ip[0], ip[1], ip[2], ip[3], ip[4], ip[5], ip[6], ip[7], ip[8], ip[9], ip[10], ip[11], ip[12], ip[13], ip[14], ip[15]);
-	ret = g_malloc0(INET6_ADDRSTRLEN + 1);
-	inet_ntop(AF_INET6, ip, ret, sizeof(ret));
-
-	return ret;
-}
-
 static gboolean
-rendezvous_find_buddy_by_ip(gpointer key, gpointer value, gpointer user_data)
+rendezvous_find_buddy_by_ipv4(gpointer key, gpointer value, gpointer user_data)
 {
 	RendezvousBuddy *rb = value;
 
 	if (rb->ipv4 == NULL)
 		return FALSE;
 
-printf("looking at ip=%hu.%hu.%hu.%hu\n", rb->ipv4[0], rb->ipv4[1], rb->ipv4[2], rb->ipv4[3]);
+int *ipv4 = user_data;
+printf("looking for ip=%hu.%hu.%hu.%hu\n", ipv4[0], ipv4[1], ipv4[2], ipv4[3]);
+printf("looking at  ip=%hu.%hu.%hu.%hu, %s\n", rb->ipv4[0], rb->ipv4[1], rb->ipv4[2], rb->ipv4[3], rb->firstandlast);
 	return !memcmp(rb->ipv4, user_data, 4);
 }
-#endif
+
+static gboolean
+rendezvous_find_buddy_by_ipv6(gpointer key, gpointer value, gpointer user_data)
+{
+	RendezvousBuddy *rb = value;
+
+	if (rb->ipv6 == NULL)
+		return FALSE;
+
+int *ipv6 = user_data;
+printf("looking for ip=%hx%hx:%hx%hx:%hx%hx:%hx%hx:%hx%hx:%hx%hx:%hx%hx:%hx%hx\n", ipv6[0], ipv6[1], ipv6[2], ipv6[3], ipv6[4], ipv6[5], ipv6[6], ipv6[7], ipv6[8], ipv6[9], ipv6[10], ipv6[11], ipv6[12], ipv6[13], ipv6[14], ipv6[15]);
+printf("looking at  ip=%hx%hx:%hx%hx:%hx%hx:%hx%hx:%hx%hx:%hx%hx:%hx%hx:%hx%hx, %s\n", rb->ipv6[0], rb->ipv6[1], rb->ipv6[2], rb->ipv6[3], rb->ipv6[4], rb->ipv6[5], rb->ipv6[6], rb->ipv6[7], rb->ipv6[8], rb->ipv6[9], rb->ipv6[10], rb->ipv6[11], rb->ipv6[12], rb->ipv6[13], rb->ipv6[14], rb->ipv6[15], rb->firstandlast);
+	return !memcmp(rb->ipv6, user_data, 16);
+}
 
 void
 rendezvous_direct_acceptconnection(gpointer data, gint source, GaimInputCondition condition)
@@ -72,10 +63,7 @@
 	int fd;
 	struct sockaddr_in6 addr;
 	socklen_t addrlen = sizeof(addr);
-#if 0
-	gchar *ip;
-#endif
-	RendezvousBuddy *rb;
+	RendezvousBuddy *rb = NULL;
 
 	fd = accept(rd->listener, (struct sockaddr *)&addr, &addrlen);
 	if (fd == -1) {
@@ -83,17 +71,10 @@
 		return;
 	}
 
-#if 0
-	printf("\nsa_family=%d\n\n", ((struct sockaddr *)&addr)->sa_family);
 	if (((struct sockaddr *)&addr)->sa_family == AF_INET)
-		ip = gaim_network_convert_ipv4_to_string((unsigned char *)&ip);
+		rb = g_hash_table_find(rd->buddies, rendezvous_find_buddy_by_ipv4, &(((struct sockaddr_in *)&addr)->sin_addr));
 	else if (((struct sockaddr *)&addr)->sa_family == AF_INET6)
-		ip = gaim_network_convert_ipv6_to_string((unsigned char *)&(addr.sin6_addr));
-	printf("\nip=%s\n", ip);
-
-	rb = g_hash_table_find(rd->buddies, rendezvous_find_buddy_by_ip, ip);
-	g_free(ip);
-#endif
+		rb = g_hash_table_find(rd->buddies, rendezvous_find_buddy_by_ipv6, &(addr.sin6_addr.s6_addr));
 
 	if (rb == NULL) {
 		/* We don't want to talk to people that don't advertise themselves */
@@ -104,4 +85,80 @@
 printf("\nip belongs to=%s\n\n", rb->aim);
 
 	rb->fd = fd;
+
+	/* TODO: Add a watcher on the connection. */
 }
+
+static void
+rendezvous_direct_connect(RendezvousBuddy *rb)
+{
+	struct sockaddr_in addr;
+
+	/* If we already have a connection then do nothing */
+	if (rb->fd != -1)
+		return;
+
+	if ((rb->ipv4 == NULL) && (rb->ipv6 == NULL))
+	{
+		gaim_debug_warning("rendezvous", "Could not connect: Unknown IP address.\n");
+		/* TODO: Show an error message to the user. */
+		return;
+	}
+
+	if ((rb->fd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
+	{
+		gaim_debug_warning("rendezvous", "Could not connect: %s.\n", strerror(errno));
+		/* TODO: Show an error message to the user. */
+		return;
+	}
+
+	addr.sin_family = AF_INET;
+	addr.sin_port = rb->p2pjport;
+	memcpy(&addr.sin_addr, rb->ipv4, 4);
+	memset(&addr.sin_zero, 0, 8);
+
+	if (connect(rb->fd, (struct sockaddr *)&addr, sizeof(struct sockaddr)) == -1)
+	{
+		gaim_debug_warning("rendezvous", "Could not connect: %s.\n", strerror(errno));
+		/* TODO: Show an error message to the user. */
+		return;
+	}
+
+	/* TODO: Connect a watcher */
+}
+
+static void
+rendezvous_direct_write_message_to_socket(int fd, const char *message)
+{
+
+}
+
+/*
+ * TODO: Establish a direct connection, then send IM.  Will need to
+ * queue the message somewhere, while the connection is established.
+ */
+void
+rendezvous_direct_send_message(GaimConnection *gc, const char *who, const char *message)
+{
+	RendezvousData *rd = gc->proto_data;
+	RendezvousBuddy *rb;
+
+	rb = g_hash_table_lookup(rd->buddies, who);
+	if (rb == NULL)
+	{
+		/* TODO: Should print an error to the user, here */
+		gaim_debug_error("rendezvous", "Could not send message to %s: Could not find user information.\n", who);
+		return;
+	}
+
+	if (rb->fd == -1)
+	{
+		rendezvous_direct_connect(rb);
+		/* TODO: Queue message */
+		//gaim_debug_warning("rendezvous", "Could not send message to %s: Unable to establish connection.\n", who);
+	}
+	else
+	{
+		rendezvous_direct_write_message_to_socket(rb->fd, message);
+	}
+}
--- a/src/protocols/rendezvous/direct.h	Mon Feb 14 03:07:06 2005 +0000
+++ b/src/protocols/rendezvous/direct.h	Mon Feb 14 03:08:43 2005 +0000
@@ -29,6 +29,10 @@
 
 #include "eventloop.h"
 
+#include "rendezvous.h"
+
 void rendezvous_direct_acceptconnection(gpointer data, gint source, GaimInputCondition condition);
 
+void rendezvous_direct_send_message(GaimConnection *gc, const char *who, const char *message);
+
 #endif /* _DIRECT_H_ */
--- a/src/protocols/rendezvous/mdns.c	Mon Feb 14 03:07:06 2005 +0000
+++ b/src/protocols/rendezvous/mdns.c	Mon Feb 14 03:08:43 2005 +0000
@@ -847,6 +847,12 @@
 int
 mdns_advertise_ptr(int fd, const char *name, const char *domain)
 {
+	return mdns_advertise_ptr_with_ttl(fd, name, domain, 0x00001c20);
+}
+
+int
+mdns_advertise_ptr_with_ttl(int fd, const char *name, const char *domain, int ttl)
+{
 	int ret;
 	ResourceRecord *rr;
 
@@ -859,7 +865,7 @@
 	rr->name = g_strdup(name);
 	rr->type = RENDEZVOUS_RRTYPE_PTR;
 	rr->class = 0x8001;
-	rr->ttl = 0x00001c20;
+	rr->ttl = ttl;
 	rr->rdata = (void *)g_strdup(domain);
 	rr->rdlength = mdns_getlength_rr_rdata(rr->type, rr->rdata);
 
--- a/src/protocols/rendezvous/mdns.h	Mon Feb 14 03:07:06 2005 +0000
+++ b/src/protocols/rendezvous/mdns.h	Mon Feb 14 03:08:43 2005 +0000
@@ -23,6 +23,10 @@
  *
  */
 
+/*
+ * TODO: Need to document a lot of these.
+ */
+
 #ifndef _MDNS_H_
 #define _MDNS_H_
 
@@ -131,7 +135,6 @@
  */
 int mdns_socket_establish();
 
-
 /**
  * Close a multicast socket.  This also clears the MDNS
  * cache.
@@ -140,7 +143,6 @@
  */
 void mdns_socket_close(int fd);
 
-
 /**
  * Sends a multicast DNS datagram.  Generally this is called
  * by other convenience functions such as mdns_query(), however
@@ -169,6 +171,7 @@
 int mdns_advertise_a(int fd, const char *name, const unsigned char *ip);
 int mdns_advertise_null(int fd, const char *name, const char *data, unsigned short rdlength);
 int mdns_advertise_ptr(int fd, const char *name, const char *domain);
+int mdns_advertise_ptr_with_ttl(int fd, const char *name, const char *domain, int ttl);
 int mdns_advertise_txt(int fd, const char *name, const GSList *txt);
 int mdns_advertise_aaaa(int fd, const char *name, const unsigned char *ip);
 int mdns_advertise_srv(int fd, const char *name, unsigned short port, const char *target);
@@ -195,6 +198,7 @@
 ResourceRecord *mdns_copy_rr(const ResourceRecord *rr);
 
 ResourceRecordRDataTXTNode *mdns_txt_find(const GSList *ret, const char *name);
+
 GSList *mdns_txt_add(GSList *ret, const char *name, const char *value, gboolean replace);
 
 
--- a/src/protocols/rendezvous/rendezvous.c	Mon Feb 14 03:07:06 2005 +0000
+++ b/src/protocols/rendezvous/rendezvous.c	Mon Feb 14 03:08:43 2005 +0000
@@ -123,6 +123,7 @@
 	gaim_prpl_got_user_status(account, b->name, "online", NULL);
 
 #if 0
+	/* Remove the buddy if the TTL on their PTR record expires */
 	RendezvousBuddy *rb;
 	rb = rendezvous_find_or_create_rendezvousbuddy(gc, name);
 	rb->ttltimer = gaim_timeout_add(time * 10000, rendezvous_buddy_timeout, gc);
@@ -188,16 +189,48 @@
 	}
 }
 
+static gboolean
+rendezvous_find_buddy_by_host(gpointer key, gpointer value, gpointer user_data)
+{
+	const gchar *domain;
+
+	if (key == NULL)
+		return FALSE;
+
+	domain = strchr(key, '@');
+	if (domain == NULL)
+		return FALSE;
+	domain++;
+
+	return !strcasecmp(user_data, domain);
+}
+
 static void
 rendezvous_handle_rr_a(GaimConnection *gc, ResourceRecord *rr, const gchar *name)
 {
+	RendezvousData *rd = gc->proto_data;
 	RendezvousBuddy *rb;
 	ResourceRecordRDataSRV *rdata;
+	const gchar *end;
+	gchar *domain;
+
+	/*
+	 * Remove the trailing ".local" from the domain.  If there is no
+	 * trailing ".local" then do nothing and exit
+	 */
+	end = g_strrstr(name, ".local");
+	if (end == NULL)
+		return;
+
+	domain = g_strndup(name, (gpointer)end - (gpointer)name);
+	rb = g_hash_table_find(rd->buddies, rendezvous_find_buddy_by_host, domain);
+	g_free(domain);
+
+	if (rb == NULL)
+		return;
 
 	rdata = rr->rdata;
 
-	rb = rendezvous_find_or_create_rendezvousbuddy(gc, name);
-
 	memcpy(rb->ipv4, rdata, 4);
 }
 
@@ -277,13 +310,29 @@
 static void
 rendezvous_handle_rr_aaaa(GaimConnection *gc, ResourceRecord *rr, const gchar *name)
 {
+	RendezvousData *rd = gc->proto_data;
 	RendezvousBuddy *rb;
 	ResourceRecordRDataSRV *rdata;
+	const gchar *end;
+	gchar *domain;
+
+	/*
+	 * Remove the trailing ".local" from the domain.  If there is no
+	 * trailing ".local" then do nothing and exit
+	 */
+	end = g_strrstr(name, ".local");
+	if (end == NULL)
+		return;
+
+	domain = g_strndup(name, (gpointer)end - (gpointer)name);
+	rb = g_hash_table_find(rd->buddies, rendezvous_find_buddy_by_host, domain);
+	g_free(domain);
+
+	if (rb == NULL)
+		return;
 
 	rdata = rr->rdata;
 
-	rb = rendezvous_find_or_create_rendezvousbuddy(gc, name);
-
 	memcpy(rb->ipv6, rdata, 16);
 }
 
@@ -313,11 +362,7 @@
 
 	switch (rr->type) {
 		case RENDEZVOUS_RRTYPE_A: {
-			name = rendezvous_extract_name(rr->name);
-			if (name != NULL) {
-				rendezvous_handle_rr_a(gc, rr, name);
-				g_free(name);
-			}
+			rendezvous_handle_rr_a(gc, rr, rr->name);
 		} break;
 
 		case RENDEZVOUS_RRTYPE_NULL: {
@@ -358,11 +403,7 @@
 		} break;
 
 		case RENDEZVOUS_RRTYPE_AAAA: {
-			name = rendezvous_extract_name(rr->name);
-			if (name != NULL) {
-				rendezvous_handle_rr_aaaa(gc, rr, name);
-				g_free(name);
-			}
+			rendezvous_handle_rr_aaaa(gc, rr, rr->name);
 		} break;
 
 		case RENDEZVOUS_RRTYPE_SRV: {
@@ -376,85 +417,6 @@
 }
 
 /****************************/
-/* Icon and Emblem Functions */
-/****************************/
-static const char *
-rendezvous_prpl_list_icon(GaimAccount *a, GaimBuddy *b)
-{
-	return "rendezvous";
-}
-
-static void
-rendezvous_prpl_list_emblems(GaimBuddy *b, const char **se, const char **sw, const char **nw, const char **ne)
-{
-	if (GAIM_BUDDY_IS_ONLINE(b)) {
-		if (b->uc & UC_UNAVAILABLE)
-			*se = "away";
-	} else {
-		*se = "offline";
-	}
-}
-
-static gchar *
-rendezvous_prpl_status_text(GaimBuddy *b)
-{
-	GaimConnection *gc = b->account->gc;
-	RendezvousData *rd = gc->proto_data;
-	RendezvousBuddy *rb;
-	gchar *ret;
-
-	rb = g_hash_table_lookup(rd->buddies, b->name);
-	if ((rb == NULL) || (rb->msg == NULL))
-		return NULL;
-
-	ret = g_strdup(rb->msg);
-
-	return ret;
-}
-
-static gchar *
-rendezvous_prpl_tooltip_text(GaimBuddy *b)
-{
-	GaimConnection *gc = b->account->gc;
-	RendezvousData *rd = gc->proto_data;
-	RendezvousBuddy *rb;
-	GString *ret;
-
-	rb = g_hash_table_lookup(rd->buddies, b->name);
-	if (rb == NULL)
-		return NULL;
-
-	ret = g_string_new("");
-
-	if (rb->aim != NULL)
-		g_string_append_printf(ret, "\n<b>%s</b>: %s", _("AIM Screen name"), rb->aim);
-
-	if (rb->msg != NULL) {
-		if (rb->status == UC_UNAVAILABLE)
-			g_string_append_printf(ret, "\n<b>%s</b>: %s", _("Away"), rb->msg);
-		else
-			g_string_append_printf(ret, "\n<b>%s</b>: %s", _("Available"), rb->msg);
-	}
-
-	return g_string_free(ret, FALSE);
-}
-
-static GList *
-rendezvous_prpl_status_types(GaimAccount *account)
-{
-	GList *status_types = NULL;
-	GaimStatusType *type;
-
-	type = gaim_status_type_new_full(GAIM_STATUS_OFFLINE, "offline", _("Offline"), FALSE, TRUE, FALSE);
-	status_types = g_list_append(status_types, type);
-
-	type = gaim_status_type_new_full(GAIM_STATUS_ONLINE, "online", _("Online"), FALSE, TRUE, FALSE);
-	status_types = g_list_append(status_types, type);
-
-	return status_types;
-}
-
-/****************************/
 /* Connection Functions      */
 /****************************/
 static void
@@ -599,8 +561,7 @@
 		for (l = gaim_accounts_get_all(); l != NULL; l = l->next) {
 			cur = (GaimAccount *)l->data;
 			if (!strcmp(gaim_account_get_protocol_id(cur), "prpl-oscar")) {
-				/* XXX - Should the name be normalized? */
-				rendezvous_add_to_txt(rd, "AIM", gaim_account_get_username(cur));
+				rendezvous_add_to_txt(rd, "AIM", gaim_normalize(cur, gaim_account_get_username(cur)));
 				break;
 			}
 		}
@@ -619,6 +580,99 @@
 }
 
 static void
+rendezvous_send_offline(GaimConnection *gc)
+{
+	RendezvousData *rd = gc->proto_data;
+	GaimAccount *account = gaim_connection_get_account(gc);
+	const gchar *me;
+	gchar *myname;
+
+	me = gaim_account_get_username(account);
+	myname = g_strdup_printf("%s._presence._tcp.local", me);
+
+	mdns_advertise_ptr_with_ttl(rd->fd, "_presence._tcp.local", myname, 0);
+}
+
+/***********************************/
+/* All the PRPL Callback Functions */
+/***********************************/
+static const char *
+rendezvous_prpl_list_icon(GaimAccount *a, GaimBuddy *b)
+{
+	return "rendezvous";
+}
+
+static void
+rendezvous_prpl_list_emblems(GaimBuddy *b, const char **se, const char **sw, const char **nw, const char **ne)
+{
+	if (GAIM_BUDDY_IS_ONLINE(b)) {
+		if (b->uc & UC_UNAVAILABLE)
+			*se = "away";
+	} else {
+		*se = "offline";
+	}
+}
+
+static gchar *
+rendezvous_prpl_status_text(GaimBuddy *b)
+{
+	GaimConnection *gc = b->account->gc;
+	RendezvousData *rd = gc->proto_data;
+	RendezvousBuddy *rb;
+	gchar *ret;
+
+	rb = g_hash_table_lookup(rd->buddies, b->name);
+	if ((rb == NULL) || (rb->msg == NULL))
+		return NULL;
+
+	ret = g_strdup(rb->msg);
+
+	return ret;
+}
+
+static gchar *
+rendezvous_prpl_tooltip_text(GaimBuddy *b)
+{
+	GaimConnection *gc = b->account->gc;
+	RendezvousData *rd = gc->proto_data;
+	RendezvousBuddy *rb;
+	GString *ret;
+
+	rb = g_hash_table_lookup(rd->buddies, b->name);
+	if (rb == NULL)
+		return NULL;
+
+	ret = g_string_new("");
+
+	if (rb->aim != NULL)
+		g_string_append_printf(ret, "\n<b>%s</b>: %s", _("AIM Screen name"), rb->aim);
+
+	if (rb->msg != NULL) {
+		if (rb->status == UC_UNAVAILABLE)
+			g_string_append_printf(ret, "\n<b>%s</b>: %s", _("Away"), rb->msg);
+		else
+			g_string_append_printf(ret, "\n<b>%s</b>: %s", _("Available"), rb->msg);
+	}
+
+	return g_string_free(ret, FALSE);
+}
+
+static GList *
+rendezvous_prpl_status_types(GaimAccount *account)
+{
+	GList *status_types = NULL;
+	GaimStatusType *type;
+
+	type = gaim_status_type_new_full(GAIM_STATUS_OFFLINE, "offline", _("Offline"), FALSE, TRUE, FALSE);
+	status_types = g_list_append(status_types, type);
+
+	type = gaim_status_type_new_full(GAIM_STATUS_ONLINE, "online", _("Online"), FALSE, TRUE, FALSE);
+	status_types = g_list_append(status_types, type);
+
+	return status_types;
+}
+
+static void
 rendezvous_prpl_login(GaimAccount *account, GaimStatus *status)
 {
 	GaimConnection *gc = gaim_account_get_connection(account);
@@ -646,7 +700,12 @@
 		return;
 	}
 
+	/*
+	 * Watch our listening multicast UDP socket for incoming DNS
+	 * packets.
+	 */
 	gc->inpa = gaim_input_add(rd->fd, GAIM_INPUT_READ, rendezvous_callback, gc);
+
 	gaim_connection_set_state(gc, GAIM_CONNECTED);
 
 	mdns_query(rd->fd, "_presence._tcp.local", RENDEZVOUS_RRTYPE_ALL);
@@ -659,6 +718,8 @@
 	RendezvousData *rd = (RendezvousData *)gc->proto_data;
 	ResourceRecordRDataTXTNode *node;
 
+	rendezvous_send_offline(gc);
+
 	if (gc->inpa)
 		gaim_input_remove(gc->inpa);
 
@@ -691,18 +752,13 @@
 static int
 rendezvous_prpl_send_im(GaimConnection *gc, const char *who, const char *message, GaimConvImFlags flags)
 {
-	RendezvousData *rd = gc->proto_data;
-	RendezvousBuddy *rb;
-
 	gaim_debug_info("rendezvous", "Sending IM\n");
 
-	rb = g_hash_table_lookup(rd->buddies, who);
-	if (rb == NULL) {
-		/* TODO: Should print an error to the user, here */
-		gaim_debug_error("rendezvous", "Could not send message to %s: Could not find user information.\n", who);
-	}
-
-	/* TODO: Establish a direct connection then send IM.  Will need to queue the message somewhere. */
+	/*
+	 * TODO: Need to interpret any GaimConvImFlags here, before
+	 * calling rendezvous_direct_send_message().
+	 */
+	rendezvous_direct_send_message(gc, who, message);
 
 	return 1;
 }