Annotation of ChivanetAimPidgin/oscarprpl/src/c/odc.c, revision 1.1.1.1

1.1       snw         1: /*
                      2:  * Purple's oscar protocol plugin
                      3:  * This file is the legal property of its developers.
                      4:  * Please see the AUTHORS file distributed alongside this file.
                      5:  *
                      6:  * This library is free software; you can redistribute it and/or
                      7:  * modify it under the terms of the GNU Lesser General Public
                      8:  * License as published by the Free Software Foundation; either
                      9:  * version 2 of the License, or (at your option) any later version.
                     10:  *
                     11:  * This library is distributed in the hope that it will be useful,
                     12:  * but WITHOUT ANY WARRANTY; without even the implied warranty of
                     13:  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
                     14:  * Lesser General Public License for more details.
                     15:  *
                     16:  * You should have received a copy of the GNU Lesser General Public
                     17:  * License along with this library; if not, write to the Free Software
                     18:  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
                     19: */
                     20: 
                     21: /* From the oscar PRPL */
                     22: #include "encoding.h"
                     23: #include "oscar.h"
                     24: #include "peer.h"
                     25: 
                     26: /* From Purple */
                     27: #include "conversation.h"
                     28: #include "imgstore.h"
                     29: #include "util.h"
                     30: 
                     31: #define DIRECTIM_MAX_FILESIZE 52428800
                     32: 
                     33: /**
                     34:  * Free any ODC related data and print a message to the conversation
                     35:  * window based on conn->disconnect_reason.
                     36:  */
                     37: void
                     38: peer_odc_close(PeerConnection *conn)
                     39: {
                     40:        gchar *tmp;
                     41: 
                     42:        if (conn->disconnect_reason == OSCAR_DISCONNECT_REMOTE_CLOSED)
                     43:                tmp = g_strdup(_("The remote user has closed the connection."));
                     44:        else if (conn->disconnect_reason == OSCAR_DISCONNECT_REMOTE_REFUSED)
                     45:                tmp = g_strdup(_("The remote user has declined your request."));
                     46:        else if (conn->disconnect_reason == OSCAR_DISCONNECT_LOST_CONNECTION)
                     47:                tmp = g_strdup_printf(_("Lost connection with the remote user:<br>%s"),
                     48:                                conn->error_message);
                     49:        else if (conn->disconnect_reason == OSCAR_DISCONNECT_INVALID_DATA)
                     50:                tmp = g_strdup(_("Received invalid data on connection with remote user."));
                     51:        else if (conn->disconnect_reason == OSCAR_DISCONNECT_COULD_NOT_CONNECT)
                     52:                tmp = g_strdup(_("Unable to establish a connection with the remote user."));
                     53:        else
                     54:                /*
                     55:                 * We shouldn't print a message for some disconnect_reasons.
                     56:                 * Like OSCAR_DISCONNECT_LOCAL_CLOSED.
                     57:                 */
                     58:                tmp = NULL;
                     59: 
                     60:        if (tmp != NULL)
                     61:        {
                     62:                PurpleAccount *account;
                     63:                PurpleConversation *conv;
                     64: 
                     65:                account = purple_connection_get_account(conn->od->gc);
                     66:                conv = purple_conversation_new(PURPLE_CONV_TYPE_IM, account, conn->bn);
                     67:                purple_conversation_write(conv, NULL, tmp, PURPLE_MESSAGE_SYSTEM, time(NULL));
                     68:                g_free(tmp);
                     69:        }
                     70: 
                     71:        if (conn->frame != NULL)
                     72:        {
                     73:                OdcFrame *frame;
                     74:                frame = conn->frame;
                     75:                g_free(frame->payload.data);
                     76:                g_free(frame);
                     77:        }
                     78: }
                     79: 
                     80: /**
                     81:  * Write the given OdcFrame to a ByteStream and send it out
                     82:  * on the established PeerConnection.
                     83:  */
                     84: static void
                     85: peer_odc_send(PeerConnection *conn, OdcFrame *frame)
                     86: {
                     87:        PurpleAccount *account;
                     88:        const char *username;
                     89:        size_t length;
                     90:        ByteStream bs;
                     91: 
                     92:        purple_debug_info("oscar", "Outgoing ODC frame to %s with "
                     93:                "type=0x%04x, flags=0x%04x, payload length=%" G_GSIZE_FORMAT "\n",
                     94:                conn->bn, frame->type, frame->flags, frame->payload.len);
                     95: 
                     96:        account = purple_connection_get_account(conn->od->gc);
                     97:        username = purple_account_get_username(account);
                     98:        memcpy(frame->bn, username, strlen(username));
                     99:        memcpy(frame->cookie, conn->cookie, 8);
                    100: 
                    101:        length = 76;
                    102:        byte_stream_new(&bs, length + frame->payload.len);
                    103:        byte_stream_putraw(&bs, conn->magic, 4);
                    104:        byte_stream_put16(&bs, length);
                    105:        byte_stream_put16(&bs, frame->type);
                    106:        byte_stream_put16(&bs, frame->subtype);
                    107:        byte_stream_put16(&bs, 0x0000);
                    108:        byte_stream_putraw(&bs, frame->cookie, 8);
                    109:        byte_stream_put16(&bs, 0x0000);
                    110:        byte_stream_put16(&bs, 0x0000);
                    111:        byte_stream_put16(&bs, 0x0000);
                    112:        byte_stream_put16(&bs, 0x0000);
                    113:        byte_stream_put32(&bs, frame->payload.len);
                    114:        byte_stream_put16(&bs, frame->encoding);
                    115:        byte_stream_put16(&bs, 0x0000);
                    116:        byte_stream_put16(&bs, 0x0000);
                    117:        byte_stream_put16(&bs, frame->flags);
                    118:        byte_stream_put16(&bs, 0x0000);
                    119:        byte_stream_put16(&bs, 0x0000);
                    120:        byte_stream_putraw(&bs, frame->bn, 32);
                    121:        byte_stream_putraw(&bs, frame->payload.data, frame->payload.len);
                    122: 
                    123:        peer_connection_send(conn, &bs);
                    124: 
                    125:        byte_stream_destroy(&bs);
                    126: }
                    127: 
                    128: /**
                    129:  * Send a very basic ODC frame (which contains the cookie) so that the
                    130:  * remote user can verify that we are the person they were expecting.
                    131:  * If we made an outgoing connection to then remote user, then we send
                    132:  * this immediately.  If the remote user connected to us, then we wait
                    133:  * for the other person to send this to us, then we send one to them.
                    134:  */
                    135: void
                    136: peer_odc_send_cookie(PeerConnection *conn)
                    137: {
                    138:        OdcFrame frame;
                    139: 
                    140:        memset(&frame, 0, sizeof(OdcFrame));
                    141:        frame.type = 0x0001;
                    142:        frame.subtype = 0x0006;
                    143:        frame.flags = 0x0060; /* Maybe this means "we're sending the cookie"? */
                    144: 
                    145:        peer_odc_send(conn, &frame);
                    146: }
                    147: 
                    148: /**
                    149:  * Send client-to-client typing notification over an established direct connection.
                    150:  */
                    151: void
                    152: peer_odc_send_typing(PeerConnection *conn, PurpleTypingState typing)
                    153: {
                    154:        OdcFrame frame;
                    155: 
                    156:        memset(&frame, 0, sizeof(OdcFrame));
                    157:        frame.type = 0x0001;
                    158:        frame.subtype = 0x0006;
                    159:        if (typing == PURPLE_TYPING)
                    160:                frame.flags = 0x0002 | 0x0008;
                    161:        else if (typing == PURPLE_TYPED)
                    162:                frame.flags = 0x0002 | 0x0004;
                    163:        else
                    164:                frame.flags = 0x0002;
                    165: 
                    166:        peer_odc_send(conn, &frame);
                    167: }
                    168: 
                    169: /**
                    170:  * Send client-to-client IM over an established direct connection.
                    171:  * To send a direct IM, call this just like you would aim_send_im.
                    172:  *
                    173:  * @param conn The already-connected ODC connection.
                    174:  * @param msg Null-terminated string to send.
                    175:  * @param len The length of the message to send, including binary data.
                    176:  * @param encoding See the AIM_CHARSET_* defines in oscar.h
                    177:  * @param autoreply TRUE if this is any auto-reply.
                    178:  */
                    179: void
                    180: peer_odc_send_im(PeerConnection *conn, const char *msg, int len, int encoding, gboolean autoreply)
                    181: {
                    182:        OdcFrame frame;
                    183: 
                    184:        g_return_if_fail(msg != NULL);
                    185:        g_return_if_fail(len > 0);
                    186: 
                    187:        memset(&frame, 0, sizeof(OdcFrame));
                    188:        frame.type = 0x0001;
                    189:        frame.subtype = 0x0006;
                    190:        frame.payload.len = len;
                    191:        frame.encoding = encoding;
                    192:        frame.flags = autoreply;
                    193:        byte_stream_new(&frame.payload, len);
                    194:        byte_stream_putraw(&frame.payload, (guint8 *)msg, len);
                    195: 
                    196:        peer_odc_send(conn, &frame);
                    197: 
                    198:        g_free(frame.payload.data);
                    199: }
                    200: 
                    201: struct embedded_data
                    202: {
                    203:        size_t size;
                    204:        const guint8 *data;
                    205: };
                    206: 
                    207: /**
                    208:  * This is called after a direct IM has been received in its entirety.  This
                    209:  * function is passed a long chunk of data which contains the IM with any
                    210:  * data chunks (images) appended to it.
                    211:  *
                    212:  * This function rips out all the data chunks and creates an imgstore for
                    213:  * each one.  In order to do this, it first goes through the IM and takes
                    214:  * out all the IMG tags.  When doing so, it rewrites the original IMG tag
                    215:  * with one compatible with the imgstore Purple core code. For each one, we
                    216:  * then read in chunks of data from the end of the message and actually
                    217:  * create the img store using the given data.
                    218:  *
                    219:  * For somewhat easy reference, here's a sample message
                    220:  * (with added whitespace):
                    221:  *
                    222:  * <HTML><BODY BGCOLOR="#ffffff">
                    223:  *     <FONT LANG="0">
                    224:  *     This is a really stupid picture:<BR>
                    225:  *     <IMG SRC="Sample.jpg" ID="1" WIDTH="283" HEIGHT="212" DATASIZE="9894"><BR>
                    226:  *     Yeah it is<BR>
                    227:  *     Here is another one:<BR>
                    228:  *     <IMG SRC="Soap Bubbles.bmp" ID="2" WIDTH="256" HEIGHT="256" DATASIZE="65978">
                    229:  *     </FONT>
                    230:  * </BODY></HTML>
                    231:  * <BINARY>
                    232:  *     <DATA ID="1" SIZE="9894">datadatadatadata</DATA>
                    233:  *     <DATA ID="2" SIZE="65978">datadatadatadata</DATA>
                    234:  * </BINARY>
                    235:  */
                    236: static void
                    237: peer_odc_handle_payload(PeerConnection *conn, const char *msg, size_t len, int encoding, gboolean autoreply)
                    238: {
                    239:        PurpleConnection *gc;
                    240:        PurpleAccount *account;
                    241:        const char *msgend, *binary_start, *dataend;
                    242:        const char *tmp, *start, *end, *idstr, *src, *sizestr;
                    243:        GData *attributes;
                    244:        GHashTable *embedded_datas;
                    245:        struct embedded_data *embedded_data;
                    246:        GSList *images;
                    247:        gchar *utf8;
                    248:        GString *newmsg;
                    249:        PurpleMessageFlags imflags;
                    250: 
                    251:        gc = conn->od->gc;
                    252:        account = purple_connection_get_account(gc);
                    253: 
                    254:        dataend = msg + len;
                    255: 
                    256:        /*
                    257:         * Create a hash table containing references to each embedded
                    258:         * data chunk.  The key is the "ID" and the value is an
                    259:         * embedded_data struct.
                    260:         */
                    261:        embedded_datas = g_hash_table_new_full(g_direct_hash,
                    262:                        g_direct_equal, NULL, g_free);
                    263: 
                    264:        /*
                    265:         * Create an index of any binary chunks.  If we run into any
                    266:         * problems while parsing the binary data section then we stop
                    267:         * parsing it, and the local user will see broken image icons.
                    268:         */
                    269:        binary_start = purple_strcasestr(msg, "<binary>");
                    270:        if (binary_start == NULL)
                    271:                msgend = dataend;
                    272:        else
                    273:        {
                    274:                msgend = binary_start;
                    275: 
                    276:                /* Move our pointer to immediately after the <binary> tag */
                    277:                tmp = binary_start + 8;
                    278: 
                    279:                /* The embedded binary markup has a mimimum length of 29 bytes */
                    280:                while ((tmp + 29 <= dataend) &&
                    281:                                purple_markup_find_tag("data", tmp, &start, &tmp, &attributes))
                    282:                {
                    283:                        unsigned int id;
                    284:                        size_t size;
                    285: 
                    286:                        /* Move the binary pointer from ">" to the start of the data */
                    287:                        tmp++;
                    288: 
                    289:                        /* Get the ID */
                    290:                        idstr = g_datalist_get_data(&attributes, "id");
                    291:                        if (idstr == NULL)
                    292:                        {
                    293:                                g_datalist_clear(&attributes);
                    294:                                break;
                    295:                        }
                    296:                        id = atoi(idstr);
                    297: 
                    298:                        /* Get the size */
                    299:                        sizestr = g_datalist_get_data(&attributes, "size");
                    300:                        if (sizestr == NULL)
                    301:                        {
                    302:                                g_datalist_clear(&attributes);
                    303:                                break;
                    304:                        }
                    305:                        size = atol(sizestr);
                    306: 
                    307:                        g_datalist_clear(&attributes);
                    308: 
                    309:                        if ((size > 0) && (tmp + size > dataend))
                    310:                                break;
                    311: 
                    312:                        embedded_data = g_new(struct embedded_data, 1);
                    313:                        embedded_data->size = size;
                    314:                        embedded_data->data = (const guint8 *)tmp;
                    315:                        tmp += size;
                    316: 
                    317:                        /* Skip past the closing </data> tag */
                    318:                        if (g_ascii_strncasecmp(tmp, "</data>", 7))
                    319:                        {
                    320:                                g_free(embedded_data);
                    321:                                break;
                    322:                        }
                    323:                        tmp += 7;
                    324: 
                    325:                        g_hash_table_insert(embedded_datas,
                    326:                                        GINT_TO_POINTER(id), embedded_data);
                    327:                }
                    328:        }
                    329: 
                    330:        /*
                    331:         * Loop through the message, replacing OSCAR img tags with the
                    332:         * equivalent Purple img tag.
                    333:         */
                    334:        images = NULL;
                    335:        newmsg = g_string_new("");
                    336:        tmp = msg;
                    337:        while (purple_markup_find_tag("img", tmp, &start, &end, &attributes))
                    338:        {
                    339:                int imgid = 0;
                    340: 
                    341:                idstr   = g_datalist_get_data(&attributes, "id");
                    342:                src     = g_datalist_get_data(&attributes, "src");
                    343:                sizestr = g_datalist_get_data(&attributes, "datasize");
                    344: 
                    345:                if ((idstr != NULL) && (src != NULL) && (sizestr!= NULL))
                    346:                {
                    347:                        unsigned int id;
                    348:                        size_t size;
                    349: 
                    350:                        id = atoi(idstr);
                    351:                        size = atol(sizestr);
                    352:                        embedded_data = g_hash_table_lookup(embedded_datas,
                    353:                                        GINT_TO_POINTER(id));
                    354: 
                    355:                        if ((embedded_data != NULL) && (embedded_data->size == size))
                    356:                        {
                    357:                                imgid = purple_imgstore_add_with_id(g_memdup(embedded_data->data, size), size, src);
                    358: 
                    359:                                /* Record the image number */
                    360:                                images = g_slist_append(images, GINT_TO_POINTER(imgid));
                    361:                        }
                    362:                }
                    363: 
                    364:                /* Delete the attribute list */
                    365:                g_datalist_clear(&attributes);
                    366: 
                    367:                /* Append the message up to the tag */
                    368:                utf8 = oscar_decode_im(account, conn->bn, encoding, tmp, start - tmp);
                    369:                if (utf8 != NULL) {
                    370:                        g_string_append(newmsg, utf8);
                    371:                        g_free(utf8);
                    372:                }
                    373: 
                    374:                if (imgid != 0)
                    375:                {
                    376:                        /* Write the new image tag */
                    377:                        g_string_append_printf(newmsg, "<IMG ID=\"%d\">", imgid);
                    378:                }
                    379: 
                    380:                /* Continue from the end of the tag */
                    381:                tmp = end + 1;
                    382:        }
                    383: 
                    384:        /* Append any remaining message data */
                    385:        if (tmp <= msgend)
                    386:        {
                    387:                utf8 = oscar_decode_im(account, conn->bn, encoding, tmp, msgend - tmp);
                    388:                if (utf8 != NULL) {
                    389:                        g_string_append(newmsg, utf8);
                    390:                        g_free(utf8);
                    391:                }
                    392:        }
                    393: 
                    394:        /* Display the message we received */
                    395:        imflags = 0;
                    396:        if (images != NULL)
                    397:                imflags |= PURPLE_MESSAGE_IMAGES;
                    398:        if (autoreply)
                    399:                imflags |= PURPLE_MESSAGE_AUTO_RESP;
                    400:        serv_got_im(gc, conn->bn, newmsg->str, imflags, time(NULL));
                    401:        g_string_free(newmsg, TRUE);
                    402: 
                    403:        /* unref any images we allocated */
                    404:        if (images)
                    405:        {
                    406:                GSList *l;
                    407:                for (l = images; l != NULL; l = l->next)
                    408:                        purple_imgstore_unref_by_id(GPOINTER_TO_INT(l->data));
                    409:                g_slist_free(images);
                    410:        }
                    411: 
                    412:        /* Delete our list of pointers to embedded images */
                    413:        g_hash_table_destroy(embedded_datas);
                    414: }
                    415: 
                    416: /**
                    417:  * This is a purple_input_add() watcher callback function for reading
                    418:  * direct IM payload data.  "Payload data" is always an IM and
                    419:  * maybe some embedded images or files or something.  The actual
                    420:  * ODC frame is read using peer_connection_recv_cb().  We temporarily
                    421:  * switch to this watcher callback ONLY to read the payload, and we
                    422:  * switch back once we're done.
                    423:  */
                    424: static void
                    425: peer_odc_recv_cb(gpointer data, gint source, PurpleInputCondition cond)
                    426: {
                    427:        PeerConnection *conn;
                    428:        OdcFrame *frame;
                    429:        ByteStream *bs;
                    430:        gssize read;
                    431: 
                    432:        conn = data;
                    433:        frame = conn->frame;
                    434:        bs = &frame->payload;
                    435: 
                    436:        /* Read data into the temporary buffer until it is complete */
                    437:        read = recv(conn->fd,
                    438:                                &bs->data[bs->offset],
                    439:                                bs->len - bs->offset,
                    440:                                0);
                    441: 
                    442:        /* Check if the remote user closed the connection */
                    443:        if (read == 0)
                    444:        {
                    445:                peer_connection_destroy(conn, OSCAR_DISCONNECT_REMOTE_CLOSED, NULL);
                    446:                return;
                    447:        }
                    448: 
                    449:        if (read < 0)
                    450:        {
                    451:                if ((errno == EAGAIN) || (errno == EWOULDBLOCK))
                    452:                        /* No worries */
                    453:                        return;
                    454: 
                    455:                peer_connection_destroy(conn,
                    456:                                OSCAR_DISCONNECT_LOST_CONNECTION, g_strerror(errno));
                    457:                return;
                    458:        }
                    459: 
                    460:        bs->offset += read;
                    461:        if (bs->offset < bs->len)
                    462:                /* Waiting for more data to arrive */
                    463:                return;
                    464:        /* TODO: Instead of null-terminating this, it would be better if we just
                    465:           respected the length of the buffer when parsing it.  But it doesn't
                    466:           really matter and this is easy. */
                    467:        bs->data[bs->len] = '\0';
                    468: 
                    469:        /* We have a complete ODC/OFT frame!  Handle it and continue reading */
                    470:        byte_stream_rewind(bs);
                    471:        peer_odc_handle_payload(conn, (const char *)bs->data,
                    472:                        bs->len, frame->encoding, frame->flags & 0x0001);
                    473:        g_free(bs->data);
                    474:        bs->data = NULL;
                    475:        g_free(frame);
                    476:        conn->frame = NULL;
                    477: 
                    478:        purple_input_remove(conn->watcher_incoming);
                    479:        conn->watcher_incoming = purple_input_add(conn->fd,
                    480:                        PURPLE_INPUT_READ, peer_connection_recv_cb, conn);
                    481: }
                    482: 
                    483: /**
                    484:  * Handle an incoming OdcFrame.  If there is a payload associated
                    485:  * with this frame, then we remove the old watcher and add the
                    486:  * ODC watcher to read in the payload.
                    487:  */
                    488: void
                    489: peer_odc_recv_frame(PeerConnection *conn, ByteStream *bs)
                    490: {
                    491:        PurpleConnection *gc;
                    492:        OdcFrame *frame;
                    493: 
                    494:        gc = conn->od->gc;
                    495: 
                    496:        frame = g_new0(OdcFrame, 1);
                    497:        frame->type = byte_stream_get16(bs);
                    498:        frame->subtype = byte_stream_get16(bs);
                    499:        byte_stream_advance(bs, 2);
                    500:        byte_stream_getrawbuf(bs, frame->cookie, 8);
                    501:        byte_stream_advance(bs, 8);
                    502:        frame->payload.len = byte_stream_get32(bs);
                    503:        frame->encoding = byte_stream_get16(bs);
                    504:        byte_stream_advance(bs, 4);
                    505:        frame->flags = byte_stream_get16(bs);
                    506:        byte_stream_advance(bs, 4);
                    507:        byte_stream_getrawbuf(bs, frame->bn, 32);
                    508: 
                    509:        purple_debug_info("oscar", "Incoming ODC frame from %s with "
                    510:                        "type=0x%04x, flags=0x%04x, payload length=%" G_GSIZE_FORMAT "\n",
                    511:                        frame->bn, frame->type, frame->flags, frame->payload.len);
                    512: 
                    513:        if (!conn->ready)
                    514:        {
                    515:                /*
                    516:                 * We need to verify the cookie so that we know we are
                    517:                 * connected to our friend and not a malicious middle man.
                    518:                 */
                    519: 
                    520:                PurpleAccount *account;
                    521:                PurpleConversation *conv;
                    522: 
                    523:                if (conn->flags & PEER_CONNECTION_FLAG_IS_INCOMING)
                    524:                {
                    525:                        if (memcmp(conn->cookie, frame->cookie, 8))
                    526:                        {
                    527:                                /*
                    528:                                 * Oh no!  The user that connected to us did not send
                    529:                                 * the correct cookie!  They are not our friend.  Go try
                    530:                                 * to accept another connection?
                    531:                                 */
                    532:                                purple_debug_info("oscar", "Received an incorrect cookie.  "
                    533:                                        "Closing connection.\n");
                    534:                                peer_connection_destroy(conn,
                    535:                                                OSCAR_DISCONNECT_INVALID_DATA, NULL);
                    536:                                g_free(frame);
                    537:                                return;
                    538:                        }
                    539: 
                    540:                        /*
                    541:                         * Ok, we know they are legit.  Now be courteous and
                    542:                         * send them our cookie.  Note: This doesn't seem
                    543:                         * to be necessary, but it also doesn't seem to hurt.
                    544:                         */
                    545:                        peer_odc_send_cookie(conn);
                    546:                }
                    547: 
                    548:                conn->ready = TRUE;
                    549: 
                    550:                /*
                    551:                 * If they connected to us then close the listener socket
                    552:                 * and send them our cookie.
                    553:                 */
                    554:                if (conn->listenerfd != -1)
                    555:                {
                    556:                        close(conn->listenerfd);
                    557:                        conn->listenerfd = -1;
                    558:                }
                    559: 
                    560:                /* Tell the local user that we are connected */
                    561:                account = purple_connection_get_account(gc);
                    562:                conv = purple_conversation_new(PURPLE_CONV_TYPE_IM, account, conn->bn);
                    563:                purple_conversation_write(conv, NULL, _("Direct IM established"),
                    564:                                PURPLE_MESSAGE_SYSTEM, time(NULL));
                    565:        }
                    566: 
                    567:        if ((frame->type != 0x0001) && (frame->subtype != 0x0006))
                    568:        {
                    569:                purple_debug_info("oscar", "Unknown ODC frame type 0x%04hx, "
                    570:                                "subtype 0x%04hx.\n", frame->type, frame->subtype);
                    571:                g_free(frame);
                    572:                return;
                    573:        }
                    574: 
                    575:        if (frame->flags & 0x0008)
                    576:        {
                    577:                /* I had to leave this. It's just too funny. It reminds me of my sister. */
                    578:                purple_debug_info("oscar", "ohmigod! %s has started typing "
                    579:                        "(DirectIM). He's going to send you a message! "
                    580:                        "*squeal*\n", conn->bn);
                    581:                serv_got_typing(gc, conn->bn, 0, PURPLE_TYPING);
                    582:        }
                    583:        else if (frame->flags & 0x0004)
                    584:        {
                    585:                serv_got_typing(gc, conn->bn, 0, PURPLE_TYPED);
                    586:        }
                    587:        else
                    588:        {
                    589:                serv_got_typing_stopped(gc, conn->bn);
                    590:        }
                    591: 
                    592:        if (frame->payload.len > 0)
                    593:        {
                    594:                if (frame->payload.len > DIRECTIM_MAX_FILESIZE)
                    595:                {
                    596:                        gchar *tmp, *size1, *size2;
                    597:                        PurpleAccount *account;
                    598:                        PurpleConversation *conv;
                    599: 
                    600:                        size1 = purple_str_size_to_units(frame->payload.len);
                    601:                        size2 = purple_str_size_to_units(DIRECTIM_MAX_FILESIZE);
                    602:                        tmp = g_strdup_printf(_("%s tried to send you a %s file, but we only allow files up to %s over Direct IM.  Try using file transfer instead.\n"), conn->bn, size1, size2);
                    603:                        g_free(size1);
                    604:                        g_free(size2);
                    605: 
                    606:                        account = purple_connection_get_account(conn->od->gc);
                    607:                        conv = purple_conversation_new(PURPLE_CONV_TYPE_IM, account, conn->bn);
                    608:                        purple_conversation_write(conv, NULL, tmp, PURPLE_MESSAGE_SYSTEM, time(NULL));
                    609:                        g_free(tmp);
                    610: 
                    611:                        peer_connection_destroy(conn, OSCAR_DISCONNECT_LOCAL_CLOSED, NULL);
                    612:                        g_free(frame);
                    613:                        return;
                    614:                }
                    615: 
                    616:                /* We have payload data!  Switch to the ODC watcher to read it. */
                    617:                frame->payload.data = g_new(guint8, frame->payload.len + 1);
                    618:                frame->payload.offset = 0;
                    619:                conn->frame = frame;
                    620:                purple_input_remove(conn->watcher_incoming);
                    621:                conn->watcher_incoming = purple_input_add(conn->fd,
                    622:                                PURPLE_INPUT_READ, peer_odc_recv_cb, conn);
                    623:                return;
                    624:        }
                    625: 
                    626:        g_free(frame);
                    627: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>