pidgin/purple-plugin-pack
Clone
Summary
Browse
Changes
Graph
closing old branch
<missing>
2017-04-08, Gary Kramlich
ae275077b5fd
closing old branch
/*************************************************************************
* Buddy Timezone Module
*
* A Purple plugin that allows you to configure a timezone on a per-contact
* basis so it can display the localtime of your contact when a conversation
* starts. Convenient if you deal with contacts from many parts of the
* world.
*
* by Martijn van Oosterhout <kleptog@svana.org> (C) April 2006
* Some code copyright (C) 2006, Richard Laager <rlaager@users.sf.net>
*
* 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., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*************************************************************************/
#define PURPLE_PLUGINS
#ifdef CUSTOM_GTK
#define PLUGIN "gtk-kleptog-buddytimezone"
#else
#define PLUGIN "core-kleptog-buddytimezone"
#endif
#define SETTING_NAME "timezone"
#define CONTROL_NAME PLUGIN "-" SETTING_NAME
#include
<glib.h>
#include
<errno.h>
#include
<ctype.h>
#include
<string.h>
#include
<math.h>
#include
"notify.h"
#include
"plugin.h"
#include
"version.h"
#include
"debug.h"
/* Debug output functions */
#include
"util.h"
/* Menu functions */
#include
"request.h"
/* Requests stuff */
#include
"conversation.h"
/* Conversation stuff */
#include
"localtime.h"
#include
"recurse.h"
#include
"gtkblist.h"
#define TIMEZONE_FLAG ((void*)1)
#define DISABLED_FLAG ((void*)2)
#define TIME_FORMAT "%X"
/* Another possible format (hides seconds) */
//#define TIME_FORMAT "%H:%M"
static
PurplePlugin
*
plugin_self
;
void
*
make_timezone_menu
(
const
char
*
selected
);
const
char
*
get_timezone_menu_selection
(
void
*
widget
);
/* Resolve specifies what the return value should mean:
*
* If TRUE, it's for display, we want to know the *effect* thus hiding the
* "none" value and going to going level to find the default
*
* If false, we only want what the user enter, thus the string "none" if
* that's what it is
*/
static
const
char
*
buddy_get_timezone
(
PurpleBlistNode
*
node
,
gboolean
resolve
)
{
PurpleBlistNode
*
datanode
=
NULL
;
const
char
*
timezone
;
switch
(
node
->
type
)
{
case
PURPLE_BLIST_BUDDY_NODE
:
datanode
=
(
PurpleBlistNode
*
)
purple_buddy_get_contact
((
PurpleBuddy
*
)
node
);
break
;
case
PURPLE_BLIST_CONTACT_NODE
:
datanode
=
node
;
break
;
case
PURPLE_BLIST_GROUP_NODE
:
datanode
=
node
;
break
;
default
:
return
NULL
;
}
timezone
=
purple_blist_node_get_string
(
datanode
,
SETTING_NAME
);
if
(
!
resolve
)
return
timezone
;
/* The effect of "none" is to stop recursion */
if
(
timezone
&&
strcmp
(
timezone
,
"none"
)
==
0
)
return
NULL
;
if
(
timezone
)
return
timezone
;
if
(
datanode
->
type
==
PURPLE_BLIST_CONTACT_NODE
)
{
/* There is no purple_blist_contact_get_group(), though there probably should be */
datanode
=
datanode
->
parent
;
timezone
=
purple_blist_node_get_string
(
datanode
,
SETTING_NAME
);
}
if
(
timezone
&&
strcmp
(
timezone
,
"none"
)
==
0
)
return
NULL
;
return
timezone
;
}
/* Calcuates the difference between two struct tm's. */
static
float
timezone_calc_difference
(
struct
tm
*
remote_tm
,
struct
tm
*
local_tm
)
{
int
datediff
=
0
,
diff
;
/* Tries to calculate the difference. Note this only works because the
* times are with 24 hours of eachother! */
if
(
remote_tm
->
tm_mday
!=
local_tm
->
tm_mday
)
{
datediff
=
remote_tm
->
tm_year
-
local_tm
->
tm_year
;
if
(
datediff
==
0
)
datediff
=
remote_tm
->
tm_mon
-
local_tm
->
tm_mon
;
if
(
datediff
==
0
)
datediff
=
remote_tm
->
tm_mday
-
local_tm
->
tm_mday
;
}
diff
=
datediff
*
24
*
60
+
(
remote_tm
->
tm_hour
-
local_tm
->
tm_hour
)
*
60
+
(
remote_tm
->
tm_min
-
local_tm
->
tm_min
);
return
(
float
)
diff
/
60.0
;
}
#ifdef PRIVATE_TZLIB
static
int
timezone_get_time
(
const
char
*
timezone
,
struct
tm
*
tm
,
float
*
diff
)
{
struct
state
*
tzinfo
=
timezone_load
(
timezone
);
struct
tm
*
local_tm
;
time_t
now
;
if
(
!
tzinfo
)
return
-1
;
time
(
&
now
);
localsub
(
&
now
,
0
,
tm
,
tzinfo
);
free
(
tzinfo
);
/* Calculate user's localtime, and compare. If same, no output */
local_tm
=
localtime
(
&
now
);
if
(
local_tm
->
tm_hour
==
tm
->
tm_hour
&&
local_tm
->
tm_min
==
tm
->
tm_min
)
return
1
;
*
diff
=
timezone_calc_difference
(
tm
,
local_tm
);
return
0
;
}
#else
static
int
timezone_get_time
(
const
char
*
timezone
,
struct
tm
*
tm
,
float
*
diff
)
{
time_t
now
;
struct
tm
*
tm_tmp
;
const
gchar
*
old_tz
;
/* Store the current TZ value. */
old_tz
=
g_getenv
(
"TZ"
);
g_setenv
(
"TZ"
,
timezone
,
TRUE
);
time
(
&
now
);
tm_tmp
=
localtime
(
&
now
);
*
tm
=
*
tm_tmp
;
/* Must copy, localtime uses local buffer */
/* Reset the old TZ value. */
if
(
old_tz
==
NULL
)
g_unsetenv
(
"TZ"
);
else
g_setenv
(
"TZ"
,
old_tz
,
TRUE
);
/* Calculate user's localtime, and compare. If same, no output */
tm_tmp
=
localtime
(
&
now
);
if
(
tm_tmp
->
tm_hour
==
tm
->
tm_hour
&&
tm_tmp
->
tm_min
==
tm
->
tm_min
)
return
1
;
*
diff
=
timezone_calc_difference
(
tm
,
tm_tmp
);
return
0
;
}
#endif
static
void
timezone_createconv_cb
(
PurpleConversation
*
conv
,
void
*
data
)
{
const
char
*
name
;
PurpleBuddy
*
buddy
;
struct
tm
tm
;
const
char
*
timezone
;
float
diff
;
int
ret
;
if
(
purple_conversation_get_type
(
conv
)
!=
PURPLE_CONV_TYPE_IM
)
return
;
name
=
purple_conversation_get_name
(
conv
);
buddy
=
purple_find_buddy
(
purple_conversation_get_account
(
conv
),
name
);
if
(
!
buddy
)
return
;
timezone
=
buddy_get_timezone
((
PurpleBlistNode
*
)
buddy
,
TRUE
);
if
(
!
timezone
)
return
;
ret
=
timezone_get_time
(
timezone
,
&
tm
,
&
diff
);
if
(
ret
==
0
)
{
const
char
*
text
=
purple_time_format
(
&
tm
);
char
*
str
=
g_strdup_printf
(
"Remote Local Time: %s (%g hours %s)"
,
text
,
fabs
(
diff
),
(
diff
<
0
)
?
"behind"
:
"ahead"
);
purple_conversation_write
(
conv
,
PLUGIN
,
str
,
PURPLE_MESSAGE_SYSTEM
,
time
(
NULL
));
g_free
(
str
);
}
}
static
void
buddytimezone_tooltip_cb
(
PurpleBlistNode
*
node
,
char
**
text
,
gboolean
full
,
void
*
data
)
{
char
*
newtext
;
const
char
*
timezone
;
struct
tm
tm
;
float
diff
;
int
ret
;
if
(
!
full
)
return
;
purple_debug
(
PURPLE_DEBUG_INFO
,
PLUGIN
,
"type %d
\n
"
,
node
->
type
);
timezone
=
buddy_get_timezone
(
node
,
TRUE
);
if
(
!
timezone
)
return
;
ret
=
timezone_get_time
(
timezone
,
&
tm
,
&
diff
);
if
(
ret
<
0
)
newtext
=
g_strdup_printf
(
"%s
\n
<b>Timezone:</b> %s (error)"
,
*
text
,
timezone
);
else
if
(
ret
==
0
)
{
const
char
*
timetext
=
purple_time_format
(
&
tm
);
newtext
=
g_strdup_printf
(
"%s
\n
<b>Local Time:</b> %s (%g hours %s)"
,
*
text
,
timetext
,
fabs
(
diff
),
(
diff
<
0
)
?
"behind"
:
"ahead"
);
}
else
return
;
g_free
(
*
text
);
*
text
=
newtext
;
}
static
void
buddytimezone_submitfields_cb
(
PurpleRequestFields
*
fields
,
PurpleBlistNode
*
data
)
{
PurpleBlistNode
*
node
;
PurpleRequestField
*
list
;
/* timezone stuff */
purple_debug
(
PURPLE_DEBUG_INFO
,
PLUGIN
,
"buddytimezone_submitfields_cb(%p,%p)
\n
"
,
fields
,
data
);
switch
(
data
->
type
)
{
case
PURPLE_BLIST_BUDDY_NODE
:
node
=
(
PurpleBlistNode
*
)
purple_buddy_get_contact
((
PurpleBuddy
*
)
data
);
break
;
case
PURPLE_BLIST_CONTACT_NODE
:
case
PURPLE_BLIST_GROUP_NODE
:
/* code handles either case */
node
=
data
;
break
;
case
PURPLE_BLIST_CHAT_NODE
:
case
PURPLE_BLIST_OTHER_NODE
:
default
:
/* Not applicable */
return
;
}
list
=
purple_request_fields_get_field
(
fields
,
CONTROL_NAME
);
#ifdef CUSTOM_GTK
const
char
*
seldata
=
get_timezone_menu_selection
(
list
->
ui_data
);
if
(
seldata
==
NULL
)
purple_blist_node_remove_setting
(
node
,
SETTING_NAME
);
else
purple_blist_node_set_string
(
node
,
SETTING_NAME
,
seldata
);
#else
const
GList
*
sellist
;
void
*
seldata
=
NULL
;
sellist
=
purple_request_field_list_get_selected
(
list
);
if
(
sellist
)
seldata
=
purple_request_field_list_get_data
(
list
,
sellist
->
data
);
/* Otherwise, it's fixed value and this means deletion */
if
(
seldata
==
TIMEZONE_FLAG
)
purple_blist_node_set_string
(
node
,
SETTING_NAME
,
sellist
->
data
);
else
if
(
seldata
==
DISABLED_FLAG
)
purple_blist_node_set_string
(
node
,
SETTING_NAME
,
"none"
);
else
purple_blist_node_remove_setting
(
node
,
SETTING_NAME
);
#endif
}
#ifndef CUSTOM_GTK
static
int
buddy_add_timezone_cb
(
char
*
filename
,
void
*
data
)
{
PurpleRequestField
*
field
=
(
PurpleRequestField
*
)
data
;
if
(
isupper
(
filename
[
0
]))
purple_request_field_list_add
(
field
,
filename
,
TIMEZONE_FLAG
);
return
0
;
}
#endif
static
void
buddytimezone_createfields_cb
(
PurpleRequestFields
*
fields
,
PurpleBlistNode
*
data
)
{
purple_debug
(
PURPLE_DEBUG_INFO
,
PLUGIN
,
"buddytimezone_createfields_cb(%p,%p)
\n
"
,
fields
,
data
);
PurpleRequestField
*
field
;
PurpleRequestFieldGroup
*
group
;
const
char
*
timezone
;
gboolean
is_default
;
switch
(
data
->
type
)
{
case
PURPLE_BLIST_BUDDY_NODE
:
case
PURPLE_BLIST_CONTACT_NODE
:
is_default
=
FALSE
;
break
;
case
PURPLE_BLIST_GROUP_NODE
:
is_default
=
TRUE
;
break
;
case
PURPLE_BLIST_CHAT_NODE
:
case
PURPLE_BLIST_OTHER_NODE
:
default
:
/* Not applicable */
return
;
}
group
=
purple_request_field_group_new
(
NULL
);
purple_request_fields_add_group
(
fields
,
group
);
timezone
=
buddy_get_timezone
(
data
,
FALSE
);
#ifdef CUSTOM_GTK
field
=
purple_request_field_new
(
CONTROL_NAME
,
is_default
?
"Default timezone for group"
:
"Timezone of contact"
,
PURPLE_REQUEST_FIELD_LIST
);
field
->
ui_data
=
make_timezone_menu
(
timezone
);
#else
field
=
purple_request_field_list_new
(
CONTROL_NAME
,
is_default
?
"Default timezone for group"
:
"Timezone of contact (type to select)"
);
purple_request_field_list_set_multi_select
(
field
,
FALSE
);
purple_request_field_list_add
(
field
,
"<Default>"
,
""
);
purple_request_field_list_add
(
field
,
"<Disabled>"
,
DISABLED_FLAG
);
recurse_directory
(
"/usr/share/zoneinfo/"
,
buddy_add_timezone_cb
,
field
);
if
(
timezone
)
{
if
(
strcmp
(
timezone
,
"none"
)
==
0
)
purple_request_field_list_add_selected
(
field
,
"<Disabled>"
);
else
purple_request_field_list_add_selected
(
field
,
timezone
);
}
else
purple_request_field_list_add_selected
(
field
,
"<Default>"
);
#endif
purple_request_field_group_add_field
(
group
,
field
);
}
static
gboolean
plugin_load
(
PurplePlugin
*
plugin
)
{
plugin_self
=
plugin
;
purple_signal_connect
(
purple_blist_get_handle
(),
"core-kleptog-buddyedit-create-fields"
,
plugin
,
PURPLE_CALLBACK
(
buddytimezone_createfields_cb
),
NULL
);
purple_signal_connect
(
purple_blist_get_handle
(),
"core-kleptog-buddyedit-submit-fields"
,
plugin
,
PURPLE_CALLBACK
(
buddytimezone_submitfields_cb
),
NULL
);
purple_signal_connect
(
pidgin_blist_get_handle
(),
"drawing-tooltip"
,
plugin
,
PURPLE_CALLBACK
(
buddytimezone_tooltip_cb
),
NULL
);
purple_signal_connect
(
purple_conversations_get_handle
(),
"conversation-created"
,
plugin
,
PURPLE_CALLBACK
(
timezone_createconv_cb
),
NULL
);
#ifdef PRIVATE_TZLIB
const
char
*
zoneinfo_dir
=
purple_prefs_get_string
(
"/plugins/timezone/zoneinfo_dir"
);
if
(
tz_init
(
zoneinfo_dir
)
<
0
)
purple_debug_error
(
PLUGIN
,
"Problem opening zoneinfo dir (%s): %s
\n
"
,
zoneinfo_dir
,
strerror
(
errno
));
#endif
return
TRUE
;
}
static
PurplePluginInfo
info
=
{
PURPLE_PLUGIN_MAGIC
,
PURPLE_MAJOR_VERSION
,
0
,
PURPLE_PLUGIN_STANDARD
,
NULL
,
0
,
NULL
,
PURPLE_PRIORITY_DEFAULT
,
PLUGIN
,
"Buddy Timezone Module"
,
G_STRINGIFY
(
PLUGIN_VERSION
),
"Quickly see the local time of a buddy"
,
"A Purple plugin that allows you to configure a timezone on a per-contact "
"basis so it can display the localtime of your contact when a conversation "
"starts. Convenient if you deal with contacts from many parts of the "
"world."
,
"Martijn van Oosterhout <kleptog@svana.org>"
,
"http://buddytools.sf.net"
,
plugin_load
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
};
static
void
init_plugin
(
PurplePlugin
*
plugin
)
{
info
.
dependencies
=
g_list_append
(
info
.
dependencies
,
"core-kleptog-buddyedit"
);
}
PURPLE_INIT_PLUGIN
(
buddytimezone
,
init_plugin
,
info
);