📄 odc.c
字号:
/* * Purple's oscar protocol plugin * This file is the legal property of its developers. * Please see the AUTHORS file distributed alongside this file. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA*//* From the oscar PRPL */#include "oscar.h"#include "peer.h"/* From Purple */#include "conversation.h"#include "imgstore.h"#include "util.h"/** * Free any ODC related data and print a message to the conversation * window based on conn->disconnect_reason. */voidpeer_odc_close(PeerConnection *conn){ gchar *tmp; if (conn->disconnect_reason == OSCAR_DISCONNECT_REMOTE_CLOSED) tmp = g_strdup(_("The remote user has closed the connection.")); else if (conn->disconnect_reason == OSCAR_DISCONNECT_REMOTE_REFUSED) tmp = g_strdup(_("The remote user has declined your request.")); else if (conn->disconnect_reason == OSCAR_DISCONNECT_LOST_CONNECTION) tmp = g_strdup_printf(_("Lost connection with the remote user:<br>%s"), conn->error_message); else if (conn->disconnect_reason == OSCAR_DISCONNECT_INVALID_DATA) tmp = g_strdup(_("Received invalid data on connection with remote user.")); else if (conn->disconnect_reason == OSCAR_DISCONNECT_COULD_NOT_CONNECT) tmp = g_strdup(_("Could not establish a connection with the remote user.")); else /* * We shouldn't print a message for some disconnect_reasons. * Like OSCAR_DISCONNECT_LOCAL_CLOSED. */ tmp = NULL; if (tmp != NULL) { PurpleAccount *account; PurpleConversation *conv; account = purple_connection_get_account(conn->od->gc); conv = purple_conversation_new(PURPLE_CONV_TYPE_IM, account, conn->sn); purple_conversation_write(conv, NULL, tmp, PURPLE_MESSAGE_SYSTEM, time(NULL)); g_free(tmp); } if (conn->frame != NULL) { OdcFrame *frame; frame = conn->frame; g_free(frame->payload.data); g_free(frame); }}/** * Write the given OdcFrame to a ByteStream and send it out * on the established PeerConnection. */static voidpeer_odc_send(PeerConnection *conn, OdcFrame *frame){ PurpleAccount *account; const char *username; size_t length; ByteStream bs; purple_debug_info("oscar", "Outgoing ODC frame to %s with " "type=0x%04x, flags=0x%04x, payload length=%u\n", conn->sn, frame->type, frame->flags, frame->payload.len); account = purple_connection_get_account(conn->od->gc); username = purple_account_get_username(account); memcpy(frame->sn, username, strlen(username)); memcpy(frame->cookie, conn->cookie, 8); length = 76; byte_stream_new(&bs, length + frame->payload.len); byte_stream_putraw(&bs, conn->magic, 4); byte_stream_put16(&bs, length); byte_stream_put16(&bs, frame->type); byte_stream_put16(&bs, frame->subtype); byte_stream_put16(&bs, 0x0000); byte_stream_putraw(&bs, frame->cookie, 8); byte_stream_put16(&bs, 0x0000); byte_stream_put16(&bs, 0x0000); byte_stream_put16(&bs, 0x0000); byte_stream_put16(&bs, 0x0000); byte_stream_put32(&bs, frame->payload.len); byte_stream_put16(&bs, 0x0000); byte_stream_put16(&bs, frame->encoding); byte_stream_put16(&bs, 0x0000); byte_stream_put16(&bs, frame->flags); byte_stream_put16(&bs, 0x0000); byte_stream_put16(&bs, 0x0000); byte_stream_putraw(&bs, frame->sn, 32); byte_stream_putraw(&bs, frame->payload.data, frame->payload.len); peer_connection_send(conn, &bs); g_free(bs.data);}/** * Send a very basic ODC frame (which contains the cookie) so that the * remote user can verify that we are the person they were expecting. * If we made an outgoing connection to then remote user, then we send * this immediately. If the remote user connected to us, then we wait * for the other person to send this to us, then we send one to them. */voidpeer_odc_send_cookie(PeerConnection *conn){ OdcFrame frame; memset(&frame, 0, sizeof(OdcFrame)); frame.type = 0x0001; frame.subtype = 0x0006; frame.flags = 0x0060; /* Maybe this means "we're sending the cookie"? */ peer_odc_send(conn, &frame);}/** * Send client-to-client typing notification over an established direct connection. */voidpeer_odc_send_typing(PeerConnection *conn, PurpleTypingState typing){ OdcFrame frame; memset(&frame, 0, sizeof(OdcFrame)); frame.type = 0x0001; frame.subtype = 0x0006; if (typing == PURPLE_TYPING) frame.flags = 0x0002 | 0x0008; else if (typing == PURPLE_TYPED) frame.flags = 0x0002 | 0x0004; else frame.flags = 0x0002; peer_odc_send(conn, &frame);}/** * Send client-to-client IM over an established direct connection. * To send a direct IM, call this just like you would aim_send_im. * * @param conn The already-connected ODC connection. * @param msg Null-terminated string to send. * @param len The length of the message to send, including binary data. * @param encoding See the AIM_CHARSET_* defines in oscar.h * @param autoreply TRUE if this is any auto-reply. */voidpeer_odc_send_im(PeerConnection *conn, const char *msg, int len, int encoding, gboolean autoreply){ OdcFrame frame; g_return_if_fail(msg != NULL); g_return_if_fail(len > 0); memset(&frame, 0, sizeof(OdcFrame)); frame.type = 0x0001; frame.subtype = 0x0006; frame.payload.len = len; frame.encoding = encoding; frame.flags = autoreply; byte_stream_new(&frame.payload, len); byte_stream_putraw(&frame.payload, (guint8 *)msg, len); peer_odc_send(conn, &frame); g_free(frame.payload.data);}struct embedded_data{ size_t size; const guint8 *data;};/** * This is called after a direct IM has been received in its entirety. This * function is passed a long chunk of data which contains the IM with any * data chunks (images) appended to it. * * This function rips out all the data chunks and creates an imgstore for * each one. In order to do this, it first goes through the IM and takes * out all the IMG tags. When doing so, it rewrites the original IMG tag * with one compatible with the imgstore Purple core code. For each one, we * then read in chunks of data from the end of the message and actually * create the img store using the given data. * * For somewhat easy reference, here's a sample message * (with added whitespace): * * <HTML><BODY BGCOLOR="#ffffff"> * <FONT LANG="0"> * This is a really stupid picture:<BR> * <IMG SRC="Sample.jpg" ID="1" WIDTH="283" HEIGHT="212" DATASIZE="9894"><BR> * Yeah it is<BR> * Here is another one:<BR> * <IMG SRC="Soap Bubbles.bmp" ID="2" WIDTH="256" HEIGHT="256" DATASIZE="65978"> * </FONT> * </BODY></HTML> * <BINARY> * <DATA ID="1" SIZE="9894">datadatadatadata</DATA> * <DATA ID="2" SIZE="65978">datadatadatadata</DATA> * </BINARY> */static voidpeer_odc_handle_payload(PeerConnection *conn, const char *msg, size_t len, int encoding, gboolean autoreply){ PurpleConnection *gc; PurpleAccount *account; const char *msgend, *binary_start, *dataend; const char *tmp, *start, *end, *idstr, *src, *sizestr; GData *attributes; GHashTable *embedded_datas; struct embedded_data *embedded_data; GSList *images; gchar *utf8; GString *newmsg; PurpleMessageFlags imflags; gc = conn->od->gc; account = purple_connection_get_account(gc); dataend = msg + len; /* * Create a hash table containing references to each embedded * data chunk. The key is the "ID" and the value is an * embedded_data struct. */ embedded_datas = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, g_free); /* * Create an index of any binary chunks. If we run into any * problems while parsing the binary data section then we stop * parsing it, and the local user will see broken image icons. */ /* TODO: Use a length argument when looking for the <binary> tag! */ binary_start = purple_strcasestr(msg, "<binary>"); if (binary_start == NULL) msgend = dataend; else { msgend = binary_start; /* Move our pointer to immediately after the <binary> tag */ tmp = binary_start + 8; /* The embedded binary markup has a mimimum length of 29 bytes */ /* TODO: Use a length argument when looking for the <data> tag! */ while ((tmp + 29 <= dataend) && purple_markup_find_tag("data", tmp, &start, &tmp, &attributes)) { unsigned int id; size_t size; /* Move the binary pointer from ">" to the start of the data */ tmp++; /* Get the ID */ idstr = g_datalist_get_data(&attributes, "id"); if (idstr == NULL) { g_datalist_clear(&attributes); break; } id = atoi(idstr); /* Get the size */ sizestr = g_datalist_get_data(&attributes, "size"); if (sizestr == NULL) { g_datalist_clear(&attributes);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -