Index: app.h
===================================================================
--- app.h	(revision 494593)
+++ app.h	(working copy)
@@ -21,6 +21,7 @@
 #include "amarok_export.h"
 #include "engineobserver.h" //baseclass
 #include <kapplication.h>   //baseclass
+#include "infoplug.h"
 
 namespace amaroK {
     class TrayIcon;
@@ -93,6 +94,7 @@
         PlaylistWindow      *m_pPlaylistWindow;
         amaroK::TrayIcon    *m_pTray;
         DeviceManager       *m_pDeviceManager;
+	InfoPlug            *m_InfoPlug;
 };
 
 #define pApp static_cast<App*>(kapp)
Index: app.cpp
===================================================================
--- app.cpp	(revision 494593)
+++ app.cpp	(working copy)
@@ -70,6 +70,8 @@
 #include <qtimer.h>              //showHyperThreadingWarning()
 #include <qtooltip.h>            //default tooltip for trayicon
 
+#include "infoplug.h"
+
 // For the HyperThreading fix
 #ifdef __linux__
     #ifdef SCHEDAFFINITY_SUPPORT
@@ -147,6 +149,10 @@
     if ( amaroK::config( "ScriptManager" )->readBoolEntry( "Auto Run" ) )
         ScriptManager::instance();
 
+    // ::InfoPlug
+    m_InfoPlug = InfoPlug::instance();
+    m_InfoPlug->starter();
+
     //notify loader application that we have started
     std::cout << "STARTUP\n" << std::flush;
 
@@ -192,6 +198,8 @@
     // Hiding the OSD before exit prevents crash
     amaroK::OSD::instance()->hide();
 
+    m_InfoPlug->shutdown();
+
     EngineBase* const engine = EngineController::engine();
 
     if ( AmarokConfig::resumePlayback() ) {
Index: Makefile.am
===================================================================
--- Makefile.am	(revision 494593)
+++ Makefile.am	(working copy)
@@ -126,7 +126,8 @@
     threadweaver.cpp \
     tracktooltip.cpp \
     trackpickerdialog.cpp \
-    trackpickerdialogbase.ui
+    trackpickerdialogbase.ui \
+    infoplug.cpp
 
 libamarok_la_LIBADD = \
     $(top_builddir)/amarok/src/amarokcore/libamarokcore.la \
--- /dev/null	2005-12-21 14:59:45.000000000 +0100
+++ infoplug.cpp	2006-01-07 03:57:59.796184250 +0100
@@ -0,0 +1,222 @@
+#define DEBUG_PREFIX "InfoPlug"
+
+#include "amarok.h"
+#include "amarokconfig.h"
+#include "collectiondb.h"
+#include "config.h"
+#include "debug.h"
+#include "enginecontroller.h"
+#include "playlist.h"
+#include "infoplug.h"
+#include "statusbar.h"
+#include <fcntl.h>
+#include <sys/poll.h>
+/*
+#include <sys/types.h>
+#include <linux/unistd.h>
+#include <sys/syscall.h>
+#include <errno.h>
+_syscall0(pid_t,gettid)
+*/
+
+InfoPlug* InfoPlug::instance()
+{
+	static InfoPlug infoplug;
+	return &infoplug;
+}
+
+InfoPlug::InfoPlug() :
+	EngineObserver(EngineController::instance()),
+	m_enabled(false),
+	m_sock((int) 0)
+{
+}
+
+void InfoPlug::shutdown()
+{
+	m_enabled = false;
+	while (m_sock) {
+//		printf("======================== Still waiting for socket to shutdown...\n");
+		sleep(5);
+	}
+
+	if (m_sock) {
+		::shutdown(m_sock, SHUT_RDWR);
+		m_sock = false;
+	}
+//	printf("======================== Aborting thread....\n");
+	ThreadWeaver::instance()->abortAllJobsNamed("InfoPlugServer");
+//	printf("======================== Aborted thread....\n");
+}
+
+InfoPlug::~InfoPlug()
+{
+/*	m_enabled = false;
+	while (m_sock) {
+		printf("==================== STILL WAITING FOR THREAD TO SHUTDOWN\n");
+		sleep(1);
+	}
+
+	if (m_sock) {
+		::shutdown(m_sock, SHUT_RDWR);
+		m_sock = false;
+	} */
+}
+
+void InfoPlug::starter()
+{
+	m_enabled = true;
+	ThreadWeaver::instance()->queueJob(new InfoPlugServer(this));
+}
+
+
+InfoPlugServer::InfoPlugServer(InfoPlug* parent) :
+	Job("InfoPlugServer"),
+	m_parent(parent)
+{
+}
+
+InfoPlugServer::~InfoPlugServer()
+{
+	m_parent->m_enabled = false;
+
+	if (m_parent->m_sock) {
+		shutdown(m_parent->m_sock, SHUT_RDWR);
+	}
+}
+
+
+bool InfoPlugServer::doJob()
+{
+	int bind;
+	socklen_t clientAddrLen;
+	struct sockaddr_in clientAddr, serverAddr;
+	struct timeval timeout;
+	QString info;
+	int status, retval, opts;
+	struct pollfd pfd;
+/*	pid_t tid;
+
+	tid = gettid();
+	printf("================== Thread ID: %d\n", tid);
+*/
+	// Reset data
+	char version[100];
+
+	serverAddr.sin_family = AF_INET;
+	serverAddr.sin_addr.s_addr = INADDR_ANY;
+	serverAddr.sin_port = htons(5353);
+
+	if (!m_parent->m_enabled) {
+		return false;
+	}
+
+	m_parent->m_sock = ::socket(PF_INET, SOCK_DGRAM, 0);
+
+	if (m_parent->m_sock == -1) {
+		warning() << "InfoPlug: socket errno: " << errno << endl;
+		return false;
+	}
+
+	bind = ::bind(m_parent->m_sock, (struct sockaddr*) &serverAddr, sizeof(serverAddr));
+	if (bind == -1) {
+		warning() << "InfoPlug: bind errno: " << errno << endl;
+		return false;
+	}
+
+	opts = fcntl(m_parent->m_sock, F_GETFL);
+	if (opts < 0) {
+		perror("fcntl(F_GETFL)");
+	}
+	fcntl(m_parent->m_sock, F_SETFL, O_ASYNC | O_NONBLOCK);
+	pfd.fd = m_parent->m_sock;
+	pfd.events = POLLIN;
+
+	while(true)
+	{
+		if (!m_parent->m_enabled) {
+//			printf("======================== InfoPipe disabled.. \n");
+			if (m_parent->m_sock) {
+				::shutdown(m_parent->m_sock, SHUT_RDWR);
+				m_parent->m_sock = false;
+			}
+			return false;
+		} else {
+			timeout.tv_sec = 1;
+			timeout.tv_usec = 0;
+			info = "";
+
+			clientAddrLen = sizeof(clientAddr);
+
+			retval = poll(&pfd, 1, 1000);
+			if (retval < 0) {
+				perror("poll()");
+			} else if (retval) {
+
+				if (recvfrom(m_parent->m_sock, NULL, 0, 0, (struct sockaddr *) &clientAddr, &clientAddrLen) == -1) {
+					warning() << "InfoPlug: recvfrom errno: " << errno << endl;
+					sleep(1);
+				} else {
+					warning() << "============== InfoPlug: connection from: " << inet_ntoa(clientAddr.sin_addr) << endl;
+
+					/*
+					 * Collect data here and put it in data.
+					 */
+					const MetaBundle &bundle = EngineController::instance()->bundle();
+					QueryBuilder qb;
+					qb.addReturnValue(QueryBuilder::tabStats, QueryBuilder::valPlayCounter);
+					qb.addMatches(QueryBuilder::tabStats, bundle.url().path());
+
+					snprintf(version, 100, "Interface: InfoPlug\nVersion: %d.%d\n", INFOPLUG_VERSION_MA, INFOPLUG_VERSION_MI);
+					info.append(version);
+				
+					status = EngineController::engine()->state();
+					if (status == Engine::Playing) info.append("\nStatus: Playing\n"); // snprintf(plStatus, 1000, "Status: Playing\n");
+					else if (status == Engine::Paused) info.append("\nStatus: Playing\n"); // snprintf(plStatus, 1000, "Status: Paused\n");
+					else info.append("\nStatus: Stopped\n"); // snprintf(plStatus, 1000, "Status: Stopped\n");
+
+					if (status == Engine::Playing || status == Engine::Paused) {
+						info += "Artist: "+			bundle.artist();
+						info += "\nTitle: "+		bundle.title();
+						info += "\nAlbum: "+		bundle.album();
+						info += "\nTrack: "+		bundle.track() ? QString::number(bundle.track()) : QString::null;
+						info += "\nTotal Time: "+	bundle.prettyLength();
+						info += "\nCurrent Time: "+	bundle.prettyLength(EngineController::engine()->position()/1000, true);
+						info += "\nGenre: "+		bundle.genre();
+						info += "\nYear: "+			QString::number(bundle.year());
+						info += "\nComment: "+		bundle.comment();
+						info += "\nBitrate: "+		bundle.prettyBitrate();
+//						info += "\nSample Rate: "+	QString::number(bundle.sampleRate());
+						info += "\nSample Rate: "+	bundle.prettySampleRate();
+						info += "\nScore: "+		QString::number(CollectionDB::instance()->getSongPercentage(bundle.url().path()));
+						info += "\nPlay Count: "+	QString::number(qb.run().first().toInt());
+						info += "\nLast Played: "+	amaroK::verboseTimeSince(bundle.lastPlay());
+						info += "\nVolume: "+		QString::number(EngineController::engine()->volume());
+						info += "\nURL: "+			bundle.url().url();
+						info += "\nCover Image: "+	CollectionDB::instance()->albumImage(bundle.artist(), bundle.album(), 0);
+					}
+	
+					if (sendto(m_parent->m_sock, info.utf8(), info.length() + 1, 0,
+							(struct sockaddr *) &clientAddr, sizeof(clientAddr)) == -1) {
+						warning() << "InfoPlug: sendto errno: " << errno << endl;
+					}
+				} /* recvfrom */
+			} else {
+//				printf("============== Poll timed out..\n");
+				/* Timeout */
+			} /* for poll */
+		} /* Was enabled */
+	} /* While-loop */
+
+	return true;
+}
+
+void InfoPlugServer::completeJob()
+{
+	if (m_parent->m_sock) {
+		::shutdown(m_parent->m_sock, SHUT_RDWR);
+		m_parent->m_sock = false;
+	}
+}
+
+#include "infoplug.moc"
--- /dev/null	2005-12-21 14:59:45.000000000 +0100
+++ infoplug.h	2006-01-07 03:58:08.588733750 +0100
@@ -0,0 +1,49 @@
+#ifndef AMAROK_INFOPLUG_H
+#define AMAROK_INFOPLUG_H
+
+#define INFOPLUG_VERSION_MA 0
+#define INFOPLUG_VERSION_MI 3
+
+
+#include "engineobserver.h"
+#include "threadweaver.h"
+
+#include <qobject.h>
+#include <qptrdict.h>
+#include <qptrlist.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <arpa/inet.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <errno.h>
+
+
+//some setups require this
+#undef PROTOCOL_VERSION
+
+class InfoPlug : public QObject, public EngineObserver
+{
+	Q_OBJECT
+
+	public:
+		static InfoPlug *instance();
+		InfoPlug();
+		~InfoPlug();
+		void starter();
+		void shutdown();
+		bool m_enabled;
+		int m_sock;
+};
+
+class InfoPlugServer : public ThreadWeaver::Job, public EngineObserver
+{
+	public:
+		InfoPlugServer(InfoPlug* parent);
+		~InfoPlugServer();
+		virtual bool doJob();
+		virtual void completeJob();
+		InfoPlug* m_parent;
+};
+#endif /* AMAROK_INFOPLUG_H */
