--- a
+++ b/tags/0.2.1/yulastfm.pl
@@ -0,0 +1,232 @@
+#!/usr/bin/perl -w
+
+#  YuLastfm - Update Pidgin TUNE status from Last.fm
+
+#  Author:  Chih-Chun Lin
+
+#  Project Homepage:
+#  https://sourceforge.net/projects/yulastfm/
+
+#  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
+
+use warnings;
+use Purple;
+
+#program version
+my $VERSION="0.2.1";
+
+#global variable
+our $plugin;
+our $lastfm_account;
+
+our $url;
+our $api_key = "7aed2418de442e85a6e7af89f325d8f6";
+our $trk_limit = "1";
+our $url_pre = "http://ws.audioscrobbler.com/2.0/?method=user.getrecenttracks&user=";
+our $url_suf = "&api_key=" . $api_key . "&limit=" . $trk_limit;
+
+our $refresh_rate = "60";
+our $presence;
+our $timeout = 0;
+
+our $cur_artist;
+our $cur_title;
+our $cur_album;
+our $cur_date;
+
+
+%PLUGIN_INFO = (
+	perl_api_version => 2,
+	name => "YuLastfm",
+	version => $VERSION,
+	summary => "This perl script is a plugin which help you update your " .
+                   "\"now playing\" information from the Last.fm musical " .
+                   "social network.",
+	description => "Updater for Pidgin TUNE status from Last.FM",
+	author => "Lin, Chih-Chun",
+	url => "https://sourceforge.net/projects/yulastfm/",
+	load => "plugin_load",
+	unload => "plugin_unload",
+	plugin_action_sub => "plugin_actions_cb",
+	prefs_info => "prefs_info_cb"
+);
+
+sub plugin_init {
+	return %PLUGIN_INFO;
+}
+
+sub plugin_load {
+	$plugin = shift;
+	dbg_msg( "plguin: " . $plugin);
+
+	Purple::Prefs::add_none( "/plugins/core/yulastfm");
+	Purple::Prefs::add_string( "/plugins/core/yulastfm/username", "");
+	Purple::Prefs::add_int( "/plugins/core/yulastfm/refreshing_rate", 60);
+	Purple::Prefs::connect_callback(
+		$plugin,
+		"/plugins/core/yulastfm/refreshing_rate",
+		\&pref_rate_cb,
+		"refresh rate"
+	);
+
+	refresh_tune();
+	dbg_msg("yulastfm loaded");
+}
+
+sub plugin_unload {
+	my @accounts = Purple::Accounts::get_all();
+	my $i = 0;
+	while ( $i<=$#accounts) {
+		if ( $account = $accounts[$i]) {
+			if( $presence = Purple::Account::get_presence($account)) {
+				Purple::Util::set_current_song( "", "", "");
+			}
+		}
+		$i++;
+	}
+	if ($timeout) {
+		dbg_msg( "remove existing timeout: " . $timeout);
+		Purple::timeout_remove($timeout);
+		$timeout = 0;
+	}
+	dbg_msg("yulastfm unloaded");
+}
+
+sub plugin_actions_cb {
+	my @actions = ("Refresh Tune");
+}
+
+%plugin_actions = (
+	"Refresh Tune" => \&refresh_tune
+);
+
+sub prefs_info_cb {
+	my $frame = Purple::PluginPref::Frame->new();
+
+	my $ppref = Purple::PluginPref->new_with_label("YuLastfm");
+	$ppref->set_type(2);
+	$frame->add($ppref);
+
+	$ppref = Purple::PluginPref->new_with_name_and_label(
+		"/plugins/core/yulastfm/username",
+		"Last.fm User");
+	$ppref->set_type(3);	# PURPLE_PLUGIN_PREF_STRING_FORMAT
+	$frame->add($ppref);
+
+	$ppref = Purple::PluginPref->new_with_name_and_label(
+		"/plugins/core/yulastfm/refreshing_rate",
+		"Refresh Rate (per sec.)");
+	$ppref->set_type(3);
+	# If no bounds are assigned, the value will be restriced to 0
+	$ppref->set_bounds( 10, 300);
+	# this line shows how to call "etan1" patched get_bounds()
+	# ( $min_v, $max_v) = $ppref->get_bounds();
+	$frame->add($ppref);
+
+	return $frame;
+}
+
+sub pref_rate_cb {
+	dbg_msg("pref_rate_cb: \"refresh rate\" changed");
+	if ($timeout) {
+		Purple::timeout_remove($timeout);
+		$timeout = 0;
+	}
+	refresh_tune();
+}
+
+sub refresh_tune {
+	$lastfm_account = Purple::Prefs::get_string("/plugins/core/yulastfm/username");
+	if (!$lastfm_account) {		# no account present
+		dbg_msg("No Last.fm account present!");
+		Purple::Notify::message(
+			$plugin,
+			1,	# Warning Type
+			"YuLastfm",
+			"A valid Last.fm account is required:",
+			"This warning message usually implies that you either " .
+			"haven't done the configuration yet or you have given " .
+			"an invalid Last.fm account. You have to give a valid " .
+			"Last.fm account to make YuLastfm work. You can remedy " .
+			"it in plugins preference setting interface of pidgin. ".
+			"It locates on menu path\n\n\tTools->Plugins.\n\nFind " .
+			"YuLastfm, and click Configure Plugin button below to " .
+			"do further configuration. After configuration, either " .
+			"reloading the plugin or refreshing it can activate the " .
+			"lastest configuration. You can refresh it by click " .
+			"menu path\n\n\tTools->YuLastfm->Refresh Tune.",
+			NULL, NULL
+		);
+		$timeout = 0;
+		dbg_msg("timeout stoped.");
+		return 0;
+	} elsif ( length($lastfm_account) < 2 || length($lastfm_account) > 15) {
+		dbg_msg("Invalid Last.fm account! (ID Length must between 2-15)");
+		$timeout = 0;
+		dbg_msg("timeout stoped.");
+		return 0;
+	} else {
+		$url = $url_pre . $lastfm_account . $url_suf;
+		Purple::Util::fetch_url( $plugin, $url, TURE, "Mozilla/5.0", TURE, \&parse_xml);
+		$refresh_rate = Purple::Prefs::get_int("/plugins/core/yulastfm/refreshing_rate");
+		if (!$timeout) {
+			$timeout = Purple::timeout_add( $plugin, $refresh_rate, \&refresh_tune, $plugin);
+		}
+		dbg_msg("timeout continues.");
+		return 1;
+	}
+}
+
+sub parse_xml {
+# 	dbg_msg($_[0]);	# dump raw xml
+	dbg_msg("parsing xml");
+	if (!$_[0]){
+		dbg_msg("Cannot get anything from Last.fm!");
+		return;
+	}
+	my $rootXmlnode = Purple::XMLNode::from_str($_[0]);
+	my $lfmStatus = $rootXmlnode->get_attrib("status");
+	dbg_msg( "lfm status: " . $lfmStatus);
+	if ( $lfmStatus == "ok") {
+		dbg_msg("web query status: ok");
+		my $trackXmlnode = $rootXmlnode->get_child("recenttracks")->get_child("track");
+		if ( $trackXmlnode->get_attrib("nowplaying") ) {
+			# now playing
+			$cur_artist = $trackXmlnode->get_child("artist")->get_data();
+			$cur_title = $trackXmlnode->get_child("name")->get_data();
+			$cur_album = $trackXmlnode->get_child("album")->get_data();
+			$cur_date = $trackXmlnode->get_child("date")->get_attrib("uts");
+			dbg_msg("artist: " . $cur_artist);
+			dbg_msg("name: " . $cur_title);
+			dbg_msg("album: " . $cur_album);
+			dbg_msg("date: " . $cur_date);
+			Purple::Util::set_current_song( $cur_title, $cur_artist, $cur_album);
+		} else {
+			# no music is playing
+			# TODO something need to take care in this situation
+			dbg_msg("no music is playing");
+			Purple::Util::set_current_song( "", "", "");
+		}
+	} elsif ( $lfmStatus == "failed") {
+		dbg_msg("web query status: failed");
+	} else {
+		dbg_msg( "unkown web query status:" . $lfmStatus);
+	}
+}
+
+sub dbg_msg {
+	Purple::Debug::info( "yulastfm: ", $_[0] . "\n");
+}
+