pidgin/purple-plugin-pack
Clone
Summary
Browse
Changes
Graph
Add the turtles target to keep the foot clan at bay
default
tip
13 months ago, Gary Kramlich
63ad7e4f10b4
Add the turtles target to keep the foot clan at bay
Testing Done:
Ran `ninja turtles` and verified it worked correctly.
Reviewed at https://reviews.imfreedom.org/r/2409/
/*
* enhanced_hist.c - Enhanced History Plugin for libpurple
* Copyright (C) 2004-2008 Andrew Pangborn <gaim@andrewpangborn.com>
* Copyright (C) 2007-2008 John Bailey <rekkanoryo@rekkanoryo.org>
* Copyright (C) 2007 Ankit Singla
*
* 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.
*/
/* SUMMARY: Puts log of past conversations in the user's IM window and
* allows the user to select the number of conversations to display from
* purple plugin preferences.
*
* Author:
* Andrew Pangborn - gaim@andrewpangborn.com
*
* Contributors:
* Ankit Singla
*/
/* If you can't figure out what this line is for, DON'T TOUCH IT. */
#include
"../common/pp_internal.h"
/* Purple headers */
#include
<conversation.h>
#include
<debug.h>
#include
<log.h>
#include
<plugin.h>
#include
<pluginpref.h>
#include
<prefs.h>
#include
<signals.h>
#include
<util.h>
/* Pidgin headers */
#include
<gtkconv.h>
#include
<gtkimhtml.h>
#include
<gtkplugin.h>
#include
<gtkprefs.h>
#include
<gtkutils.h>
#include
<pidgin.h>
/* libc headers */
#include
<time.h>
#define ENHANCED_HISTORY_ID "gtk-plugin_pack-enhanced_history"
#define PREF_ROOT_GPPATH "/plugins/gtk"
#define PREF_ROOT_PPATH "/plugins/gtk/plugin_pack"
#define PREF_ROOT_PATH "/plugins/gtk/plugin_pack/enhanced_history"
#define PREF_NUMBER_PATH "/plugins/gtk/plugin_pack/enhanced_history/number"
#define PREF_BYTES_PATH "/plugins/gtk/plugin_pack/enhanced_history/bytes"
#define PREF_MINS_PATH "/plugins/gtk/plugin_pack/enhanced_history/minutes"
#define PREF_HOURS_PATH "/plugins/gtk/plugin_pack/enhanced_history/hours"
#define PREF_DAYS_PATH "/plugins/gtk/plugin_pack/enhanced_history/days"
#define PREF_DATES_PATH "/plugins/gtk/plugin_pack/enhanced_history/dates"
#define PREF_IM_PATH "/plugins/gtk/plugin_pack/enhanced_history/im"
#define PREF_CHAT_PATH "/plugins/gtk/plugin_pack/enhanced_history/chat"
#define PREF_NUMBER_VAL purple_prefs_get_int(PREF_NUMBER_PATH)
#define PREF_BYTES_VAL purple_prefs_get_int(PREF_BYTES_PATH)
#define PREF_MINS_VAL purple_prefs_get_int(PREF_MINS_PATH)
#define PREF_HOURS_VAL purple_prefs_get_int(PREF_HOURS_PATH)
#define PREF_DAYS_VAL purple_prefs_get_int(PREF_DAYS_PATH)
#define PREF_DATES_VAL purple_prefs_get_bool(PREF_DATES_PATH)
#define PREF_IM_VAL purple_prefs_get_bool(PREF_IM_PATH)
#define PREF_CHAT_VAL purple_prefs_get_bool(PREF_CHAT_PATH)
static
gboolean
_scroll_imhtml_to_end
(
gpointer
data
)
{
GtkIMHtml
*
imhtml
=
data
;
gtk_imhtml_scroll_to_end
(
GTK_IMHTML
(
imhtml
),
FALSE
);
g_object_unref
(
G_OBJECT
(
imhtml
));
return
FALSE
;
}
static
void
historize
(
PurpleConversation
*
c
)
{
PurpleAccount
*
account
=
NULL
;
PurpleConversationType
convtype
;
PidginConversation
*
gtkconv
=
NULL
;
GtkTextIter
start
;
GtkIMHtmlOptions
options
;
GList
*
logs
=
NULL
,
*
logs_head
=
NULL
;
struct
tm
*
log_tm
=
NULL
,
*
local_tm
=
NULL
;
time_t
t
,
log_time
;
double
limit_time
=
0.0
;
const
char
*
name
=
NULL
,
*
alias
=
NULL
,
*
LOG_MODE
=
NULL
;
char
*
header
=
NULL
,
*
protocol
=
NULL
,
*
history
=
NULL
;
int
conv_counter
=
0
;
int
limit_offset
=
0
;
int
byte_counter
=
0
;
int
check_time
=
0
;
int
log_size
,
overshoot
;
account
=
purple_conversation_get_account
(
c
);
name
=
purple_conversation_get_name
(
c
);
alias
=
name
;
LOG_MODE
=
purple_prefs_get_string
(
"/purple/logging/format"
);
/* If logging isn't enabled, don't show any history */
if
(
!
purple_prefs_get_bool
(
"/purple/logging/log_ims"
)
&&
!
purple_prefs_get_bool
(
"/purple/logging/log_chats"
))
return
;
/* If the user wants to show 0 logs, stop now */
if
(
PREF_NUMBER_VAL
==
0
)
{
return
;
}
/* If the logging mode is html, set the output options to include no newline.
* Otherwise, it's normal text, so we don't need extra lines */
if
(
strcasecmp
(
LOG_MODE
,
"html"
)
==
0
)
{
options
=
GTK_IMHTML_NO_NEWLINE
;
}
else
{
options
=
GTK_IMHTML_NO_COLOURS
;
}
/* Determine whether this is an IM or a chat. In either case, if the user has that
* particular log type disabled, the logs file doesnt not get specified */
convtype
=
purple_conversation_get_type
(
c
);
if
(
convtype
==
PURPLE_CONV_TYPE_IM
&&
PREF_IM_VAL
)
{
GSList
*
cur
;
GSList
*
buddies
=
NULL
;
/* Find buddies for this conversation. */
buddies
=
purple_find_buddies
(
account
,
name
);
/* If we found at least one buddy, save the first buddy's alias. */
if
(
buddies
!=
NULL
)
alias
=
purple_buddy_get_contact_alias
((
PurpleBuddy
*
)
buddies
->
data
);
for
(
cur
=
buddies
;
cur
;
cur
=
cur
->
next
)
{
PurpleBlistNode
*
node
=
cur
->
data
;
if
(
node
&&
(
node
->
prev
||
node
->
next
))
{
PurpleBlistNode
*
node2
;
for
(
node2
=
node
->
parent
->
child
;
node2
;
node2
=
node2
->
next
)
{
logs
=
g_list_concat
(
purple_log_get_logs
(
PURPLE_LOG_IM
,
purple_buddy_get_name
((
PurpleBuddy
*
)
node2
),
purple_buddy_get_account
((
PurpleBuddy
*
)
node2
)),
logs
);
}
break
;
}
}
g_slist_free
(
buddies
);
if
(
logs
)
logs
=
g_list_sort
(
logs
,
purple_log_compare
);
else
logs
=
purple_log_get_logs
(
PURPLE_LOG_IM
,
name
,
account
);
}
else
if
(
convtype
==
PURPLE_CONV_TYPE_CHAT
&&
PREF_CHAT_VAL
)
{
logs
=
purple_log_get_logs
(
PURPLE_LOG_CHAT
,
purple_conversation_get_name
(
c
),
purple_conversation_get_account
(
c
));
}
gtkconv
=
PIDGIN_CONVERSATION
(
c
);
/* The logs are non-existant or the user has disabled this type for log displaying. */
if
(
!
logs
)
{
return
;
}
/* Keep a pointer to the head of the logs for freeing later */
logs_head
=
logs
;
/* If all time prefs are not 0, prepare to check times */
if
(
!
(
PREF_MINS_VAL
==
0
&&
PREF_HOURS_VAL
==
0
&&
PREF_DAYS_VAL
==
0
))
{
check_time
=
1
;
/* Grab current time and normalize it to UTC */
t
=
time
(
NULL
);
local_tm
=
gmtime
(
&
t
);
t
=
mktime
(
local_tm
);
limit_time
=
(
PREF_MINS_VAL
*
60.0
)
+
(
PREF_HOURS_VAL
*
60.0
*
60.0
)
+
(
PREF_DAYS_VAL
*
60.0
*
60.0
*
24.0
);
}
/* The protocol will need to be adjusted for each log for correct display,
so save the current imhtml protocol_name to restore it later */
protocol
=
g_strdup
(
gtk_imhtml_get_protocol_name
(
GTK_IMHTML
(
gtkconv
->
imhtml
)));
/* Calculate time for the first log */
log_tm
=
gmtime
(
&
((
PurpleLog
*
)
logs
->
data
)
->
time
);
log_time
=
mktime
(
log_tm
);
/* Continue to add older logs until they run out or the conditions are no
longer met */
while
(
logs
&&
conv_counter
<
PREF_NUMBER_VAL
&&
byte_counter
<
PREF_BYTES_VAL
&&
(
!
check_time
||
difftime
(
t
,
log_time
)
<
limit_time
))
{
guint
flags
;
/* Get the current log's contents as a char* */
history
=
purple_log_read
((
PurpleLog
*
)
logs
->
data
,
&
flags
);
log_size
=
strlen
(
history
);
if
(
flags
&
PURPLE_LOG_READ_NO_NEWLINE
)
options
|=
GTK_IMHTML_NO_NEWLINE
;
else
options
&=
~
GTK_IMHTML_NO_NEWLINE
;
/* Update the overall byte count and determine if this log exceeds the limit */
byte_counter
+=
log_size
;
overshoot
=
byte_counter
-
PREF_BYTES_VAL
;
if
(
overshoot
>
0
)
{
/* Start looking at the maximum log size for a newline to break at */
limit_offset
=
overshoot
;
/* Find the next \n, or stop if the end of the log is reached */
while
(
history
[
limit_offset
]
&&
history
[
limit_offset
]
!=
'\n'
)
{
limit_offset
++
;
}
/* If we're at or very close to the end of the log, forget this log */
if
(
!
history
[
limit_offset
]
||
(
log_size
-
limit_offset
<
3
))
{
limit_offset
=
-1
;
}
else
{
/* Start at the first character after the newline */
limit_offset
++
;
}
}
conv_counter
++
;
/* If this log won't fit at all, don't display it in the conversation */
if
(
limit_offset
!=
-1
)
{
/* Set the correct protocol_name for this log */
gtk_imhtml_set_protocol_name
(
GTK_IMHTML
(
gtkconv
->
imhtml
),
purple_account_get_protocol_name
(((
PurpleLog
*
)
logs
->
data
)
->
account
));
/* Prepend the contents of the log starting at the calculated offset */
gtk_text_buffer_get_iter_at_offset
(
GTK_IMHTML
(
gtkconv
->
imhtml
)
->
text_buffer
,
&
start
,
0
);
gtk_imhtml_insert_html_at_iter
(
GTK_IMHTML
(
gtkconv
->
imhtml
),
history
+
limit_offset
,
options
,
&
start
);
/* Prepend the conversation header */
if
(
PREF_DATES_VAL
)
{
header
=
g_strdup_printf
(
_
(
"<b>Conversation with %s on %s:</b><br>"
),
alias
,
purple_date_format_full
(
localtime
(
&
((
PurpleLog
*
)
logs
->
data
)
->
time
)));
gtk_text_buffer_get_iter_at_offset
(
GTK_IMHTML
(
gtkconv
->
imhtml
)
->
text_buffer
,
&
start
,
0
);
gtk_imhtml_insert_html_at_iter
(
GTK_IMHTML
(
gtkconv
->
imhtml
),
header
,
options
,
&
start
);
g_free
(
header
);
}
}
g_free
(
history
);
if
(
limit_offset
>
0
)
{
/* This log had to be chopped to fit, so stop after this one */
break
;
}
logs
=
logs
->
next
;
/* Recalculate log time if we haven't run out of logs */
if
(
logs
)
{
log_tm
=
gmtime
(
&
((
PurpleLog
*
)
logs
->
data
)
->
time
);
log_time
=
mktime
(
log_tm
);
}
}
gtk_imhtml_append_text
(
GTK_IMHTML
(
gtkconv
->
imhtml
),
"<hr>"
,
options
);
/* Restore the original protocol_name */
gtk_imhtml_set_protocol_name
(
GTK_IMHTML
(
gtkconv
->
imhtml
),
protocol
);
g_free
(
protocol
);
g_object_ref
(
G_OBJECT
(
gtkconv
->
imhtml
));
g_idle_add
(
_scroll_imhtml_to_end
,
gtkconv
->
imhtml
);
/* Clear the allocated memory that the logs are using */
g_list_foreach
(
logs_head
,
(
GFunc
)
purple_log_free
,
NULL
);
g_list_free
(
logs_head
);
}
static
gboolean
plugin_load
(
PurplePlugin
*
plugin
)
{
purple_signal_connect
(
purple_conversations_get_handle
(),
"conversation-created"
,
plugin
,
PURPLE_CALLBACK
(
historize
),
NULL
);
return
TRUE
;
}
static
GtkWidget
*
eh_prefs_get_frame
(
PurplePlugin
*
plugin
)
{
GtkSizeGroup
*
sg
=
NULL
;
GtkWidget
*
vbox
=
NULL
,
*
frame
=
NULL
;
sg
=
gtk_size_group_new
(
GTK_SIZE_GROUP_HORIZONTAL
);
vbox
=
gtk_vbox_new
(
TRUE
,
PIDGIN_HIG_BOX_SPACE
);
/* heading for the more general options */
frame
=
pidgin_make_frame
(
vbox
,
_
(
"Display Options"
));
/* the integer pref for the number of logs to display */
pidgin_prefs_labeled_spin_button
(
frame
,
_
(
"Maximum number of conversations:"
),
PREF_NUMBER_PATH
,
0
,
255
,
NULL
);
/* the integer pref for maximum number of bytes to read back */
pidgin_prefs_labeled_spin_button
(
frame
,
_
(
"Maximum number of bytes:"
),
PREF_BYTES_PATH
,
0
,
1024
*
1024
,
NULL
);
/* the boolean preferences */
pidgin_prefs_checkbox
(
_
(
"Show dates with text"
),
PREF_DATES_PATH
,
frame
);
pidgin_prefs_checkbox
(
_
(
"Show logs for IMs"
),
PREF_IM_PATH
,
frame
);
pidgin_prefs_checkbox
(
_
(
"Show logs for chats"
),
PREF_CHAT_PATH
,
frame
);
/* heading for the age limit options */
frame
=
pidgin_make_frame
(
vbox
,
_
(
"Age Limit for Logs (0 to disable):"
));
/* the integer preferences for time limiting */
pidgin_prefs_labeled_spin_button
(
frame
,
"Days:"
,
PREF_DAYS_PATH
,
0
,
255
,
sg
);
pidgin_prefs_labeled_spin_button
(
frame
,
"Hours:"
,
PREF_HOURS_PATH
,
0
,
255
,
sg
);
pidgin_prefs_labeled_spin_button
(
frame
,
"Minutes:"
,
PREF_MINS_PATH
,
0
,
255
,
sg
);
gtk_widget_show_all
(
vbox
);
return
vbox
;
}
static
PidginPluginUiInfo
ui_info
=
{
eh_prefs_get_frame
,
/* get prefs frame */
0
,
/* page number - reserved */
/* reserved pointers */
NULL
,
NULL
,
NULL
,
NULL
};
static
PurplePluginInfo
info
=
{
PURPLE_PLUGIN_MAGIC
,
PURPLE_MAJOR_VERSION
,
PURPLE_MINOR_VERSION
,
PURPLE_PLUGIN_STANDARD
,
PIDGIN_PLUGIN_TYPE
,
0
,
NULL
,
PURPLE_PRIORITY_DEFAULT
,
ENHANCED_HISTORY_ID
,
NULL
,
PP_VERSION
,
NULL
,
NULL
,
"Andrew Pangborn <gaim@andrewpangborn.com>"
,
PP_WEBSITE
,
plugin_load
,
NULL
,
NULL
,
&
ui_info
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
};
static
void
init_plugin
(
PurplePlugin
*
plugin
)
{
gboolean
dates
=
FALSE
,
ims
=
FALSE
,
chats
=
FALSE
;
purple_prefs_add_none
(
PREF_ROOT_GPPATH
);
purple_prefs_add_none
(
PREF_ROOT_PPATH
);
purple_prefs_add_none
(
PREF_ROOT_PATH
);
if
(
purple_prefs_exists
(
"/plugins/core/enhanced_history/int"
))
{
if
(
strcmp
(
purple_prefs_get_string
(
"/plugins/core/enhanced_history/string_date"
),
"no"
))
dates
=
TRUE
;
if
(
strcmp
(
purple_prefs_get_string
(
"/plugins/core/enhanced_history/string_im"
),
"no"
))
ims
=
TRUE
;
if
(
strcmp
(
purple_prefs_get_string
(
"/plugins/core/enhanced_history/string_chat"
),
"no"
))
chats
=
TRUE
;
purple_prefs_add_int
(
PREF_NUMBER_PATH
,
purple_prefs_get_int
(
"/plugins/core/enhanced_history/int"
));
purple_prefs_add_int
(
PREF_BYTES_PATH
,
purple_prefs_get_int
(
"/plugins/core/enhanced_history/bytes"
));
purple_prefs_add_int
(
PREF_MINS_PATH
,
purple_prefs_get_int
(
"/plugins/core/enhanced_history/mins"
));
purple_prefs_add_int
(
PREF_HOURS_PATH
,
purple_prefs_get_int
(
"/plugins/core/enhanced_history/hours"
));
purple_prefs_add_int
(
PREF_DAYS_PATH
,
purple_prefs_get_int
(
"/plugins/core/enhanced_history/days"
));
purple_prefs_add_bool
(
PREF_DATES_PATH
,
dates
);
purple_prefs_add_bool
(
PREF_IM_PATH
,
ims
);
purple_prefs_add_bool
(
PREF_CHAT_PATH
,
chats
);
purple_prefs_remove
(
"/plugins/core/enhanced_history/int"
);
purple_prefs_remove
(
"/plugins/core/enhanced_history/bytes"
);
purple_prefs_remove
(
"/plugins/core/enhanced_history/mins"
);
purple_prefs_remove
(
"/plugins/core/enhanced_history/hours"
);
purple_prefs_remove
(
"/plugins/core/enhanced_history/days"
);
purple_prefs_remove
(
"/plugins/core/enhanced_history/string_date"
);
purple_prefs_remove
(
"/plugins/core/enhanced_history/string_im"
);
purple_prefs_remove
(
"/plugins/core/enhanced_history/string_chat"
);
purple_prefs_remove
(
"/plugins/core/enhanced_history"
);
}
else
{
/* Create these prefs with sensible defaults */
purple_prefs_add_int
(
PREF_NUMBER_PATH
,
10
);
purple_prefs_add_int
(
PREF_BYTES_PATH
,
4096
);
purple_prefs_add_int
(
PREF_MINS_PATH
,
0
);
purple_prefs_add_int
(
PREF_HOURS_PATH
,
0
);
purple_prefs_add_int
(
PREF_DAYS_PATH
,
0
);
purple_prefs_add_bool
(
PREF_DATES_PATH
,
TRUE
);
purple_prefs_add_bool
(
PREF_IM_PATH
,
TRUE
);
purple_prefs_add_bool
(
PREF_CHAT_PATH
,
FALSE
);
}
info
.
name
=
_
(
"Enhanced History"
);
info
.
summary
=
_
(
"An enhanced version of the history plugin."
);
info
.
description
=
_
(
"An enhanced versoin of the history plugin. Grants ability to "
"select the number of previous conversations to show instead of just one."
);
}
PURPLE_INIT_PLUGIN
(
enhanced_history
,
init_plugin
,
info
)