pidgin/pidgin
Clone
Summary
Browse
Changes
Graph
Use a source identifier for fb_data_add_timeout
2022-03-13, Elliott Sales de Andrade
2f1bed3c4738
Use a source identifier for fb_data_add_timeout
And have the caller add the timeout itself. This avoids us having to define a
scope for the data parameter.
/*
* Pidgin - Internet Messenger
* Copyright (C) Pidgin Developers <devel@pidgin.im>
*
* Pidgin 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, see <https://www.gnu.org/licenses/>.
*/
#include
<glib/gi18n-lib.h>
#include
<glib/gstdio.h>
#include
<gdk-pixbuf/gdk-pixbuf.h>
#include
<talkatu.h>
#include
"pidgindnd.h"
#include
"gtkconv.h"
#include
"pidgincore.h"
#include
"pidgingdkpixbuf.h"
enum
{
DND_FILE_TRANSFER
,
DND_IM_IMAGE
,
DND_BUDDY_ICON
};
typedef
struct
{
char
*
filename
;
PurpleAccount
*
account
;
char
*
who
;
}
_DndData
;
static
void
dnd_image_ok_callback
(
_DndData
*
data
,
int
choice
)
{
const
gchar
*
shortname
;
gchar
*
filedata
;
size_t
size
;
GStatBuf
st
;
GError
*
err
=
NULL
;
PurpleBuddy
*
buddy
;
PurpleContact
*
contact
;
PurpleImage
*
img
;
switch
(
choice
)
{
case
DND_BUDDY_ICON
:
if
(
g_stat
(
data
->
filename
,
&
st
))
{
char
*
str
;
str
=
g_strdup_printf
(
_
(
"The following error has occurred loading %s: %s"
),
data
->
filename
,
g_strerror
(
errno
));
purple_notify_error
(
NULL
,
NULL
,
_
(
"Failed to load image"
),
str
,
NULL
);
g_free
(
str
);
break
;
}
buddy
=
purple_blist_find_buddy
(
data
->
account
,
data
->
who
);
if
(
!
buddy
)
{
purple_debug_info
(
"custom-icon"
,
"You can only set custom icons for people on your buddylist.
\n
"
);
break
;
}
contact
=
purple_buddy_get_contact
(
buddy
);
purple_buddy_icons_node_set_custom_icon_from_file
((
PurpleBlistNode
*
)
contact
,
data
->
filename
);
break
;
case
DND_FILE_TRANSFER
:
purple_serv_send_file
(
purple_account_get_connection
(
data
->
account
),
data
->
who
,
data
->
filename
);
break
;
case
DND_IM_IMAGE
:
if
(
!
g_file_get_contents
(
data
->
filename
,
&
filedata
,
&
size
,
&
err
))
{
char
*
str
;
str
=
g_strdup_printf
(
_
(
"The following error has occurred loading %s: %s"
),
data
->
filename
,
err
->
message
);
purple_notify_error
(
NULL
,
NULL
,
_
(
"Failed to load image"
),
str
,
NULL
);
g_error_free
(
err
);
g_free
(
str
);
break
;
}
shortname
=
strrchr
(
data
->
filename
,
G_DIR_SEPARATOR
);
shortname
=
shortname
?
shortname
+
1
:
data
->
filename
;
img
=
purple_image_new_from_data
((
guint8
*
)
filedata
,
size
);
purple_image_set_friendly_filename
(
img
,
shortname
);
# warning fix this when talkatu has a way to programmatically insert an image
// pidgin_webview_insert_image(PIDGIN_WEBVIEW(gtkconv->entry), img);
g_object_unref
(
img
);
break
;
}
g_free
(
data
->
filename
);
g_free
(
data
->
who
);
g_free
(
data
);
}
static
void
dnd_image_cancel_callback
(
_DndData
*
data
,
int
choice
)
{
g_free
(
data
->
filename
);
g_free
(
data
->
who
);
g_free
(
data
);
}
static
void
dnd_set_icon_ok_cb
(
_DndData
*
data
)
{
dnd_image_ok_callback
(
data
,
DND_BUDDY_ICON
);
}
static
void
dnd_set_icon_cancel_cb
(
_DndData
*
data
)
{
g_free
(
data
->
filename
);
g_free
(
data
->
who
);
g_free
(
data
);
}
static
void
pidgin_dnd_file_send_image
(
PurpleAccount
*
account
,
const
gchar
*
who
,
const
gchar
*
filename
)
{
PurpleConnection
*
gc
=
purple_account_get_connection
(
account
);
PurpleProtocol
*
protocol
=
NULL
;
_DndData
*
data
=
g_new0
(
_DndData
,
1
);
gboolean
ft
=
FALSE
,
im
=
FALSE
;
data
->
who
=
g_strdup
(
who
);
data
->
filename
=
g_strdup
(
filename
);
data
->
account
=
account
;
if
(
gc
)
protocol
=
purple_connection_get_protocol
(
gc
);
if
(
!
(
purple_connection_get_flags
(
gc
)
&
PURPLE_CONNECTION_FLAG_NO_IMAGES
))
im
=
TRUE
;
if
(
protocol
&&
PURPLE_IS_PROTOCOL_XFER
(
protocol
))
{
PurpleProtocolXferInterface
*
iface
=
PURPLE_PROTOCOL_XFER_GET_IFACE
(
protocol
);
if
(
iface
->
can_receive
)
{
ft
=
purple_protocol_xfer_can_receive
(
PURPLE_PROTOCOL_XFER
(
protocol
),
gc
,
who
);
}
else
{
ft
=
(
iface
->
send_file
)
?
TRUE
:
FALSE
;
}
}
if
(
im
&&
ft
)
{
purple_request_choice
(
NULL
,
NULL
,
_
(
"You have dragged an image"
),
_
(
"You can send this image as a file "
"transfer, embed it into this message, "
"or use it as the buddy icon for this user."
),
(
gpointer
)
DND_FILE_TRANSFER
,
_
(
"OK"
),
(
GCallback
)
dnd_image_ok_callback
,
_
(
"Cancel"
),
(
GCallback
)
dnd_image_cancel_callback
,
purple_request_cpar_from_account
(
account
),
data
,
_
(
"Set as buddy icon"
),
DND_BUDDY_ICON
,
_
(
"Send image file"
),
DND_FILE_TRANSFER
,
_
(
"Insert in message"
),
DND_IM_IMAGE
,
NULL
);
}
else
if
(
!
(
im
||
ft
))
{
purple_request_yes_no
(
NULL
,
NULL
,
_
(
"You have dragged an image"
),
_
(
"Would you like to set it as the buddy icon for this user?"
),
PURPLE_DEFAULT_ACTION_NONE
,
purple_request_cpar_from_account
(
account
),
data
,
(
GCallback
)
dnd_set_icon_ok_cb
,
(
GCallback
)
dnd_set_icon_cancel_cb
);
}
else
{
purple_request_choice
(
NULL
,
NULL
,
_
(
"You have dragged an image"
),
(
ft
?
_
(
"You can send this image as a file transfer, or use it as the buddy icon for this user."
)
:
_
(
"You can insert this image into this message, or use it as the buddy icon for this user"
)),
GINT_TO_POINTER
(
ft
?
DND_FILE_TRANSFER
:
DND_IM_IMAGE
),
_
(
"OK"
),
(
GCallback
)
dnd_image_ok_callback
,
_
(
"Cancel"
),
(
GCallback
)
dnd_image_cancel_callback
,
purple_request_cpar_from_account
(
account
),
data
,
_
(
"Set as buddy icon"
),
DND_BUDDY_ICON
,
(
ft
?
_
(
"Send image file"
)
:
_
(
"Insert in message"
)),
(
ft
?
DND_FILE_TRANSFER
:
DND_IM_IMAGE
),
NULL
);
}
}
#ifndef _WIN32
static
void
pidgin_dnd_file_send_desktop
(
PurpleAccount
*
account
,
const
gchar
*
who
,
const
gchar
*
filename
)
{
gchar
*
name
;
gchar
*
type
;
gchar
*
url
;
GKeyFile
*
desktop_file
;
PurpleConversation
*
conv
;
PidginConversation
*
gtkconv
;
GError
*
error
=
NULL
;
desktop_file
=
g_key_file_new
();
if
(
!
g_key_file_load_from_file
(
desktop_file
,
filename
,
G_KEY_FILE_NONE
,
&
error
))
{
if
(
error
)
{
purple_debug_warning
(
"D&D"
,
"Failed to load %s: %s
\n
"
,
filename
,
error
->
message
);
g_error_free
(
error
);
}
return
;
}
name
=
g_key_file_get_string
(
desktop_file
,
G_KEY_FILE_DESKTOP_GROUP
,
G_KEY_FILE_DESKTOP_KEY_NAME
,
&
error
);
if
(
error
)
{
purple_debug_warning
(
"D&D"
,
"Failed to read the Name from a desktop file: %s
\n
"
,
error
->
message
);
g_error_free
(
error
);
}
type
=
g_key_file_get_string
(
desktop_file
,
G_KEY_FILE_DESKTOP_GROUP
,
G_KEY_FILE_DESKTOP_KEY_TYPE
,
&
error
);
if
(
error
)
{
purple_debug_warning
(
"D&D"
,
"Failed to read the Type from a desktop file: %s
\n
"
,
error
->
message
);
g_error_free
(
error
);
}
url
=
g_key_file_get_string
(
desktop_file
,
G_KEY_FILE_DESKTOP_GROUP
,
G_KEY_FILE_DESKTOP_KEY_URL
,
&
error
);
if
(
error
)
{
purple_debug_warning
(
"D&D"
,
"Failed to read the Type from a desktop file: %s
\n
"
,
error
->
message
);
g_error_free
(
error
);
}
/* If any of this is null, do nothing. */
if
(
!
name
||
!
type
||
!
url
)
{
g_free
(
type
);
g_free
(
name
);
g_free
(
url
);
return
;
}
/* I don't know if we really want to do anything here. Most of
* the desktop item types are crap like "MIME Type" (I have no
* clue how that would be a desktop item) and "Comment"...
* nothing we can really send. The only logical one is
* "Application," but do we really want to send a binary and
* nothing else? Probably not. I'll just give an error and
* return. */
/* The original patch sent the icon used by the launcher. That's probably wrong */
if
(
purple_strequal
(
type
,
"Link"
))
{
purple_notify_error
(
NULL
,
NULL
,
_
(
"Cannot send launcher"
),
_
(
"You dragged a desktop launcher. Most "
"likely you wanted to send the target "
"of this launcher instead of this "
"launcher itself."
),
NULL
);
}
else
{
GtkTextBuffer
*
buffer
=
NULL
;
GtkTextMark
*
mark
=
NULL
;
GtkTextIter
iter
;
conv
=
PURPLE_CONVERSATION
(
purple_im_conversation_new
(
account
,
who
));
gtkconv
=
PIDGIN_CONVERSATION
(
conv
);
buffer
=
talkatu_editor_get_buffer
(
TALKATU_EDITOR
(
gtkconv
->
editor
));
mark
=
gtk_text_buffer_get_insert
(
buffer
);
gtk_text_buffer_get_iter_at_mark
(
buffer
,
&
iter
,
mark
);
talkatu_buffer_insert_link
(
TALKATU_BUFFER
(
buffer
),
&
iter
,
name
,
url
);
}
g_free
(
type
);
g_free
(
name
);
g_free
(
url
);
}
#endif
/* _WIN32 */
void
pidgin_dnd_file_manage
(
GtkSelectionData
*
sd
,
PurpleAccount
*
account
,
const
char
*
who
)
{
GdkPixbuf
*
pb
;
GList
*
files
=
purple_uri_list_extract_filenames
((
const
gchar
*
)
gtk_selection_data_get_data
(
sd
));
PurpleConnection
*
gc
=
purple_account_get_connection
(
account
);
gchar
*
filename
=
NULL
;
gchar
*
basename
=
NULL
;
g_return_if_fail
(
account
!=
NULL
);
g_return_if_fail
(
who
!=
NULL
);
for
(
;
files
;
files
=
g_list_delete_link
(
files
,
files
))
{
g_free
(
filename
);
g_free
(
basename
);
filename
=
files
->
data
;
basename
=
g_path_get_basename
(
filename
);
/* XXX - Make ft API support creating a transfer with more than one file */
if
(
!
g_file_test
(
filename
,
G_FILE_TEST_EXISTS
))
{
continue
;
}
/* XXX - make ft api suupport sending a directory */
/* Are we dealing with a directory? */
if
(
g_file_test
(
filename
,
G_FILE_TEST_IS_DIR
))
{
char
*
str
,
*
str2
;
str
=
g_strdup_printf
(
_
(
"Cannot send folder %s."
),
basename
);
str2
=
g_strdup_printf
(
_
(
"%s cannot transfer a folder. You will need to send the files within individually."
),
PIDGIN_NAME
);
purple_notify_error
(
NULL
,
NULL
,
str
,
str2
,
purple_request_cpar_from_connection
(
gc
));
g_free
(
str
);
g_free
(
str2
);
continue
;
}
/* Are we dealing with an image? */
pb
=
pidgin_pixbuf_new_from_file
(
filename
);
if
(
pb
)
{
pidgin_dnd_file_send_image
(
account
,
who
,
filename
);
g_object_unref
(
G_OBJECT
(
pb
));
continue
;
}
#ifndef _WIN32
/* Are we trying to send a .desktop file? */
else
if
(
g_str_has_suffix
(
basename
,
".desktop"
))
{
pidgin_dnd_file_send_desktop
(
account
,
who
,
filename
);
continue
;
}
#endif
/* _WIN32 */
/* Everything is fine, let's send */
purple_serv_send_file
(
gc
,
who
,
filename
);
}
g_free
(
filename
);
g_free
(
basename
);
}