1//
2// This file is part of the aMule Project.
3//
4// Copyright (c) 2010-2011 Werner Mahr (Vollstrecker) <amule@vollstreckernet.de>
5//
6// Any parts of this program contributed by third-party developers are copyrighted
7// by their respective authors.
8//
9// This program is free software; you can redistribute it and/or modify
10// it under the terms of the GNU General Public License as published by
11// the Free Software Foundation; either version 3 of the License, or
12// (at your option) any later version.
13//
14// This program is distributed in the hope that it will be useful,
15// but WITHOUT ANY WARRANTY; without even the implied warranty of
16// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17// GNU General Public License for more details.
18//
19// You should have received a copy of the GNU General Public License
20// along with this program; if not, write to the Free Software
21// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA
22//
23
24#include "plasma-engine-plasmamule.h"
25#include "qt-emc.h"
26
27#include <kdebug.h>
28#include <knotification.h>
29
30#include <kio/scheduler.h>
31
32#include <plasma/datacontainer.h>
33
34#include <QDir>
35#include <QTimer>
36
37#include <QtDBus/QDBusInterface>
38
39PlasmaMuleEngine::PlasmaMuleEngine (QObject* parent, const QVariantList& args)
40	: Plasma::DataEngine (parent, args)
41{
42	Q_UNUSED (args)
43	setMinimumPollingInterval (0);
44}
45
46bool PlasmaMuleEngine::sourceRequestEvent (const QString &name)
47{
48	return updateSourceEvent (name);
49}
50
51QStringList PlasmaMuleEngine::sources() const
52{
53	return QStringList() << "cat_dirs"
54		<< "cat_names"
55		<< "clients_in_up_queue"
56		<< "config_found"
57		<< "down_speed"
58		<< "ed2k_state"
59		<< "ed2k_server_name"
60		<< "ed2k_server_ip"
61		<< "ed2k_server_port"
62		<< "ed2k_id_high_low"
63		<< "kad_status"
64		<< "nickname"
65		<< "os_active"
66		<< "session_bytes_downloaded"
67		<< "session_bytes_uploaded"
68		<< "shared_files_count"
69		<< "total_bytes_downloaded"
70		<< "total_bytes_uploaded"
71		<< "up_speed"
72		<< "uptime"
73		<< "version";
74}
75
76void PlasmaMuleEngine::init ()
77{
78	Home = QDir::homePath();
79
80	QTimer *timer = new QTimer(this);
81	connect(timer, SIGNAL(timeout()), this, SLOT(timeout()));
82	timer->start(60000);
83	m_timer = TRUE;
84	setData(I18N_NOOP("uptime"), 0);
85
86	if (!Home.endsWith("/"))
87	{
88		Home += "/";
89	}
90
91	m_debugChannel = KDebug::registerArea ("plasmamule-engine",
92#ifdef __DEBUG__
93	true
94#else
95	false
96#endif
97	);
98
99	regDbus();
100	initVals();
101}
102
103void PlasmaMuleEngine::regDbus ()
104{
105	new EngineAdaptor(this);
106	QDBusConnection dbus = QDBusConnection::sessionBus();
107	dbus.registerObject("/Link", this);
108	kDebug(m_debugChannel) << "Registerred dbus: " << dbus.registerService("org.amule.engine");
109}
110
111void PlasmaMuleEngine::downloadFinished (KIO::Job* job,const QByteArray& data)
112{
113
114	if (data.length() == 0)
115	{
116		KNotification::event(KNotification::Notification, QString("Download of %1 failed.").arg(job->queryMetaData("Name")));
117		return;
118	}
119
120	kDebug(m_debugChannel) << QString("Finished download of %1").arg(job->queryMetaData("Name"));
121
122	QString downloadFileName(QString("/tmp/plasmamule-download-%1.emulecollection").arg(qrand()));
123
124	QFile downloadFile(downloadFileName);
125
126	if (!downloadFile.open (QIODevice::WriteOnly | QIODevice::Append))
127	{
128		KNotification::event(KNotification::Notification, QString("%1 can't be written to temp-file.").arg(job->queryMetaData("Name")));
129		return;
130	}
131
132	QDataStream out(&downloadFile);
133	out.writeRawData(data, data.length());
134	downloadFile.close();
135
136	engine_add_link (downloadFileName, job->queryMetaData("Category").toInt(), job->queryMetaData("Name"));
137
138	downloadFile.remove();
139}
140
141void PlasmaMuleEngine::engine_add_link (const QString &link, const int &category, const QString &printname)
142{
143	kDebug(m_debugChannel) << "Received Link " << link << " with cat " << category;
144
145	QString link_to_write;
146
147
148	if (link.startsWith("ed2k:") || link.startsWith("magnet:"))
149	{
150		link_to_write = link;
151
152		if (category > 0)
153		{
154			link_to_write.append(QString(":%1").arg(category));
155		}
156
157		link_to_write.append("\n");
158	} else if (link.contains(".emulecollection") && KUrl(link).isLocalFile())
159	{
160		qtEmc* collection = new qtEmc(link);
161		if (collection->isValid())
162		{
163			QStringList links = collection->getLinks();
164			for (QStringList::const_iterator constIterator = links.constBegin(); constIterator != links.constEnd(); constIterator++)
165			{
166				link_to_write.append(*constIterator);
167
168				if (category > 0)
169				{
170					link_to_write.append(QString(":%1").arg(category));
171				}
172
173				link_to_write.append("\n");
174			}
175		} else {
176			KNotification::event(KNotification::Notification, collection->getErrorMessage());
177		}
178
179		delete collection;
180	} else {
181		KIO::TransferJob *job = KIO::get(KUrl(link));
182		job->addMetaData("Name", link);
183		job->addMetaData("Category", QString(category));
184		connect (job, SIGNAL(data(KIO::Job *, const QByteArray&)), this,
185			SLOT(downloadFinished(KIO::Job *,const QByteArray&)));
186		kDebug(m_debugChannel) << QString("Starting download of %1").arg(printname);
187		return;
188	}
189
190	QFile link_file (Home + ".aMule/ED2KLinks");
191
192	if (!link_file.open (QIODevice::WriteOnly | QIODevice::Append))
193	{
194		KNotification::event(KNotification::Notification, QString("Problem opening %1 for writing").arg(link_file.fileName()));
195		return;
196	}
197
198	QTextStream out (&link_file);
199	out << link_to_write;
200	out.flush();
201	link_file.close();
202
203	KNotification::event(KNotification::Notification, QString("Downloading %1").arg(printname));
204
205}
206
207void PlasmaMuleEngine::initVals ()
208{
209	QStringList catDir;
210	QStringList catName;
211	QStringList tempIncomingDirs;
212	QStringList cleanedIncomingDirs;
213	QStringList::const_iterator constIterator;
214
215	QFile config_file (Home + ".aMule/amule.conf");
216
217	catName.append("Default");
218	if (!config_file.open (QIODevice::ReadOnly | QIODevice::Text))
219	{
220		setData(I18N_NOOP ("config_found"), FALSE);
221		return;
222	}
223
224	QTextStream in (&config_file);
225	while (!in.atEnd())
226	{
227		QString line = in.readLine();
228		if (line.startsWith ("OnlineSignature="))
229		{
230			if (line.remove (0,line.indexOf ("=")+1) == "1")
231			{
232				m_OSActive = TRUE;
233			} else {
234				m_OSActive = FALSE;
235			}
236
237			setData(I18N_NOOP ("os_active"), m_OSActive);
238		} else if (line.contains ("OSDirectory"))
239		{
240			m_OSFile.setFileName(line.remove (0,line.indexOf ("=")+1) + "amulesig.dat");
241
242		} else if (line.contains ("Incoming"))
243		{
244			if (!tempIncomingDirs.contains(line.remove (0,line.indexOf ("=")+1)))
245			{
246				tempIncomingDirs.append(line.remove (0,line.indexOf ("=")+1));
247			}
248
249			catDir.append(line.remove (0,line.indexOf ("=")+1));
250		} else if (line.startsWith ("Title"))
251		{
252			catName.append(line.remove (0,line.indexOf ("=")+1));
253		}
254        }
255
256	setData(I18N_NOOP ("cat_names"), catName);
257	setData(I18N_NOOP ("cat_dirs"), catDir);
258
259	if (m_OSActive && !m_dirwatcher.contains(m_OSFile.fileName()))
260	{
261		kDebug(m_debugChannel) << "Registering: " << m_OSFile.fileName() << " for monitoring";
262		m_dirwatcher.addFile (m_OSFile.fileName());
263		connect (&m_dirwatcher, SIGNAL (dirty (const QString &)), SLOT (file_changed (const QString&)));
264		connect (&m_dirwatcher, SIGNAL (created (const QString &)), SLOT (new_file (const QString&)));
265	}
266
267	for (constIterator = tempIncomingDirs.constBegin(); constIterator != tempIncomingDirs.constEnd(); constIterator++)
268	{
269		if (!m_dirwatcher.contains(*constIterator))
270		{
271			kDebug(m_debugChannel) << "Registering: " << *constIterator << " for monitoring";
272			cleanedIncomingDirs.append (*constIterator);
273			m_dirwatcher.addDir (*constIterator, KDirWatch::WatchFiles);
274		} else {
275			cleanedIncomingDirs.append (*constIterator);
276		}
277	}
278
279	for (constIterator = m_incoming_dirs.constBegin(); constIterator != m_incoming_dirs.constEnd(); constIterator++)
280	{
281		if (!cleanedIncomingDirs.contains (*constIterator))
282		{
283			kDebug(m_debugChannel) << "Removing " << *constIterator << " from monitored dirs";
284			m_dirwatcher.removeDir (*constIterator);
285		}
286	}
287
288	m_incoming_dirs = cleanedIncomingDirs;
289	config_file.close ();
290	setName("plasmamule");
291	setData(I18N_NOOP ("config_found"), TRUE);
292	scheduleSourcesUpdated();
293}
294
295void PlasmaMuleEngine::file_changed (const QString &path)
296{
297	if (path == m_OSFile.fileName())
298	{
299		kDebug(m_debugChannel) << "Rereading " << path;
300		updateSourceEvent ("dummy");
301	}
302}
303
304void PlasmaMuleEngine::new_file (const QString &path)
305{
306	if (path != m_OSFile.fileName())
307	{
308		kDebug(m_debugChannel) << "File " << path << "was created";
309		KNotification::event(KNotification::Notification, QString("Finished Download of %1").arg(path));
310	} else {
311		kDebug(m_debugChannel) << "Rereading " << path;
312		updateSourceEvent ("dummy");
313	}
314}
315
316void PlasmaMuleEngine::timeout()
317{
318	initVals();
319}
320
321bool PlasmaMuleEngine::updateSourceEvent(const QString &name)
322{
323	Q_UNUSED (name)
324
325	if (m_OSFile.open (QIODevice::ReadOnly | QIODevice::Text) && m_OSActive)
326	{
327		QTextStream in (&m_OSFile);
328		setData(I18N_NOOP("ed2k_state"), in.readLine().toInt());
329		setData(I18N_NOOP("ed2k_server_name"), in.readLine());
330		setData(I18N_NOOP("ed2k_server_ip"), in.readLine());
331		setData(I18N_NOOP("ed2k_server_port"), in.readLine().toInt());
332		setData(I18N_NOOP("ed2k_id_high_low"), in.readLine());
333		setData(I18N_NOOP("kad_status"), in.readLine().toInt());
334		setData(I18N_NOOP("down_speed"), in.readLine().toDouble());
335		setData(I18N_NOOP("up_speed"), in.readLine().toDouble());
336		setData(I18N_NOOP("clients_in_up_queue"), in.readLine().toInt());
337		setData(I18N_NOOP("shared_files_count"), in.readLine().toInt());
338		setData(I18N_NOOP("nickname"), in.readLine());
339		setData(I18N_NOOP("total_bytes_downloaded"), in.readLine().toLongLong());
340		setData(I18N_NOOP("total_bytes_uploaded"), in.readLine().toLongLong());
341		setData(I18N_NOOP("version"), in.readLine());
342		setData(I18N_NOOP("session_bytes_downloaded"), in.readLine().toLongLong());
343		setData(I18N_NOOP("session_bytes_uploaded"), in.readLine().toLongLong());
344		setData(I18N_NOOP("uptime"), in.readLine().toInt());
345		m_OSFile.close();
346		scheduleSourcesUpdated();
347		return true;
348	} else {
349		return false;
350	}
351}
352
353K_EXPORT_PLASMA_DATAENGINE(plasmamule, PlasmaMuleEngine)
354
355EngineAdaptor::EngineAdaptor(QObject *parent): QDBusAbstractAdaptor(parent)
356{
357	setAutoRelaySignals(true);
358}
359
360EngineAdaptor::~EngineAdaptor()
361{
362}
363
364void EngineAdaptor::engine_add_link(const QString &link, const int &category)
365{
366	QMetaObject::invokeMethod(parent(), "engine_add_link", Q_ARG(QString, link), Q_ARG(int, category), Q_ARG(QString, link));
367}
368
369#include "plasma-engine-plasmamule.moc"
370