You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdepim/kmobile/kioslave/kio_mobile.cpp

637 lines
17 KiB

/* This file is part of the KDE KMobile library
Copyright (C) 2003 Helge Deller <deller@kde.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License version 2 as published by the Free Software Foundation.
This library 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <time.h>
#include <qregexp.h>
#include <kdebug.h>
#include <klocale.h>
#include <kinstance.h>
#include <kabc/vcardconverter.h>
#include "kio_mobile.h"
#include <kdepimmacros.h>
using namespace KIO;
#define KIO_MOBILE_DEBUG_AREA 7126
#define PRINT_DEBUG kdDebug(KIO_MOBILE_DEBUG_AREA) << "kio_mobile: "
extern "C" { KDE_EXPORT int kdemain(int argc, char **argv); }
/**
* The main program.
*/
int kdemain(int argc, char **argv)
{
KInstance instance( "kio_mobile" );
PRINT_DEBUG << "Starting " << getpid() << endl;
if (argc != 4) {
fprintf(stderr, "Usage kio_mobile protocol pool app\n");
return -1;
}
// let the protocol class do its work
KMobileProtocol slave(argv[2], argv[3]);
slave.dispatchLoop();
PRINT_DEBUG << "Done" << endl;
return 0;
}
/**
* Initialize the mobile slave
*/
KMobileProtocol::KMobileProtocol(const QCString &pool, const QCString &app)
: SlaveBase( "mobile", pool, app)
{
}
KMobileProtocol::~KMobileProtocol()
{
}
/*
* getDeviceAndRessource("mobile:/<devicename>/<resource>/...") - split
*/
int KMobileProtocol::getDeviceAndRessource(const QString &_path,
QString &devName, QString &resource, QString &devPath,
KMobileDevice::Capabilities &devCaps)
{
// PRINT_DEBUG << QString("###getDeviceAndRessource### %1\n").arg(_path);
QStringList path = QStringList::split('/', _path, false);
devName = resource = devPath = QString::null;
devCaps = KMobileDevice::hasNothing;
if (path.count() >= 1) { devName = path[0]; path.pop_front(); };
if (path.count() >= 1) { resource = path[0]; path.pop_front(); };
if (path.count() >= 1) devPath = path.join("/");
if (devName.isEmpty())
return 0;
int _caps = m_dev.capabilities(devName);
if (resource.isEmpty()) {
devCaps = (KMobileDevice::Capabilities) _caps;
return 0;
}
for (int i=0; i<31; i++) {
int cap = 1UL << i;
if ((_caps & cap) == 0)
continue;
QString capname = m_dev.nameForCap(devName,cap);
if (capname != resource)
continue;
devCaps = (KMobileDevice::Capabilities) cap;
return 0;
}
return KIO::ERR_DOES_NOT_EXIST;
}
static
void addAtom(KIO::UDSEntry& entry, unsigned int ID, long l, const QString& s = QString::null)
{
KIO::UDSAtom atom;
atom.m_uds = ID;
atom.m_long = l;
atom.m_str = s;
entry.append(atom);
}
static
void createDirEntry(KIO::UDSEntry& entry, const QString& name, const QString& url, const QString& mime)
{
entry.clear();
addAtom(entry, KIO::UDS_NAME, 0, name);
addAtom(entry, KIO::UDS_FILE_TYPE, S_IFDIR);
addAtom(entry, KIO::UDS_ACCESS, 0500);
addAtom(entry, KIO::UDS_MIME_TYPE, 0, mime);
addAtom(entry, KIO::UDS_URL, 0, url);
addAtom(entry, KIO::UDS_USER, 0, getenv("USER"));
addAtom(entry, KIO::UDS_GROUP, 0, getenv("USER"));
PRINT_DEBUG << QString("createDirEntry: File: %1 MIME: %2 URL: %3\n").arg(name).arg(mime).arg(url);
// addAtom(entry, KIO::UDS_SIZE, 0);
addAtom(entry, KIO::UDS_GUESSED_MIME_TYPE, 0, mime);
}
static
void createFileEntry(KIO::UDSEntry& entry, const QString& name, const QString& url, const QString& mime,
const unsigned long size = 0)
{
entry.clear();
addAtom(entry, KIO::UDS_NAME, 0, name);
addAtom(entry, KIO::UDS_FILE_TYPE, S_IFREG);
addAtom(entry, KIO::UDS_URL, 0, url);
addAtom(entry, KIO::UDS_ACCESS, 0400);
addAtom(entry, KIO::UDS_USER, 0, getenv("USER"));
addAtom(entry, KIO::UDS_GROUP, 0, getenv("USER"));
addAtom(entry, KIO::UDS_MIME_TYPE, 0, mime);
if (size) addAtom(entry, KIO::UDS_SIZE, size);
addAtom(entry, KIO::UDS_GUESSED_MIME_TYPE, 0, mime);
PRINT_DEBUG << QString("createFileEntry: File: %1, Size: %2, MIME: %3\n").arg(name).arg(size).arg(mime);
}
/**
* Get the information contained in the URL.
*/
void KMobileProtocol::get(const KURL &url)
{
PRINT_DEBUG << "###############################\n";
PRINT_DEBUG << QString("get(%1)\n").arg(url.path());
KMobileDevice::Capabilities devCaps;
QString devName, resource, devPath;
int err = getDeviceAndRessource(url.path(), devName, resource, devPath, devCaps);
if (err) {
error(err, url.path());
return;
}
if (devName.isEmpty() || resource.isEmpty()) {
error(KIO::ERR_DOES_NOT_EXIST, url.path());
return;
}
// collect the result
QCString result;
QString mime;
switch (devCaps) {
case KMobileDevice::hasAddressBook: err = getVCard(devName, result, mime, devPath);
break;
case KMobileDevice::hasCalendar: err = getCalendar(devName, result, mime, devPath);
break;
case KMobileDevice::hasNotes: err = getNote(devName, result, mime, devPath);
break;
case KMobileDevice::hasFileStorage: err = getFileStorage(devName, result, mime, devPath);
break;
default: err = KIO::ERR_CANNOT_ENTER_DIRECTORY; /* TODO */
}
if (err) {
error(err, url.path());
return;
}
// tell the mimetype
mimeType(mime);
// tell the length
KIO::filesize_t processed_size = result.length();
totalSize(processed_size);
// tell the contents of the URL
QByteArray array;
array.setRawData( result.data(), result.length() );
data(array);
array.resetRawData( result.data(), result.length() );
processedSize( processed_size );
// tell we are finished
data(QByteArray());
// tell we are finished
finished();
}
/*
* listRoot() - gives listing of all devices
*/
void KMobileProtocol::listRoot(const KURL& url)
{
PRINT_DEBUG << QString("########## listRoot(%1) for %2:/\n").arg(url.path()).arg(url.protocol());
KIO::UDSEntry entry;
QStringList deviceNames = m_dev.deviceNames();
unsigned int dirs = deviceNames.count();
totalSize(dirs);
int classMask = KMobileDevice::Unclassified;
/* handle all possible protocols here and just add a <protocol>.protocol file */
if (url.protocol() == "cellphone") // cellphone:/
classMask = KMobileDevice::Phone;
if (url.protocol() == "organizer" || // organizer:/
url.protocol() == "pda") // pda:/
classMask = KMobileDevice::Organizer;
if (url.protocol() == "phonecamera") // camera:/
classMask = KMobileDevice::Camera;
for (unsigned int i=0; i<dirs; i++) {
QString devName = deviceNames[i];
if (classMask != KMobileDevice::Unclassified &&
m_dev.classType(devName) != classMask)
continue;
createDirEntry(entry, devName, "mobile:/"+devName,
KMOBILE_MIMETYPE_DEVICE_KONQUEROR(devName));
listEntry(entry, false);
processedSize(i+1);
}
listEntry(entry, true);
finished();
}
/*
* folderMimeType() - returns mimetype of the folder itself
*/
QString KMobileProtocol::folderMimeType(int cap)
{
QString mimetype;
switch (cap) {
case KMobileDevice::hasAddressBook: mimetype = KMOBILE_MIMETYPE_INODE "addressbook";
break;
case KMobileDevice::hasCalendar: mimetype = KMOBILE_MIMETYPE_INODE "calendar";
break;
case KMobileDevice::hasNotes: mimetype = KMOBILE_MIMETYPE_INODE "notes";
break;
case KMobileDevice::hasFileStorage:
default: mimetype = "inode/directory";
}
return mimetype;
}
/*
* entryMimeType() - returns mimetype of the entries in the given folder
*/
QString KMobileProtocol::entryMimeType(int cap)
{
QString mimetype;
switch (cap) {
case KMobileDevice::hasAddressBook: mimetype = "text/x-vcard";
break;
case KMobileDevice::hasCalendar: mimetype = "text/x-vcalendar";
break;
case KMobileDevice::hasNotes: mimetype = "text/plain";
break;
case KMobileDevice::hasFileStorage:
default: mimetype = "text/plain";
}
return mimetype;
}
/*
* listTopDeviceDir("mobile:/<devicename>") - sub-directory of a devices
*/
void KMobileProtocol::listTopDeviceDir(const QString &devName)
{
PRINT_DEBUG << QString("listTopDeviceDir(%1)\n").arg(devName);
KIO::UDSEntry entry;
unsigned int caps = m_dev.capabilities(devName);
for (int i=0; i<31; i++) {
unsigned int cap = 1UL<<i;
if ((caps & cap) == 0)
continue;
QString filename = m_dev.nameForCap(devName, cap);
QString mimetype = folderMimeType(cap);
createDirEntry(entry, filename, QString("mobile:/%1/%2/").arg(devName).arg(filename), mimetype);
listEntry(entry, false);
}
listEntry(entry, true);
finished();
}
/*
* listEntries("mobile:/<devicename>/<resource>") - resources of a device
*/
void KMobileProtocol::listEntries(const QString &devName,
const QString &resource, const QString &devPath,
const KMobileDevice::Capabilities devCaps)
{
PRINT_DEBUG << QString("listEntries(%1,%2,%3)\n").arg(devName).arg(resource).arg(devPath);
switch (devCaps) {
case KMobileDevice::hasAddressBook: listAddressBook(devName, resource);
break;
case KMobileDevice::hasCalendar: listCalendar(devName, resource);
break;
case KMobileDevice::hasNotes: listNotes(devName, resource);
break;
case KMobileDevice::hasFileStorage: listFileStorage(devName, resource, devPath);
break;
default: error( ERR_CANNOT_ENTER_DIRECTORY,
QString("/%1/%2").arg(devName).arg(resource) );
}
}
/*
* listAddressBook("mobile:/<devicename>/Addressbook) - list the addressbook
*/
void KMobileProtocol::listAddressBook(const QString &devName, const QString &resource)
{
PRINT_DEBUG << QString("listAddressBook(%1)\n").arg(devName);
KIO::UDSEntry entry;
int fieldwidth;
int entries = m_dev.numAddresses(devName);
if (entries>=1000) fieldwidth=4; else
if (entries>=100) fieldwidth=3; else
if (entries>=10) fieldwidth=2; else fieldwidth=1;
totalSize(entries);
// QRegExp rx; rx.setPattern( ".*FN:([\\w\\s]*)[\\n\\r]{2}.*" );
QString name;
for (int i=0; i<entries; i++) {
#if 0
QString content = m_dev.readAddress(devName, i);
if ( rx.search( content ) < 0 )
name = QString::null;
else
name = "_" + rx.cap(1);
#endif
QString filename = QString("%1%2.vcf").arg(i,fieldwidth).arg(name);
for (int p=0; p<fieldwidth; p++) {
if (filename[p]==' ') filename[p]='0'; else break;
}
QString url = QString("mobile:/%1/%2/%3").arg(devName).arg(resource).arg(filename);
createFileEntry(entry, filename, url, entryMimeType(KMobileDevice::hasAddressBook),
400 /*content.utf8().length()*/ );
listEntry(entry, false);
processedSize(i+1);
}
listEntry(entry, true);
finished();
}
/*
* getVCard() - gives the vCard of the given file
*/
int KMobileProtocol::getVCard( const QString &devName, QCString &result, QString &mime, const QString &path )
{
PRINT_DEBUG << QString("getVCard(%1)\n").arg(path);
int index = path.find('.');
if (index>0)
index = path.left(index).toInt();
if (index<0 || index>=m_dev.numAddresses(devName))
return KIO::ERR_DOES_NOT_EXIST;
QString str = m_dev.readAddress(devName, index);
if (str.isEmpty())
return KIO::ERR_INTERNAL;
result = str.utf8();
mime = entryMimeType(KMobileDevice::hasAddressBook);
// setMetaData("plugin", "const QString &key, const QString &value);
return 0;
}
/*
* listCalendar("mobile:/<devicename>/Calendar) - list the calendar entries
*/
void KMobileProtocol::listCalendar( const QString &devName, const QString &resource)
{
PRINT_DEBUG << QString("listCalendar(%1)\n").arg(devName);
KIO::UDSEntry entry;
int entries = m_dev.numCalendarEntries(devName);
totalSize(entries);
for (int i=0; i<entries; i++) {
QString filename = QString("%1_%2.vcs").arg(i).arg(i18n("calendar"));
QString url = QString("mobile:/%1/%2/%3").arg(devName).arg(resource).arg(filename);
createFileEntry(entry, filename, url, entryMimeType(KMobileDevice::hasCalendar));
listEntry(entry, false);
processedSize(i+1);
}
listEntry(entry, true);
finished();
}
/*
* getCalendar() - reads a calendar entry
*/
int KMobileProtocol::getCalendar( const QString &devName, QCString &result, QString &mime, const QString &path)
{
PRINT_DEBUG << QString("getCalendar(%1, #%2)\n").arg(devName).arg(path);
/* TODO */
Q_UNUSED(result);
Q_UNUSED(mime);
return KIO::ERR_CANNOT_ENTER_DIRECTORY;
}
/*
* listNotes("mobile:/<devicename>/Notes) - list the notes
*/
void KMobileProtocol::listNotes( const QString &devName, const QString &resource)
{
PRINT_DEBUG << QString("listNotes(%1)\n").arg(devName);
KIO::UDSEntry entry;
int entries = m_dev.numNotes(devName);
totalSize(entries);
for (int i=0; i<entries; i++) {
QString note /*= m_dev.readNote(devName, i)*/;
QString filename = QString("%1_%2.txt").arg(i).arg(i18n("note"));
QString url = QString("mobile:/%1/%2/%3").arg(devName).arg(resource).arg(filename);
createFileEntry(entry, filename, url, entryMimeType(KMobileDevice::hasNotes),
0 /*note.utf8().length()*/);
listEntry(entry, false);
processedSize(i+1);
}
listEntry(entry, true);
finished();
}
/*
* getNote() - gives the Note of the given file
*/
int KMobileProtocol::getNote( const QString &devName, QCString &result, QString &mime, const QString &path )
{
PRINT_DEBUG << QString("getNote(%1)\n").arg(path);
int index = path.find('_');
if (index>0)
index = path.left(index).toInt();
if (index<0 || index>=m_dev.numNotes(devName))
return KIO::ERR_DOES_NOT_EXIST;
QString note = m_dev.readNote(devName, index);
if (note.isEmpty())
return KIO::ERR_DOES_NOT_EXIST;
result = note.utf8();
mime = entryMimeType(KMobileDevice::hasNotes);
return 0;
}
/*
* listFileStorage("mobile:/<devicename>/Files) - list the files on the device
*/
void KMobileProtocol::listFileStorage(const QString &devName, const QString &resource, const QString &devPath)
{
PRINT_DEBUG << QString("listFileStorage(%1,%2)\n").arg(devName).arg(devPath);
/* TODO */
error( KIO::ERR_DOES_NOT_EXIST, QString("/%1/%2/%3").arg(devName).arg(resource).arg(devPath) );
}
/*
* getFileStorage() - gives the file contents of the given file
*/
int KMobileProtocol::getFileStorage(const QString &devName, QCString &result, QString &mime, const QString &path)
{
PRINT_DEBUG << QString("getFileStorage(%1)\n").arg(path);
/* TODO */
Q_UNUSED(devName);
Q_UNUSED(result);
Q_UNUSED(mime);
return KIO::ERR_CANNOT_ENTER_DIRECTORY;
}
/**
* Test if the url contains a directory or a file.
*/
void KMobileProtocol::stat( const KURL &url )
{
PRINT_DEBUG << "###############################\n";
PRINT_DEBUG << QString("stat(%1)\n").arg(url.path());
KMobileDevice::Capabilities devCaps;
QString devName, resource, devPath;
int err = getDeviceAndRessource(url.path(), devName, resource, devPath, devCaps);
if (err) {
error(err, url.path());
return;
}
QStringList path = QStringList::split('/', url.path(), false);
QString filename = (path.count()>0) ? path[path.count()-1] : "/";
QString fullPath = path.join("/");
QString fullUrl = QString("mobile:/%1").arg(fullPath);
UDSEntry entry;
bool isDir = devPath.isEmpty();
if (isDir) {
createDirEntry(entry, filename, fullUrl, folderMimeType(devCaps));
} else {
createFileEntry(entry, filename, fullUrl, entryMimeType(devCaps));
}
statEntry(entry);
finished();
}
/**
* Get the mimetype.
*/
void KMobileProtocol::mimetype(const KURL &url)
{
PRINT_DEBUG << "###############################\n";
PRINT_DEBUG << QString("mimetype(%1)\n").arg(url.path());
KMobileDevice::Capabilities devCaps;
QString devName, resource, devPath;
int err = getDeviceAndRessource(url.path(), devName, resource, devPath, devCaps);
if (err) {
error(err, url.path());
return;
}
// tell the mimetype
mimeType(entryMimeType(devCaps));
finished();
}
/**
* List the contents of a directory.
*/
void KMobileProtocol::listDir(const KURL &url)
{
PRINT_DEBUG << "###############################\n";
PRINT_DEBUG << QString("listDir(%1)\n").arg(url.path());
if (!m_dev.isKMobileAvailable()) {
error( KIO::ERR_CONNECTION_BROKEN, i18n("KDE Mobile Device Manager") );
return;
}
KMobileDevice::Capabilities devCaps;
QString devName, resource, devPath;
int err = getDeviceAndRessource(url.path(), devName, resource, devPath, devCaps);
if (err) {
error(err, url.path());
return;
}
if (devName.isEmpty()) {
listRoot(url);
return;
}
#if 0
if (!dev) {
error( KIO::ERR_DOES_NOT_EXIST, QString("/%1").arg(devName) );
return;
}
#endif
if (resource.isEmpty()) {
listTopDeviceDir(devName);
return;
}
listEntries(devName, resource, devPath, devCaps);
}