pidgin/pidgin

Fix coverity 1255966 and 1255964

2016-12-10, Gary Kramlich
20f33f108f99
Fix coverity 1255966 and 1255964
/**
* @file msnslp.c MSNSLP support
*
* purple
*
* Purple is the legal property of its developers, whose names are too numerous
* to list here. Please refer to the COPYRIGHT file distributed with this
* source distribution.
*
* 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 02111-1301 USA
*/
#include "internal.h"
#include "debug.h"
#include "http.h"
#include "slp.h"
#include "slpcall.h"
#include "slpmsg.h"
#include "msnutils.h"
#include "object.h"
#include "user.h"
#include "sbconn.h"
#include "directconn.h"
#include "p2p.h"
#include "ft.h"
/* seconds to delay between sending buddy icon requests to the server. */
#define BUDDY_ICON_DELAY 20
typedef struct {
MsnSession *session;
const char *remote_user;
const char *sha1;
} MsnFetchUserDisplayData;
/**************************************************************************
* SLP Control
**************************************************************************/
void
msn_slp_send_ok(MsnSlpCall *slpcall, const char *branch,
const char *type, const char *content)
{
MsnSlpLink *slplink;
MsnSlpMessage *slpmsg;
slplink = slpcall->slplink;
/* 200 OK */
slpmsg = msn_slpmsg_sip_new(slpcall, 1,
"MSNSLP/1.0 200 OK",
branch, type, content);
slpmsg->info = "SLP 200 OK";
slpmsg->text_body = TRUE;
msn_slplink_queue_slpmsg(slplink, slpmsg);
}
void
msn_slp_send_decline(MsnSlpCall *slpcall, const char *branch,
const char *type, const char *content)
{
MsnSlpLink *slplink;
MsnSlpMessage *slpmsg;
slplink = slpcall->slplink;
/* 603 Decline */
slpmsg = msn_slpmsg_sip_new(slpcall, 1,
"MSNSLP/1.0 603 Decline",
branch, type, content);
slpmsg->info = "SLP 603 Decline";
slpmsg->text_body = TRUE;
msn_slplink_queue_slpmsg(slplink, slpmsg);
}
/**************************************************************************
* Msg Callbacks
**************************************************************************/
/*
* Called on a timeout from end_user_display(). Frees a buddy icon window slow and dequeues the next
* buddy icon request if there is one.
*/
static gboolean
msn_release_buddy_icon_request_timeout(gpointer data)
{
MsnUserList *userlist = (MsnUserList *)data;
/* Free one window slot */
userlist->buddy_icon_window++;
/* Clear the tag for our former request timer */
userlist->buddy_icon_request_timer = 0;
msn_release_buddy_icon_request(userlist);
return FALSE;
}
static void
got_user_display(MsnSlpCall *slpcall,
const guchar *data, gsize size)
{
const char *info;
PurpleAccount *account;
g_return_if_fail(slpcall != NULL);
info = slpcall->data_info;
if (purple_debug_is_verbose())
purple_debug_info("msn", "Got User Display: %s\n", slpcall->slplink->remote_user);
account = slpcall->slplink->session->account;
purple_buddy_icons_set_for_user(account, slpcall->slplink->remote_user,
g_memdup(data, size), size, info);
}
static void
end_user_display(MsnSlpCall *slpcall, MsnSession *session)
{
MsnUserList *userlist;
g_return_if_fail(session != NULL);
if (purple_debug_is_verbose())
purple_debug_info("msn", "End User Display\n");
userlist = session->userlist;
/* If the session is being destroyed we better stop doing anything. */
if (session->destroying)
return;
/* Delay before freeing a buddy icon window slot and requesting the next icon, if appropriate.
* If we don't delay, we'll rapidly hit the MSN equivalent of AIM's rate limiting; the server will
* send us an error 800 like so:
*
* C: NS 000: XFR 21 SB
* S: NS 000: 800 21
*/
if (userlist->buddy_icon_request_timer) {
/* Free the window slot used by this previous request */
userlist->buddy_icon_window++;
/* Clear our pending timeout */
purple_timeout_remove(userlist->buddy_icon_request_timer);
}
/* Wait BUDDY_ICON_DELAY s before freeing our window slot and requesting the next icon. */
userlist->buddy_icon_request_timer = purple_timeout_add_seconds(BUDDY_ICON_DELAY,
msn_release_buddy_icon_request_timeout, userlist);
}
static void
fetched_user_display(PurpleHttpConnection *http_conn,
PurpleHttpResponse *response, gpointer _data)
{
MsnFetchUserDisplayData *data = _data;
MsnSession *session = data->session;
if (purple_http_response_is_successful(response)) {
size_t len;
const gchar *icon_data;
icon_data = purple_http_response_get_data(response, &len);
purple_buddy_icons_set_for_user(session->account,
data->remote_user, g_memdup(icon_data, len), len,
data->sha1);
}
end_user_display(NULL, session);
g_free(data);
}
static void
request_own_user_display(MsnUser *user)
{
PurpleAccount *account;
MsnSession *session;
MsnObject *my_obj = NULL;
gconstpointer data = NULL;
const char *info = NULL;
size_t len = 0;
if (purple_debug_is_verbose())
purple_debug_info("msn", "Requesting our own user display\n");
session = user->userlist->session;
account = session->account;
my_obj = msn_user_get_object(user);
if (my_obj != NULL) {
PurpleImage *img = msn_object_get_image(my_obj);
data = purple_image_get_data(img);
len = purple_image_get_size(img);
info = msn_object_get_sha1(my_obj);
}
purple_buddy_icons_set_for_user(account, user->passport, g_memdup(data, len), len, info);
/* Free one window slot */
session->userlist->buddy_icon_window++;
if (purple_debug_is_verbose())
purple_debug_info("msn", "msn_request_user_display(): buddy_icon_window++ yields =%d\n",
session->userlist->buddy_icon_window);
msn_release_buddy_icon_request(session->userlist);
}
void
msn_request_user_display(MsnUser *user)
{
PurpleAccount *account;
MsnSession *session;
MsnSlpLink *slplink;
MsnObject *obj;
const char *info;
session = user->userlist->session;
account = session->account;
slplink = msn_session_get_slplink(session, user->passport);
obj = msn_user_get_object(user);
info = msn_object_get_sha1(obj);
if (g_ascii_strcasecmp(user->passport,
purple_account_get_username(account)))
{
const char *url = msn_object_get_url1(obj);
if (url) {
PurpleHttpRequest *req;
MsnFetchUserDisplayData *data = g_new0(MsnFetchUserDisplayData, 1);
data->session = session;
data->remote_user = user->passport;
data->sha1 = info;
req = purple_http_request_new(url);
purple_http_request_set_max_len(req, 200*1024);
purple_http_connection_set_add(session->http_reqs,
purple_http_request(NULL, req,
fetched_user_display, data));
purple_http_request_unref(req);
} else {
msn_slplink_request_object(slplink, info, got_user_display,
end_user_display, obj);
}
}
else
request_own_user_display(user);
}
static void
send_file_cb(MsnSlpCall *slpcall)
{
MsnSlpMessage *slpmsg;
PurpleXfer *xfer;
xfer = (PurpleXfer *)slpcall->xfer;
if (purple_xfer_get_status(xfer) >= PURPLE_XFER_STATUS_STARTED)
return;
g_object_ref(xfer);
purple_xfer_start(xfer, -1, NULL, 0);
if (purple_xfer_get_status(xfer) != PURPLE_XFER_STATUS_STARTED) {
g_object_unref(xfer);
return;
}
g_object_unref(xfer);
slpmsg = msn_slpmsg_file_new(slpcall, purple_xfer_get_size(xfer));
msn_slplink_send_slpmsg(slpcall->slplink, slpmsg);
}
static gchar *
gen_context(PurpleXfer *xfer, const char *file_name, const char *file_path)
{
goffset size = 0;
MsnFileContext context;
gchar *u8 = NULL;
gchar *ret;
gunichar2 *uni = NULL;
glong currentChar = 0;
glong len = 0;
const char *preview;
gsize preview_len;
size = purple_xfer_get_size(xfer);
purple_xfer_prepare_thumbnail(xfer, "png");
if (!file_name) {
gchar *basename = g_path_get_basename(file_path);
u8 = purple_utf8_try_convert(basename);
g_free(basename);
file_name = u8;
}
uni = g_utf8_to_utf16(file_name, -1, NULL, &len, NULL);
if (u8) {
g_free(u8);
file_name = NULL;
u8 = NULL;
}
preview = purple_xfer_get_thumbnail(xfer, &preview_len);
context.length = MSN_FILE_CONTEXT_SIZE_V2;
context.version = 2; /* V.3 contains additional unnecessary data */
context.file_size = size;
if (preview)
context.type = 0;
else
context.type = 1;
len = MIN(len, MAX_FILE_NAME_LEN);
for (currentChar = 0; currentChar < len; currentChar++) {
context.file_name[currentChar] = GUINT16_TO_LE(uni[currentChar]);
}
memset(&context.file_name[currentChar], 0x00, (MAX_FILE_NAME_LEN - currentChar) * 2);
#if 0
memset(&context.unknown1, 0, sizeof(context.unknown1));
context.unknown2 = 0xffffffff;
#endif
/* Mind the cast, as in, don't free it after! */
context.preview = (char *)preview;
context.preview_len = preview_len;
u8 = msn_file_context_to_wire(&context);
ret = purple_base64_encode((const guchar *)u8, MSN_FILE_CONTEXT_SIZE_V2 + preview_len);
g_free(uni);
g_free(u8);
return ret;
}
void
msn_request_ft(PurpleXfer *xfer)
{
MsnSlpCall *slpcall;
MsnSlpLink *slplink;
char *context;
const char *fn;
const char *fp;
fn = purple_xfer_get_filename(xfer);
fp = purple_xfer_get_local_filename(xfer);
slplink = purple_xfer_get_protocol_data(xfer);
g_return_if_fail(slplink != NULL);
g_return_if_fail(fp != NULL);
slpcall = msn_slpcall_new(slplink);
msn_slpcall_init(slpcall, MSN_SLPCALL_DC);
slpcall->session_init_cb = send_file_cb;
slpcall->end_cb = msn_xfer_end_cb;
slpcall->cb = msn_xfer_completed_cb;
slpcall->xfer = xfer;
g_object_ref(slpcall->xfer);
slpcall->pending = TRUE;
purple_xfer_set_cancel_send_fnc(xfer, msn_xfer_cancel);
purple_xfer_set_read_fnc(xfer, msn_xfer_read);
purple_xfer_set_write_fnc(xfer, msn_xfer_write);
purple_xfer_set_protocol_data(xfer, slpcall);
context = gen_context(xfer, fn, fp);
msn_slpcall_invite(slpcall, MSN_FT_GUID, P2P_APPID_FILE, context);
msn_slplink_unref(slplink);
g_free(context);
}