Example #1
0
/**
 * Subtype 0x0004 - Request someone's icon.
 *
 * @param sess The oscar session.
 * @param conn The icon connection for this session.
 * @param sn The screen name of the person who's icon you are requesting.
 * @param iconcsum The MD5 checksum of the icon you are requesting.
 * @param iconcsumlen Length of the MD5 checksum given above.  Should be 10 bytes.
 * @return Return 0 if no errors, otherwise return the error number.
 */
faim_export int aim_bart_request(aim_session_t *sess, const char *sn, fu8_t iconcsumtype, const fu8_t *iconcsum, fu16_t iconcsumlen)
{
	aim_conn_t *conn;
	aim_frame_t *fr;
	aim_snacid_t snacid;

	if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0010)) || !sn || !strlen(sn) || !iconcsum || !iconcsumlen)
		return -EINVAL;

	if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10 + 1+strlen(sn) + 4 + 1+iconcsumlen)))
		return -ENOMEM;
	snacid = aim_cachesnac(sess, 0x0010, 0x0004, 0x0000, NULL, 0);
	aim_putsnac(&fr->data, 0x0010, 0x0004, 0x0000, snacid);

	/* Screen name */
	aimbs_put8(&fr->data, strlen(sn));
	aimbs_putraw(&fr->data, sn, strlen(sn));

	/* Some numbers.  You like numbers, right? */
	aimbs_put8(&fr->data, 0x01);
	aimbs_put16(&fr->data, 0x0001);
	aimbs_put8(&fr->data, iconcsumtype);

	/* Icon string */
	aimbs_put8(&fr->data, iconcsumlen);
	aimbs_putraw(&fr->data, iconcsum, iconcsumlen);

	aim_tx_enqueue(sess, fr);

	return 0;
}
Example #2
0
faim_export int aim_chatnav_createroom(aim_session_t *sess, aim_conn_t *conn, const char *name, fu16_t exchange)
{
	static const char ck[] = {"create"};
	static const char lang[] = {"en"};
	static const char charset[] = {"us-ascii"};
	aim_frame_t *fr;
	aim_snacid_t snacid;
	aim_tlvlist_t *tl = NULL;

	if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 1152)))
		return -ENOMEM;

	snacid = aim_cachesnac(sess, 0x000d, 0x0008, 0x0000, NULL, 0);
	aim_putsnac(&fr->data, 0x000d, 0x0008, 0x0000, snacid);

	/* exchange */
	aimbs_put16(&fr->data, exchange);

	/*
	 * This looks to be a big hack.  You'll note that this entire
	 * SNAC is just a room info structure, but the hard room name,
	 * here, is set to "create".  
	 *
	 * Either this goes on the "list of questions concerning
	 * why-the-hell-did-you-do-that", or this value is completly
	 * ignored.  Without experimental evidence, but a good knowledge of
	 * AOL style, I'm going to guess that it is the latter, and that
	 * the value of the room name in create requests is ignored.
	 */
	aimbs_put8(&fr->data, strlen(ck));
	aimbs_putraw(&fr->data, ck, strlen(ck));

	/* 
	 * instance
	 * 
	 * Setting this to 0xffff apparently assigns the last instance.
	 *
	 */
	aimbs_put16(&fr->data, 0xffff);

	/* detail level */
	aimbs_put8(&fr->data, 0x01);

	aim_addtlvtochain_raw(&tl, 0x00d3, strlen(name), name);
	aim_addtlvtochain_raw(&tl, 0x00d6, strlen(charset), charset);
	aim_addtlvtochain_raw(&tl, 0x00d7, strlen(lang), lang);

	/* tlvcount */
	aimbs_put16(&fr->data, aim_counttlvchain(&tl));
	aim_writetlvchain(&fr->data, &tl);

	aim_freetlvchain(&tl);

	aim_tx_enqueue(sess, fr);

	return 0;
}
Example #3
0
faim_export int aim_getinfo(aim_session_t *sess, aim_conn_t *conn, const char *sn, fu16_t infotype)
{
	struct aim_priv_inforeq privdata;
	aim_frame_t *fr;
	aim_snacid_t snacid;

	if (!sess || !conn || !sn)
		return -EINVAL;

	if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 12+1+strlen(sn))))
		return -ENOMEM;

	strncpy(privdata.sn, sn, sizeof(privdata.sn));
	privdata.infotype = infotype;
	snacid = aim_cachesnac(sess, 0x0002, 0x0005, 0x0000, &privdata, sizeof(struct aim_priv_inforeq));
	
	aim_putsnac(&fr->data, 0x0002, 0x0005, 0x0000, snacid);
	aimbs_put16(&fr->data, infotype);
	aimbs_put8(&fr->data, strlen(sn));
	aimbs_putraw(&fr->data, sn, strlen(sn));

	aim_tx_enqueue(sess, fr);

	return 0;
}
Example #4
0
/*
 * Inverse of aim_extractuserinfo()
 */
int aim_putuserinfo(aim_bstream_t *bs, aim_userinfo_t *info)
{
	aim_tlvlist_t *tlvlist = NULL;

	if (!bs || !info)
		return -EINVAL;

	aimbs_put8(bs, strlen(info->sn));
	aimbs_putraw(bs, (guint8 *)info->sn, strlen(info->sn));

	aimbs_put16(bs, info->warnlevel);


	aim_addtlvtochain16(&tlvlist, 0x0001, info->flags);
	aim_addtlvtochain32(&tlvlist, 0x0002, info->membersince);
	aim_addtlvtochain32(&tlvlist, 0x0003, info->onlinesince);
	aim_addtlvtochain16(&tlvlist, 0x0004, info->idletime);

#if ICQ_OSCAR_SUPPORT
	if (atoi(info->sn) != 0) {
		aim_addtlvtochain16(&tlvlist, 0x0006, info->icqinfo.status);
		aim_addtlvtochain32(&tlvlist, 0x000a, info->icqinfo.ipaddr);
	}
#endif

	aim_addtlvtochain_caps(&tlvlist, 0x000d, info->capabilities);

	aim_addtlvtochain32(&tlvlist, (guint16)((info->flags & AIM_FLAG_AOL) ? 0x0010 : 0x000f), info->sessionlen);

	aimbs_put16(bs, aim_counttlvchain(&tlvlist));
	aim_writetlvchain(bs, &tlvlist);
	aim_freetlvchain(&tlvlist);

	return 0;
}
Example #5
0
/**
 * answers status message requests
 * @param sess the oscar session
 * @param sender the guy whos asking
 * @param cookie message id which we are answering for
 * @param message away message
 * @param state our current away state the way icq requests it (0xE8 for away, 0xE9 occupied, ...)
 * @return 0 if no error
 */
int aim_send_im_ch2_statusmessage(aim_session_t *sess, const char *sender, const guint8 *cookie,
        const char *message, const guint8 state, const guint16 dc)
{
    aim_conn_t *conn;
    aim_frame_t *fr;
    aim_snacid_t snacid;

    if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0004)))
                return -EINVAL;
        
    if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 
					10+8+2+1+strlen(sender)+2+0x1d+0x10+9+strlen(message)+1)))
                return -ENOMEM;

    snacid = aim_cachesnac(sess, 0x0004, 0x000b, 0x0000, NULL, 0);
    aim_putsnac(&fr->data, 0x0004, 0x000b, 0x0000, snacid);
    
    aimbs_putraw(&fr->data, cookie, 8);
    
    aimbs_put16(&fr->data, 0x0002); /* channel */
    aimbs_put8(&fr->data, strlen(sender));
    aimbs_putraw(&fr->data, (guint8 *)sender, strlen(sender));

    aimbs_put16(&fr->data, 0x0003); /* reason: channel specific */

    aimbs_putle16(&fr->data, 0x001b); /* length of data SEQ1 */
    aimbs_putle16(&fr->data, 0x0008); /* protocol version */

    aimbs_putle32(&fr->data, 0x0000); /* no plugin -> 16 times 0x00 */ 
    aimbs_putle32(&fr->data, 0x0000); 
    aimbs_putle32(&fr->data, 0x0000); 
    aimbs_putle32(&fr->data, 0x0000);

    aimbs_putle16(&fr->data, 0x0000); /* unknown */
    aimbs_putle32(&fr->data, 0x0003); /* client features */
    aimbs_putle8(&fr->data, 0x00); /* unknown */
    aimbs_putle16(&fr->data, dc); /* Sequence number?  XXX - This should decrement by 1 with each request */
    /* end of SEQ1 */

    aimbs_putle16(&fr->data, 0x000e); /* Length of SEQ2 */
    aimbs_putle16(&fr->data, dc); /* Sequence number? same as above
                                       * XXX - This should decrement by 1 with each request */
    aimbs_putle32(&fr->data, 0x00000000); /* Unknown */
    aimbs_putle32(&fr->data, 0x00000000); /* Unknown */
    aimbs_putle32(&fr->data, 0x00000000); /* Unknown */
    /* end of SEQ2 */

    /* now for the real fun */
    aimbs_putle8(&fr->data, state); /* away state */
    aimbs_putle8(&fr->data, 0x03); /* msg-flag: 03 for states */
    aimbs_putle16(&fr->data, 0x0000); /* status code ? */
    aimbs_putle16(&fr->data, 0x0000); /* priority code */
    aimbs_putle16(&fr->data, strlen(message) + 1); /* message length + termination */
    aimbs_putraw(&fr->data, (guint8 *) message, strlen(message) + 1); /* null terminated string */
    
    aim_tx_enqueue(sess, fr);


    return 0;
}
Example #6
0
/*
 * Stubtypes 0x0005, 0x0006, 0x0007, and 0x0008 - Modify permit/deny lists.
 *
 * Changes your visibility depending on changetype:
 *
 *  AIM_VISIBILITYCHANGE_PERMITADD: Lets provided list of names see you
 *  AIM_VISIBILITYCHANGE_PERMIDREMOVE: Removes listed names from permit list
 *  AIM_VISIBILITYCHANGE_DENYADD: Hides you from provided list of names
 *  AIM_VISIBILITYCHANGE_DENYREMOVE: Lets list see you again
 *
 * list should be a list of 
 * screen names in the form "Screen Name One&ScreenNameTwo&" etc.
 *
 * Equivelents to options in WinAIM:
 *   - Allow all users to contact me: Send an AIM_VISIBILITYCHANGE_DENYADD
 *      with only your name on it.
 *   - Allow only users on my Buddy List: Send an 
 *      AIM_VISIBILITYCHANGE_PERMITADD with the list the same as your
 *      buddy list
 *   - Allow only the uesrs below: Send an AIM_VISIBILITYCHANGE_PERMITADD 
 *      with everyone listed that you want to see you.
 *   - Block all users: Send an AIM_VISIBILITYCHANGE_PERMITADD with only 
 *      yourself in the list
 *   - Block the users below: Send an AIM_VISIBILITYCHANGE_DENYADD with
 *      the list of users to be blocked
 *
 * XXX ye gods.
 */
faim_export int aim_bos_changevisibility(aim_session_t *sess, aim_conn_t *conn, int changetype, const char *denylist)
{
	aim_frame_t *fr;
	int packlen = 0;
	fu16_t subtype;
	char *localcpy = NULL, *tmpptr = NULL;
	int i;
	int listcount;
	aim_snacid_t snacid;

	if (!denylist)
		return -EINVAL;

	if (changetype == AIM_VISIBILITYCHANGE_PERMITADD)
		subtype = 0x05;
	else if (changetype == AIM_VISIBILITYCHANGE_PERMITREMOVE)
		subtype = 0x06;
	else if (changetype == AIM_VISIBILITYCHANGE_DENYADD)
		subtype = 0x07;
	else if (changetype == AIM_VISIBILITYCHANGE_DENYREMOVE)
		subtype = 0x08;
	else
		return -EINVAL;

	localcpy = strdup(denylist);

	listcount = aimutil_itemcnt(localcpy, '&');
	packlen = aimutil_tokslen(localcpy, 99, '&') + listcount + 9;

	if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, packlen))) {
		free(localcpy);
		return -ENOMEM;
	}

	snacid = aim_cachesnac(sess, 0x0009, subtype, 0x0000, NULL, 0);
	aim_putsnac(&fr->data, 0x0009, subtype, 0x00, snacid);

	for (i = 0; (i < (listcount - 1)) && (i < 99); i++) {
		tmpptr = aimutil_itemindex(localcpy, i, '&');

		aimbs_put8(&fr->data, strlen(tmpptr));
		aimbs_putraw(&fr->data, tmpptr, strlen(tmpptr));

		free(tmpptr);
	}
	free(localcpy);

	aim_tx_enqueue(sess, fr);

	return 0;
}
Example #7
0
/*
 * Subtype 0x0014 - Send a mini typing notification (mtn) packet.
 *
 * This is supported by winaim5 and newer, MacAIM bleh and newer, iChat bleh and newer, 
 * and Gaim 0.60 and newer.
 *
 */
int aim_im_sendmtn(aim_session_t *sess, guint16 type1, const char *sn, guint16 type2)
{
	aim_conn_t *conn;
	aim_frame_t *fr;
	aim_snacid_t snacid;

	if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0002)))
		return -EINVAL;

	if (!sn)
		return -EINVAL;

	if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+11+strlen(sn)+2)))
		return -ENOMEM;

	snacid = aim_cachesnac(sess, 0x0004, 0x0014, 0x0000, NULL, 0);
	aim_putsnac(&fr->data, 0x0004, 0x0014, 0x0000, snacid);

	/*
	 * 8 days of light
	 * Er, that is to say, 8 bytes of 0's
	 */
	aimbs_put16(&fr->data, 0x0000);
	aimbs_put16(&fr->data, 0x0000);
	aimbs_put16(&fr->data, 0x0000);
	aimbs_put16(&fr->data, 0x0000);

	/*
	 * Type 1 (should be 0x0001 for mtn)
	 */
	aimbs_put16(&fr->data, type1);

	/*
	 * Dest sn
	 */
	aimbs_put8(&fr->data, strlen(sn));
	aimbs_putraw(&fr->data, (const guint8*)sn, strlen(sn));

	/*
	 * Type 2 (should be 0x0000, 0x0001, or 0x0002 for mtn)
	 */
	aimbs_put16(&fr->data, type2);

	aim_tx_enqueue(sess, fr);

	return 0;
}
Example #8
0
/*
 * Inverse of aim_extractuserinfo()
 */
faim_internal int aim_putuserinfo(aim_bstream_t *bs, aim_userinfo_t *info)
{
	aim_tlvlist_t *tlvlist = NULL;

	if (!bs || !info)
		return -EINVAL;

	aimbs_put8(bs, strlen(info->sn));
	aimbs_putraw(bs, info->sn, strlen(info->sn));

	aimbs_put16(bs, info->warnlevel);


	if (info->present & AIM_USERINFO_PRESENT_FLAGS)
		aim_addtlvtochain16(&tlvlist, 0x0001, info->flags);
	if (info->present & AIM_USERINFO_PRESENT_MEMBERSINCE)
		aim_addtlvtochain32(&tlvlist, 0x0002, info->membersince);
	if (info->present & AIM_USERINFO_PRESENT_ONLINESINCE)
		aim_addtlvtochain32(&tlvlist, 0x0003, info->onlinesince);
	if (info->present & AIM_USERINFO_PRESENT_IDLE)
		aim_addtlvtochain16(&tlvlist, 0x0004, info->idletime);

#if ICQ_OSCAR_SUPPORT
	if (atoi(info->sn) != 0) {
		if (info->present & AIM_USERINFO_PRESENT_ICQEXTSTATUS)
			aim_addtlvtochain16(&tlvlist, 0x0006, info->icqinfo.status);
		if (info->present & AIM_USERINFO_PRESENT_ICQIPADDR)
			aim_addtlvtochain32(&tlvlist, 0x000a, info->icqinfo.ipaddr);
	}
#endif

	if (info->present & AIM_USERINFO_PRESENT_CAPABILITIES)
		aim_addtlvtochain_caps(&tlvlist, 0x000d, info->capabilities);

	if (info->present & AIM_USERINFO_PRESENT_SESSIONLEN)
		aim_addtlvtochain32(&tlvlist, (fu16_t)((info->flags & AIM_FLAG_AOL) ? 0x0010 : 0x000f), info->sessionlen);

	aimbs_put16(bs, aim_counttlvchain(&tlvlist));
	aim_writetlvchain(bs, &tlvlist);
	aim_freetlvchain(&tlvlist);

	return 0;
}
Example #9
0
/*
 * Subtype 0x0004 - Add multiple buddies to your buddy list.
 *
 * This just builds the "set buddy list" command then queues it.
 *
 * buddy_list = "Screen Name One&ScreenNameTwo&";
 *
 * XXX Clean this up.  
 *
 */
faim_export int aim_bos_setbuddylist(aim_session_t *sess, aim_conn_t *conn,
	const char *buddy_list)
{
	aim_frame_t *fr;
	aim_snacid_t snacid;
	int len = 0;
	char *localcpy = NULL;
	char *tmpptr = NULL;

	if (!buddy_list || !(localcpy = strdup(buddy_list)))
		return -EINVAL;

	for (tmpptr = strtok(localcpy, "&"); tmpptr;) {
		faimdprintf(sess, 2, "---adding: %s (%d)\n", tmpptr,
			strlen(tmpptr));
		len += 1 + strlen(tmpptr);
		tmpptr = strtok(NULL, "&");
	}

	if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10 + len)))
		return -ENOMEM;

	snacid = aim_cachesnac(sess, 0x0003, 0x0004, 0x0000, NULL, 0);
	aim_putsnac(&fr->data, 0x0003, 0x0004, 0x0000, snacid);

	strncpy(localcpy, buddy_list, strlen(buddy_list) + 1);

	for (tmpptr = strtok(localcpy, "&"); tmpptr;) {

		faimdprintf(sess, 2, "---adding: %s (%d)\n", tmpptr,
			strlen(tmpptr));

		aimbs_put8(&fr->data, strlen(tmpptr));
		aimbs_putraw(&fr->data, tmpptr, strlen(tmpptr));
		tmpptr = strtok(NULL, "&");
	}

	aim_tx_enqueue(sess, fr);

	free(localcpy);

	return 0;
}
Example #10
0
/*
 * Huh? What is this?
 */
faim_export int aim_0002_000b(aim_session_t *sess, aim_conn_t *conn, const char *sn)
{
	aim_frame_t *fr;
	aim_snacid_t snacid;

	if (!sess || !conn || !sn)
		return -EINVAL;

	if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10+1+strlen(sn))))
		return -ENOMEM;

	snacid = aim_cachesnac(sess, 0x0002, 0x000b, 0x0000, NULL, 0);
	
	aim_putsnac(&fr->data, 0x0002, 0x000b, 0x0000, snacid);
	aimbs_put8(&fr->data, strlen(sn));
	aimbs_putraw(&fr->data, sn, strlen(sn));

	aim_tx_enqueue(sess, fr);

	return 0;
}
Example #11
0
/*
 * Send a warning to destsn.
 *
 * Flags:
 *  AIM_WARN_ANON  Send as an anonymous (doesn't count as much)
 *
 * returns -1 on error (couldn't alloc packet), 0 on success.
 *
 */
int aim_send_warning(aim_session_t *sess, aim_conn_t *conn, const char *destsn, guint32 flags)
{
    aim_frame_t *fr;
    aim_snacid_t snacid;
    guint16 outflags = 0x0000;

    if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, strlen(destsn)+13)))
        return -ENOMEM;

    snacid = aim_cachesnac(sess, 0x0004, 0x0008, 0x0000, destsn, strlen(destsn)+1);

    aim_putsnac(&fr->data, 0x0004, 0x0008, 0x0000, snacid);

    if (flags & AIM_WARN_ANON)
        outflags |= 0x0001;

    aimbs_put16(&fr->data, outflags);
    aimbs_put8(&fr->data, strlen(destsn));
    aimbs_putraw(&fr->data, (guint8 *)destsn, strlen(destsn));

    aim_tx_enqueue(sess, fr);

    return 0;
}
Example #12
0
static int aim_addtlvtochain_chatroom(aim_tlvlist_t **list, fu16_t type, fu16_t exchange, const char *roomname, fu16_t instance)
{
	fu8_t *buf;
	int buflen;
	aim_bstream_t bs;

	buflen = 2 + 1 + strlen(roomname) + 2;
	
	if (!(buf = malloc(buflen)))
		return 0;

	aim_bstream_init(&bs, buf, buflen);

	aimbs_put16(&bs, exchange);
	aimbs_put8(&bs, strlen(roomname));
	aimbs_putraw(&bs, roomname, strlen(roomname));
	aimbs_put16(&bs, instance);

	aim_addtlvtochain_raw(list, type, aim_bstream_curpos(&bs), buf);

	free(buf);

	return 0;
}
Example #13
0
/*
 * Send a Chat Message.
 *
 * Possible flags:
 *   AIM_CHATFLAGS_NOREFLECT   --  Unset the flag that requests messages
 *                                 should be sent to their sender.
 *   AIM_CHATFLAGS_AWAY        --  Mark the message as an autoresponse
 *                                 (Note that WinAIM does not honor this,
 *                                 and displays the message as normal.)
 *
 * XXX convert this to use tlvchains 
 */
faim_export int aim_chat_send_im(aim_session_t *sess, aim_conn_t *conn, fu16_t flags, const char *msg, int msglen)
{   
	int i;
	aim_frame_t *fr;
	aim_msgcookie_t *cookie;
	aim_snacid_t snacid;
	fu8_t ckstr[8];
	aim_tlvlist_t *otl = NULL, *itl = NULL;

	if (!sess || !conn || !msg || (msglen <= 0))
		return 0;

	if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 1152)))
		return -ENOMEM;

	snacid = aim_cachesnac(sess, 0x000e, 0x0005, 0x0000, NULL, 0);
	aim_putsnac(&fr->data, 0x000e, 0x0005, 0x0000, snacid);


	/* 
	 * Generate a random message cookie.
	 *
	 * XXX mkcookie should generate the cookie and cache it in one
	 * operation to preserve uniqueness.
	 *
	 */
	for (i = 0; i < sizeof(ckstr); i++)
		aimutil_put8(ckstr+i, (fu8_t) rand());

	cookie = aim_mkcookie(ckstr, AIM_COOKIETYPE_CHAT, NULL);
	cookie->data = NULL; /* XXX store something useful here */

	aim_cachecookie(sess, cookie);

	for (i = 0; i < sizeof(ckstr); i++)
		aimbs_put8(&fr->data, ckstr[i]);


	/*
	 * Channel ID. 
	 */
	aimbs_put16(&fr->data, 0x0003);


	/*
	 * Type 1: Flag meaning this message is destined to the room.
	 */
	aim_addtlvtochain_noval(&otl, 0x0001);

	/*
	 * Type 6: Reflect
	 */
	if (!(flags & AIM_CHATFLAGS_NOREFLECT))
		aim_addtlvtochain_noval(&otl, 0x0006);

	/*
	 * Type 7: Autoresponse
	 */
	if (flags & AIM_CHATFLAGS_AWAY)
		aim_addtlvtochain_noval(&otl, 0x0007);

	/*
	 * SubTLV: Type 1: Message
	 */
	aim_addtlvtochain_raw(&itl, 0x0001, strlen(msg), msg);

	/*
	 * Type 5: Message block.  Contains more TLVs.
	 *
	 * This could include other information... We just
	 * put in a message TLV however.  
	 * 
	 */
	aim_addtlvtochain_frozentlvlist(&otl, 0x0005, &itl);

	aim_writetlvchain(&fr->data, &otl);
	
	aim_freetlvchain(&itl);
	aim_freetlvchain(&otl);
	
	aim_tx_enqueue(sess, fr);

	return 0;
}
Example #14
0
/*
 * conn must be a BOS connection!
 */
faim_export int aim_chat_invite(aim_session_t *sess, aim_conn_t *conn, const char *sn, const char *msg, fu16_t exchange, const char *roomname, fu16_t instance)
{
	int i;
	aim_frame_t *fr;
	aim_msgcookie_t *cookie;
	struct aim_invite_priv *priv;
	fu8_t ckstr[8];
	aim_snacid_t snacid;
	aim_tlvlist_t *otl = NULL, *itl = NULL;
	fu8_t *hdr;
	int hdrlen;
	aim_bstream_t hdrbs;
	
	if (!sess || !conn || !sn || !msg || !roomname)
		return -EINVAL;

	if (conn->type != AIM_CONN_TYPE_BOS)
		return -EINVAL;

	if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 1152+strlen(sn)+strlen(roomname)+strlen(msg))))
		return -ENOMEM;

	snacid = aim_cachesnac(sess, 0x0004, 0x0006, 0x0000, sn, strlen(sn)+1);
	aim_putsnac(&fr->data, 0x0004, 0x0006, 0x0000, snacid);


	/*
	 * Cookie
	 */
	for (i = 0; i < sizeof(ckstr); i++)
		aimutil_put8(ckstr, (fu8_t) rand());

	/* XXX should be uncached by an unwritten 'invite accept' handler */
	if ((priv = malloc(sizeof(struct aim_invite_priv)))) {
		priv->sn = strdup(sn);
		priv->roomname = strdup(roomname);
		priv->exchange = exchange;
		priv->instance = instance;
	}

	if ((cookie = aim_mkcookie(ckstr, AIM_COOKIETYPE_INVITE, priv)))
		aim_cachecookie(sess, cookie);
	else
		free(priv);

	for (i = 0; i < sizeof(ckstr); i++)
		aimbs_put8(&fr->data, ckstr[i]);


	/*
	 * Channel (2)
	 */
	aimbs_put16(&fr->data, 0x0002);

	/*
	 * Dest sn
	 */
	aimbs_put8(&fr->data, strlen(sn));
	aimbs_putraw(&fr->data, sn, strlen(sn));

	/*
	 * TLV t(0005)
	 *
	 * Everything else is inside this TLV.
	 *
	 * Sigh.  AOL was rather inconsistent right here.  So we have
	 * to play some minor tricks.  Right inside the type 5 is some
	 * raw data, followed by a series of TLVs.  
	 *
	 */
	hdrlen = 2+8+16+6+4+4+strlen(msg)+4+2+1+strlen(roomname)+2;
	hdr = malloc(hdrlen);
	aim_bstream_init(&hdrbs, hdr, hdrlen);
	
	aimbs_put16(&hdrbs, 0x0000); /* Unknown! */
	aimbs_putraw(&hdrbs, ckstr, sizeof(ckstr)); /* I think... */
	aim_putcap(&hdrbs, AIM_CAPS_CHAT);

	aim_addtlvtochain16(&itl, 0x000a, 0x0001);
	aim_addtlvtochain_noval(&itl, 0x000f);
	aim_addtlvtochain_raw(&itl, 0x000c, strlen(msg), msg);
	aim_addtlvtochain_chatroom(&itl, 0x2711, exchange, roomname, instance);
	aim_writetlvchain(&hdrbs, &itl);
	
	aim_addtlvtochain_raw(&otl, 0x0005, aim_bstream_curpos(&hdrbs), hdr);

	aim_writetlvchain(&fr->data, &otl);

	free(hdr);
	aim_freetlvchain(&itl);
	aim_freetlvchain(&otl);
	
	aim_tx_enqueue(sess, fr);

	return 0;
}
Example #15
0
/*
 * Send an ICBM (instant message).  
 *
 *
 * Possible flags:
 *   AIM_IMFLAGS_AWAY  -- Marks the message as an autoresponse
 *   AIM_IMFLAGS_ACK   -- Requests that the server send an ack
 *                        when the message is received (of type 0x0004/0x000c)
 *   AIM_IMFLAGS_OFFLINE--If destination is offline, store it until they are
 *                        online (probably ICQ only).
 *   AIM_IMFLAGS_UNICODE--Instead of ASCII7, the passed message is
 *                        made up of UNICODE duples.  If you set
 *                        this, you'd better be damn sure you know
 *                        what you're doing.
 *   AIM_IMFLAGS_ISO_8859_1 -- The message contains the ASCII8 subset
 *                        known as ISO-8859-1.  
 *
 * Generally, you should use the lowest encoding possible to send
 * your message.  If you only use basic punctuation and the generic
 * Latin alphabet, use ASCII7 (no flags).  If you happen to use non-ASCII7
 * characters, but they are all clearly defined in ISO-8859-1, then 
 * use that.  Keep in mind that not all characters in the PC ASCII8
 * character set are defined in the ISO standard. For those cases (most
 * notably when the (r) symbol is used), you must use the full UNICODE
 * encoding for your message.  In UNICODE mode, _all_ characters must
 * occupy 16bits, including ones that are not special.  (Remember that
 * the first 128 UNICODE symbols are equivelent to ASCII7, however they
 * must be prefixed with a zero high order byte.)
 *
 * I strongly discourage the use of UNICODE mode, mainly because none
 * of the clients I use can parse those messages (and besides that,
 * wchars are difficult and non-portable to handle in most UNIX environments).
 * If you really need to include special characters, use the HTML UNICODE 
 * entities.  These are of the form &#2026; where 2026 is the hex 
 * representation of the UNICODE index (in this case, UNICODE 
 * "Horizontal Ellipsis", or 133 in in ASCII8).
 *
 * Implementation note:  Since this is one of the most-used functions
 * in all of libfaim, it is written with performance in mind.  As such,
 * it is not as clear as it could be in respect to how this message is
 * supposed to be layed out. Most obviously, tlvlists should be used 
 * instead of writing out the bytes manually. 
 *
 * XXX more precise verification that we never send SNACs larger than 8192
 * XXX check SNAC size for multipart
 *
 */
int aim_send_im_ext(aim_session_t *sess, struct aim_sendimext_args *args)
{
	static const guint8 deffeatures[] = {
		0x01, 0x01, 0x01, 0x02
	};
	aim_conn_t *conn;
	int i, msgtlvlen;
	aim_frame_t *fr;
	aim_snacid_t snacid;

	if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0004)))
		return -EINVAL;

	if (!args)
		return -EINVAL;

	if (args->flags & AIM_IMFLAGS_MULTIPART) {
		if (args->mpmsg->numparts <= 0)
			return -EINVAL;
	} else {
		if (!args->msg || (args->msglen <= 0))
			return -EINVAL;

		if (args->msglen >= MAXMSGLEN)
			return -E2BIG;
	}

	/* Painfully calculate the size of the message TLV */
	msgtlvlen = 1 + 1; /* 0501 */

	if (args->flags & AIM_IMFLAGS_CUSTOMFEATURES)
		msgtlvlen += 2 + args->featureslen;
	else
		msgtlvlen += 2 + sizeof(deffeatures);

	if (args->flags & AIM_IMFLAGS_MULTIPART) {
		aim_mpmsg_section_t *sec;

		for (sec = args->mpmsg->parts; sec; sec = sec->next) {
			msgtlvlen += 2 /* 0101 */ + 2 /* block len */;
			msgtlvlen += 4 /* charset */ + sec->datalen;
		}

	} else {
		msgtlvlen += 2 /* 0101 */ + 2 /* block len */;
		msgtlvlen += 4 /* charset */ + args->msglen;
	}


	if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, msgtlvlen+128)))
		return -ENOMEM;

	/* XXX should be optional */	
	snacid = aim_cachesnac(sess, 0x0004, 0x0006, 0x0000, args->destsn, strlen(args->destsn)+1);
	aim_putsnac(&fr->data, 0x0004, 0x0006, 0x0000, snacid);

	/* 
	 * Generate a random message cookie 
	 *
	 * We could cache these like we do SNAC IDs.  (In fact, it 
	 * might be a good idea.)  In the message error functions, 
	 * the 8byte message cookie is returned as well as the 
	 * SNAC ID.
	 *
	 */
	for (i = 0; i < 8; i++)
		aimbs_put8(&fr->data, (guint8) rand());

	/*
	 * Channel ID
	 */
	aimbs_put16(&fr->data, 0x0001);

	/*
	 * Destination SN (prepended with byte length)
	 */
	aimbs_put8(&fr->data, strlen(args->destsn));
	aimbs_putraw(&fr->data, (guint8 *)args->destsn, strlen(args->destsn));

	/*
	 * Message TLV (type 2).
	 */
	aimbs_put16(&fr->data, 0x0002);
	aimbs_put16(&fr->data, msgtlvlen);

	/*
	 * Features 
	 *
	 */
	aimbs_put8(&fr->data, 0x05);
	aimbs_put8(&fr->data, 0x01);

	if (args->flags & AIM_IMFLAGS_CUSTOMFEATURES) {
		aimbs_put16(&fr->data, args->featureslen);
		aimbs_putraw(&fr->data, args->features, args->featureslen);
	} else {
		aimbs_put16(&fr->data, sizeof(deffeatures));
		aimbs_putraw(&fr->data, deffeatures, sizeof(deffeatures));
	}

	if (args->flags & AIM_IMFLAGS_MULTIPART) {
		aim_mpmsg_section_t *sec;

		for (sec = args->mpmsg->parts; sec; sec = sec->next) {
			aimbs_put16(&fr->data, 0x0101);
			aimbs_put16(&fr->data, sec->datalen + 4);
			aimbs_put16(&fr->data, sec->charset);
			aimbs_put16(&fr->data, sec->charsubset);
			aimbs_putraw(&fr->data, sec->data, sec->datalen);
		}

	} else {

		aimbs_put16(&fr->data, 0x0101);

		/* 
		 * Message block length.
		 */
		aimbs_put16(&fr->data, args->msglen + 0x04);

		/*
		 * Character set.
		 */
		if (args->flags & AIM_IMFLAGS_CUSTOMCHARSET) {

			aimbs_put16(&fr->data, args->charset);
			aimbs_put16(&fr->data, args->charsubset);

		} else {
			if (args->flags & AIM_IMFLAGS_UNICODE)
				aimbs_put16(&fr->data, 0x0002);
			else if (args->flags & AIM_IMFLAGS_ISO_8859_1)
				aimbs_put16(&fr->data, 0x0003);
			else
				aimbs_put16(&fr->data, 0x0000);

			aimbs_put16(&fr->data, 0x0000);
		}

		/*
		 * Message.  Not terminated.
		 */
		aimbs_putraw(&fr->data, (guint8 *)args->msg, args->msglen);
	}

	/*
	 * Set the Request Acknowledge flag.  
	 */
	if (args->flags & AIM_IMFLAGS_ACK) {
		aimbs_put16(&fr->data, 0x0003);
		aimbs_put16(&fr->data, 0x0000);
	}

	/*
	 * Set the Autoresponse flag.
	 */
	if (args->flags & AIM_IMFLAGS_AWAY) {
		aimbs_put16(&fr->data, 0x0004);
		aimbs_put16(&fr->data, 0x0000);
	}

	if (args->flags & AIM_IMFLAGS_OFFLINE) {
		aimbs_put16(&fr->data, 0x0006);
		aimbs_put16(&fr->data, 0x0000);
	}

	/*
	 * Set the I HAVE A REALLY PURTY ICON flag.
	 */
	if (args->flags & AIM_IMFLAGS_HASICON) {
		aimbs_put16(&fr->data, 0x0008);
		aimbs_put16(&fr->data, 0x000c);
		aimbs_put32(&fr->data, args->iconlen);
		aimbs_put16(&fr->data, 0x0001);
		aimbs_put16(&fr->data, args->iconsum);
		aimbs_put32(&fr->data, args->iconstamp);
	}

	/*
	 * Set the Buddy Icon Requested flag.
	 */
	if (args->flags & AIM_IMFLAGS_BUDDYREQ) {
		aimbs_put16(&fr->data, 0x0009);
		aimbs_put16(&fr->data, 0x0000);
	}

	aim_tx_enqueue(sess, fr);

	if (!(sess->flags & AIM_SESS_FLAGS_DONTTIMEOUTONICBM))
		aim_cleansnacs(sess, 60); /* clean out SNACs over 60sec old */

	return 0;
}
Example #16
0
faim_export int aim_icq_sendsms(aim_session_t *sess, const char *dest, const char *body)
{
	aim_conn_t *conn;
	aim_frame_t *fr;
	aim_snacid_t snacid;
	int bslen;
	int a;
	char *xml;
	int xmllen;
	char timestr[30];
	time_t t;
	struct tm *tm;

	if (!body || !strlen(body))
		return -EINVAL;

	if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0015)))
		return -EINVAL;

	time(&t);
	tm = gmtime(&t);
	strftime(timestr, 30, "%a, %d %b %Y %T %Z", tm);
	xmllen = 17 + 13 + strlen(dest) + 14 + 6 + strlen(body) + 7 +
			25 + 13 + strlen(sess->sn) + 14 +
			14 + strlen(sess->sn /* should be nick */) + 15 +
			18 + 2 + 19 + 6 + strlen(timestr) + 7 + 18 + 1;

	bslen = 2 + 4 + 2 + 2 + 2 + 2 + 2 + 16 + 4 + xmllen;

	if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10 + 4 + bslen)))
		return -ENOMEM;

	xml = (char *) malloc(xmllen);
	snprintf(xml, xmllen, "<icq_sms_message><destination>%s</destination>"\
			"<text>%s</text><codepage>1252</codepage>"\
			"<senders_UIN>%s</senders_UIN>"\
			"<senders_name>%s</senders_name>"\
			"<delivery_receipt>No</delivery_receipt>"\
			"<time>%s</time></icq_sms_message>",
			dest, body, sess->sn, sess->sn /* should be nick */, timestr);

	snacid = aim_cachesnac(sess, 0x0015, 0x0002, 0x0000, NULL, 0);
	aim_putsnac(&fr->data, 0x0015, 0x0002, 0x0000, snacid);

	/* For simplicity, don't bother using a tlvlist */
	aimbs_put16(&fr->data, 0x0001);
	aimbs_put16(&fr->data, bslen);

	aimbs_putle16(&fr->data, bslen - 2);
	aimbs_putle32(&fr->data, atoi(sess->sn));
	aimbs_putle16(&fr->data, 2000); /* I command thee. */
	aimbs_putle16(&fr->data, snacid); /* eh. */
	aimbs_put16(&fr->data, 0x8214); /* SMS send subtype */
	aimbs_put16(&fr->data, 0x0001);
	aimbs_put16(&fr->data, 0x0016);
	for(a = 0; a < 16; a++)
		aimbs_put8(&fr->data, 0x00);
	aimbs_put32(&fr->data, xmllen); /* yes, this has to be 32 bits */
	aimbs_putraw(&fr->data, xml, xmllen);

	aim_tx_enqueue(sess, fr);

	free(xml);

	return 0;
}