/***************************************************************************\
* *
* BitlBee - An IRC to IM gateway *
* Jabber module - Handling of message(s) (tags), etc *
* *
* Copyright 2006-2012 Wilmer van der Gaast <wilmer@gaast.net> *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License along *
* with this program; if not, write to the Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *
* *
\***************************************************************************/
#include "jabber.h"
static xt_status jabber_pkt_message_normal(struct xt_node *node, gpointer data, gboolean carbons_sent)
{
struct im_connection *ic = data;
char *from = xt_find_attr(node, carbons_sent ? "to" : "from");
char *type = xt_find_attr(node, "type");
char *id = xt_find_attr(node, pre { line-height: 125%; }
td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
.highlight .hll { background-color: #ffffcc }
.highlight .c { color: #888888 } /* Comment */
.highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */
.highlight .k { color: #008800; font-weight: bold } /* Keyword */
.highlight .ch { color: #888888 } /* Comment.Hashbang */
.highlight .cm { color: #888888 } /* Comment.Multiline */
.highlight .cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */
.highlight .cpf { color: #888888 } /* Comment.PreprocFile */
.highlight .c1 { color: #888888 } /* Comment.Single */
.highlight .cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */
.highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .ges { font-weight: bold; font-style: italic } /* Generic.EmphStrong */
.highlight .gr { color: #aa0000 } /* Generic.Error */
.highlight .gh { color: #333333 } /* Generic.Heading */
.highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */
.highlight .go { color: #888888 } /* Generic.Output */
.highlight .gp { color: #555555 } /* Generic.Prompt */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #666666 } /* Generic.Subheading */
.highlight .gt { color: #aa0000 } /* Generic.Traceback */
.highlight .kc { color: #008800; font-weight: bold } /* Keyword.Constant */
.highlight .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */
.highlight .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */
.highlight .kp { color: #008800 } /* Keyword.Pseudo */
.highlight .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */
.highlight .kt { color: #888888; font-weight: bold } /* Keyword.Type */
.highlight .m { color: #0000DD; font-weight: bold } /* Literal.Number */
.highlight .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */
.highlight .na { color: #336699 } /* Name.Attribute */
.highlight .nb { color: #003388 } /* Name.Builtin */
.highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */
.highlight .no { color: #003366; font-weight: bold } /* Name.Constant */
.highlight .nd { color: #555555 } /* Name.Decorator */
.highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */
.highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */
.highlight .nl { color: #336699; font-style: italic } /* Name.Label */
.highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */
.highlight .py { color: #336699; font-weight: bold } /* Name.Property */
.highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */
.highlight .nv { color: #336699 } /* Name.Variable */
.highlight .ow { color: #008800 } /* Operator.Word */
.highlight .w { color: #bbbbbb } /* Text.Whitespace */
.highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */
.highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */
.highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */
.highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */
.highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */
.highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */
.highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */
.highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */
.highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */
.highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */
.highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */
.highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */
.highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */
.highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */
.highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */
.highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */
.highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */
.highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */
.highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */
.highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */
.highlight .vc { color: #336699 } /* Name.Variable.Class */
.highlight .vg { color: #dd7700 } /* Name.Variable.Global */
.highlight .vi { color: #3333bb } /* Name.Variable.Instance */
.highlight .vm { color: #336699 } /* Name.Variable.Magic */
.highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long *//*
* aim_rxqueue.c
*
* This file contains the management routines for the receive
* (incoming packet) queue. The actual packet handlers are in
* aim_rxhandlers.c.
*/
#include <aim.h>
#ifndef _WIN32
#include <sys/socket.h>
#endif
/*
*
*/
int aim_recv(int fd, void *buf, size_t count)
{
int left, cur;
for (cur = 0, left = count; left; ) {
int ret;
ret = recv(fd, ((unsigned char *)buf)+cur, left, 0);
/* Of course EOF is an error, only morons disagree with that. */
if (ret <= 0)
return -1;
cur += ret;
left -= ret;
}
return cur;
}
/*
* Read into a byte stream. Will not read more than count, but may read
* less if there is not enough room in the stream buffer.
*/
static int aim_bstream_recv(aim_bstream_t *bs, int fd, size_t count)
{
int red = 0;
if (!bs || (fd < 0) || (count < 0))
return -1;
if (count > (bs->len - bs->offset))
count = bs->len - bs->offset; /* truncate to remaining space */
if (count) {
red = aim_recv(fd, bs->data + bs->offset, count);
if (red <= 0)
return -1;
}
bs->offset += red;
return red;
}
int aim_bstream_init(aim_bstream_t *bs, guint8 *data, int len)
{
if (!bs)
return -1;
bs->data = data;
bs->len = len;
bs->offset = 0;
return 0;
}
int aim_bstream_empty(aim_bstream_t *bs)
{
return bs->len - bs->offset;
}
int aim_bstream_curpos(aim_bstream_t *bs)
{
return bs->offset;
}
int aim_bstream_setpos(aim_bstream_t *bs, int off)
{
if (off > bs->len)
return -1;
bs->offset = off;
return off;
}
void aim_bstream_rewind(aim_bstream_t *bs)
{
aim_bstream_setpos(bs, 0);
return;
}
int aim_bstream_advance(aim_bstream_t *bs, int n)
{
if (aim_bstream_empty(bs) < n)
return 0; /* XXX throw an exception */
bs->offset += n;
return n;
}
guint8 aimbs_get8(aim_bstream_t *bs)
{
if (aim_bstream_empty(bs) < 1)
return 0; /* XXX throw an exception */
bs->offset++;
return aimutil_get8(bs->data + bs->offset - 1);
}
guint16 aimbs_get16(aim_bstream_t *bs)
{
if (aim_bstream_empty(bs) < 2)
return 0; /* XXX throw an exception */
bs->offset += 2;
return aimutil_get16(bs->data + bs->offset - 2);
}
guint32 aimbs_get32(aim_bstream_t *bs)
{
if (aim_bstream_empty(bs) < 4)
return 0; /* XXX throw an exception */
bs->offset += 4;
return aimutil_get32(bs->data + bs->offset - 4);
}
guint8 aimbs_getle8(aim_bstream_t *bs)
{
if (aim_bstream_empty(bs) < 1)
return 0; /* XXX throw an exception */
bs->offset++;
return aimutil_getle8(bs->data + bs->offset - 1);
}
guint16 aimbs_getle16(aim_bstream_t *bs)
{
if (aim_bstream_empty(bs) < 2)
return 0; /* XXX throw an exception */
bs->offset += 2;
return aimutil_getle16(bs->data + bs->offset - 2);
}
guint32 aimbs_getle32(aim_bstream_t *bs)
{
if (aim_bstream_empty(bs) < 4)
return 0; /* XXX throw an exception */
bs->offset += 4;
return aimutil_getle32(bs->data + bs->offset - 4);
}
int aimbs_put8(aim_bstream_t *bs, guint8 v)
{
if (aim_bstream_empty(bs) < 1)
return 0; /* XXX throw an exception */
bs->offset += aimutil_put8(bs->data + bs->offset, v);
return 1;
}
int aimbs_put16(aim_bstream_t *bs, guint16 v)
{
if (aim_bstream_empty(bs) < 2)
return 0; /* XXX throw an exception */
bs->offset += aimutil_put16(bs->data + bs->offset, v);
return 2;
}
int aimbs_put32(aim_bstream_t *bs, guint32 v)
{
if (aim_bstream_empty(bs) < 4)
return 0; /* XXX throw an exception */
bs->offset += aimutil_put32(bs->data + bs->offset, v);
return 1;
}
int aimbs_putle8(aim_bstream_t *bs, guint8 v)
{
if (aim_bstream_empty(bs) < 1)
return 0; /* XXX throw an exception */
bs->offset += aimutil_putle8(bs->data + bs->offset, v);
return 1;
}
int aimbs_putle16(aim_bstream_t *bs, guint16 v)
{
if (aim_bstream_empty(bs) < 2)
return 0; /* XXX throw an exception */
bs->offset += aimutil_putle16(bs->data + bs->offset, v);
return 2;
}
int aimbs_putle32(aim_bstream_t *bs, guint32 v)
{
if (aim_bstream_empty(bs) < 4)
return 0; /* XXX throw an exception */
bs->offset += aimutil_putle32(bs->data + bs->offset, v);
return 1;
}
int aimbs_getrawbuf(aim_bstream_t *bs, guint8 *buf, int len)
{
if (aim_bstream_empty(bs) < len)
return 0;
memcpy(buf, bs->data + bs->offset, len);
bs->offset += len;
return len;
}
guint8 *aimbs_getraw(aim_bstream_t *bs, int len)
{
guint8 *ob;
if (!(ob = g_malloc(len)))
return NULL;
if (aimbs_getrawbuf(bs, ob, len) < len) {
g_free(ob);
return NULL;
}
return ob;
}
char *aimbs_getstr(aim_bstream_t *bs, int len)
{
guint8 *ob;
if (!(ob = g_malloc(len+1)))
return NULL;
if (aimbs_getrawbuf(bs, ob, len) < len) {
g_free(ob);
return NULL;
}
ob[len] = '\0';
return (char *)ob;
}
int aimbs_putraw(aim_bstream_t *bs, const guint8 *v, int len)
{
if (aim_bstream_empty(bs) < len)
return 0; /* XXX throw an exception */
memcpy(bs->data + bs->offset, v, len);
bs->offset += len;
return len;
}
int aimbs_putbs(aim_bstream_t *bs, aim_bstream_t *srcbs, int len)
{
if (aim_bstream_empty(srcbs) < len)
return 0; /* XXX throw exception (underrun) */
if (aim_bstream_empty(bs) < len)
return 0; /* XXX throw exception (overflow) */
memcpy(bs->data + bs->offset, srcbs->data + srcbs->offset, len);
bs->offset += len;
srcbs->offset += len;
return len;
}
/**
* aim_frame_destroy - free aim_frame_t
* @frame: the frame to free
*
* returns -1 on error; 0 on success.
*
*/
void aim_frame_destroy(aim_frame_t *frame)
{
g_free(frame->data.data); /* XXX aim_bstream_free */
g_free(frame);
}
/*
* Grab a single command sequence off the socket, and enqueue
* it in the incoming event queue in a seperate struct.
*/
int aim_get_command(aim_session_t *sess, aim_conn_t *conn)
{
guint8 flaphdr_raw[6];
aim_bstream_t flaphdr;
aim_frame_t *newrx;
guint16 payloadlen;
if (!sess || !conn)
return 0;
if (conn->fd == -1)
return -1; /* its a aim_conn_close()'d connection */
/* KIDS, THIS IS WHAT HAPPENS IF YOU USE CODE WRITTEN FOR GUIS IN A DAEMON!
And wouldn't it make sense to return something that prevents this function
from being called again IMMEDIATELY (and making the program suck up all
CPU time)?...
if (conn->fd < 3)
return 0;
*/
if (conn->status & AIM_CONN_STATUS_INPROGRESS)
return aim_conn_completeconnect(sess, conn);
aim_bstream_init(&flaphdr, flaphdr_raw, sizeof(flaphdr_raw));
/*
* Read FLAP header. Six bytes:
*
* 0 char -- Always 0x2a
* 1 char -- Channel ID. Usually 2 -- 1 and 4 are used during login.
* 2 short -- Sequence number
* 4 short -- Number of data bytes that follow.
*/
if (aim_bstream_recv(&flaphdr, conn->fd, 6) < 6) {
aim_conn_close(conn);
return -1;
}
aim_bstream_rewind(&flaphdr);
/*
* This shouldn't happen unless the socket breaks, the server breaks,
* or we break. We must handle it just in case.
*/
if (aimbs_get8(&flaphdr) != 0x2a) {
guint8 start;
aim_bstream_rewind(&flaphdr);
start = aimbs_get8(&flaphdr);
imcb_error(sess->aux_data, "FLAP framing disrupted");
aim_conn_close(conn);
return -1;
}
/* allocate a new struct */
if (!(newrx = (aim_frame_t *)g_new0(aim_frame_t,1)))
return -1;
/* we're doing FLAP if we're here */
newrx->hdrtype = AIM_FRAMETYPE_FLAP;
newrx->hdr.flap.type = aimbs_get8(&flaphdr);
newrx->hdr.flap.seqnum = aimbs_get16(&flaphdr);
payloadlen = aimbs_get16(&flaphdr);
newrx->nofree = 0; /* free by default */
if (payloadlen) {
guint8 *payload = NULL;
if (!(payload = (guint8 *) g_malloc(payloadlen))) {
aim_frame_destroy(newrx);
return -1;
}
aim_bstream_init(&newrx->data, payload, payloadlen);
/* read the payload */
if (aim_bstream_recv(&newrx->data, conn->fd, payloadlen) < payloadlen) {
aim_frame_destroy(newrx); /* free's payload */
aim_conn_close(conn);
return -1;
}
} else
aim_bstream_init(&newrx->data, NULL, 0);
aim_bstream_rewind(&newrx->data);
newrx->conn = conn;
newrx->next = NULL; /* this will always be at the bottom */
if (!sess->queue_incoming)
sess->queue_incoming = newrx;
else {
aim_frame_t *cur;
for (cur = sess->queue_incoming; cur->next; cur = cur->next)
;
cur->next = newrx;
}
newrx->conn->lastactivity = time(NULL);
return 0;
}
/*
* Purge recieve queue of all handled commands (->handled==1). Also
* allows for selective freeing using ->nofree so that the client can
* keep the data for various purposes.
*
* If ->nofree is nonzero, the frame will be delinked from the global list,
* but will not be free'ed. The client _must_ keep a pointer to the
* data -- libfaim will not! If the client marks ->nofree but
* does not keep a pointer, it's lost forever.
*
*/
void aim_purge_rxqueue(aim_session_t *sess)
{
aim_frame_t *cur, **prev;
for (prev = &sess->queue_incoming; (cur = *prev); ) {
if (cur->handled) {
*prev = cur->next;
if (!cur->nofree)
aim_frame_destroy(cur);
} else
prev = &cur->next;
}
return;
}
/*
* Since aim_get_command will aim_conn_kill dead connections, we need
* to clean up the rxqueue of unprocessed connections on that socket.
*
* XXX: this is something that was handled better in the old connection
* handling method, but eh.
*/
void aim_rxqueue_cleanbyconn(aim_session_t *sess, aim_conn_t *conn)
{
aim_frame_t *currx;
for (currx = sess->queue_incoming; currx; currx = currx->next) {
if ((!currx->handled) && (currx->conn == conn))
currx->handled = 1;
}
return;
}