kpilot

kpilotProbeDialog.cc

Go to the documentation of this file.
00001 /* conduitConfigDialog.cc                KPilot
00002 **
00003 ** Copyright (C) 2004 Reinhold Kainhofer <reinhold@kainhofer.com>
00004 **
00005 ** This file defines a .ui-based configuration dialog for conduits.
00006 */
00007 
00008 /*
00009 ** This program is free software; you can redistribute it and/or modify
00010 ** it under the terms of the GNU General Public License as published by
00011 ** the Free Software Foundation; either version 2 of the License, or
00012 ** (at your option) any later version.
00013 **
00014 ** This program is distributed in the hope that it will be useful,
00015 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
00016 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00017 ** GNU General Public License for more details.
00018 **
00019 ** You should have received a copy of the GNU General Public License
00020 ** along with this program in a file called COPYING; if not, write to
00021 ** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
00022 ** MA 02110-1301, USA.
00023 */
00024 
00025 /*
00026 ** Bug reports and questions can be sent to kde-pim@kde.org
00027 */
00028 
00029 #include "options.h"
00030 
00031 #include <qlayout.h>
00032 #include <qgroupbox.h>
00033 #include <qlabel.h>
00034 #include <qvbox.h>
00035 #include <qtimer.h>
00036 #include <qptrlist.h>
00037 #include <qmap.h>
00038 #include <qvaluelist.h>
00039 
00040 #include <kmessagebox.h>
00041 #include <kglobal.h>
00042 #include <klocale.h>
00043 #include <kconfigskeleton.h>
00044 #include <kapplication.h>
00045 #include <kprogress.h>
00046 
00047 #include "kpilotConfig.h"
00048 #include "pilotUser.h"
00049 #include "pilotSysInfo.h"
00050 #include "options.h"
00051 #include "kpilotdevicelink.h"
00052 
00053 #include "kpilotProbeDialog.moc"
00054 #include "pilotDaemonDCOP_stub.h"
00055 
00056 /*
00057 We can't connect to /dev/ttyUSB0 and /dev/ttyUSB1 at the same time, because that
00058 will lock up kpilot completely. In particular, it gets a connection on /dev/ttyUSB0,
00059 which it processes, and while processing, a connection on USB1 is also detected.
00060 However, when kpilot gets 'round to process it, the link is already closed, and
00061 pi_connect hangs forever.
00062 
00063 Now, I split up the list of devices to probe into three list, one holding /dev/pilot,
00064 the second holding all /dev/xxx0 and /dev/xxx2 (e.g. /dev/ttyUSB0 and /dev/ttyUSB2),
00065 and finally a third holding the remaining /dev/xxx1 and /dev/xxx3 devices. Each of
00066 these three sets of devices is activated for a few seconds, and then the next set is
00067 probed. This way, I ensure that kpilot never listens on /dev/ttyUSB0 and /dev/ttyUSB1
00068 at the same time.
00069 
00070 Now the first detection works fine. However, it seems the Linux kernel has another
00071 problem with /dev/ttyUSB0. I have a Clie, which uses ttyUSB0, and as soon as the
00072 wizard tries to listen on ttyUSB1 (after it detected the handheld on ttyUSB0 already),
00073 the kernel writes a warning message to the syslog:
00074 visor ttyUSB1: Device lied about number of ports, please use a lower one.
00075 
00076 If I continue autodetection once again afterwards, the visor module kind of crashes.
00077 lsmod shows an impossible usage count for the module:
00078 
00079 reinhold@einstein:/kde/builddir$ lsmod
00080 Module                  Size  Used by
00081 visor                  17164  4294967294
00082 usbserial              30704  1 visor
00083 
00084 After that, the kernel doesn't detect the device ever again (until the computer is rebooted),
00085 and the module can't be unloaded.
00086 */
00087 
00088 
00089 ProbeDialog::ProbeDialog(QWidget *parent, const char *n) :
00090     KDialogBase(parent, n, true, i18n("Autodetecting Your Handheld"), KDialogBase::Ok|KDialogBase::Cancel|KDialogBase::User1, KDialogBase::Cancel, true, i18n("Restart Detection")),
00091     mDetected(false), mUserName(), mDevice()
00092 {
00093     FUNCTIONSETUP;
00094 
00095     QVBox *mainWidget = makeVBoxMainWidget();
00096 
00097     fInfoText = new QLabel( i18n( "KPilot is now trying to automatically detect the device of your handheld. Please press the hotsync button if you have not done so already." ), mainWidget, "fInfoText" );
00098     fInfoText->setAlignment( QLabel::WordBreak );
00099 
00100     fStatusGroup = new QGroupBox( i18n("Status"), mainWidget, "fStatusGroup" );
00101     fStatusGroup->setColumnLayout(0, Qt::Vertical );
00102     fStatusGroupLayout = new QGridLayout( fStatusGroup->layout() );
00103 
00104     fStatus = new QLabel( i18n("Autodetection not yet started..."), fStatusGroup, "fStatus" );
00105     fStatus->setAlignment( QLabel::WordBreak );
00106     fStatusGroupLayout->addWidget( fStatus, 0, 0 );
00107 
00108     fProgress = new KProgress( 100, fStatusGroup, "fProgress" );
00109     fStatusGroupLayout->addWidget( fProgress, 1, 0 );
00110 
00111 
00112 
00113     fResultsGroup = new QGroupBox( i18n( "Detected Values" ), mainWidget, "fResultsGroup" );
00114     fResultsGroup->setEnabled( FALSE );
00115     fResultsGroup->setColumnLayout(0, Qt::Vertical );
00116     fResultsGroupLayout = new QGridLayout( fResultsGroup->layout() );
00117     fResultsGroupLayout->setAlignment( Qt::AlignTop );
00118 
00119     fUserLabel = new QLabel( i18n( "Handheld user:" ), fResultsGroup, "fUserLabel" );
00120     fUserLabel->setSizePolicy( QSizePolicy( (QSizePolicy::SizeType)4, (QSizePolicy::SizeType)5, 0, 0, fUserLabel->sizePolicy().hasHeightForWidth() ) );
00121     fResultsGroupLayout->addWidget( fUserLabel, 0, 0 );
00122 
00123     fDeviceLabel = new QLabel( i18n( "Device:" ), fResultsGroup, "fDeviceLabel" );
00124     fResultsGroupLayout->addWidget( fDeviceLabel, 1, 0 );
00125 
00126     fUser = new QLabel( i18n("[Not yet known]"), fResultsGroup, "fUser" );
00127     fResultsGroupLayout->addWidget( fUser, 0, 1 );
00128 
00129     fDevice = new QLabel( i18n("[Not yet known]"), fResultsGroup, "fDevice" );
00130     fResultsGroupLayout->addWidget( fDevice, 1, 1 );
00131 
00132 
00133     resize( QSize(459, 298).expandedTo(minimumSizeHint()) );
00134     clearWState( WState_Polished );
00135     enableButtonOK(false);
00136 
00137     mDevicesToProbe[0] << "/dev/pilot";
00138     mDevicesToProbe[1] <<"/dev/ttyS0"<<"/dev/ttyS2"
00139                     <<"/dev/tts/0"<<"/dev/tts/2"
00140                     <<"/dev/ttyUSB0"<<"/dev/ttyUSB2"
00141                     <<"/dev/usb/tts/0"<<"/dev/usb/tts/2"
00142                     <<"/dev/cuaa0"<<"/dev/cuaa2"
00143             <<"/dev/cuad0"<<"/dev/cuad2"
00144                     <<"/dev/ucom0"<<"/dev/ucom2";
00145     mDevicesToProbe[2] <<"/dev/ttyS1"<<"/dev/ttyS3"
00146                     <<"/dev/tts/1"<<"/dev/tts/3"
00147                     <<"/dev/ttyUSB1"<<"/dev/ttyUSB3"
00148                     <<"/dev/usb/tts/1"<<"/dev/usb/tts/3"
00149                     <<"/dev/cuaa1"<<"/dev/cuaa3"
00150             <<"/dev/cuad1"<<"/dev/cuad3"
00151                     <<"/dev/ucom1"<<"/dev/ucom3";
00152 
00153     fProcessEventsTimer = new QTimer( this );
00154     fTimeoutTimer = new QTimer( this );
00155     fProgressTimer = new QTimer( this );
00156     fRotateLinksTimer = new QTimer( this );
00157     connect( fProcessEventsTimer, SIGNAL(timeout()), this, SLOT(processEvents()) );
00158     connect( fTimeoutTimer, SIGNAL(timeout()), this, SLOT(timeout()) );
00159     connect( fProgressTimer, SIGNAL(timeout()), this, SLOT( progress()) );
00160     connect( fRotateLinksTimer, SIGNAL(timeout()), this, SLOT( detect()) );
00161     connect( this, SIGNAL(finished()), this, SLOT(disconnectDevices()) );
00162 }
00163 
00164 ProbeDialog::~ProbeDialog()
00165 {
00166     FUNCTIONSETUP;
00167 }
00168 
00169 void ProbeDialog::processEvents()
00170 {
00171     FUNCTIONSETUP;
00172     KApplication::kApplication()->processEvents();
00173 }
00174 
00175 void ProbeDialog::progress()
00176 {
00177     fProgress->advance(1);
00178 }
00179 
00180 int ProbeDialog::exec()
00181 {
00182     mDetected = false;
00183     mUserName = QString();
00184     mDevice = QString();
00185     QTimer::singleShot( 0, this, SLOT( startDetection() ) );
00186     return KDialogBase::exec();
00187 }
00188 
00189 void ProbeDialog::startDetection()
00190 {
00191     FUNCTIONSETUP;
00192 
00193     disconnectDevices();
00194     fProgress->setProgress(0);
00195     fStatus->setText( i18n("Starting detection...") );
00196     QTimer::singleShot(0, this, SLOT(processEvents()) );
00197     processEvents();
00198     PilotDaemonDCOP_stub *daemonStub = new PilotDaemonDCOP_stub("kpilotDaemon", "KPilotDaemonIface");
00199     if (daemonStub) {
00200         daemonStub->stopListening();
00201     }
00202     KPILOT_DELETE(daemonStub);
00203     processEvents();
00204     if (!fTimeoutTimer->start( 30000, true ) )
00205     {
00206         WARNINGKPILOT << "Could not start fTimeoutTimer" << endl;
00207     }
00208     if (!fProcessEventsTimer->start( 100, false ) )
00209     {
00210         WARNINGKPILOT << "Could not start fProcessEventsTimer" << endl;
00211     }
00212     if (!fProgressTimer->start( 300, false) )
00213     {
00214         WARNINGKPILOT << "Could not start Progress timer" << endl;
00215     }
00216 
00217     KPilotDeviceLink*link;
00218     for (int i=0; i<3; i++)
00219     {
00220         QStringList::iterator end(mDevicesToProbe[i].end());
00221         for (QStringList::iterator it=mDevicesToProbe[i].begin(); it!=end; ++it)
00222         {
00223             link = new KPilotDeviceLink();
00224             link->setDevice((*it));
00225 #ifdef DEBUG
00226             DEBUGKPILOT<<"new kpilotDeviceLink for "<<(*it)<<endl;
00227 #endif
00228             mDeviceLinks[i].append( link );
00229             connect( link, SIGNAL(deviceReady(KPilotDeviceLink*)), this, SLOT(connection(KPilotDeviceLink*)) );
00230             processEvents();
00231         }
00232     }
00233     fStatus->setText( i18n("Waiting for handheld to connect...") );
00234     mProbeDevicesIndex=0;
00235 
00236     detect();
00237     if (!fRotateLinksTimer->start( 3000, false) )
00238     {
00239         WARNINGKPILOT << "Could not start Device link rotation timer" << endl;
00240     }
00241 }
00242 
00243 
00244 void ProbeDialog::detect(int i)
00245 {
00246     FUNCTIONSETUP;
00247 
00248     mProbeDevicesIndex = i;
00249     PilotLinkList::iterator end(mDeviceLinks[mProbeDevicesIndex].end());
00250 
00251     for (PilotLinkList::iterator it=mDeviceLinks[mProbeDevicesIndex].begin(); it!=end; ++it)
00252     {
00253         if (*it) (*it)->reset();
00254     }
00255 }
00256 
00257 void ProbeDialog::detect()
00258 {
00259     detect( (mProbeDevicesIndex+1)%3 );
00260 }
00261 
00262 void ProbeDialog::timeout()
00263 {
00264     disconnectDevices();
00265     if (!mDetected) {
00266         fStatus->setText( i18n("Timeout reached, could not detect a handheld.") );
00267         KMessageBox::information ( this, i18n("<qt>A handheld could not be detected. Possible check the following things:</p>"
00268             "<ul><li> Have you pressed the hotsync button on the handheld?\n"
00269             "<li> Make sure the device sits in the cradle correctly.\n"
00270             "<li> Make sure the cradle is correctly plugged in to the computer.\n"
00271             "<li> Have you checked that your device is actually supported by kpilot (see http://www.kpilot.org).\n"
00272             "</ul>"
00273             ), i18n("Automatic Detection Failed"), "AutoDetectionFailed");
00274     }
00275 }
00276 
00277 void ProbeDialog::connection( KPilotDeviceLink*lnk)
00278 {
00279     FUNCTIONSETUP;
00280 
00281     mActiveLink = lnk;
00282     if ( !mActiveLink ) return;
00283     const KPilotUser &usr( mActiveLink->getPilotUser() );
00284 
00285     mUserName = usr.name();
00286     mDevice = mActiveLink->pilotPath();
00287 
00288     fStatus->setText( i18n("Found a connected device on %1").arg(mDevice) );
00289     fUser->setText( mUserName );
00290     fDevice->setText( mDevice );
00291     mDetected = true;
00292 
00293     fResultsGroup->setEnabled( true );
00294     enableButtonOK(true);
00295 
00296     QTimer::singleShot(0, this, SLOT(retrieveDBList()));
00297 }
00298 
00299 void ProbeDialog::retrieveDBList()
00300 {
00301     KPilotLink::DBInfoList dbs = mActiveLink->getDBList();
00302     mDBs.clear();
00303     char buff[7];
00304     buff[0] = '[';
00305 
00306     for ( KPilotLink::DBInfoList::ConstIterator i = dbs.begin();
00307         i != dbs.end(); ++i )
00308     {
00309         set_long( &buff[1], (*i).creator );
00310         buff[5] = ']';
00311         buff[6] = '\0';
00312         QString cr( buff );
00313         mDBs << cr;
00314         mDBs << QString( (*i).name );
00315     }
00316     mDBs.sort();
00317 
00318     QString old( QString::null );
00319     QStringList::Iterator itr = mDBs.begin();
00320     while ( itr != mDBs.end() ) {
00321         if ( old == *itr ) {
00322             itr = mDBs.remove( itr );
00323         } else {
00324             old = *itr;
00325             ++itr;
00326         }
00327     }
00328 
00329     // End sync gracefully, but don't change settings on the handheld.
00330     mActiveLink->endSync( KPilotLink::NoUpdate );
00331 
00332     QTimer::singleShot(0, this, SLOT(disconnectDevices()));
00333 }
00334 void ProbeDialog::disconnectDevices()
00335 {
00336     FUNCTIONSETUP;
00337 
00338     if (!mDetected) fStatus->setText( i18n("Disconnected from all devices") );
00339     fProcessEventsTimer->stop( );
00340     fTimeoutTimer->stop();
00341     fProgressTimer->stop();
00342     fRotateLinksTimer->stop();
00343     fProgress->setProgress(fProgress->totalSteps());
00344     for (int i=0; i<3; ++i)
00345     {
00346         PilotLinkList::iterator end(mDeviceLinks[i].end());
00347         for (PilotLinkList::iterator it=mDeviceLinks[i].begin(); it!=end; ++it)
00348         {
00349             (*it)->close();
00350             KPILOT_DELETE(*it);
00351         }
00352         mDeviceLinks[i].clear();
00353     }
00354 
00355 
00356     PilotDaemonDCOP_stub *daemonStub = new PilotDaemonDCOP_stub("kpilotDaemon", "KPilotDaemonIface");
00357     if (daemonStub)
00358     {
00359         daemonStub->startListening();
00360     }
00361     KPILOT_DELETE(daemonStub);
00362 }
00363