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/kmobiledevice.cpp

471 lines
12 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 <errno.h>
#include <signal.h>
#include <fcntl.h>
#include <tqstring.h>
#include <tqstringlist.h>
#include <tqfile.h>
#include <klibloader.h>
#include <kstandarddirs.h>
#include "kmobiledevice.h"
#include <kmessagebox.h>
#include <kconfig.h>
#include <kio/global.h>
#include <kdebug.h>
#include <klocale.h>
#define KMOBILEDEVICE_DEBUG_AREA 5730
#define PRINT_DEBUG kdDebug(KMOBILEDEVICE_DEBUG_AREA) << "KMobileDevice: "
/**
* The base plugin class of all mobile device drivers.
*/
KMobileDevice::KMobileDevice(TQObject *obj, const char *name, const TQStringList &args)
: KLibFactory(obj,name),
m_config(0L), d(0L)
{
setClassType(Unclassified);
setCapabilities(hasNothing);
m_deviceName = i18n("Unknown Device");
m_deviceRevision = i18n("n/a"); /* not available */
m_connectionName = i18n("Unknown Connection");
// set the config file name
m_configFileName = args[0];
if (m_configFileName.isEmpty())
m_config = new KConfig();
else
m_config = new KConfig(m_configFileName);
PRINT_DEBUG << TQString("name of config file is %1\n").arg(m_configFileName);
}
KMobileDevice::~KMobileDevice()
{
delete m_config;
}
bool KMobileDevice::connected()
{
return m_connected;
}
// returns e.g. "Nokia mobile phone", "MP3 Player", "Handspring Organizer"
TQString KMobileDevice::deviceClassName() const
{
return m_deviceClassName;
}
// returns real device name, e.g. "Nokia 6310" or "Rio MP3 Player"
TQString KMobileDevice::deviceName() const
{
return m_deviceName;
}
TQString KMobileDevice::revision() const
{
return m_deviceRevision;
}
bool KMobileDevice::isSlowDevice() const
{
return false;
}
bool KMobileDevice::isReadOnly() const
{
return false;
}
bool KMobileDevice::configDialog( TQWidget *parent )
{
KMessageBox::information( parent,
i18n("This device does not need any configuration."),
deviceName() );
return true;
}
void KMobileDevice::setClassType( enum ClassType ct )
{
m_classType = ct;
m_deviceClassName = defaultClassName(ct);
}
enum KMobileDevice::ClassType KMobileDevice::classType() const
{
return m_classType;
}
TQString KMobileDevice::iconFileName() const
{
return defaultIconFileName( classType() );
}
TQString KMobileDevice::defaultIconFileName( ClassType ct )
{
TQString name;
switch (ct) {
case Phone: name = "mobile_phone"; break;
case Organizer: name = "mobile_organizer"; break;
case Camera: name = "mobile_camera"; break;
case MusicPlayer: name = "mobile_mp3player"; break;
case Unclassified:
default: name = KMOBILE_ICON_UNKNOWN; break;
}
return name;
}
TQString KMobileDevice::defaultClassName( ClassType ct )
{
TQString name;
switch (ct) {
case Phone: name = i18n("Cellular Mobile Phone"); break;
case Organizer: name = i18n("Organizer"); break;
case Camera: name = i18n("Digital Camera"); break;
case MusicPlayer: name = i18n("Music/MP3 Player"); break;
case Unclassified:
default: name = i18n("Unclassified Device"); break;
}
return name;
}
void KMobileDevice::setCapabilities( int caps )
{
m_caps = caps;
}
int KMobileDevice::capabilities() const
{
return m_caps;
}
const TQString KMobileDevice::nameForCap(int cap) const
{
switch (cap) {
case hasAddressBook: return i18n("Contacts");
case hasCalendar: return i18n("Calendar");
case hasNotes: return i18n("Notes");
case hasFileStorage: return i18n("Files");
default: return i18n("Unknown");
}
}
// returns an error string for the given error code
TQString KMobileDevice::buildErrorString(KIO::Error err, const TQString &errorText) const
{
return KIO::buildErrorString( err, errorText);
}
/*
* Addressbook / Phonebook support
*/
int KMobileDevice::numAddresses()
{
return 0;
}
int KMobileDevice::readAddress( int, KABC::Addressee & )
{
return KIO::ERR_UNSUPPORTED_ACTION;
}
int KMobileDevice::storeAddress( int, const KABC::Addressee &, bool )
{
return KIO::ERR_UNSUPPORTED_ACTION;
}
/*
* Calendar support
*/
int KMobileDevice::numCalendarEntries()
{
return 0;
}
int KMobileDevice::readCalendarEntry( int, KCal::Event & )
{
return KIO::ERR_UNSUPPORTED_ACTION;
}
int KMobileDevice::storeCalendarEntry( int, const KCal::Event & )
{
return KIO::ERR_UNSUPPORTED_ACTION;
}
/*
* Notes support
*/
int KMobileDevice::numNotes()
{
return 0;
}
int KMobileDevice::readNote( int, TQString & )
{
return KIO::ERR_UNSUPPORTED_ACTION;
}
int KMobileDevice::storeNote( int, const TQString & )
{
return KIO::ERR_UNSUPPORTED_ACTION;
}
/*
* File storage support
* @param fileName path and name of a file in the mobile device, e.g. "/MYFILE.TXT", "/mp3/song1.mp3"
*/
static
void addAtom(KIO::UDSEntry& entry, unsigned int ID, long l, const TQString& s = TQString::null)
{
KIO::UDSAtom atom;
atom.m_uds = ID;
atom.m_long = l;
atom.m_str = s;
entry.append(atom);
}
void KMobileDevice::createDirEntry(KIO::UDSEntry& entry, const TQString& name, const TQString& url, const TQString& mime) const
{
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);
PRINT_DEBUG << TQString("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);
}
void KMobileDevice::createFileEntry(KIO::UDSEntry& entry, const TQString& name, const TQString& url, const TQString& mime,
const unsigned long size) const
{
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_MIME_TYPE, 0, mime);
if (size) addAtom(entry, KIO::UDS_SIZE, size);
addAtom(entry, KIO::UDS_GUESSED_MIME_TYPE, 0, mime);
PRINT_DEBUG << TQString("createFileEntry: File: %1, Size: %2, MIME: %3\n").arg(name).arg(size).arg(mime);
}
void KMobileDevice::listDir( const TQString & )
{
emit error(KIO::ERR_CANNOT_ENTER_DIRECTORY,TQString::null);
}
void KMobileDevice::mkdir( const TQString &, int )
{
emit error(KIO::ERR_COULD_NOT_MKDIR, TQString::null);
}
void KMobileDevice::rename( const TQString &, const TQString &, bool )
{
emit error(KIO::ERR_UNSUPPORTED_ACTION, TQString::null);
}
void KMobileDevice::symlink( const TQString &, const TQString &, bool )
{
emit error(KIO::ERR_UNSUPPORTED_ACTION, TQString::null);
}
void KMobileDevice::del( const TQString &, bool )
{
emit error(KIO::ERR_UNSUPPORTED_ACTION, TQString::null);
}
void KMobileDevice::stat( const TQString & )
{
emit error(KIO::ERR_UNSUPPORTED_ACTION, TQString::null);
}
void KMobileDevice::chmod( const TQString &, int )
{
emit error(KIO::ERR_UNSUPPORTED_ACTION, TQString::null);
}
void KMobileDevice::get( const TQString & )
{
emit error(KIO::ERR_UNSUPPORTED_ACTION, TQString::null);
}
void KMobileDevice::put( const TQString &, int, bool, bool )
{
emit error(KIO::ERR_UNSUPPORTED_ACTION, TQString::null);
}
void KMobileDevice::mimetype( const TQString & )
{
emit error(KIO::ERR_UNSUPPORTED_ACTION, TQString::null);
}
void KMobileDevice::special( const TQByteArray & )
{
emit error(KIO::ERR_UNSUPPORTED_ACTION, TQString::null);
}
/*
* device locking/unlocking functions
*/
#ifdef HAVE_BAUDBOY_H
// Header shipped with newer RedHat distributions.
// We have to use this here, because /var/lock is owned by root:lock
// and no one is in this group. Only the binary /usr/sbin/lockdev is
// owned by this group and has the setgid flag set. This binary is called
// in ttylock etc ...
# include <sys/types.h>
# include <sys/stat.h>
# include <fcntl.h>
# include <baudboy.h>
# include <cstdlib>
#else
# ifdef HAVE_LOCKDEV_H
// Library shipped with newer RedHat and Debian(?) distributions.
// Use this if bauddev is not available.
# include <lockdev.h>
# include <sys/types.h>
# include <unistd.h>
# else
// If lockdev.h is also unavailable do locking
// like described in the serial HOWTO.
# include <sys/types.h>
# include <sys/stat.h>
# include <unistd.h>
# include <tqfile.h>
# include <signal.h>
# include <errno.h>
# endif
#endif
#define DEVICE_LOCK_PATH_PREFIX "/var/lock/LCK.."
bool KMobileDevice::lockDevice(const TQString &device, TQString &err_reason)
{
#ifdef HAVE_BAUDBOY_H
return ttylock(device.local8bit()) == EXIT_SUCCESS;
#else
# ifdef HAVE_LOCKDEV_H
return !dev_lock(device.local8bit());
# else
int pid = -1;
TQStringList all = TQStringList::split('/', device);
if (!all.count()) {
err_reason = i18n("Invalid device (%1)").arg(device);
return false;
}
TQString lockName = DEVICE_LOCK_PATH_PREFIX + all[all.count()-1];
TQFile file(lockName);
if (file.exists() && file.open(IO_ReadOnly)) {
if (file.size() == 0) {
err_reason = i18n("Unable to read lockfile %s. Please check for reason and "
"remove the lockfile by hand.").arg(lockName);
PRINT_DEBUG << err_reason;
return false;
}
if (file.size() == 4 && sizeof(int)==4) {
file.readLine((char *)(&pid), 4); /* Kermit-style lockfile */
} else {
TQTextStream ts(&file);
ts >> pid; /* Ascii lockfile */
}
file.close();
if (pid > 0 && kill((pid_t)pid, 0) < 0 && errno == ESRCH) {
PRINT_DEBUG << TQString("Lockfile %1 is stale. Overriding it..\n").arg(lockName);
sleep(1);
if (!file.remove()) {
PRINT_DEBUG << TQString("Overriding failed, please check the permissions\n");
PRINT_DEBUG << TQString("Cannot lock device %1\n").arg(device);
err_reason = i18n("Lockfile %1 is stale. Please check permissions.").arg(lockName);
return false;
}
} else {
err_reason = i18n("Device %1 already locked.").arg(device);
return false;
}
}
/* Try to create a new file, with 0644 mode */
int fd = open(lockName.local8Bit(), O_CREAT | O_EXCL | O_WRONLY, 0644);
if (fd == -1) {
if (errno == EEXIST)
err_reason = i18n("Device %1 seems to be locked by unknown process.").arg(device);
else if (errno == EACCES)
err_reason = i18n("Please check permission on lock directory.");
else if (errno == ENOENT)
err_reason = i18n("Cannot create lockfile %1. Please check for existence of path.").arg(lockName);
else
err_reason = i18n("Could not create lockfile %1. Error-Code is %2.").arg(lockName).arg(errno);
return false;
}
TQString lockText;
lockText = TQString("%1 kmobile\n").arg(getpid(),10);
write(fd, lockText.utf8(), lockText.utf8().length());
close(fd);
PRINT_DEBUG << TQString("%1: Device %2 locked with lockfile %3.\n")
.arg(deviceName()).arg(device).arg(lockName);
err_reason = TQString::null;
return true;
# endif
#endif
}
bool KMobileDevice::unlockDevice(const TQString &device)
{
#ifdef HAVE_BAUDBOY_H
return ttyunlock(device.local8bit()) == EXIT_SUCCESS;
#else
# ifdef HAVE_LOCKDEV_H
return 0 <= dev_unlock(device.local8bit(), getpid());
# else
TQStringList all = TQStringList::split('/', device);
if (!all.count()) return false;
TQString lockName = DEVICE_LOCK_PATH_PREFIX + all[all.count()-1];
TQFile file(lockName);
if (!file.exists())
return true;
return file.remove();
# endif
#endif
}
#include "kmobiledevice.moc"