pidgin/purple-plugin-pack

6db34043e925
Added tag pp_2_8_0 for changeset 1e6de767dd01
/*
* Old Logger - Re-implements the legacy, deficient, logging
* Copyright (C) 2004-2008 Stu Tomlinson <stu@nosnilmot.com>
*
* 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.
*/
/* If you can't figure out what this line is for, DON'T TOUCH IT. */
#include "../common/pp_internal.h"
#define OLDLOGGER_PLUGIN_ID "core-plugin_pack-oldlogger"
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#include <account.h>
#include <debug.h>
#include <log.h>
#include <prefs.h>
#include <prpl.h>
#include <stringref.h>
#include <util.h>
/* We want to use the gstdio functions when possible so that non-ASCII
* filenames are handled properly on Windows. */
#include <glib/gstdio.h>
static PurpleLogLogger *oldtxt_logger;
static PurpleLogLogger *oldhtml_logger;
#define return_written return written
struct basic_logger_data {
FILE *file;
char *filename;
gboolean new;
long offset;
time_t old_last_modified;
};
static const gchar *
oldlogger_date_full(void)
{
gchar *buf;
time_t tme;
time(&tme);
buf = ctime(&tme);
buf[strlen(buf) - 1] = '\0';
return buf;
}
static void old_logger_create(PurpleLog *log)
{
if(log->type == PURPLE_LOG_SYSTEM){
const char *ud = purple_user_dir();
char *dir;
char *filename;
struct basic_logger_data *data;
struct stat st;
dir = g_build_filename(ud, "logs", NULL);
purple_build_dir (dir, S_IRUSR | S_IWUSR | S_IXUSR);
filename = g_build_filename(dir, "system", NULL);
g_free(dir);
log->logger_data = data = g_new0(struct basic_logger_data, 1);
if (g_stat(filename, &st) < 0)
data->new = TRUE;
else
data->old_last_modified = st.st_mtime;
data->file = g_fopen(filename, "a");
if (!data->file) {
purple_debug(PURPLE_DEBUG_ERROR, "log",
"Could not create log file %s\n", filename);
g_free(filename);
g_free(data);
log->logger_data = NULL;
return;
}
data->filename = filename;
data->offset = ftell(data->file);
}
}
static void old_logger_update_index(PurpleLog *log)
{
struct basic_logger_data *data = log->logger_data;
struct stat st;
char *index_path;
char *index_data;
GError *error = NULL;
int index_fd;
char *index_tmp;
FILE *index;
g_return_if_fail(data->offset > 0);
index_path = g_strdup(data->filename);
/* Change the .log extension to .idx */
strcpy(index_path + strlen(index_path) - 3, "idx");
if (!data->new && (g_stat(index_path, &st) || st.st_mtime < data->old_last_modified))
{
g_free(index_path);
return;
}
/* The index file exists and is at least as new as the log, so open it. */
if (!data->new && !g_file_get_contents(index_path, &index_data, NULL, &error))
{
purple_debug_error("log", "Failed to read contents of index \"%s\": %s\n",
index_path, error->message);
g_error_free(error);
g_free(index_path);
return;
}
if (data->new)
index_data = g_strdup("");
index_tmp = g_strdup_printf("%s.XXXXXX", index_path);
if ((index_fd = g_mkstemp(index_tmp)) == -1) {
purple_debug_error("log", "Failed to open index temp file: %s\n",
strerror(errno));
g_free(index_path);
g_free(index_data);
g_free(index_tmp);
return;
} else {
if ((index = fdopen(index_fd, "wb")) == NULL)
{
purple_debug_error("log", "Failed to fdopen() index temp file: %s\n",
strerror(errno));
close(index_fd);
if (index_tmp != NULL)
{
g_unlink(index_tmp);
g_free(index_tmp);
}
g_free(index_path);
g_free(index_data);
return;
}
}
fprintf(index, "%s", index_data);
fprintf(index, "%ld\t%ld\t%lu\n", data->offset, ftell(data->file) - data->offset, (unsigned long)log->time);
fclose(index);
if (g_rename(index_tmp, index_path))
{
purple_debug_warning("log", "Failed to rename index temp file \"%s\" to \"%s\": %s\n",
index_tmp, index_path, strerror(errno));
g_unlink(index_tmp);
}
g_free(index_tmp);
g_free(index_path);
g_free(index_data);
}
static void old_logger_finalize(PurpleLog *log)
{
struct basic_logger_data *data = log->logger_data;
if (data) {
if(data->file)
fflush(data->file);
old_logger_update_index(log);
if(data->file)
fclose(data->file);
g_free(data->filename);
g_free(data);
}
}
/*******************************
** Ye Olde PLAIN TEXT LOGGER **
*******************************/
static gsize
oldtxt_logger_write(PurpleLog *log, PurpleMessageFlags type,
const char *from, time_t time, const char *message)
{
char date[64];
char *stripped = NULL;
struct basic_logger_data *data = log->logger_data;
const char *prpl = (purple_find_prpl(purple_account_get_protocol_id(log->account)))->info->name;
gsize written = 0;
if (!data) {
/* This log is new. We could use the logger's 'new' function, but
* creating a new file there would result in empty files in the case
* that you open a convo with someone, but don't say anything.
*
* The log is also not system log. Because if it is, data would be
* created in old_logger_create
* Stu: well, this isn't really necessary with crappy old logging, but I'm
* too lazy to do it any other way.
*/
const char *ud = purple_user_dir();
char *filename;
char *guy = g_strdup(purple_normalize(log->account, log->name));
char *chat;
char *dir;
char *logfile;
struct stat st;
for (filename = guy; *filename != '\0'; filename++) {
if (*filename == '/')
*filename = '.';
}
if (log->type == PURPLE_LOG_CHAT) {
chat = g_strdup_printf("%s.chat", guy);
g_free(guy);
guy = chat;
}
logfile = g_strdup_printf("%s.log", guy);
g_free(guy);
dir = g_build_filename(ud, "logs", NULL);
purple_build_dir (dir, S_IRUSR | S_IWUSR | S_IXUSR);
filename = g_build_filename(dir, logfile, NULL);
g_free(dir);
g_free(logfile);
log->logger_data = data = g_new0(struct basic_logger_data, 1);
if (g_stat(filename, &st) < 0)
data->new = TRUE;
else
data->old_last_modified = st.st_mtime;
data->file = g_fopen(filename, "a");
if (!data->file) {
purple_debug(PURPLE_DEBUG_ERROR, "log", "Could not create log file %s\n", filename);
g_free(filename);
g_free(data);
log->logger_data = NULL;
return_written;
}
data->filename = filename;
if (data->new)
written += fprintf(data->file, _("IM Sessions with %s\n"), purple_normalize(log->account, log->name));
written += fprintf(data->file, "---- New Conversation @ %s ----\n",
oldlogger_date_full());
data->offset = ftell(data->file);
}
/* if we can't write to the file, give up before we hurt ourselves */
if(!data->file)
return_written;
purple_markup_html_to_xhtml(message, NULL, &stripped);
if(log->type == PURPLE_LOG_SYSTEM){
if (!strncmp(stripped, "+++ ", 4)) {
written += fprintf(data->file, "---- %s @ %s ----\n", stripped, oldlogger_date_full());
} else {
written += fprintf(data->file, "---- %s (%s) reported that %s @ %s ----\n", purple_account_get_username(log->account), prpl, stripped, oldlogger_date_full());
}
} else {
strftime(date, sizeof(date), "%H:%M:%S", localtime(&time));
if (type & PURPLE_MESSAGE_SEND ||
type & PURPLE_MESSAGE_RECV) {
if (type & PURPLE_MESSAGE_AUTO_RESP) {
written += fprintf(data->file, _("(%s) %s <AUTO-REPLY>: %s\n"), date,
from, stripped);
} else {
if(purple_message_meify(stripped, -1))
written += fprintf(data->file, "(%s) ***%s %s\n", date, from,
stripped);
else
written += fprintf(data->file, "(%s) %s: %s\n", date, from,
stripped);
}
} else if ((type & PURPLE_MESSAGE_SYSTEM) || (type & PURPLE_MESSAGE_ERROR))
written += fprintf(data->file, "(%s) %s\n", date, stripped);
else if (type & PURPLE_MESSAGE_RAW)
written += fprintf(data->file, "%s\n", stripped);
else if (type & PURPLE_MESSAGE_NO_LOG) {
/* This shouldn't happen */
g_free(stripped);
return_written;
} else if (type & PURPLE_MESSAGE_WHISPER)
written += fprintf(data->file, "(%s) *%s* %s\n", date, from, stripped);
else
written += fprintf(data->file, "(%s) %s%s %s\n", date, from ? from : "",
from ? ":" : "", stripped);
}
fflush(data->file);
g_free(stripped);
return_written;
}
/****************************
** Ye Olde HTML LOGGER *****
****************************/
static gsize
oldhtml_logger_write(PurpleLog *log, PurpleMessageFlags type,
const char *from, time_t time, const char *message)
{
char date[64];
char *msg_fixed = NULL;
struct basic_logger_data *data = log->logger_data;
const char *prpl = (purple_find_prpl(purple_account_get_protocol_id(log->account)))->info->name;
gsize written = 0;
if(!data) {
/* This log is new */
const char *ud = purple_user_dir();
char *filename;
char *guy = g_strdup(purple_normalize(log->account, log->name));
char *chat;
char *dir;
char *logfile;
struct stat st;
for (filename = guy; *filename != '\0'; filename++) {
if (*filename == '/')
*filename = '.';
}
if (log->type == PURPLE_LOG_CHAT) {
chat = g_strdup_printf("%s.chat", guy);
g_free(guy);
guy = chat;
}
logfile = g_strdup_printf("%s.log", guy);
g_free(guy);
dir = g_build_filename(ud, "logs", NULL);
purple_build_dir (dir, S_IRUSR | S_IWUSR | S_IXUSR);
filename = g_build_filename(dir, logfile, NULL);
g_free(dir);
g_free(logfile);
log->logger_data = data = g_new0(struct basic_logger_data, 1);
if (g_stat(filename, &st) < 0)
data->new = TRUE;
else
data->old_last_modified = st.st_mtime;
data->file = g_fopen(filename, "a");
if (!data->file) {
purple_debug(PURPLE_DEBUG_ERROR, "log",
"Could not create log file %s\n", filename);
g_free(filename);
g_free(data);
log->logger_data = NULL;
return_written;
}
data->filename = filename;
if (data->new) {
written += fprintf(data->file, "<HTML><HEAD><TITLE>");
written += fprintf(data->file, _("IM Sessions with %s"), purple_normalize(log->account, log->name));
written += fprintf(data->file, "</TITLE></HEAD><BODY BGCOLOR=\"#ffffff\">\n");
}
written += fprintf(data->file, "<HR><BR><H3 Align=Center> ");
written += fprintf(data->file, "---- New Conversation @ %s ----</H3><BR>\n",
oldlogger_date_full());
data->offset = ftell(data->file);
}
/* if we can't write to the file, give up before we hurt ourselves */
if(!data->file)
return_written;
purple_markup_html_to_xhtml(message, &msg_fixed, NULL);
if(log->type == PURPLE_LOG_SYSTEM){
if (!strncmp(msg_fixed, "+++ ", 4)) {
written += fprintf(data->file, "---- %s @ %s ----<BR>\n", msg_fixed, oldlogger_date_full());
} else {
written += fprintf(data->file, "---- %s (%s) reported that %s @ %s ----<BR>\n", purple_account_get_username(log->account), prpl, msg_fixed, oldlogger_date_full());
}
} else {
strftime(date, sizeof(date), "%H:%M:%S", localtime(&time));
if (type & PURPLE_MESSAGE_SYSTEM)
written += fprintf(data->file, "<FONT COLOR=\"#000000\" sml=\"%s\">(%s) <B>%s</B></FONT><BR>\n", prpl, date, msg_fixed);
else if (type & PURPLE_MESSAGE_ERROR)
written += fprintf(data->file, "<FONT COLOR=\"#FF0000\" sml=\"%s\">(%s) <B>%s</B></FONT><BR>\n", prpl, date, msg_fixed);
else if (type & PURPLE_MESSAGE_RAW)
written += fprintf(data->file, "%s<BR>\n", msg_fixed);
else if (type & PURPLE_MESSAGE_WHISPER)
written += fprintf(data->file, "<FONT COLOR=\"#6C2585\" sml=\"%s\">(%s) <B>%s:</B></FONT> %s<BR>\n",
prpl, date, from, msg_fixed);
else if (type & PURPLE_MESSAGE_AUTO_RESP) {
if (type & PURPLE_MESSAGE_SEND)
written += fprintf(data->file, _("<FONT COLOR=\"#16569E\" sml=\"%s\">(%s) <B>%s &lt;AUTO-REPLY&gt;:</B></FONT> %s<BR>\n"), prpl, date, from, msg_fixed);
else if (type & PURPLE_MESSAGE_RECV)
written += fprintf(data->file, _("<FONT COLOR=\"#A82F2F\" sml=\"%s\">(%s) <B>%s &lt;AUTO-REPLY&gt;:</B></FONT> %s<BR>\n"), prpl, date, from, msg_fixed);
} else if (type & PURPLE_MESSAGE_RECV) {
if(purple_message_meify(msg_fixed, -1))
written += fprintf(data->file, "<FONT COLOR=\"#6C2585\" sml=\"%s\">(%s) <B>***%s</B></FONT> <font sml=\"%s\">%s</FONT><BR>\n",
prpl, date, from, prpl, msg_fixed);
else
written += fprintf(data->file, "<FONT COLOR=\"#A82F2F\" sml=\"%s\">(%s) <B>%s:</B></FONT> <font sml=\"%s\">%s</FONT><BR>\n",
prpl, date, from, prpl, msg_fixed);
} else if (type & PURPLE_MESSAGE_SEND) {
if(purple_message_meify(msg_fixed, -1))
written += fprintf(data->file, "<FONT COLOR=\"#6C2585\" sml=\"%s\">(%s) <B>***%s</B></FONT> <font sml=\"%s\">%s</FONT><BR>\n",
prpl, date, from, prpl, msg_fixed);
else
written += fprintf(data->file, "<FONT COLOR=\"#16569E\" sml=\"%s\">(%s) <B>%s:</B></FONT> <font sml=\"%s\">%s</FONT><BR>\n",
prpl, date, from, prpl, msg_fixed);
}
}
fflush(data->file);
g_free(msg_fixed);
return_written;
}
static gboolean
plugin_load(PurplePlugin *plugin)
{
oldtxt_logger = purple_log_logger_new("oldtxt", N_("Old plain text"), 3,
old_logger_create,
oldtxt_logger_write,
old_logger_finalize);
purple_log_logger_add(oldtxt_logger);
oldhtml_logger = purple_log_logger_new("oldhtml", N_("Old HTML"), 3,
old_logger_create,
oldhtml_logger_write,
old_logger_finalize);
purple_log_logger_add(oldhtml_logger);
purple_prefs_trigger_callback("/purple/logging/format");
return TRUE;
}
static gboolean
plugin_unload(PurplePlugin *plugin)
{
purple_log_logger_remove(oldtxt_logger);
purple_log_logger_remove(oldhtml_logger);
purple_prefs_trigger_callback("/purple/logging/format");
return TRUE;
}
static PurplePluginInfo info =
{
PURPLE_PLUGIN_MAGIC, /**< magic */
PURPLE_MAJOR_VERSION, /**< major version */
PURPLE_MINOR_VERSION, /**< minor version */
PURPLE_PLUGIN_STANDARD, /**< type */
NULL, /**< ui_requirement */
0, /**< flags */
NULL, /**< dependencies */
PURPLE_PRIORITY_DEFAULT, /**< priority */
OLDLOGGER_PLUGIN_ID, /**< id */
NULL, /**< name */
PP_VERSION, /**< version */
NULL, /**< summary */
NULL, /**< description */
"Stu Tomlinson <stu@nosnilmot.com>", /**< author */
PP_WEBSITE, /**< homepage */
plugin_load, /**< load */
plugin_unload, /**< unload */
NULL, /**< destroy */
NULL, /**< ui_info */
NULL, /**< extra_info */
NULL, /**< prefs_info */
NULL, /**< actions */
NULL, /**< reserved 1 */
NULL, /**< reserved 2 */
NULL, /**< reserved 3 */
NULL /**< reserved 4 */
};
static void
init_plugin(PurplePlugin *plugin) {
#ifdef ENABLE_NLS
bindtextdomain(GETTEXT_PACKAGE, PP_LOCALEDIR);
bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
#endif /* ENABLE_NLS */
info.name = _("Old Logger");
info.summary = _("Re-implements the legacy, deficient, logging");
info.description = _("Re-implements the legacy, deficient, logging");
}
PURPLE_INIT_PLUGIN(oldlogger, init_plugin, info)