pidgin/purple-plugin-pack

42c40c1eadf2
Parents 54bc97cc78bc
Children 9139b9e7fa53
Add the timelog plugin, which is Jon Oberheide's gaim-timelog plugin ported
to Pidgin
--- a/configure.ac Sat Oct 20 17:44:22 2007 -0400
+++ b/configure.ac Sun Oct 21 19:20:31 2007 -0400
@@ -342,6 +342,7 @@
stocker/Makefile
switchspell/Makefile
talkfilters/Makefile
+ timelog/Makefile
xchat-chats/Makefile
xmmsremote/Makefile
xmmsremote/pixmaps/Makefile
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/timelog/Makefile.am Sun Oct 21 19:20:31 2007 -0400
@@ -0,0 +1,31 @@
+EXTRA_DIST = .pidgin-plugin .build
+
+timelogdir = $(PIDGIN_LIBDIR)
+
+timelog_la_LDFLAGS = -module -avoid-version
+
+if HAVE_PIDGIN
+
+timelog_LTLIBRARIES = timelog.la
+
+timelog_la_SOURCES = \
+ log-widget.c \
+ log-widget.h \
+ range-widget.c \
+ range-widget.h \
+ timelog.c \
+ timelog.h
+
+timelog_la_LIBADD = \
+ $(PIDGIN_LIBS) \
+ $(GTK_LIBS)
+
+endif
+
+AM_CPPFLAGS = \
+ -DLIBDIR=\"$(PIDGIN_LIBDIR)\" \
+ -DDATADIR=\"$(PIDGIN_DATADIR)\" \
+ -DPIXMAPSDIR=\"$(PIDGIN_PIXMAPSDIR)\" \
+ $(GTK_CFLAGS) \
+ $(DEBUG_CFLAGS) \
+ $(PIDGIN_CFLAGS)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/timelog/Makefile.mingw Sun Oct 21 19:20:31 2007 -0400
@@ -0,0 +1,21 @@
+#
+# Makefile.mingw
+#
+# Description: Makefile for timelog plugin.
+#
+
+PP_TOP := ..
+
+PP = timelog
+
+
+PP_SRC := \
+ log-widget.c \
+ log-widget.h \
+ range-widget.c \
+ range-widget.h \
+ timelog.c \
+ timelog.h
+
+include $(PP_TOP)/win_pp.mak
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/timelog/log-widget.c Sun Oct 21 19:20:31 2007 -0400
@@ -0,0 +1,379 @@
+/*
+ * TimeLog plugin.
+ *
+ * Copyright (c) 2006 Jon Oberheide.
+ *
+ * Based on code from Gaim's gtklog.c
+ *
+ * $Id: log-widget.c,v 1.30 2005/12/24 05:14:55 binaryjono Exp $
+ *
+ * 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.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <glib.h>
+#include <gtk/gtk.h>
+
+#include <pidgin.h>
+#include <account.h>
+#include <gtkblist.h>
+#include <gtkutils.h>
+#include <gtkimhtml.h>
+#include <gtklog.h>
+#include <log.h>
+#include <notify.h>
+#include <util.h>
+
+#include "timelog.h"
+#include "log-widget.h"
+
+static PidginLogViewer *syslog_viewer = NULL;
+
+static gint
+log_compare(gconstpointer y, gconstpointer z)
+{
+ const PurpleLog *a = y;
+ const PurpleLog *b = z;
+
+ return strcmp(a->name, b->name);
+}
+
+static void
+populate_log_tree(PidginLogViewer *lv)
+{
+ char name[64];
+ char title[64];
+ char prev_top_name[64] = "";
+ char *utf8_tmp; /* temporary variable for utf8 conversion */
+ GtkTreeIter toplevel, child;
+ GList *logs = lv->logs;
+
+ while (logs != NULL) {
+ PurpleLog *log = logs->data;
+
+ strncpy(name, log->name, sizeof(name));
+ strftime(title, sizeof(title), "%c", localtime(&log->time));
+
+ /* do utf8 conversions */
+ utf8_tmp = purple_utf8_try_convert(name);
+ strncpy(name, utf8_tmp, sizeof(name));
+ g_free(utf8_tmp);
+ utf8_tmp = purple_utf8_try_convert(title);
+ strncpy(title, utf8_tmp, sizeof(title));
+ g_free(utf8_tmp);
+
+ if (strncmp(name, prev_top_name, sizeof(name)) != 0) {
+ /* top level */
+ gtk_tree_store_append(lv->treestore, &toplevel, NULL);
+ gtk_tree_store_set(lv->treestore, &toplevel, 0, name, 1, NULL, -1);
+
+ strncpy(prev_top_name, name, sizeof(prev_top_name));
+ }
+
+ /* sub */
+ gtk_tree_store_append(lv->treestore, &child, &toplevel);
+ gtk_tree_store_set(lv->treestore, &child, 0, title, 1, log, -1);
+
+ logs = logs->next;
+ }
+}
+
+static void
+search_cb(GtkWidget *button, PidginLogViewer *lv)
+{
+ const char *search_term = gtk_entry_get_text(GTK_ENTRY(lv->entry));
+ GList *logs;
+ GdkCursor *cursor;
+
+ if (lv->search != NULL)
+ g_free(lv->search);
+
+ gtk_tree_store_clear(lv->treestore);
+ if (!(*search_term)) {
+ /* reset the tree */
+ populate_log_tree(lv);
+ lv->search = NULL;
+ gtk_imhtml_search_clear(GTK_IMHTML(lv->imhtml));
+ return;
+ }
+
+ lv->search = g_strdup(search_term);
+
+ cursor = gdk_cursor_new(GDK_WATCH);
+ gdk_window_set_cursor(lv->window->window, cursor);
+ gdk_cursor_unref(cursor);
+ while (gtk_events_pending())
+ gtk_main_iteration();
+
+ for (logs = lv->logs; logs != NULL; logs = logs->next) {
+ char *read = purple_log_read((PurpleLog*)logs->data, NULL);
+ if (read && *read && purple_strcasestr(read, search_term)) {
+ GtkTreeIter iter;
+ PurpleLog *log = logs->data;
+ char title[64];
+ char *title_utf8; /* temporary variable for utf8 conversion */
+
+ strftime(title, sizeof(title), "%c", localtime(&log->time));
+ title_utf8 = purple_utf8_try_convert(title);
+ strncpy(title, title_utf8, sizeof(title));
+ g_free(title_utf8);
+
+ gtk_tree_store_append (lv->treestore, &iter, NULL);
+ gtk_tree_store_set(lv->treestore, &iter,
+ 0, title,
+ 1, log, -1);
+ }
+ g_free(read);
+ }
+
+ gdk_window_set_cursor(lv->window->window, NULL);
+}
+
+static gboolean
+destroy_cb(GtkWidget *w, gint resp, gpointer data)
+{
+ PidginLogViewer *lv = syslog_viewer;
+ syslog_viewer = NULL;
+
+ while (lv->logs != NULL) {
+ GList *logs2;
+
+ purple_log_free((PurpleLog *)lv->logs->data);
+
+ logs2 = lv->logs->next;
+ g_list_free_1(lv->logs);
+ lv->logs = logs2;
+ }
+
+ if (lv->search != NULL)
+ g_free(lv->search);
+
+ g_free(lv);
+ gtk_widget_destroy(w);
+
+ return TRUE;
+}
+
+static void
+log_row_activated_cb(GtkTreeView *tv, GtkTreePath *path, GtkTreeViewColumn *col, PidginLogViewer *viewer)
+{
+ if (gtk_tree_view_row_expanded(tv, path)) {
+ gtk_tree_view_collapse_row(tv, path);
+ } else {
+ gtk_tree_view_expand_row(tv, path, FALSE);
+ }
+}
+
+static void
+log_select_cb(GtkTreeSelection *sel, PidginLogViewer *viewer)
+{
+ GtkTreeIter iter;
+ GValue val;
+ GtkTreeModel *model = GTK_TREE_MODEL(viewer->treestore);
+ PurpleLog *log = NULL;
+ GdkCursor *cursor;
+ PurpleLogReadFlags flags;
+ char *read = NULL;
+ char time[64];
+
+ if (!gtk_tree_selection_get_selected(sel, &model, &iter)) {
+ return;
+ }
+
+ val.g_type = 0;
+ gtk_tree_model_get_value (model, &iter, 1, &val);
+ log = g_value_get_pointer(&val);
+ g_value_unset(&val);
+
+ if (log == NULL) {
+ return;
+ }
+
+ /* When we set the initial log, this gets called and the window is still NULL. */
+ if (viewer->window->window != NULL) {
+ cursor = gdk_cursor_new(GDK_WATCH);
+ gdk_window_set_cursor(viewer->window->window, cursor);
+ gdk_cursor_unref(cursor);
+ while (gtk_events_pending())
+ gtk_main_iteration();
+ }
+
+ if (log->type != PURPLE_LOG_SYSTEM) {
+ char *title;
+ char *title_utf8; /* temporary variable for utf8 conversion */
+
+ strftime(time, sizeof(time), "%c", localtime(&log->time));
+
+ if (log->type == PURPLE_LOG_CHAT)
+ title = g_strdup_printf("Conversation in %s on %s", log->name, time);
+ else
+ title = g_strdup_printf("Conversation with %s on %s", log->name, time);
+
+ title_utf8 = purple_utf8_try_convert(title);
+ g_free(title);
+
+ title = g_strdup_printf("<span size='larger' weight='bold'>%s</span>", title_utf8);
+ g_free(title_utf8);
+
+ gtk_label_set_markup(GTK_LABEL(viewer->label), title);
+ g_free(title);
+ }
+
+ read = purple_log_read(log, &flags);
+ viewer->flags = flags;
+
+ gtk_imhtml_clear(GTK_IMHTML(viewer->imhtml));
+ gtk_imhtml_set_protocol_name(GTK_IMHTML(viewer->imhtml),
+ purple_account_get_protocol_name(log->account));
+ gtk_imhtml_append_text(GTK_IMHTML(viewer->imhtml), read,
+ GTK_IMHTML_NO_COMMENTS | GTK_IMHTML_NO_TITLE | GTK_IMHTML_NO_SCROLL |
+ ((flags & PURPLE_LOG_READ_NO_NEWLINE) ? GTK_IMHTML_NO_NEWLINE : 0));
+ g_free(read);
+
+ if (viewer->search != NULL) {
+ gtk_imhtml_search_clear(GTK_IMHTML(viewer->imhtml));
+ gtk_imhtml_search_find(GTK_IMHTML(viewer->imhtml), viewer->search);
+ }
+
+ /* When we set the initial log, this gets called and the window is still NULL. */
+ if (viewer->window->window != NULL)
+ gdk_window_set_cursor(viewer->window->window, NULL);
+}
+
+void
+log_widget_display_logs(GList *logs)
+{
+ PidginLogViewer *lv;
+ GtkWidget *title_box;
+ char *text;
+ GtkWidget *pane;
+ GtkWidget *sw;
+ GtkCellRenderer *rend;
+ GtkTreeViewColumn *col;
+ GtkTreeSelection *sel;
+#if GTK_CHECK_VERSION(2,2,0)
+ GtkTreePath *path_to_first_log;
+#endif
+ GtkWidget *vbox;
+ GtkWidget *frame;
+ GtkWidget *hbox;
+ GtkWidget *button;
+
+ if (syslog_viewer != NULL) {
+ gtk_window_present(GTK_WINDOW(syslog_viewer->window));
+ return;
+ }
+
+ lv = g_new0(PidginLogViewer, 1);
+ lv->logs = logs;
+
+ if (logs == NULL) {
+ /* No logs were found. */
+ purple_notify_info(NULL, TIMELOG_TITLE, "No logs were found", NULL);
+ return;
+ }
+
+ lv->logs = g_list_sort(lv->logs, log_compare);
+
+ /* Window ***********/
+ lv->window = gtk_dialog_new_with_buttons(TIMELOG_TITLE, NULL, 0,
+ GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE, NULL);
+ gtk_container_set_border_width (GTK_CONTAINER(lv->window), PIDGIN_HIG_BOX_SPACE);
+ gtk_dialog_set_has_separator(GTK_DIALOG(lv->window), FALSE);
+ gtk_box_set_spacing(GTK_BOX(GTK_DIALOG(lv->window)->vbox), 0);
+ g_signal_connect(G_OBJECT(lv->window), "response", G_CALLBACK(destroy_cb), NULL);
+ gtk_window_set_role(GTK_WINDOW(lv->window), "log_viewer");
+
+ title_box = GTK_DIALOG(lv->window)->vbox;
+
+ /* Label ************/
+ lv->label = gtk_label_new(NULL);
+
+ text = g_strdup_printf("<span size='larger' weight='bold'>%s</span>", TIMELOG_TITLE);
+
+ gtk_label_set_markup(GTK_LABEL(lv->label), text);
+ gtk_misc_set_alignment(GTK_MISC(lv->label), 0, 0);
+ gtk_box_pack_start(GTK_BOX(title_box), lv->label, FALSE, FALSE, 0);
+ g_free(text);
+
+ /* Pane *************/
+ pane = gtk_hpaned_new();
+ gtk_container_set_border_width(GTK_CONTAINER(pane), PIDGIN_HIG_BOX_SPACE);
+ gtk_box_pack_start(GTK_BOX(GTK_DIALOG(lv->window)->vbox), pane, TRUE, TRUE, 0);
+
+ /* List *************/
+ sw = gtk_scrolled_window_new (NULL, NULL);
+ gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw), GTK_SHADOW_IN);
+ gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), GTK_POLICY_NEVER, GTK_POLICY_ALWAYS);
+ gtk_paned_add1(GTK_PANED(pane), sw);
+ lv->treestore = gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_POINTER);
+ lv->treeview = gtk_tree_view_new_with_model (GTK_TREE_MODEL (lv->treestore));
+ rend = gtk_cell_renderer_text_new();
+ col = gtk_tree_view_column_new_with_attributes ("time", rend, "markup", 0, NULL);
+ gtk_tree_view_append_column (GTK_TREE_VIEW(lv->treeview), col);
+ gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (lv->treeview), FALSE);
+ gtk_container_add (GTK_CONTAINER (sw), lv->treeview);
+
+ populate_log_tree(lv);
+
+ sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (lv->treeview));
+ g_signal_connect (G_OBJECT (sel), "changed",
+ G_CALLBACK (log_select_cb),
+ lv);
+ g_signal_connect (G_OBJECT(lv->treeview), "row-activated",
+ G_CALLBACK(log_row_activated_cb),
+ lv);
+ pidgin_set_accessible_label(lv->treeview, lv->label);
+
+ /* A fancy little box ************/
+ vbox = gtk_vbox_new(FALSE, PIDGIN_HIG_BOX_SPACE);
+ gtk_paned_add2(GTK_PANED(pane), vbox);
+
+ /* Viewer ************/
+ frame = pidgin_create_imhtml(FALSE, &lv->imhtml, NULL, NULL);
+ gtk_widget_set_name(lv->imhtml, "pidginlog_imhtml");
+ gtk_widget_set_size_request(lv->imhtml, 320, 200);
+ gtk_box_pack_start(GTK_BOX(vbox), frame, TRUE, TRUE, 0);
+ gtk_widget_show(frame);
+
+ /* Search box **********/
+ hbox = gtk_hbox_new(FALSE, PIDGIN_HIG_BOX_SPACE);
+ gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
+ lv->entry = gtk_entry_new();
+ gtk_box_pack_start(GTK_BOX(hbox), lv->entry, TRUE, TRUE, 0);
+ button = gtk_button_new_from_stock(GTK_STOCK_FIND);
+ gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
+ g_signal_connect(GTK_ENTRY(lv->entry), "activate", G_CALLBACK(search_cb), lv);
+ g_signal_connect(GTK_BUTTON(button), "activate", G_CALLBACK(search_cb), lv);
+ g_signal_connect(GTK_BUTTON(button), "clicked", G_CALLBACK(search_cb), lv);
+
+#if GTK_CHECK_VERSION(2,2,0)
+ /* Show most recent log **********/
+ path_to_first_log = gtk_tree_path_new_from_string("0:0");
+ if (path_to_first_log)
+ {
+ gtk_tree_view_expand_to_path(GTK_TREE_VIEW(lv->treeview), path_to_first_log);
+ gtk_tree_selection_select_path(sel, path_to_first_log);
+ gtk_tree_path_free(path_to_first_log);
+ }
+#endif
+
+ gtk_widget_show_all(lv->window);
+ syslog_viewer = lv;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/timelog/log-widget.h Sun Oct 21 19:20:31 2007 -0400
@@ -0,0 +1,29 @@
+/*
+ * Gaim-TimeLog plugin.
+ *
+ * Copyright (c) 2006 Jon Oberheide.
+ *
+ * $Id: log-widget.h,v 1.30 2005/12/24 05:14:55 binaryjono Exp $
+ *
+ * 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.
+ */
+
+#ifndef _LOG_WIDGET_H_
+#define _LOG_WIDGET_H_
+
+void log_widget_display_logs(GList *logs);
+
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/timelog/range-widget.c Sun Oct 21 19:20:31 2007 -0400
@@ -0,0 +1,359 @@
+/*
+ * TimeLog plugin.
+ *
+ * Copyright (c) 2006 Jon Oberheide.
+ *
+ * $Id: range-widget.c,v 1.30 2005/12/24 05:14:55 binaryjono Exp $
+ *
+ * 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.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <glib.h>
+#include <gtk/gtk.h>
+
+#include "timelog.h"
+#include "range-widget.h"
+
+static GtkWidget *start_calendar;
+static GtkWidget *end_calendar;
+static GtkWidget *start_hours;
+static GtkWidget *start_minutes;
+static GtkWidget *start_seconds;
+static GtkWidget *end_hours;
+static GtkWidget *end_minutes;
+static GtkWidget *end_seconds;
+
+static void
+calendar_update(GtkWidget *calendar, gint add)
+{
+ static const gint month_length[2][13] =
+ {
+ { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
+ { 0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
+ };
+
+ guint day, month, year;
+ gint days_in_month;
+ gboolean leap_year;
+
+ gtk_calendar_get_date(GTK_CALENDAR(calendar), &year, &month, &day);
+
+ leap_year = g_date_is_leap_year(year);
+ days_in_month = month_length[leap_year][month+1];
+
+ if (add != 0) {
+ day += add;
+ if (day < 1) {
+ day = (month_length[leap_year][month]) + day;
+ month--;
+ } else if (day > days_in_month) {
+ day -= days_in_month;
+ month++;
+ }
+
+ if (month < 0) {
+ year--;
+ leap_year = g_date_is_leap_year(year);
+ month = 11;
+ day = month_length[leap_year][month+1];
+ } else if (month > 11) {
+ year++;
+ leap_year = g_date_is_leap_year(year);
+ month = 0;
+ day = 1;
+ }
+ }
+
+ gtk_calendar_select_month(GTK_CALENDAR(calendar), month, year);
+ gtk_calendar_select_day(GTK_CALENDAR(calendar), day);
+}
+
+static void
+cb_time_value_changed(GtkSpinButton *widget, gpointer data)
+{
+ gint value = gtk_spin_button_get_value(widget);
+
+ if (widget == GTK_SPIN_BUTTON(start_seconds)) {
+ if (value > 59) {
+ gtk_spin_button_set_value(widget, value - 60);
+ gtk_spin_button_spin(GTK_SPIN_BUTTON(start_minutes), GTK_SPIN_STEP_FORWARD, 1);
+ } else if (value < 0) {
+ gtk_spin_button_set_value(widget, value + 60);
+ gtk_spin_button_spin(GTK_SPIN_BUTTON(start_minutes), GTK_SPIN_STEP_BACKWARD, 1);
+ }
+ } else if (widget == GTK_SPIN_BUTTON(start_minutes)) {
+ if (value > 59) {
+ gtk_spin_button_set_value(widget, value - 60);
+ gtk_spin_button_spin(GTK_SPIN_BUTTON(start_hours), GTK_SPIN_STEP_FORWARD, 1);
+ } else if (value < 0) {
+ gtk_spin_button_set_value(widget, value + 60);
+ gtk_spin_button_spin(GTK_SPIN_BUTTON(start_hours), GTK_SPIN_STEP_BACKWARD, 1);
+ }
+ } else if (widget == GTK_SPIN_BUTTON(start_hours)) {
+ if (value > 23) {
+ gtk_spin_button_set_value(widget, value - 24);
+ calendar_update(start_calendar, 1);
+ } else if (value < 0) {
+ calendar_update(start_calendar, -1);
+ gtk_spin_button_set_value(widget, value + 24);
+ }
+ } else if (widget == GTK_SPIN_BUTTON(end_seconds)) {
+ if (value > 59) {
+ gtk_spin_button_set_value(widget, value - 60);
+ gtk_spin_button_spin(GTK_SPIN_BUTTON(end_minutes), GTK_SPIN_STEP_FORWARD, 1);
+ } else if (value < 0) {
+ gtk_spin_button_set_value(widget, value + 60);
+ gtk_spin_button_spin(GTK_SPIN_BUTTON(end_minutes), GTK_SPIN_STEP_BACKWARD, 1);
+ }
+ } else if (widget == GTK_SPIN_BUTTON(end_minutes)) {
+ if (value > 59) {
+ gtk_spin_button_set_value(widget, value - 60);
+ gtk_spin_button_spin(GTK_SPIN_BUTTON(end_hours), GTK_SPIN_STEP_FORWARD, 1);
+ } else if (value < 0) {
+ gtk_spin_button_set_value(widget, value + 60);
+ gtk_spin_button_spin(GTK_SPIN_BUTTON(end_hours), GTK_SPIN_STEP_BACKWARD, 1);
+ }
+ } else if (widget == GTK_SPIN_BUTTON(end_hours)) {
+ if (value > 23) {
+ gtk_spin_button_set_value(widget, value - 24);
+ calendar_update(end_calendar, 1);
+ } else if (value < 0) {
+ calendar_update(end_calendar, -1);
+ gtk_spin_button_set_value(widget, value + 24);
+ }
+ }
+
+ gchar *val = g_strdup_printf("%02d", value);
+ gtk_entry_set_text(GTK_ENTRY(widget), val);
+ g_free(val);
+}
+
+void
+range_widget_get_bounds(GtkWidget *dialog, time_t *start, time_t *end)
+{
+ guint year, month, day;
+ struct tm start_tm, end_tm;
+
+ memset(&start_tm, 0, sizeof(struct tm));
+ memset(&end_tm, 0, sizeof(struct tm));
+
+ gtk_calendar_get_date(GTK_CALENDAR(start_calendar), &year, &month, &day);
+ start_tm.tm_year = year - 1900;
+ start_tm.tm_mon = month;
+ start_tm.tm_mday = day;
+ start_tm.tm_hour = gtk_spin_button_get_value(GTK_SPIN_BUTTON(start_hours));
+ start_tm.tm_min = gtk_spin_button_get_value(GTK_SPIN_BUTTON(start_minutes));
+ start_tm.tm_sec = gtk_spin_button_get_value(GTK_SPIN_BUTTON(start_seconds));
+
+ gtk_calendar_get_date(GTK_CALENDAR(end_calendar), &year, &month, &day);
+ end_tm.tm_year = year - 1900;
+ end_tm.tm_mon = month;
+ end_tm.tm_mday = day;
+ end_tm.tm_hour = gtk_spin_button_get_value(GTK_SPIN_BUTTON(end_hours));
+ end_tm.tm_min = gtk_spin_button_get_value(GTK_SPIN_BUTTON(end_minutes));
+ end_tm.tm_sec = gtk_spin_button_get_value(GTK_SPIN_BUTTON(end_seconds));
+
+ *start = mktime(&start_tm);
+ *end = mktime(&end_tm);
+}
+
+void
+range_widget_destroy(GtkWidget *dialog)
+{
+ gtk_widget_destroy(dialog);
+}
+
+GtkWidget *
+range_widget_create()
+{
+ GtkWidget *range_dialog;
+ GtkWidget *dialog_vbox4;
+ GtkWidget *vbox7;
+ GtkWidget *hbox46;
+ GtkWidget *label43;
+ GtkWidget *label44;
+ GtkWidget *hbox42;
+ GtkWidget *hbox43;
+ GtkWidget *hbox44;
+ GtkObject *start_hours_adj;
+ GtkObject *start_minutes_adj;
+ GtkObject *start_seconds_adj;
+ GtkWidget *hbox45;
+ GtkObject *end_hours_adj;
+ GtkObject *end_minutes_adj;
+ GtkObject *end_seconds_adj;
+ GtkWidget *dialog_action_area4;
+ GtkWidget *cancel_button;
+ GtkWidget *ok_button;
+ GtkWidget *alignment55;
+ GtkWidget *hbox341;
+ GtkWidget *image49;
+ GtkWidget *label97;
+
+ range_dialog = gtk_dialog_new();
+ gtk_window_set_title(GTK_WINDOW(range_dialog), TIMELOG_TITLE);
+ gtk_window_set_modal(GTK_WINDOW(range_dialog), FALSE);
+ gtk_window_set_type_hint(GTK_WINDOW(range_dialog), GDK_WINDOW_TYPE_HINT_DIALOG);
+
+ dialog_vbox4 = GTK_DIALOG(range_dialog)->vbox;
+ gtk_widget_show(dialog_vbox4);
+
+ vbox7 = gtk_vbox_new(FALSE, 0);
+ gtk_widget_show(vbox7);
+ gtk_box_pack_start(GTK_BOX(dialog_vbox4), vbox7, TRUE, TRUE, 0);
+
+ hbox46 = gtk_hbox_new(FALSE, 20);
+ gtk_widget_show(hbox46);
+ gtk_box_pack_start(GTK_BOX(vbox7), hbox46, FALSE, FALSE, 5);
+
+ label43 = gtk_label_new("Start Time");
+ gtk_widget_show(label43);
+ gtk_box_pack_start(GTK_BOX(hbox46), label43, TRUE, TRUE, 0);
+
+ label44 = gtk_label_new("End Time");
+ gtk_widget_show(label44);
+ gtk_box_pack_start(GTK_BOX(hbox46), label44, TRUE, TRUE, 0);
+
+ hbox42 = gtk_hbox_new(FALSE, 20);
+ gtk_widget_show(hbox42);
+ gtk_box_pack_start(GTK_BOX(vbox7), hbox42, TRUE, TRUE, 0);
+
+ start_calendar = gtk_calendar_new();
+ gtk_widget_show(start_calendar);
+ gtk_box_pack_start(GTK_BOX(hbox42), start_calendar, TRUE, TRUE, 0);
+ gtk_calendar_display_options(GTK_CALENDAR(start_calendar),
+ GTK_CALENDAR_SHOW_HEADING | GTK_CALENDAR_SHOW_DAY_NAMES);
+
+ end_calendar = gtk_calendar_new();
+ gtk_widget_show(end_calendar);
+ gtk_box_pack_start(GTK_BOX(hbox42), end_calendar, TRUE, TRUE, 0);
+ gtk_calendar_display_options(GTK_CALENDAR(end_calendar),
+ GTK_CALENDAR_SHOW_HEADING | GTK_CALENDAR_SHOW_DAY_NAMES);
+
+ hbox43 = gtk_hbox_new(FALSE, 20);
+ gtk_widget_show(hbox43);
+ gtk_box_pack_start(GTK_BOX(vbox7), hbox43, FALSE, TRUE, 10);
+
+ hbox44 = gtk_hbox_new(FALSE, 0);
+ gtk_widget_show(hbox44);
+ gtk_box_pack_start(GTK_BOX(hbox43), hbox44, TRUE, TRUE, 0);
+
+ start_hours_adj = gtk_adjustment_new(0, -100, 100, 1, 10, 10);
+ start_hours = gtk_spin_button_new(GTK_ADJUSTMENT(start_hours_adj), 1, 0);
+ gtk_widget_show(start_hours);
+ gtk_box_pack_start(GTK_BOX(hbox44), start_hours, TRUE, TRUE, 0);
+ gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(start_hours), TRUE);
+ gtk_spin_button_set_snap_to_ticks(GTK_SPIN_BUTTON(start_hours), TRUE);
+
+ start_minutes_adj = gtk_adjustment_new(0, -100, 100, 1, 10, 10);
+ start_minutes = gtk_spin_button_new(GTK_ADJUSTMENT(start_minutes_adj), 1, 0);
+ gtk_widget_show(start_minutes);
+ gtk_box_pack_start(GTK_BOX(hbox44), start_minutes, TRUE, TRUE, 0);
+ gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(start_minutes), TRUE);
+ gtk_spin_button_set_snap_to_ticks(GTK_SPIN_BUTTON(start_minutes), TRUE);
+
+ start_seconds_adj = gtk_adjustment_new(0, -100, 100, 1, 10, 10);
+ start_seconds = gtk_spin_button_new(GTK_ADJUSTMENT(start_seconds_adj), 1, 0);
+ gtk_widget_show(start_seconds);
+ gtk_box_pack_start(GTK_BOX(hbox44), start_seconds, TRUE, TRUE, 0);
+ gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(start_seconds), TRUE);
+ gtk_spin_button_set_snap_to_ticks(GTK_SPIN_BUTTON(start_seconds), TRUE);
+
+ hbox45 = gtk_hbox_new(FALSE, 0);
+ gtk_widget_show(hbox45);
+ gtk_box_pack_start(GTK_BOX(hbox43), hbox45, TRUE, TRUE, 0);
+
+ end_hours_adj = gtk_adjustment_new(0, -100, 100, 1, 10, 10);
+ end_hours = gtk_spin_button_new(GTK_ADJUSTMENT(end_hours_adj), 1, 0);
+ gtk_widget_show(end_hours);
+ gtk_box_pack_start(GTK_BOX(hbox45), end_hours, TRUE, TRUE, 0);
+ gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(end_hours), TRUE);
+ gtk_spin_button_set_snap_to_ticks(GTK_SPIN_BUTTON(end_hours), TRUE);
+
+ end_minutes_adj = gtk_adjustment_new(0, -100, 100, 1, 10, 10);
+ end_minutes = gtk_spin_button_new(GTK_ADJUSTMENT(end_minutes_adj), 1, 0);
+ gtk_widget_show(end_minutes);
+ gtk_box_pack_start(GTK_BOX(hbox45), end_minutes, TRUE, TRUE, 0);
+ gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(end_minutes), TRUE);
+ gtk_spin_button_set_snap_to_ticks(GTK_SPIN_BUTTON(end_minutes), TRUE);
+
+ end_seconds_adj = gtk_adjustment_new(0, -100, 100, 1, 10, 10);
+ end_seconds = gtk_spin_button_new(GTK_ADJUSTMENT(end_seconds_adj), 1, 0);
+ gtk_widget_show(end_seconds);
+ gtk_box_pack_start(GTK_BOX(hbox45), end_seconds, TRUE, TRUE, 0);
+ gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(end_seconds), TRUE);
+ gtk_spin_button_set_snap_to_ticks(GTK_SPIN_BUTTON(end_seconds), TRUE);
+
+ dialog_action_area4 = GTK_DIALOG(range_dialog)->action_area;
+ gtk_widget_show(dialog_action_area4);
+ gtk_button_box_set_layout(GTK_BUTTON_BOX(dialog_action_area4), GTK_BUTTONBOX_END);
+
+ cancel_button = gtk_button_new_from_stock("gtk-cancel");
+ gtk_widget_show(cancel_button);
+ gtk_dialog_add_action_widget(GTK_DIALOG(range_dialog), cancel_button, GTK_RESPONSE_CANCEL);
+ GTK_WIDGET_SET_FLAGS(cancel_button, GTK_CAN_DEFAULT);
+
+ ok_button = gtk_button_new();
+ gtk_widget_show(ok_button);
+ gtk_dialog_add_action_widget(GTK_DIALOG(range_dialog), ok_button, GTK_RESPONSE_OK);
+ GTK_WIDGET_SET_FLAGS(ok_button, GTK_CAN_DEFAULT);
+
+ alignment55 = gtk_alignment_new(0.5, 0.5, 0, 0);
+ gtk_widget_show(alignment55);
+ gtk_container_add(GTK_CONTAINER(ok_button), alignment55);
+
+ hbox341 = gtk_hbox_new(FALSE, 2);
+ gtk_widget_show(hbox341);
+ gtk_container_add(GTK_CONTAINER(alignment55), hbox341);
+
+ image49 = gtk_image_new_from_stock("gtk-ok", GTK_ICON_SIZE_BUTTON);
+ gtk_widget_show(image49);
+ gtk_box_pack_start(GTK_BOX(hbox341), image49, FALSE, FALSE, 0);
+
+ label97 = gtk_label_new_with_mnemonic("Select Time Range");
+ gtk_widget_show(label97);
+ gtk_box_pack_start(GTK_BOX(hbox341), label97, FALSE, FALSE, 0);
+
+ g_signal_connect((gpointer) start_hours, "value_changed",
+ G_CALLBACK(cb_time_value_changed), NULL);
+ g_signal_connect((gpointer) start_minutes, "value_changed",
+ G_CALLBACK(cb_time_value_changed), NULL);
+ g_signal_connect((gpointer) start_seconds, "value_changed",
+ G_CALLBACK(cb_time_value_changed), NULL);
+ g_signal_connect((gpointer) end_hours, "value_changed",
+ G_CALLBACK(cb_time_value_changed), NULL);
+ g_signal_connect((gpointer) end_minutes, "value_changed",
+ G_CALLBACK(cb_time_value_changed), NULL);
+ g_signal_connect((gpointer) end_seconds, "value_changed",
+ G_CALLBACK(cb_time_value_changed), NULL);
+
+ gchar *val = g_strdup_printf("%02d", 0);
+ gtk_entry_set_text(GTK_ENTRY(start_hours), val);
+ gtk_entry_set_text(GTK_ENTRY(start_minutes), val);
+ gtk_entry_set_text(GTK_ENTRY(start_seconds), val);
+ gtk_entry_set_text(GTK_ENTRY(end_hours), val);
+ gtk_entry_set_text(GTK_ENTRY(end_minutes), val);
+ gtk_entry_set_text(GTK_ENTRY(end_seconds), val);
+ g_free(val);
+
+ gtk_widget_grab_default(ok_button);
+
+ return range_dialog;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/timelog/range-widget.h Sun Oct 21 19:20:31 2007 -0400
@@ -0,0 +1,31 @@
+/*
+ * Gaim-TimeLog plugin.
+ *
+ * Copyright (c) 2006 Jon Oberheide.
+ *
+ * $Id: range-widget.h,v 1.30 2005/12/24 05:14:55 binaryjono Exp $
+ *
+ * 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.
+ */
+
+#ifndef _RANGE_WIDGET_H_
+#define _RANGE_WIDGET_H_
+
+GtkWidget *range_widget_create();
+void range_widget_destroy(GtkWidget *dialog);
+void range_widget_get_bounds(GtkWidget *dialog, time_t *start, time_t *end);
+
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/timelog/timelog.c Sun Oct 21 19:20:31 2007 -0400
@@ -0,0 +1,191 @@
+/*
+ * TimeLog plugin.
+ *
+ * Copyright (c) 2006 Jon Oberheide.
+ *
+ * $Id: timelog.c,v 1.30 2005/12/24 05:14:55 binaryjono Exp $
+ *
+ * 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.
+ */
+
+#include "../common/pp_internal.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <glib.h>
+#include <gtk/gtk.h>
+
+#include <plugin.h>
+#include <request.h>
+#include <log.h>
+#include <util.h>
+#include <debug.h>
+#include <version.h>
+
+#include <gtkplugin.h>
+
+#include "timelog.h"
+#include "log-widget.h"
+#include "range-widget.h"
+
+typedef struct {
+ PurpleAccount *account;
+ GList *logs;
+ time_t start;
+ time_t end;
+} log_query_t;
+
+static void
+foreach_log(gpointer value, gpointer data)
+{
+ PurpleLog *log = (PurpleLog *) value;
+ log_query_t *query = (log_query_t *) data;
+
+ if (log->time >= query->start && log->time <= query->end) {
+ query->logs = g_list_append(query->logs, log);
+ }
+}
+
+static void
+foreach_log_set(gpointer key, gpointer value, gpointer data)
+{
+ GList *logs;
+ PurpleLogSet *set = (PurpleLogSet *) value;
+ log_query_t *query = (log_query_t *) data;
+
+ if (query->account != set->account) {
+ return;
+ }
+
+ logs = purple_log_get_logs(set->type, set->name, set->account);
+
+ g_list_foreach(logs, foreach_log, query);
+}
+
+static void
+cb_select_time(gpointer data, PurpleRequestFields *fields)
+{
+ GHashTable *log_sets;
+ GtkWidget *range_dialog;
+ log_query_t *query;
+
+ query = g_new0(log_query_t, 1);
+ query->account = purple_request_fields_get_account(fields, "acct");
+
+ range_dialog = range_widget_create();
+
+ if (gtk_dialog_run(GTK_DIALOG(range_dialog)) == GTK_RESPONSE_OK) {
+ range_widget_get_bounds(range_dialog, &query->start, &query->end);
+
+ log_sets = purple_log_get_log_sets();
+ g_hash_table_foreach(log_sets, foreach_log_set, query);
+
+ tl_debug("found %u logs for %s between %u and %u\n",
+ g_list_length(query->logs),
+ query->account->username,
+ query->start, query->end);
+
+ log_widget_display_logs(query->logs);
+
+ g_hash_table_destroy(log_sets);
+ }
+
+ range_widget_destroy(range_dialog);
+
+ g_free(query);
+}
+
+static void
+cb_select_account(PurplePluginAction *action)
+{
+ PurpleRequestFields *request;
+ PurpleRequestFieldGroup *group;
+ PurpleRequestField *field;
+
+ group = purple_request_field_group_new(NULL);
+
+ field = purple_request_field_account_new("acct", "Account", NULL);
+ purple_request_field_account_set_show_all(field, TRUE);
+ purple_request_field_group_add_field(group, field);
+
+ request = purple_request_fields_new();
+ purple_request_fields_add_group(request, group);
+
+ purple_request_fields(action->plugin, TIMELOG_TITLE,
+ "Select account to view logs for:", NULL, request,
+ "Select Account", G_CALLBACK(cb_select_time),
+ "Cancel", NULL, NULL, NULL, NULL, NULL);
+}
+
+static GList *
+actions(PurplePlugin *plugin, gpointer context)
+{
+ GList *l = NULL;
+ PurplePluginAction *act = NULL;
+
+ act = purple_plugin_action_new("Select Account/Time", cb_select_account);
+ l = g_list_append(l, act);
+
+ return l;
+}
+
+static gboolean
+load_plugin(PurplePlugin *plugin)
+{
+ return TRUE;
+}
+
+static gboolean
+unload_plugin(PurplePlugin *plugin)
+{
+ return TRUE;
+}
+
+static PurplePluginInfo info =
+{
+ PURPLE_PLUGIN_MAGIC,
+ PURPLE_MAJOR_VERSION,
+ PURPLE_MINOR_VERSION,
+ PURPLE_PLUGIN_STANDARD, /**< type */
+ PIDGIN_PLUGIN_TYPE, /**< ui_req */
+ 0, /**< flags */
+ NULL, /**< deps */
+ PURPLE_PRIORITY_DEFAULT, /**< priority */
+ TIMELOG_PLUGIN_ID, /**< id */
+ TIMELOG_TITLE, /**< name */
+ PP_VERSION, /**< version */
+ /** summary */
+ "Allows the viewing of Pidgin logs within a specific time range",
+ /** desc */
+ "Allows the viewing of Pidgin logs within a specific time range",
+ "Jon Oberheide <jon@oberheide.org>", /**< author */
+ "http://jon.oberheide.org/projects/gaim-timelog/",
+ /**< homepage */
+ load_plugin, /**< load */
+ unload_plugin, /**< unload */
+ NULL, /**< destroy */
+ NULL, /**< ui_info */
+ NULL, /**< extra_info */
+ NULL, /**< pref info */
+ actions
+};
+
+static void
+init_plugin(PurplePlugin *plugin)
+{
+}
+
+PURPLE_INIT_PLUGIN(timelog, init_plugin, info)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/timelog/timelog.h Sun Oct 21 19:20:31 2007 -0400
@@ -0,0 +1,35 @@
+/*
+ * TimeLog plugin.
+ *
+ * Copyright (c) 2006 Jon Oberheide.
+ *
+ * $Id: gaim-timelog.h,v 1.30 2005/12/24 05:14:55 binaryjono Exp $
+ *
+ * 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.
+ */
+
+#ifndef _TIMELOG_H_
+#define _TIMELOG_H
+
+#define TIMELOG_PLUGIN_ID "gtk-binaryjono-timelog"
+#define TIMELOG_TITLE "TimeLog"
+
+#define tl_debug(fmt, ...) purple_debug(PURPLE_DEBUG_INFO, TIMELOG_TITLE, \
+ fmt, ## __VA_ARGS__);
+#define tl_error(fmt, ...) purple_debug(PURPLE_DEBUG_ERROR, TIMELOG_TITLE, \
+ fmt, ## __VA_ARGS__);
+
+#endif