pidgin/purple-plugin-pack

4b64e3618c52
ChangeLog the removal of the irssi easter egg
/*
* Purple Plugin Pack
* Copyright (C) 2003-2008
* See ../AUTHORS for a list of all authors
*
* listhandler: Provides importing, exporting, and copying functions
* for accounts' buddy lists.
*
* 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.
*/
#include "listhandler.h"
#include "aim_blt_files.h"
static gchar *filename = NULL, *file_contents = NULL;
static gsize length;
static GString *bltfile_string = NULL;
static PurpleAccount *source_account = NULL, *target_account = NULL;
static PurpleBuddyList *buddies = NULL;
static PurpleConnection *gc = NULL;
static gboolean /* used to filter the account list to oscar accounts only */
lh_aim_filter(PurpleAccount *account)
{
const gchar *prpl_id = purple_account_get_protocol_id(account);
if(!prpl_id)
return FALSE;
if(!strcmp(prpl_id, "prpl-aim"))
return TRUE;
return FALSE;
}
static gchar * /* remove '{' and leading and trailing spaces from string */
lh_aim_str_normalize(gchar *s)
{
/* replace all instances of the { and " characters with spaces, then
* strip whitespace */
return g_strstrip(g_strdelimit(g_strdelimit(s, "\"", ' '), "{", ' '));
}
static gchar * /* extract alias from string by stripping AliasString and "s */
lh_aim_get_alias(gchar * s, gboolean v2)
{
gint i, limit;
/* Magic numbers: 18 = length of the string up to = for v2 files,
* 17 = length of the string up to "AliasString" for v1 files */
if(v2) /* if a v2 file, we need to convert FriendlyName= to spaces */
limit = 18;
else /* else, v1 file, we need to convert AliasString to spaces */
limit = 17;
/* go through and kill off the chars that aren't part of the alias */
for(i = 0; i < limit; i++)
if(s[i] != ' ' && s[i] != '\0')
s[i] = ' ';
/* now strip the stupid, useless whitespace from the string */
return g_strstrip(s);
}
static gchar ** /* read and split the file into manageable strings */
lh_aim_get_file_strings(gchar *file_contents, gsize *length, guint *strings_len)
{
gchar **ret;
GError *error = NULL;
/* read the file as one bigass string */
g_file_get_contents(filename, &file_contents, length, &error);
if(error)
purple_debug_misc("listhandler: import", "Error from glib: %s\n",
error->message);
/* split that bigass string into manageable ones ;) */
ret = g_strsplit(file_contents, "\n", 0);
/* find out how many "manageable strings" we have */
if(strings_len)
*strings_len = g_strv_length(ret);
if(error)
g_error_free(error);
g_free(filename);
return ret; /* leave this stupid function already! */
}
static void /* find where the buddy list begins and ends */
lh_aim_list_find(gchar **strings, guint strings_len, guint *begin, guint *end)
{
int i;
/* this is a bit ugly but it works */
for(i = 0; i < strings_len; i++) {
if(!strncmp(strings[i], " list {", 7))
*begin = i;
if(*begin && i > *begin && !strncmp(strings[i], " }", 2)) {
*end = i;
break;
}
}
return;
}
static void /* parse this damn buddy list already */
lh_aim_list_parse_and_add(gchar **strings, guint length, guint begin, guint end)
{
gchar *current_group = NULL, *current_buddy = NULL, *current_alias = NULL;
gint i, current_group_begin = 0, current_group_end = 0;
PurpleGroup *current_purple_group = NULL;
PurpleBuddy *tmpbuddy = NULL;
GList *buddies = NULL, *groups = NULL;
/* loop until we find the end of the buddy list */
while(current_group_end < end && current_group_end != end - 1) {
purple_debug_info("listhandler: import", "Started the parsing loop\n");
/* it's safe to start one after and end one before the start and end
* of the list section, so save the two iterations. the if statement
* determines if we've already been through at least one group or not
* and sets i accordingly to prevent missing or reparsing a group */
if(current_group_end > 0)
i = current_group_end + 1;
else
i = begin + 1;
/* pass through the list from the starting point determined above
* until the end of the current group's section in the blt file is
* found */
for(; i < end; i++) {
if(!strncmp(strings[i], " ", 2) && strlen(strings[i]) >= 3 &&
strings[i][2] != ' ' && strings[i][2] != '}')
current_group_begin = i;
if(!strncmp(strings[i], " }", 3)) {
current_group_end = i;
break;
}
}
purple_debug_info("listhandler: import", "Current group begins %d, ends %d\n",
current_group_begin, current_group_end);
/* now strip {, ", and whitespace from the group and keep an extra
* pointer to it around for easy access */
current_group = lh_aim_str_normalize(strings[current_group_begin]);
/* create a PurpleGroup and add to the list. This is surprisingly easy. */
current_purple_group = purple_group_new(current_group);
purple_blist_add_group(current_purple_group, NULL);
/* now parse the actual group */
for(i = current_group_begin + 1; i < current_group_end; i++) {
if(!strncmp(strings[i], " ", 3) && strlen(strings[i]) >= 4 &&
strings[i][3] != ' ' && strings[i][3] != '}')
{
/* this is the buddy name; keep extra pointer for easy access */
current_buddy = lh_aim_str_normalize(strings[i]);
/* since the geniuses that designed the blt format decided
* that "M y S cr ee nn a m e" is acceptable in their blt files,
* I have to work around their incompetence */
lh_aim_str_normalize(current_buddy);
purple_debug_info("listhandler: import", "current buddy is %s\n",
current_buddy);
/* test to see if the buddy has an alias set */
if(!strncmp(strings[i + 1], " AliasKey {", 14) &&
!strncmp(strings[i + 2], " AliasString ", 17))
{
/* grab the alias */
current_alias = lh_aim_get_alias(strings[i + 2], FALSE);
i += 2; /* advance counter to prevent reparsing the alias */
} else if(!strncmp(strings[i + 1], " FriendlyName=", 17)) {
/* Version 2 .blt format uses FriendlyName= to denote an alias */
/* grab the alias */
current_alias = lh_aim_get_alias(strings[i + 1], TRUE);
i++; /* advance the counter to prevent reparsing the alias */
} else /* no alias is set */
current_alias = NULL;
tmpbuddy = purple_buddy_new(target_account, current_buddy,
current_alias);
purple_debug_info("listhandler: import",
"new PurpleBuddy created: %s, %s, %s\n", current_buddy,
current_alias ? current_alias : "NULL",
purple_account_get_username(target_account));
if(tmpbuddy && current_purple_group) {
buddies = g_list_prepend(buddies, tmpbuddy);
groups = g_list_prepend(groups, current_purple_group);
purple_debug_info("listhandler: import", "added current "
"buddy to the GLists\n");
}
}
}
}
if(buddies && groups) {
lh_util_add_to_blist(buddies, groups);
#if PURPLE_VERSION_CHECK(3,0,0)
purple_account_add_buddies(target_account, buddies, NULL);
#else
purple_account_add_buddies(target_account, buddies);
#endif
} else {
if(!buddies && !groups)
purple_debug_info("listhandler: import", "BOTH GLISTS NULL!!!!!\n");
if(!buddies)
purple_debug_info("listhandler: import", "BUDDY GLIST NULL!!!\n");
if(!groups)
purple_debug_info("listhandler: import", "GROUP GLIST NULL!!!!\n");
}
return;
}
static void
lh_aim_import_target_request_cb(void *ignored, PurpleRequestFields *fields)
{
gchar **strings = NULL;
guint strings_len = 0, list_begin = 0, list_end = 0;
/* get the target account from the dialog we requested */
target_account = purple_request_fields_get_account(fields,
"aim_target_acct");
/* read and split the file */
strings = lh_aim_get_file_strings(file_contents, &length, &strings_len);
/* find the list in that crapload of memory that just got allocated */
lh_aim_list_find(strings, strings_len, &list_begin, &list_end);
purple_debug_info("listhandler: import", "List begins at %d; ends at %d\n",
list_begin, list_end);
/* parse the freaking list already */
lh_aim_list_parse_and_add(strings, strings_len, list_begin, list_end);
/* clean up all that crap that got allocated */
g_strfreev(strings);
g_free(file_contents);
return;
}
static void /* does the request API calls needed */
lh_aim_import_target_request(void)
{
PurpleRequestFields *request;
PurpleRequestFieldGroup *group;
PurpleRequestField *field;
purple_debug_info("listhandler: import", "Beginning Request API calls\n");
/* It seems Purple is super-picky about the order of these first three calls */
/* create a request */
request = purple_request_fields_new();
/* now create a field group */
group = purple_request_field_group_new(NULL);
/* and add that group to the request created above */
purple_request_fields_add_group(request, group);
/* create a field */
field = purple_request_field_account_new("aim_target_acct",
_("Account"), NULL);
/* set the account field filter so we only see oscar accounts */
purple_request_field_account_set_filter(field, lh_aim_filter);
/* mark the field as required */
purple_request_field_set_required(field, TRUE);
/* add the field to the group created above */
purple_request_field_group_add_field(group, field);
/* and finally we can create the request */
purple_request_fields(purple_get_blist(), _("List Handler: Importing"),
_("Choose the account to import to:"), NULL,
request, _("_Import"),
G_CALLBACK(lh_aim_import_target_request_cb),
_("_Cancel"), NULL, NULL, NULL, NULL, NULL);
purple_debug_info("listhandler: import", "Ending Request API calls\n");
return;
}
static void
lh_aim_import_cb(void *user_data, const char *file)
{
purple_debug_info("listhandler: import", "Beginning import\n");
if(file) {
filename = g_strdup(file);
lh_aim_import_target_request();
}
return;
}
static void
lh_aim_string_add_buddy(PurpleBlistNode *node)
{
PurpleBuddy *buddy = (PurpleBuddy *)node;
const char *tmpalias = purple_buddy_get_contact_alias(buddy),
*tmpname = purple_buddy_get_name(buddy);
purple_debug_info("listhandler: export", "Node is buddy. Name is: %s\n", tmpname);
/* only export if the buddy is on the right account */
if(purple_buddy_get_account(buddy) == source_account) {
/* add the buddy's screenname to the string */
g_string_append_printf(bltfile_string, " \"%s\"", tmpname);
/* if the alias is NOT the same as the screenname, add it to the string */
if(strcmp(tmpalias, tmpname))
g_string_append_printf(bltfile_string,
" {\n AliasKey {\n \"%s\"\n }\n }\n",
tmpalias );
else /* otherwise we're done with this buddy */
g_string_append_printf(bltfile_string, "\n");
}
return;
}
static void
lh_aim_build_string(void)
{
PurpleBlistNode *root_node = buddies->root, *g = NULL,
*c = NULL, *b = NULL;
bltfile_string = g_string_new("Config {\n version 1\n}\n");
g_string_append_printf(bltfile_string, "User {\n screenname %s\n}\n",
purple_account_get_username(source_account));
g_string_append(bltfile_string, "Buddy {\n list {\n");
/* this outer loop iterates through the group level of the tree */
for(g = root_node; g && PURPLE_BLIST_NODE_IS_GROUP(g); g = g->next)
{
purple_debug_info("listhandler: export", "Node is group. Name is: %s\n",
((PurpleGroup *)g)->name);
/* add the group to the string */
g_string_append_printf(bltfile_string, " \"%s\" {\n",
((PurpleGroup *)g)->name);
/* iterate through the contact level in this group */
for(c = g->child; c && PURPLE_BLIST_NODE_IS_CONTACT(c); c = c->next) {
purple_debug_info("listhandler: export",
"Node is contact. Will parse its children.\n");
/* iterate through the contact's buddies */
for(b = c->child; b && PURPLE_BLIST_NODE_IS_BUDDY(b); b = b->next)
lh_aim_string_add_buddy(b);
}
g_string_append(bltfile_string, " }\n");
}
/* finish the string we'll dump to the file */
g_string_append(bltfile_string, " }\n}\n");
purple_debug_info("listhandler: export", "String built. String is:\n\n%s\n",
bltfile_string->str);
return;
}
static void
lh_aim_export_request_cb(void *user_data, const char *filename)
{
FILE *export = fopen(filename, "w");
if(export) {
lh_aim_build_string();
fprintf(export, "%s", bltfile_string->str);
fclose(export);
} else
purple_debug_info("listhandler: export", "Can't save file %s\n",
filename ? filename : "NULL");
g_string_free(bltfile_string, TRUE);
return;
}
static void
lh_aim_export_cb(void *ignored, PurpleRequestFields *fields)
{
/* get the source account from the dialog we requested */
source_account = purple_request_fields_get_account(fields,
"aim_source_acct");
/* get the connection from the account */
gc = purple_account_get_connection(source_account);
/* this grabs the purple buddy list, which will be walked thru later */
buddies = purple_get_blist();
if(buddies)
purple_request_file(listhandler, _("Save AIM .blt File"), NULL, TRUE,
G_CALLBACK(lh_aim_export_request_cb), NULL,
source_account, NULL, NULL, NULL);
else
purple_debug_info("listhandler: export", "blist not returned\n");
return;
}
void /* do some work and export the damn blist already */
lh_aim_export_action_cb(PurplePluginAction *action)
{
PurpleRequestFields *request;
PurpleRequestFieldGroup *group;
PurpleRequestField *field;
purple_debug_info("listhandler: export", "Beginning Request API calls\n");
/* It seems Purple is super-picky about the order of these first three calls */
/* create a request */
request = purple_request_fields_new();
/* now create a field group */
group = purple_request_field_group_new(NULL);
/* and add that group to the request created above */
purple_request_fields_add_group(request, group);
/* create a field */
field = purple_request_field_account_new("aim_source_acct",
_("Account"), NULL);
/* set the account field filter so we only see oscar accounts */
purple_request_field_account_set_filter(field, lh_aim_filter);
/* mark the field as required */
purple_request_field_set_required(field, TRUE);
/* add the field to the group created above */
purple_request_field_group_add_field(group, field);
/* and finally we can create the request */
purple_request_fields(purple_get_blist(), _("List Handler: Exporting"),
_("Choose the account to export from:"), NULL, request,
_("_Export"), G_CALLBACK(lh_aim_export_cb), _("_Cancel"),
NULL, NULL, NULL, NULL, NULL);
purple_debug_info("listhandler: export", "Ending Request API calls\n");
return;
}
void
lh_aim_import_action_cb(PurplePluginAction *action)
{
purple_debug_info("listhandler: import", "Requesting the file.\n");
purple_request_file(listhandler, _("Choose An AIM .blt File To Import"),
NULL, FALSE, G_CALLBACK(lh_aim_import_cb),
NULL, NULL, NULL, NULL, NULL);
return;
}