diff options
Diffstat (limited to 'protocols/oscar/snac.c')
| -rw-r--r-- | protocols/oscar/snac.c | 147 | 
1 files changed, 147 insertions, 0 deletions
| diff --git a/protocols/oscar/snac.c b/protocols/oscar/snac.c new file mode 100644 index 00000000..8a75b2a0 --- /dev/null +++ b/protocols/oscar/snac.c @@ -0,0 +1,147 @@ +/* + * + * Various SNAC-related dodads...  + * + * outstanding_snacs is a list of aim_snac_t structs.  A SNAC should be added + * whenever a new SNAC is sent and it should remain in the list until the + * response for it has been receieved.   + * + * cleansnacs() should be called periodically by the client in order + * to facilitate the aging out of unreplied-to SNACs. This can and does + * happen, so it should be handled. + * + */ + +#include <aim.h> + +static aim_snacid_t aim_newsnac(aim_session_t *sess, aim_snac_t *newsnac); + +/* + * Called from aim_session_init() to initialize the hash. + */ +void aim_initsnachash(aim_session_t *sess) +{ +	int i; + +	for (i = 0; i < AIM_SNAC_HASH_SIZE; i++) +		sess->snac_hash[i] = NULL; + +	return; +} + +aim_snacid_t aim_cachesnac(aim_session_t *sess, const guint16 family, const guint16 type, const guint16 flags, const void *data, const int datalen) +{ +	aim_snac_t snac; + +	snac.id = sess->snacid_next++; +	snac.family = family; +	snac.type = type; +	snac.flags = flags; + +	if (datalen) { +		if (!(snac.data = g_malloc(datalen))) +			return 0; /* er... */ +		memcpy(snac.data, data, datalen); +	} else +		snac.data = NULL; + +	return aim_newsnac(sess, &snac); +} + +/* + * Clones the passed snac structure and caches it in the + * list/hash. + */ +static aim_snacid_t aim_newsnac(aim_session_t *sess, aim_snac_t *newsnac) +{ +	aim_snac_t *snac; +	int index; + +	if (!newsnac) +		return 0; + +	if (!(snac = g_malloc(sizeof(aim_snac_t)))) +		return 0; +	memcpy(snac, newsnac, sizeof(aim_snac_t)); +	snac->issuetime = time(NULL); + +	index = snac->id % AIM_SNAC_HASH_SIZE; + +	snac->next = (aim_snac_t *)sess->snac_hash[index]; +	sess->snac_hash[index] = (void *)snac; + +	return snac->id; +} + +/* + * Finds a snac structure with the passed SNAC ID,  + * removes it from the list/hash, and returns a pointer to it. + * + * The returned structure must be freed by the caller. + * + */ +aim_snac_t *aim_remsnac(aim_session_t *sess, aim_snacid_t id)  +{ +	aim_snac_t *cur, **prev; +	int index; + +	index = id % AIM_SNAC_HASH_SIZE; + +	for (prev = (aim_snac_t **)&sess->snac_hash[index]; (cur = *prev); ) { +		if (cur->id == id) { +			*prev = cur->next; +			return cur; +		} else +			prev = &cur->next; +	} + +	return cur; +} + +/* + * This is for cleaning up old SNACs that either don't get replies or + * a reply was never received for.  Garabage collection. Plain and simple. + * + * maxage is the _minimum_ age in seconds to keep SNACs. + * + */ +void aim_cleansnacs(aim_session_t *sess, int maxage) +{ +	int i; + +	for (i = 0; i < AIM_SNAC_HASH_SIZE; i++) { +		aim_snac_t *cur, **prev; +		time_t curtime; + +		if (!sess->snac_hash[i]) +			continue; + +		curtime = time(NULL); /* done here in case we waited for the lock */ + +		for (prev = (aim_snac_t **)&sess->snac_hash[i]; (cur = *prev); ) { +			if ((curtime - cur->issuetime) > maxage) { + +				*prev = cur->next; + +				/* XXX should we have destructors here? */ +				g_free(cur->data); +				g_free(cur); + +			} else +				prev = &cur->next; +		} +	} + +	return; +} + +int aim_putsnac(aim_bstream_t *bs, guint16 family, guint16 subtype, guint16 flags, aim_snacid_t snacid) +{ + +	aimbs_put16(bs, family); +	aimbs_put16(bs, subtype); +	aimbs_put16(bs, flags); +	aimbs_put32(bs, snacid); + +	return 10; +} | 
