view libfaim/aim_snac.c @ 1106:5bc8fdacd2cb

[gaim-migrate @ 1116] lots of changes. buddy.c: just in general tried to get things to work better. moving things in the edit list window and signing off should be handled better in the main buddy list window (watch out for flashes). gaim.h: removed toc-specific things and moved them to toc.c and rvous.c as needed. gtkhtml.c: possible fix for AOL 6.0 problems (I wasn't able to reproduce the problem before or after the fix, but i fixed what i think might have been causing the problem). multi.c: moved LOGIN_STEPS from gaim.h here and actually use it now oscar.c: moved an oscar-specific struct definition from gaim.h here and also handle problems better perl.c: fix for stupid problem rvous.c: first pass at attempt to be able to remove toc.c and rvous.c (though this will never happen; gaim will support toc as long as aol does) without cruft. gaim is now only dependent on toc.c and rvous.c for toc_build_config and parse_toc_buddy_list, which gaim needs to save and read its buddy list. toc.c: rewrote the signin process so that the read()'s won't block. it's not actually a non-blocking read; it's just that it won't ever get to the read until there's data to be read (thanks to the gdk_input watcher). this means the cancel button should work after it's connected, but it's still not a non-blocking connect. committer: Tailor Script <tailor@pidgin.im>
author Eric Warmenhoven <eric@warmenhoven.org>
date Mon, 20 Nov 2000 07:24:18 +0000
parents 595ac7759563
children 1e7625916fa7
line wrap: on
line source


/*
 *
 * 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 <faim/aim.h>

/*
 * Called from aim_session_init() to initialize the hash.
 */
faim_internal void aim_initsnachash(struct aim_session_t *sess)
{
  int i;

  for (i = 0; i < FAIM_SNAC_HASH_SIZE; i++) {
    sess->snac_hash[i] = NULL;
    faim_mutex_init(&sess->snac_hash_locks[i]);
  }

  return;
}

/*
 * Clones the passed snac structure and caches it in the
 * list/hash.
 */
faim_internal unsigned long aim_newsnac(struct aim_session_t *sess,
					struct aim_snac_t *newsnac) 
{
  struct aim_snac_t *snac = NULL;
  int index;

  if (!newsnac)
    return 0;

  if (!(snac = calloc(1, sizeof(struct aim_snac_t))))
    return 0;
  memcpy(snac, newsnac, sizeof(struct aim_snac_t));
  snac->issuetime = time(&snac->issuetime);
  snac->next = NULL;

  index = snac->id % FAIM_SNAC_HASH_SIZE;

  faim_mutex_lock(&sess->snac_hash_locks[index]);
  snac->next = sess->snac_hash[index];
  sess->snac_hash[index] = snac;
  faim_mutex_unlock(&sess->snac_hash_locks[index]);

  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.
 *
 */
faim_internal struct aim_snac_t *aim_remsnac(struct aim_session_t *sess, 
					     u_long id) 
{
  struct aim_snac_t *cur = NULL;
  int index;

  index = id % FAIM_SNAC_HASH_SIZE;

  faim_mutex_lock(&sess->snac_hash_locks[index]);
  if (!sess->snac_hash[index])
    ;
  else if (sess->snac_hash[index]->id == id) {
    cur = sess->snac_hash[index];
    sess->snac_hash[index] = cur->next;
  } else {
    cur = sess->snac_hash[index];
    while (cur->next) {
      if (cur->next->id == id) {
	struct aim_snac_t *tmp;
	
	tmp = cur->next;
	cur->next = cur->next->next;
	cur = tmp;
	break;
      }
      cur = cur->next;
    }
  }
  faim_mutex_unlock(&sess->snac_hash_locks[index]);

  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.
 *
 */
faim_internal int aim_cleansnacs(struct aim_session_t *sess,
				 int maxage)
{
  struct aim_snac_t *cur, *next, *prev = NULL;
  time_t curtime;
  int i;

  for (i = 0; i < FAIM_SNAC_HASH_SIZE; i++) {
    faim_mutex_lock(&sess->snac_hash_locks[i]);
    if (!sess->snac_hash[i]) {
      faim_mutex_unlock(&sess->snac_hash_locks[i]);
      continue;
    }

    curtime = time(NULL); /* done here in case we waited for the lock */

    cur = sess->snac_hash[i];
    while (cur) {
      next = cur->next;
      if ((curtime - cur->issuetime) > maxage) {
	if (sess->snac_hash[i] == cur)
	  prev = sess->snac_hash[i] = next;
	else
	  prev->next = next;

	/* XXX should we have destructors here? */
	if (cur->data)
	  free(cur->data);
	free(cur);

      } else {
	prev = cur;
      }
      cur = next;
    }

    faim_mutex_unlock(&sess->snac_hash_locks[i]);
  }

  return 0;
}

faim_internal int aim_putsnac(u_char *buf, int family, int subtype, int flags, u_long snacid)
{
  int curbyte = 0;
  curbyte += aimutil_put16(buf+curbyte, (u_short)(family&0xffff));
  curbyte += aimutil_put16(buf+curbyte, (u_short)(subtype&0xffff));
  curbyte += aimutil_put16(buf+curbyte, (u_short)(flags&0xffff));
  curbyte += aimutil_put32(buf+curbyte, snacid);
  return curbyte;
}