Beispiel #1
0
/*
 * Subtype 0x0004 - Set your client's capabilities.
 */
int
aim_locate_setcaps(OscarData *od, guint32 caps)
{
	FlapConnection *conn;
	ByteStream bs;
	aim_snacid_t snacid;
	GSList *tlvlist = NULL;

	if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_LOCATE)))
		return -EINVAL;

	aim_tlvlist_add_caps(&tlvlist, 0x0005, caps);

	byte_stream_new(&bs, aim_tlvlist_size(tlvlist));

	snacid = aim_cachesnac(od, SNAC_FAMILY_LOCATE, 0x0004, 0x0000, NULL, 0);

	aim_tlvlist_write(&bs, &tlvlist);
	aim_tlvlist_free(tlvlist);

	flap_connection_send_snac(od, conn, SNAC_FAMILY_LOCATE, 0x0004, 0x0000, snacid, &bs);

	byte_stream_destroy(&bs);

	return 0;
}
Beispiel #2
0
/*
 * Subtype 0x0004 - Set your client's capabilities.
 */
int
aim_locate_setcaps(OscarData *od, guint32 caps)
{
	FlapConnection *conn;
	FlapFrame *frame;
	aim_snacid_t snacid;
	GSList *tlvlist = NULL;

	if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_LOCATE)))
		return -EINVAL;

	aim_tlvlist_add_caps(&tlvlist, 0x0005, caps);

	frame = flap_frame_new(od, 0x02, 10 + aim_tlvlist_size(tlvlist));

	snacid = aim_cachesnac(od, 0x0002, 0x0004, 0x0000, NULL, 0);
	aim_putsnac(&frame->data, 0x0002, 0x004, 0x0000, snacid);

	aim_tlvlist_write(&frame->data, &tlvlist);
	aim_tlvlist_free(tlvlist);

	flap_connection_send(conn, frame);

	return 0;
}
/*
 * Subtype 0x0004 - Set your client's capabilities.
 */
int
aim_locate_setcaps(OscarData *od, guint64 caps)
{
	FlapConnection *conn;
	PurpleAccount *account = purple_connection_get_account(od->gc);
	PurplePresence *presence = purple_account_get_presence(account);
	PurpleStatus *status = purple_presence_get_status(presence, "mood");
	const char *mood = purple_status_get_attr_string(status, PURPLE_MOOD_NAME);
	ByteStream bs;
	aim_snacid_t snacid;
	GSList *tlvlist = NULL;

	if (!(conn = flap_connection_findbygroup(od, SNAC_FAMILY_LOCATE)))
		return -EINVAL;

	aim_tlvlist_add_caps(&tlvlist, 0x0005, caps, mood);

	byte_stream_new(&bs, aim_tlvlist_size(tlvlist));

	snacid = aim_cachesnac(od, SNAC_FAMILY_LOCATE, 0x0004, 0x0000, NULL, 0);

	aim_tlvlist_write(&bs, &tlvlist);
	aim_tlvlist_free(tlvlist);

	flap_connection_send_snac(od, conn, SNAC_FAMILY_LOCATE, 0x0004, snacid, &bs);

	byte_stream_destroy(&bs);

	return 0;
}
Beispiel #4
0
/*
 * Subtype 0x0002
 *
 * Request Location services rights.
 *
 */
int
aim_locate_reqrights(OscarData *od)
{
	FlapConnection *conn;

	if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_LOCATE)))
		return -EINVAL;

	aim_genericreq_n_snacid(od, conn, SNAC_FAMILY_LOCATE, SNAC_SUBTYPE_LOCATE_REQRIGHTS);

	return 0;
}
Beispiel #5
0
/*
 * Subtype 0x0009 - Set directory profile data.
 *
 * This is not the same as aim_location_setprofile!
 * privacy: 1 to allow searching, 0 to disallow.
 *
 */
int aim_locate_setdirinfo(OscarData *od, const char *first, const char *middle, const char *last, const char *maiden, const char *nickname, const char *street, const char *city, const char *state, const char *zip, int country, guint16 privacy)
{
	FlapConnection *conn;
	ByteStream bs;
	aim_snacid_t snacid;
	GSList *tlvlist = NULL;

	if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_LOCATE)))
		return -EINVAL;

	aim_tlvlist_add_16(&tlvlist, 0x000a, privacy);

	if (first)
		aim_tlvlist_add_str(&tlvlist, 0x0001, first);
	if (last)
		aim_tlvlist_add_str(&tlvlist, 0x0002, last);
	if (middle)
		aim_tlvlist_add_str(&tlvlist, 0x0003, middle);
	if (maiden)
		aim_tlvlist_add_str(&tlvlist, 0x0004, maiden);

	if (state)
		aim_tlvlist_add_str(&tlvlist, 0x0007, state);
	if (city)
		aim_tlvlist_add_str(&tlvlist, 0x0008, city);

	if (nickname)
		aim_tlvlist_add_str(&tlvlist, 0x000c, nickname);
	if (zip)
		aim_tlvlist_add_str(&tlvlist, 0x000d, zip);

	if (street)
		aim_tlvlist_add_str(&tlvlist, 0x0021, street);

	byte_stream_new(&bs, aim_tlvlist_size(tlvlist));

	snacid = aim_cachesnac(od, SNAC_FAMILY_LOCATE, 0x0009, 0x0000, NULL, 0);

	aim_tlvlist_write(&bs, &tlvlist);
	aim_tlvlist_free(tlvlist);

	flap_connection_send_snac(od, conn, SNAC_FAMILY_LOCATE, 0x0009, 0x0000, snacid, &bs);

	byte_stream_destroy(&bs);

	return 0;
}
Beispiel #6
0
/*
 * Subtype 0x0015 - Request the info of a user using the short method.  This is
 * what iChat uses.  It normally is VERY leniently rate limited.
 *
 * @param bn The buddy name whose info you wish to request.
 * @param flags The bitmask which specifies the type of info you wish to request.
 *        0x00000001 - Info/profile.
 *        0x00000002 - Away message.
 *        0x00000004 - Capabilities.
 *        0x00000008 - Certification.
 * @return Return 0 if no errors, otherwise return the error number.
 */
int
aim_locate_getinfoshort(OscarData *od, const char *bn, guint32 flags)
{
	FlapConnection *conn;
	ByteStream bs;
	aim_snacid_t snacid;

	if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_LOCATE)) || !bn)
		return -EINVAL;

	byte_stream_new(&bs, 4 + 1 + strlen(bn));
	byte_stream_put32(&bs, flags);
	byte_stream_put8(&bs, strlen(bn));
	byte_stream_putstr(&bs, bn);

	snacid = aim_cachesnac(od, SNAC_FAMILY_LOCATE, 0x0015, 0x0000, bn, strlen(bn)+1);
	flap_connection_send_snac_with_priority(od, conn, SNAC_FAMILY_LOCATE, 0x0015, 0x0000, snacid, &bs, FALSE);

	byte_stream_destroy(&bs);

	return 0;
}
Beispiel #7
0
/*
 * Subtype 0x0015 - Request the info a user using the short method.  This is
 * what iChat uses.  It normally is VERY leniently rate limited.
 *
 * @param sn The screen name whose info you wish to request.
 * @param flags The bitmask which specifies the type of info you wish to request.
 *        0x00000001 - Info/profile.
 *        0x00000002 - Away message.
 *        0x00000004 - Capabilities.
 *        0x00000008 - Certification.
 * @return Return 0 if no errors, otherwise return the error number.
 */
int
aim_locate_getinfoshort(OscarData *od, const char *sn, guint32 flags)
{
	FlapConnection *conn;
	ByteStream data;
	aim_snacid_t snacid;

	if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_LOCATE)) || !sn)
		return -EINVAL;

	byte_stream_new(&data, 4 + 1 + strlen(sn));
	byte_stream_put32(&data, flags);
	byte_stream_put8(&data, strlen(sn));
	byte_stream_putstr(&data, sn);

	snacid = aim_cachesnac(od, 0x0002, 0x0015, 0x0000, sn, strlen(sn)+1);
	flap_connection_send_snac(od, conn, 0x0002, 0x0015, 0x0000, snacid, &data);

	g_free(data.data);

	return 0;
}
Beispiel #8
0
/*
 * Subtype 0x000b - Huh? What is this?
 */
int aim_locate_000b(OscarData *od, const char *sn)
{
	FlapConnection *conn;
	FlapFrame *frame;
	aim_snacid_t snacid;

		return -EINVAL;

	if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_LOCATE)) || !sn)
		return -EINVAL;

	frame = flap_frame_new(od, 0x02, 10+1+strlen(sn));

	snacid = aim_cachesnac(od, 0x0002, 0x000b, 0x0000, NULL, 0);

	aim_putsnac(&frame->data, 0x0002, 0x000b, 0x0000, snacid);
	byte_stream_put8(&frame->data, strlen(sn));
	byte_stream_putstr(&frame->data, sn);

	flap_connection_send(conn, frame);

	return 0;
}
Beispiel #9
0
/*
 * Subtype 0x000f
 *
 * XXX pass these in better
 *
 */
int
aim_locate_setinterests(OscarData *od, const char *interest1, const char *interest2, const char *interest3, const char *interest4, const char *interest5, guint16 privacy)
{
	FlapConnection *conn;
	ByteStream bs;
	aim_snacid_t snacid;
	GSList *tlvlist = NULL;

	if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_LOCATE)))
		return -EINVAL;

	/* ?? privacy ?? */
	aim_tlvlist_add_16(&tlvlist, 0x000a, privacy);

	if (interest1)
		aim_tlvlist_add_str(&tlvlist, 0x0000b, interest1);
	if (interest2)
		aim_tlvlist_add_str(&tlvlist, 0x0000b, interest2);
	if (interest3)
		aim_tlvlist_add_str(&tlvlist, 0x0000b, interest3);
	if (interest4)
		aim_tlvlist_add_str(&tlvlist, 0x0000b, interest4);
	if (interest5)
		aim_tlvlist_add_str(&tlvlist, 0x0000b, interest5);

	byte_stream_new(&bs, aim_tlvlist_size(tlvlist));

	snacid = aim_cachesnac(od, SNAC_FAMILY_LOCATE, 0x000f, 0x0000, NULL, 0);

	aim_tlvlist_write(&bs, &tlvlist);
	aim_tlvlist_free(tlvlist);

	flap_connection_send_snac(od, conn, SNAC_FAMILY_LOCATE, 0x000f, 0x0000, snacid, &bs);

	byte_stream_destroy(&bs);
	return 0;
}
Beispiel #10
0
/*
 * Subtype 0x000f
 *
 * XXX pass these in better
 *
 */
int
aim_locate_setinterests(OscarData *od, const char *interest1, const char *interest2, const char *interest3, const char *interest4, const char *interest5, guint16 privacy)
{
	FlapConnection *conn;
	FlapFrame *frame;
	aim_snacid_t snacid;
	GSList *tlvlist = NULL;

	if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_LOCATE)))
		return -EINVAL;

	/* ?? privacy ?? */
	aim_tlvlist_add_16(&tlvlist, 0x000a, privacy);

	if (interest1)
		aim_tlvlist_add_str(&tlvlist, 0x0000b, interest1);
	if (interest2)
		aim_tlvlist_add_str(&tlvlist, 0x0000b, interest2);
	if (interest3)
		aim_tlvlist_add_str(&tlvlist, 0x0000b, interest3);
	if (interest4)
		aim_tlvlist_add_str(&tlvlist, 0x0000b, interest4);
	if (interest5)
		aim_tlvlist_add_str(&tlvlist, 0x0000b, interest5);

	frame = flap_frame_new(od, 0x02, 10+aim_tlvlist_size(tlvlist));

	snacid = aim_cachesnac(od, 0x0002, 0x000f, 0x0000, NULL, 0);

	aim_putsnac(&frame->data, 0x0002, 0x000f, 0x0000, 0);
	aim_tlvlist_write(&frame->data, &tlvlist);
	aim_tlvlist_free(tlvlist);

	flap_connection_send(conn, frame);

	return 0;
}
Beispiel #11
0
/*
 * Subtype 0x000b - Huh? What is this?
 */
int aim_locate_000b(OscarData *od, const char *bn)
{
	FlapConnection *conn;
	ByteStream bs;
	aim_snacid_t snacid;

		return -EINVAL;

	if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_LOCATE)) || !bn)
		return -EINVAL;

	byte_stream_new(&bs, 1+strlen(bn));

	snacid = aim_cachesnac(od, SNAC_FAMILY_LOCATE, 0x000b, 0x0000, NULL, 0);

	byte_stream_put8(&bs, strlen(bn));
	byte_stream_putstr(&bs, bn);

	flap_connection_send_snac(od, conn, SNAC_FAMILY_LOCATE, 0x000b, 0x0000, snacid, &bs);

	byte_stream_destroy(&bs);

	return 0;
}
Beispiel #12
0
/*
 * Subtype 0x0004
 *
 * Gives BOS your profile.
 *
 * profile_encoding and awaymsg_encoding MUST be set if profile or
 * away are set, respectively, and their value may or may not be
 * restricted to a few choices.  I am currently aware of:
 *
 * us-ascii		Just that
 * unicode-2-0		UTF-16BE
 *
 * profile_len and awaymsg_len MUST be set similarly, and they MUST
 * be the length of their respective strings in bytes.
 *
 * To get the previous behavior of awaymsg == "" un-setting the away
 * message, set awaymsg non-NULL and awaymsg_len to 0 (this is the
 * obvious equivalent).
 *
 */
int
aim_locate_setprofile(OscarData *od,
				  const char *profile_encoding, const gchar *profile, const int profile_len,
				  const char *awaymsg_encoding, const gchar *awaymsg, const int awaymsg_len)
{
	FlapConnection *conn;
	ByteStream bs;
	aim_snacid_t snacid;
	GSList *tlvlist = NULL;
	char *encoding;
	static const char defencoding[] = {"text/aolrtf; charset=\"%s\""};

	if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_LOCATE)))
		return -EINVAL;

	if (!profile && !awaymsg)
		return -EINVAL;

	if ((profile && profile_encoding == NULL) || (awaymsg && awaymsg_len && awaymsg_encoding == NULL)) {
		return -EINVAL;
	}

	/* Build the packet first to get real length */
	if (profile) {
		/* no + 1 here because of %s */
		encoding = g_malloc(strlen(defencoding) + strlen(profile_encoding));
		snprintf(encoding, strlen(defencoding) + strlen(profile_encoding), defencoding, profile_encoding);
		aim_tlvlist_add_str(&tlvlist, 0x0001, encoding);
		aim_tlvlist_add_raw(&tlvlist, 0x0002, profile_len, (const guchar *)profile);
		g_free(encoding);
	}

	/*
	 * So here's how this works:
	 *   - You are away when you have a non-zero-length type 4 TLV stored.
	 *   - You become unaway when you clear the TLV with a zero-length
	 *       type 4 TLV.
	 *   - If you do not send the type 4 TLV, your status does not change
	 *       (that is, if you were away, you'll remain away).
	 */
	if (awaymsg) {
		if (awaymsg_len) {
			encoding = g_malloc(strlen(defencoding) + strlen(awaymsg_encoding));
			snprintf(encoding, strlen(defencoding) + strlen(awaymsg_encoding), defencoding, awaymsg_encoding);
			aim_tlvlist_add_str(&tlvlist, 0x0003, encoding);
			aim_tlvlist_add_raw(&tlvlist, 0x0004, awaymsg_len, (const guchar *)awaymsg);
			g_free(encoding);
		} else
			aim_tlvlist_add_noval(&tlvlist, 0x0004);
	}

	byte_stream_new(&bs, aim_tlvlist_size(tlvlist));

	snacid = aim_cachesnac(od, SNAC_FAMILY_LOCATE, 0x0004, 0x0000, NULL, 0);

	aim_tlvlist_write(&bs, &tlvlist);
	aim_tlvlist_free(tlvlist);

	flap_connection_send_snac(od, conn, SNAC_FAMILY_LOCATE, 0x0004, 0x0000, snacid, &bs);

	byte_stream_destroy(&bs);

	return 0;
}
Beispiel #13
0
/**
 * We've just opened a listener socket, so we send the remote
 * user an ICBM and ask them to connect to us.
 */
static void
peer_connection_establish_listener_cb(int listenerfd, gpointer data)
{
	PeerConnection *conn;
	OscarData *od;
	PurpleConnection *gc;
	PurpleAccount *account;
	PurpleConversation *conv;
	char *tmp;
	FlapConnection *bos_conn;
	const char *listener_ip;
	const guchar *ip_atoi;
	unsigned short listener_port;

	conn = data;
	conn->listen_data = NULL;

	if (listenerfd < 0)
	{
		/* Could not open listener socket */
		peer_connection_trynext(conn);
		return;
	}

	od = conn->od;
	gc = od->gc;
	account = purple_connection_get_account(gc);
	conn->listenerfd = listenerfd;

	/* Watch for new connections on our listener socket */
	conn->watcher_incoming = purple_input_add(conn->listenerfd,
			PURPLE_INPUT_READ, peer_connection_listen_cb, conn);

	/* Send the "please connect to me!" ICBM */
	bos_conn = flap_connection_findbygroup(od, SNAC_FAMILY_ICBM);
	if (bos_conn == NULL)
	{
		/* Not good */
		peer_connection_trynext(conn);
		return;
	}

	if (bos_conn->gsc)
		listener_ip = purple_network_get_my_ip(bos_conn->gsc->fd);
	else
		listener_ip = purple_network_get_my_ip(bos_conn->fd);

	ip_atoi = purple_network_ip_atoi(listener_ip);
	if (ip_atoi == NULL) {
		/* Could not convert IP to 4 byte array--weird, but this does
		   happen for some users (#4829, Adium #15839).  Maybe they're
		   connecting with IPv6...?  Maybe through a proxy? */
		purple_debug_error("oscar", "Can't ask peer to connect to us "
				"because purple_network_ip_atoi(%s) returned NULL. "
				"fd=%d. is_ssl=%d\n",
				listener_ip ? listener_ip : "(null)",
				bos_conn->gsc ? bos_conn->gsc->fd : bos_conn->fd,
				bos_conn->gsc ? 1 : 0);
		peer_connection_trynext(conn);
		return;
	}

	listener_port = purple_network_get_port_from_fd(conn->listenerfd);

	if (conn->type == OSCAR_CAPABILITY_DIRECTIM)
	{
		aim_im_sendch2_odc_requestdirect(od,
				conn->cookie, conn->bn, ip_atoi,
				listener_port, ++conn->lastrequestnumber);

		/* Print a message to a local conversation window */
		conv = purple_conversation_new(PURPLE_CONV_TYPE_IM, account, conn->bn);
		tmp = g_strdup_printf(_("Asking %s to connect to us at %s:%hu for "
				"Direct IM."), conn->bn, listener_ip, listener_port);
		purple_conversation_write(conv, NULL, tmp, PURPLE_MESSAGE_SYSTEM, time(NULL));
		g_free(tmp);
	}
	else if (conn->type == OSCAR_CAPABILITY_SENDFILE)
	{
		aim_im_sendch2_sendfile_requestdirect(od,
				conn->cookie, conn->bn,
				ip_atoi,
				listener_port, ++conn->lastrequestnumber,
				(const gchar *)conn->xferdata.name,
				conn->xferdata.size, conn->xferdata.totfiles);
	}
}
Beispiel #14
0
/**
 * We've just opened a listener socket, so we send the remote
 * user an ICBM and ask them to connect to us.
 */
static void
peer_connection_establish_listener_cb(int listenerfd, gpointer data)
{
	PeerConnection *conn;
	OscarData *od;
	PurpleConnection *gc;
	PurpleAccount *account;
	PurpleConversation *conv;
	char *tmp;
	FlapConnection *bos_conn;
	const char *listener_ip;
	unsigned short listener_port;

	conn = data;
	conn->listen_data = NULL;

	if (listenerfd < 0)
	{
		/* Could not open listener socket */
		peer_connection_trynext(conn);
		return;
	}

	od = conn->od;
	gc = od->gc;
	account = purple_connection_get_account(gc);
	conn->listenerfd = listenerfd;

	/* Watch for new connections on our listener socket */
	conn->watcher_incoming = purple_input_add(conn->listenerfd,
			PURPLE_INPUT_READ, peer_connection_listen_cb, conn);

	/* Send the "please connect to me!" ICBM */
	bos_conn = flap_connection_findbygroup(od, SNAC_FAMILY_ICBM);
	if (bos_conn == NULL)
	{
		/* Not good */
		peer_connection_trynext(conn);
		return;
	}

	if (bos_conn->gsc)
		listener_ip = purple_network_get_my_ip(bos_conn->gsc->fd);
	else
		listener_ip = purple_network_get_my_ip(bos_conn->fd);
	listener_port = purple_network_get_port_from_fd(conn->listenerfd);
	if (conn->type == OSCAR_CAPABILITY_DIRECTIM)
	{
		aim_im_sendch2_odc_requestdirect(od,
				conn->cookie, conn->sn, purple_network_ip_atoi(listener_ip),
				listener_port, ++conn->lastrequestnumber);

		/* Print a message to a local conversation window */
		conv = purple_conversation_new(PURPLE_CONV_TYPE_IM, account, conn->sn);
		tmp = g_strdup_printf(_("Asking %s to connect to us at %s:%hu for "
				"Direct IM."), conn->sn, listener_ip, listener_port);
		purple_conversation_write(conv, NULL, tmp, PURPLE_MESSAGE_SYSTEM, time(NULL));
		g_free(tmp);
	}
	else if (conn->type == OSCAR_CAPABILITY_SENDFILE)
	{
		aim_im_sendch2_sendfile_requestdirect(od,
				conn->cookie, conn->sn,
				purple_network_ip_atoi(listener_ip),
				listener_port, ++conn->lastrequestnumber,
				(const gchar *)conn->xferdata.name,
				conn->xferdata.size, conn->xferdata.totfiles);
	}
}
Beispiel #15
0
/*
 * Add the userinfo to our linked list.  If we already have userinfo
 * for this buddy, then just overwrite parts of the old data.
 *
 * @param userinfo Contains the new information for the buddy.
 */
static void
aim_locate_adduserinfo(OscarData *od, aim_userinfo_t *userinfo)
{
	aim_userinfo_t *cur;
	FlapConnection *conn;
	aim_rxcallback_t userfunc;

	cur = aim_locate_finduserinfo(od, userinfo->sn);

	if (cur == NULL) {
		cur = (aim_userinfo_t *)g_new0(aim_userinfo_t, 1);
		cur->sn = g_strdup(userinfo->sn);
		cur->next = od->locate.userinfo;
		od->locate.userinfo = cur;
	}

	cur->warnlevel = userinfo->warnlevel;
	cur->idletime = userinfo->idletime;
	if (userinfo->flags != 0)
		cur->flags = userinfo->flags;
	if (userinfo->createtime != 0)
		cur->createtime = userinfo->createtime;
	if (userinfo->membersince != 0)
		cur->membersince = userinfo->membersince;
	if (userinfo->onlinesince != 0)
		cur->onlinesince = userinfo->onlinesince;
	if (userinfo->sessionlen != 0)
		cur->sessionlen = userinfo->sessionlen;
	if (userinfo->capabilities != 0)
		cur->capabilities = userinfo->capabilities;
	cur->present |= userinfo->present;

	if (userinfo->iconcsumlen > 0) {
		g_free(cur->iconcsum);
		cur->iconcsum = (guint8 *)g_malloc(userinfo->iconcsumlen);
		memcpy(cur->iconcsum, userinfo->iconcsum, userinfo->iconcsumlen);
		cur->iconcsumlen = userinfo->iconcsumlen;
	}

	if (userinfo->info != NULL) {
		g_free(cur->info);
		g_free(cur->info_encoding);
		if (userinfo->info_len > 0) {
			cur->info = (char *)g_malloc(userinfo->info_len);
			memcpy(cur->info, userinfo->info, userinfo->info_len);
		} else
			cur->info = NULL;
		cur->info_encoding = g_strdup(userinfo->info_encoding);
		cur->info_len = userinfo->info_len;
	}

	if (userinfo->status != NULL) {
		g_free(cur->status);
		g_free(cur->status_encoding);
		if (userinfo->status_len > 0) {
			cur->status = (char *)g_malloc(userinfo->status_len);
			memcpy(cur->status, userinfo->status, userinfo->status_len);
		} else
			cur->status = NULL;
		if (userinfo->status_encoding != NULL)
			cur->status_encoding = g_strdup(userinfo->status_encoding);
		else
			cur->status_encoding = NULL;
		cur->status_len = userinfo->status_len;
	}

	if (userinfo->itmsurl != NULL) {
		g_free(cur->itmsurl);
		g_free(cur->itmsurl_encoding);
		if (userinfo->itmsurl_len > 0) {
			cur->itmsurl = (char *)g_malloc(userinfo->itmsurl_len);
			memcpy(cur->itmsurl, userinfo->itmsurl, userinfo->itmsurl_len);
		} else
			cur->itmsurl = NULL;
		if (userinfo->itmsurl_encoding != NULL)
			cur->itmsurl_encoding = g_strdup(userinfo->itmsurl_encoding);
		else
			cur->itmsurl_encoding = NULL;
		cur->itmsurl_len = userinfo->itmsurl_len;
	}

	if (userinfo->away != NULL) {
		g_free(cur->away);
		g_free(cur->away_encoding);
		if (userinfo->away_len > 0) {
			cur->away = (char *)g_malloc(userinfo->away_len);
			memcpy(cur->away, userinfo->away, userinfo->away_len);
		} else
			cur->away = NULL;
		cur->away_encoding = g_strdup(userinfo->away_encoding);
		cur->away_len = userinfo->away_len;

	} else if (!(userinfo->flags & AIM_FLAG_AWAY)) {
		/*
		 * We don't have an away message specified in this user_info block.
		 * If the user is not away, clear any cached away message now.
		 */
		if (cur->away) {
			g_free(cur->away);
			cur->away = NULL;
		}
		if (cur->away_encoding) {
			g_free(cur->away_encoding);
			cur->away_encoding = NULL;
		}
		cur->away_len = 0;
	}

	/*
	 * This callback can be used by a client if they want to know whenever
	 * info for a buddy is updated.  For example, if a client shows away
	 * messages in its buddy list, then it would need to know if a user's
	 * away message changes.
	 */
	conn = flap_connection_findbygroup(od, SNAC_FAMILY_LOCATE);
	if ((userfunc = aim_callhandler(od, SNAC_FAMILY_LOCATE, SNAC_SUBTYPE_LOCATE_GOTINFOBLOCK)))
		userfunc(od, conn, NULL, cur);
}