www.pudn.com > AnyQ服务端源码.rar > buddies.c


/*
 * Jabber AIM-Transport libfaim interface
 *
*/

#include "aimtrans.h"

struct buddy_clean_data
{
    ati ti;
    xmlnode node;
};

void _at_buddies_unsubscribe(xht ht, const char *key, void *data, void * arg)
{
    xmlnode pres;
    at_session s;
    ati ti;

    s = (at_session)arg;
    ti = s->ti;

    pres = jutil_presnew(JPACKET__UNSUBSCRIBE, jid_full(s->cur), "Transport Removal");
    xmlnode_put_attrib(pres, "from", key);
    at_deliver(ti,pres);
}

result at_buddy_pending_clean(void *arg)
{
    struct buddy_clean_data *bcd;
    ati ti;
    char *user;
    xmlnode node;

    bcd = (struct buddy_clean_data *)arg;
    node = bcd->node;
    ti = bcd->ti;
    user = xmlnode_get_attrib(node, "user");

    log_debug(ZONE, "[AT] Cleaning pending for %s: %s", user, xmlnode2str(node));
    pth_mutex_acquire(&ti->buddies_mutex, 0, NULL);

    xhash_zap(ti->pending__buddies, user);

    xmlnode_free(node);
    pth_mutex_release(&ti->buddies_mutex);

    return r_UNREG;
}

void at_buddy_addtolist(at_session s, spool sp, xmlnode x)
{
    at_buddy new;
    at_buddy old;
    xmlnode item;

    for(item = xmlnode_get_firstchild(x); item != NULL; 
                    item = xmlnode_get_nextsibling(item))
    {
        char *sn;

        sn = at_normalize(xmlnode_get_attrib(item, "name"));
        old = xhash_get(s->buddies, sn);
        if(old != NULL)
        {
            log_debug(ZONE, "[AT] We already have %s in our list", sn);
            continue;
        }

        log_debug(ZONE, "[AIM] Adding buddy %s", sn);

        spooler(sp, sn, "&", sp);
        new = pmalloco(s->p, sizeof(_at_buddy));
        new->full = jid_new(s->p, s->ti->i->id);
        jid_set(new->full, sn, JID_USER);
        new->last = xmlnode_new_tag_pool(s->p,"query");
        new->is_away = -1;
        xmlnode_put_attrib(new->last,"xmlns",NS_LAST);
        xmlnode_put_attrib(new->last,"stamp",jutil_timestamp()); 

        xhash_put(s->buddies, new->full->user, new);
    }
}

char *at_buddy_buildlist(at_session s, jid from)
{
    char *list;
	char *blist;
	spool sp;
    pool p, bp;
    xmlnode x;
    xmlnode msg;

    p = pool_new();
	sp = spool_new(p);

    log_debug(ZONE, "[AIM] Building buddy list for new session - XDB");

    /* Get buddies from transport's XDB roster */
    x = at_xdb_get(s->ti, from, AT_NS_ROSTER);
    if(x != NULL)
    {
        at_buddy_addtolist(s, sp, x);
    }

    log_debug(ZONE, "[AIM] Building buddy list for new session - pending list");

    /* Get buddies from instance's pending list - this list */
    /* has been built by incoming presence/probe packets before */
    /* a session has been established */
    x = xhash_get(s->ti->pending__buddies, jid_full(jid_user(from)));
    if(x == NULL)
    {
        return NULL;
    } else {
        at_buddy_addtolist(s, sp, x);
    }
    
    list = spool_print(sp);
    if(list)
    {
        blist = strdup(list);
    } else {
        blist = NULL;
    }
    log_debug(ZONE, "[AT] Buddylist generation complete");

    pool_free(p);

    return blist;
}

int at_buddy_subscribe(ati ti, jpacket jp)
{
    xmlnode dup,dup2;
    at_session s=at_session_find_by_jid(ti, jp->from);

    /* check for a valid session */
    if(s==NULL)
    {
        xmlnode err,error;
        /* if no session, and subscribing to a buddy, not aim-t */
        err=xmlnode_new_tag("message");
        xmlnode_put_attrib(err,"type","error");
        xmlnode_put_attrib(err,"from",ti->i->id);
        xmlnode_put_attrib(err,"to",jid_full(jp->from));
        error=xmlnode_insert_tag(err,"error");
        xmlnode_insert_cdata(error,"Cannot Subscribe to a AIM Buddy without a registration",-1);
        xmlnode_put_attrib(error,"code","407");
        at_deliver(ti,err);

        return 0;
    }
    /* XXX
	 * Create the duplicate for the subscribe notice
	 * Construct a subscribed notification
	 * 
	 * I had to do these in this odd order due to memory concerns
	 * Dunno why I didn't just make two dups.
	 *
	 */
	dup = xmlnode_dup(jp->x);
	dup2 = xmlnode_dup(jp->x);

	xmlnode_put_attrib(dup, "to", jid_full(jp->from));
	xmlnode_put_attrib(dup, "from", jid_full(jp->to));
	xmlnode_put_attrib(dup, "type", "subscribed");
	log_debug(ZONE, "[AIM] Sending subscribed notice\n");
    at_deliver(ti,dup);

	/* Construct the subscribe back */
	xmlnode_put_attrib(dup2, "type", "subscribe");
    xmlnode_put_attrib(dup2, "to", jid_full(jp->from));
    xmlnode_put_attrib(dup2, "from", jid_full(jp->to));
	log_debug(ZONE, "[AIM] Asking for a subscribe\n");
    at_deliver(ti,dup2);

	return 0;
}

/** Got some hint for a buddy (presence/probe/s10n Jabber packet) */
int at_buddy_add(ati ti, jpacket jp)
{
	at_session s;
	at_buddy buddy;
    pool p;
	int newbud=0;
    struct buddy_clean_data *bcd;
	
	s = at_session_find_by_jid(ti, jp->from);
	if(s==NULL || s->loggedin == 0) 
    {
        xmlnode cur, item;

        /* No session yet, add to pending list for this user */
        log_debug(ZONE, "[AIM] Add buddy %s to pending list for %s", jid_full(jp->to),jid_full(jid_user(jp->from)));
        pth_mutex_acquire(&ti->buddies_mutex, 0, NULL);
        cur = xhash_get(ti->pending__buddies, jid_full(jid_user(jp->from)));
        if(cur == NULL)
        {
            log_debug(ZONE, "[AIM] Creating pending list for %s", jid_full(jid_user(jp->from)));
            cur = xmlnode_new_tag("buddies");
            xmlnode_put_attrib(cur, "user", jid_full(jid_user(jp->from)));
            bcd = pmalloco(xmlnode_pool(cur), sizeof(struct buddy_clean_data));
            bcd->node = cur;
            bcd->ti = ti;
            /* Free pending list after a while */
            register_beat(30, at_buddy_pending_clean, bcd);
        }
        item = xmlnode_insert_tag(cur, "item");
        xmlnode_put_attrib(item, "name", jp->to->user);
        xmlnode_free(jp->x);
        log_debug(ZONE, "[AT] Resulting pending list: %s", xmlnode2str(cur));
        xhash_put(ti->pending__buddies, xmlnode_get_attrib(cur, "user"), cur);
        pth_mutex_release(&ti->buddies_mutex);
        return 1;
	}

    /* We have a session */
    
    if(xhash_get(s->buddies, jp->to->user) == NULL)
    {
        log_debug(ZONE, "[AIM] Add buddy %s to session %s\n", jp->to->user, jid_full(jp->from));
        buddy = pmalloco(s->p, sizeof(_at_buddy));
        buddy->full=jid_new(s->p, jid_full(jp->to));
        buddy->last = xmlnode_new_tag_pool(s->p,"query");
        buddy->is_away = -1;
        xmlnode_put_attrib(buddy->last,"xmlns",NS_LAST);
        xmlnode_put_attrib(buddy->last,"stamp",jutil_timestamp());
        xhash_put(s->buddies, buddy->full->user, buddy);
        at_buddy_subscribe(ti, jp);
    }
    else
        log_debug(ZONE, "[AIM] Already have buddy %s in session %s\n", jp->to->user, jid_full(jp->from));

    aim_add_buddy(s->ass, aim_getconn_type(s->ass, AIM_CONN_TYPE_BOS),
                  jp->to->user);
    
    xmlnode_free(jp->x);
    return 1;
}

int at_parse_oncoming(aim_session_t *ass, 
                      aim_frame_t *command, ...)
{

    xmlnode away;
    xmlnode status;
	xmlnode x;
	at_session s;
    at_buddy buddy;
    ati ti;
    jpacket jp;
    char *msg;
    aim_userinfo_t *userinfo;
    int was_away;

    va_list ap;
    va_start(ap, command);
    userinfo = va_arg(ap, aim_userinfo_t *);
    va_end(ap);

    log_debug(ZONE, "Oncoming buddy %s", userinfo->sn);

	s = (at_session)ass->aux_data;
    ti = s->ti;

    buddy = xhash_get(s->buddies, userinfo->sn);
    if(buddy == NULL)
    {
        jid jtmp;

        buddy = pmalloco(s->p, (sizeof(_at_buddy)));
        buddy->full = jid_new(s->p, ti->i->id);
        jid_set(buddy->full, userinfo->sn, JID_USER);
        buddy->last = xmlnode_new_tag_pool(s->p,"query");
        buddy->is_away = -1;
        xmlnode_put_attrib(buddy->last,"xmlns",NS_LAST);
        xmlnode_put_attrib(buddy->last,"stamp",jutil_timestamp());

        xhash_put(s->buddies, buddy->full->user, buddy);
    }
    if(buddy->login_time == 0)
    {
        buddy->login_time = userinfo->onlinesince;
    }
    buddy->idle_time = userinfo->idletime;

    was_away = buddy->is_away;
    if(s->icq)
        buddy->is_away = userinfo->icqinfo.status;
    else
        buddy->is_away = (userinfo->flags&AIM_FLAG_AWAY) != 0;

    if(((buddy->is_away == 0) || s->icq) && (buddy->is_away != was_away))
    {
        char *status_msg;
        char *show;

        x = xmlnode_new_tag("presence");
	    xmlnode_put_attrib(x, "to", jid_full(s->cur));
    	xmlnode_put_attrib(x, "from", ti->i->id);
	    jp = jpacket_new(x);
    	jid_set(jp->from, at_normalize(userinfo->sn), JID_USER);
	    xmlnode_put_attrib(jp->x, "from", jid_full(jp->from));
        if((!s->icq) || (s->icq && (buddy->is_away == 0)))
        {
            status = xmlnode_insert_tag(x, "status");
            status_msg = pmalloco(xmlnode_pool(x), 30);
            if(!s->icq)
                sprintf(status_msg, "Online (Idle %d Seconds)", buddy->idle_time);
            else
                sprintf(status_msg, "Online");
        }
        else
        {
            status = xmlnode_insert_tag(x, "show");
            show = pmalloco(xmlnode_pool(x), 30);
            if(buddy->is_away&AIM_ICQ_STATE_CHAT)
                sprintf(show, "chat");
            else if(buddy->is_away&AIM_ICQ_STATE_OCCUPIED)
                sprintf(show, "dnd");
            else if(buddy->is_away&AIM_ICQ_STATE_NA)
                sprintf(show, "xa");
            else if(buddy->is_away&AIM_ICQ_STATE_DND)
                sprintf(show, "dnd");
            else if(buddy->is_away&AIM_ICQ_STATE_AWAY)
                sprintf(show, "away");
            else
                sprintf(show, "xa");
            xmlnode_insert_cdata(status, show, -1);
            status = xmlnode_insert_tag(x, "status");
            status_msg = pmalloco(xmlnode_pool(x), 30);
            if(buddy->is_away&AIM_ICQ_STATE_NA)
                sprintf(status_msg, "not available");
            else if(buddy->is_away&AIM_ICQ_STATE_OCCUPIED &&
                    !(buddy->is_away&AIM_ICQ_STATE_DND))
                sprintf(status_msg, "occupied");
            else
                sprintf(status_msg, "%s", show);
        }
        xmlnode_insert_cdata(status, status_msg, -1);
        at_deliver(ti,jp->x);
    } 
    else if(buddy->is_away == 1 && (buddy->is_away != was_away))
    {
        log_debug(ZONE, "[AT] Requesting Away message for %s", userinfo->sn);
        aim_getinfo(ass, command->conn, userinfo->sn, AIM_GETINFO_AWAYMESSAGE);
    }

	return 1;
}

int at_parse_offgoing(aim_session_t *ass, 
                      aim_frame_t *command, ...)
{

	xmlnode x;
	jpacket jp;
    at_buddy buddy;
	at_session s;
    ati ti;
    char *sn;
    aim_userinfo_t *userinfo;
    
    va_list ap;
    va_start(ap, command);
    userinfo = va_arg(ap, aim_userinfo_t *);
    va_end(ap);
            
	s = (at_session)ass->aux_data;
    ti = s->ti;
    sn = userinfo->sn;
    buddy = (at_buddy)xhash_get(s->buddies, sn);
    if(buddy == NULL)
    {
        jid jtmp;

        buddy = pmalloco(s->p, (sizeof(_at_buddy)));
        buddy->full = jid_new(s->p, ti->i->id);
        jid_set(buddy->full, sn, JID_USER);
        buddy->last = xmlnode_new_tag_pool(s->p,"query");
        xmlnode_put_attrib(buddy->last,"xmlns",NS_LAST);
        xmlnode_put_attrib(buddy->last,"stamp",jutil_timestamp());

        xhash_put(s->buddies, buddy->full->user, buddy);
    }

    buddy->is_away = -1;

    xmlnode_put_attrib(buddy->last,"stamp",jutil_timestamp());    

	x = xmlnode_new_tag("presence");
	xmlnode_put_attrib(x, "to", jid_full(s->cur));
	xmlnode_put_attrib(x, "from", ti->i->id);
	xmlnode_put_attrib(x, "type","unavailable");
	jp = jpacket_new(x);
	jid_set(jp->from, at_normalize(sn), JID_USER);
	xmlnode_put_attrib(jp->x, "from", jid_full(jp->from));

    at_deliver(ti,jp->x);

	return 1;
}

int at_parse_evilnotify(aim_session_t *sess, 
                              aim_frame_t *command, ...)
{
    va_list ap;
    xmlnode x;
    xmlnode body;
    jpacket jp;
    at_session s;
    ati ti;
    char msg[100];
    int newevil;
    aim_userinfo_t *userinfo;

    va_start(ap, command);
    newevil = va_arg(ap, int);
    userinfo = va_arg(ap, aim_userinfo_t *);
    va_end(ap);

    memset(msg, '\0', 100);
    snprintf(msg, 100, "Warning from: %s (new level: %2.1f%%", 
             (userinfo && strlen(userinfo->sn))?userinfo->sn:"anonymous",
             ((float)newevil)/10);

    s = (at_session)sess->aux_data;
    ti = s->ti;

	x = xmlnode_new_tag("message");
	xmlnode_put_attrib(x, "to", jid_full(s->cur));
	xmlnode_put_attrib(x, "from", jid_full(s->from));
	xmlnode_put_attrib(x, "type","error");
	body = xmlnode_insert_tag(x, "error");
    xmlnode_insert_cdata(body, (char *)&msg, strlen((char *)&msg));

    jp = jpacket_new(x);
    at_deliver(ti,jp->x);

    return 1;
}

int at_parse_userinfo(aim_session_t *sess, 
                            aim_frame_t *command, ...)
{
    aim_userinfo_t *userinfo;
    char *prof_encoding = NULL;
    char *prof = NULL;
    unsigned short inforeq = 0;
    xmlnode x;
    xmlnode show;
    xmlnode status;
    jpacket jp;
    at_session s;
    ati ti;

    va_list ap;
    va_start(ap, command);
    userinfo = va_arg(ap, aim_userinfo_t *);
    prof_encoding = va_arg(ap, char *);
    prof = va_arg(ap, char *);
    inforeq = va_arg(ap, int);
    va_end(ap);

    s = (at_session)sess->aux_data;
    ti = s->ti;

    if (inforeq == AIM_GETINFO_GENERALINFO) {
        /*
         printf("faimtest: userinfo: profile_encoding: %s\n", prof_encoding ? prof_encoding : "[none]");
        printf("faimtest: userinfo: prof: %s\n", prof ? prof : "[none]");
        */
    } else if (inforeq == AIM_GETINFO_AWAYMESSAGE) {
        x = xmlnode_new_tag("presence");
	    xmlnode_put_attrib(x, "to", jid_full(s->cur));
    	xmlnode_put_attrib(x, "from", ti->i->id);
	    jp = jpacket_new(x);
    	jid_set(jp->from, at_normalize(userinfo->sn), JID_USER);
	    xmlnode_put_attrib(jp->x, "from", jid_full(jp->from));
        show = xmlnode_insert_tag(x, "show");
        xmlnode_insert_cdata(show, "away", -1);
        status = xmlnode_insert_tag(x, "status");
        if(prof != NULL)
        {
		char *p1, *p2;
		char charset[32];
		int len;
		char *utf8_str;
		utf8_str = malloc(8192);

		// obtain charset
		charset[0] = 0;
		p1 = strstr(prof_encoding, "charset=");
		if(p1) {
			p1 += 8;
			if(*p1 == '\"') {
				++p1;
				p2 = strchr(p1, '\"');
				if(p2) {
					len = p2 - p1;
					if(len < 32) {
						strncpy(charset, p1, len);
						charset[len] = 0;
					}
				}
			}
		}

		// not utf8?
		if(strcmp(charset, "utf-8"))
			prof = str_to_UTF8(jp->p, prof);

		if(!s->icq) {
			msgconv_aim2plain(prof, utf8_str, 8192);
			prof = utf8_str;
		}
            xmlnode_insert_cdata(status, prof, -1);
		free(utf8_str);
        } else {
            xmlnode_insert_cdata(status, "Away", -1);
        }
        at_deliver(ti,jp->x);
    } else 
        log_debug(ZONE, "[AT] userinfo: unknown info request");

    return 1;
}

#define VCARD_ADD(q, parent, name, value) \
    xmlnode_insert_cdata(xmlnode_insert_tag(xmlnode_insert_tag(q,parent),name), \
    it_convert_windows2utf8(p,value),-1)

int at_parse_icq_simpleinfo(aim_session_t *sess,
                            aim_frame_t *command, ...)
{
	va_list ap;
	struct aim_icq_simpleinfo *info;
	jpacket jp;
	at_session s;
	xmlnode t, q;
	pool p;

	s = (at_session)sess->aux_data;

	va_start(ap, command);
	info = va_arg(ap, struct aim_icq_simpleinfo *);
	va_end(ap);

	jp = s->icq_vcard_response;
	if(!jp)
	    log_debug(ZONE, "[AT] got icq_simpleinfo without request, dropped");

	q = jp->iq;
	p = jp->p;

	t = xmlnode_insert_tag(q,"FN");
	if (info->first)
	{
	    /* we have a first name - if we have a last name, we have to concatenate it */
	    if (info->last)
	        xmlnode_insert_cdata(t,it_convert_windows2utf8(p,spools(p,info->first," ",info->last,p)),-1);
	    else
	        xmlnode_insert_cdata(t,it_convert_windows2utf8(p,info->first),-1);
	}
	else if (info->last)
	    xmlnode_insert_cdata(t,it_convert_windows2utf8(p,info->last),-1);

	t = xmlnode_insert_tag(q,"N");
	if (info->first)
	    xmlnode_insert_cdata(xmlnode_insert_tag(t,"GIVEN"),it_convert_windows2utf8(p,info->first),-1);
	if (info->last)
	    xmlnode_insert_cdata(xmlnode_insert_tag(t,"FAMILY"),it_convert_windows2utf8(p,info->last),-1);
	if (info->nick)
	    xmlnode_insert_cdata(xmlnode_insert_tag(q,"NICKNAME"),it_convert_windows2utf8(p,info->nick),-1);
	if (info->email)
	{
	    t = VCARD_ADD(q,"EMAIL","USERID",info->email);
	    xmlnode_insert_tag(t,"INTERNET");
	    xmlnode_insert_tag(t,"PREF");
	}

	at_deliver(s->ti,jp->x);

	s->icq_vcard_response = NULL;

	return 1;
}

int at_parse_locerr(aim_session_t *sess, 
                          aim_frame_t *command, ...)
{
/* XXX Do we want this?
    va_list ap;
    char *destsn;
    unsigned short reason;
    char *sn;
    xmlnode x;
    xmlnode body;
    jpacket jp;
    session s;
    char msg[1024];

    va_start(ap, command);
    reason = va_arg(ap, unsigned short);
    destsn = va_arg(ap, char *);
    va_end(ap);

    memset(&msg, '\0', 1024);
    snprintf("User information for %s unavailable (reason 0x%04x: %s)\n", destsn, reason, (reasonaux_data;

	x = xmlnode_new_tag("message");
	xmlnode_put_attrib(x, "to", jid_full(s->j));
	xmlnode_put_attrib(x, "from", aimtrans__instance->id);
	xmlnode_put_attrib(x, "type","error");
	body = xmlnode_insert_tag(x, "error");
    xmlnode_insert_cdata(body, &msg, strlen(&msg));

    jp = jpacket_new(x);
	ehandler_send(ehandler_at, jp->x, s->j->server);
*/  
    return 1;
}