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/kandy/src/mobilegui.cpp

1672 lines
44 KiB

/*
This file is part of Kandy.
Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
As a special exception, permission is given to link this program
with any edition of Qt, and distribute the resulting executable,
without including the source code for Qt in the source distribution.
*/
#include <time.h>
#include <tqlabel.h>
#include <tqlistview.h>
#include <tqfile.h>
#include <tqtextstream.h>
#include <tqmessagebox.h>
#include <tqtextedit.h>
#include <tqgroupbox.h>
#include <tqpushbutton.h>
#include <kdebug.h>
#include <kfiledialog.h>
#include <kmessagebox.h>
#include <klocale.h>
#include <kapplication.h>
#include <kstatusbar.h>
#include <kabc/stdaddressbook.h>
#include "modem.h"
#include "atcommand.h"
#include "commandscheduler.h"
#include "mobilegui.h"
#include "mobilegui.moc"
#include "mobilemain.h"
class SyncEntry
{
public:
SyncEntry()
{
mOn = true;
mToBeUpdated = false;
mToBeInserted = false;
}
bool mOn;
bool mToBeUpdated;
bool mToBeInserted;
};
class SyncEntryKab : public SyncEntry
{
public:
SyncEntryKab( bool on, const TQString &index, const TQString &name,
const TQString &phone )
{
mOn = on;
mIndex = index;
mName = name;
mPhone = phone;
mKABindex = -1;
mPhoneNumberIndex = -1;
}
TQString mIndex;
TQString mName;
TQString mPhone;
KABC::Addressee mAddressee;
int mKABindex;
int mPhoneNumberIndex;
};
class SyncEntryMobile : public SyncEntry
{
public:
SyncEntryMobile( bool on, const TQString &index, const TQString &phone,
const TQString &name )
{
mOn = on;
mToBeDeleted = false;
mIndex = index;
mName = name;
mPhone = phone;
}
TQString mIndex;
TQString mName;
TQString mPhone;
bool mToBeDeleted;
};
class SyncEntryCommon : public SyncEntry
{
public:
SyncEntryCommon( bool on, SyncEntryKab *kabEntry,
SyncEntryMobile *mobileEntry )
{
mOn = on;
mKabEntry = kabEntry;
mMobileEntry = mobileEntry;
}
SyncEntryKab *mKabEntry;
SyncEntryMobile *mMobileEntry;
};
class AddressSyncer
{
public:
AddressSyncer()
{
mKabEntries.setAutoDelete( true );
mMobileEntries.setAutoDelete( true );
mCommonEntries.setAutoDelete( true );
}
TQPtrList<SyncEntryKab> mKabEntries;
TQPtrList<SyncEntryMobile> mMobileEntries;
TQPtrList<SyncEntryCommon> mCommonEntries;
};
class PhoneBookItem : public QCheckListItem
{
public:
PhoneBookItem( TQListView *v ) :
TQCheckListItem( v, "", TQCheckListItem::CheckBox )
{
mSyncEntry = 0;
}
PhoneBookItem( TQListView *v, SyncEntry *syncEntry, const TQString &name,
const TQString &phone, const TQString &index ) :
TQCheckListItem( v, index, TQCheckListItem::CheckBox )
{
mSyncEntry = syncEntry;
setText( 0, name );
setText( 1, phone );
setText( 2, index );
}
SyncEntry *syncEntry() { return mSyncEntry; }
private:
SyncEntry *mSyncEntry;
};
/*
* Constructs a MobileGui which is a child of 'parent', with the
* name 'name' and widget flags set to 'f'
*
* The dialog will by default be modeless, unless you set 'modal' to
* TRUE to construct a modal dialog.
*/
MobileGui::MobileGui( CommandScheduler *scheduler, KandyPrefs *kprefs,
TQWidget* parent, const char* name, WFlags fl ) :
DCOPObject( "KandyIface" ), MobileGui_base( parent, name, fl )
{
// Setup links to related classes
mScheduler = scheduler;
mSyncer = new AddressSyncer;
mPrefs = kprefs;
mparent = parent;
// Setup mobile phone specific data
mMobManufacturer = "";
mMobModel = "";
mPBStartIndex = 0;
mPBLength = 0;
mPBNameLength = 0;
mPBIndexOccupied.resize( 0, false );
mMobHasFD = false;
mMobHasLD = false;
mMobHasME = false;
mMobHasMT = false;
mMobHasTA = false;
mMobHasOW = false;
mMobHasMC = false;
mMobHasRC = false;
// Setup status for asynchronous control flow
mLastWriteId = "";
mComingFromToggleConnection = false;
mComingFromReadPhonebook = false;
mComingFromSyncPhonebooks = false;
mComingFromExit = false;
// Setup initial state of phone books
setKabState( UNLOADED );
setMobState( UNLOADED );
// Setup signal handlers
connect( mScheduler, TQT_SIGNAL( commandProcessed( ATCommand * ) ),
TQT_SLOT( processResult( ATCommand * ) ) );
connect( mScheduler->modem(), TQT_SIGNAL( gotLine( const char * ) ),
TQT_SLOT( termAddOutput( const char * ) ) );
}
MobileGui::~MobileGui()
{
delete mSyncer;
}
void MobileGui::exit()
{
warnKabState( UNLOADED );
mComingFromExit = true;
if ( !warnMobState( UNLOADED ) ) {
mComingFromExit = false;
kapp->quit();
}
}
void MobileGui::readModelInformation()
{
// Read generic manufacturer and model information
mScheduler->executeId( "+cgmi" );
mScheduler->executeId( "+cgmm" );
mScheduler->executeId( "+cgmr" );
mScheduler->executeId( "+cgsn" );
// Read information about additional phonebook memories
ATCommand *cmd = new ATCommand( "+cpbs=?" );
cmd->setAutoDelete( true );
mScheduler->execute( cmd );
// Select SIM phonebook by default
cmd = new ATCommand( "+cpbs=" );
cmd->setAutoDelete( true );
cmd->addParameter( new ATParameter( "SM" ) );
mScheduler->execute( cmd );
// Read phonebook properties
mScheduler->executeId( "+cpbr=?" );
mScheduler->executeId( "+cpbs?" );
// Set clock
if ( (*mPrefs).autoSetClock() )
setClock();
}
void MobileGui::readPhonebook()
{
if ( mMobState == LOADED )
return;
mComingFromReadPhonebook = true;
if ( !warnMobState( LOADED ) ) {
mComingFromReadPhonebook = false;
TQString tmp = "";
ATCommand *cmd = new ATCommand( "+cpbr=" );
cmd->setAutoDelete( true );
cmd->addParameter( new ATParameter( tmp.setNum( mPBStartIndex ) ) );
cmd->addParameter( new ATParameter( tmp.setNum( mPBStartIndex +
mPBLength - 1 ) ) );
mScheduler->execute( cmd );
emit statusMessage( i18n( "Reading mobile phonebook..." ) );
}
}
void MobileGui::writePhonebook()
{
bool ModemCommandScheduled = false;
if ( mMobState != MODIFIED )
return;
PushButton12->setEnabled( false );
//
// Remove all entries from data structures which are marked as
// deleted but which are not found on the mobile phone
//
for ( uint i = 0; i < mSyncer->mMobileEntries.count(); i++ ) {
SyncEntryMobile *entry = mSyncer->mMobileEntries.at( i );
if ( entry->mToBeDeleted )
if ( entry->mIndex.isEmpty() ) {
// The current entry has to be deleted but doesn't come from
// the mobile phone. Hence, it was inserted during phonebook
// synchronisation or so.
// => It is sufficient to remove it from mMobileEntries, no
// ATCommand for deletion needs to be scheduled.
mSyncer->mMobileEntries.remove( i );
i--;
} else {
// The current entry has to be deleted and stems from the
// mobile phone. First thing to do is to free its associated
// index. This way, its index can be reused for entries which
// have be newly inserted to the mobile phone and we can save
// an explicit ATCommand for deletion and save time & battery
// energy.
uint theIndex = entry->mIndex.toUInt();
mPBIndexOccupied[ theIndex - mPBStartIndex ] = false;
}
}
//
// Write all elements which need an update to the mobile phone
//
for ( uint i = 0; i < mSyncer->mMobileEntries.count(); i++ ) {
SyncEntryMobile *entry = mSyncer->mMobileEntries.at( i );
TQString id;
// Only process changed items of the mobile phonebook in
// order to save time.
if ( entry->mToBeUpdated || entry->mToBeInserted ) {
TQString tmp = "";
if ( entry->mToBeUpdated ) {
id = "+cpbw=" + entry->mIndex;
} else {
int index = firstFreeIndex();
mPBIndexOccupied[ index ] = true;
id = "+cpbw=" + tmp.setNum( index + mPBStartIndex );
}
mLastWriteId = id;
entry->mToBeUpdated = false;
entry->mToBeInserted = false;
ATCommand *cmd = new ATCommand( id );
cmd->setAutoDelete( true );
cmd->addParameter( new ATParameter( quote( entry->mPhone ) ) );
if ( entry->mPhone.left( 1 ) == "+" )
cmd->addParameter( new ATParameter( "145" ) );
else
cmd->addParameter( new ATParameter( "129" ) );
cmd->addParameter( new ATParameter(
quote( string2GSM( entry->mName ) ) ) );
mScheduler->execute( cmd );
ModemCommandScheduled = true;
}
}
//
// As a final step, we need to check again all entries which should be
// deleted. If entries exist stemming from the mobile phone and whose
// index-position was not reused for updating or inserting other entries in
// the previous loop, we need to issue an explicit ATCommand for its deletion.
//
for ( uint i = 0; i < mSyncer->mMobileEntries.count(); i++ ) {
SyncEntryMobile *entry = mSyncer->mMobileEntries.at( i );
if ( entry->mToBeDeleted ) {
uint theIndex = entry->mIndex.toUInt();
if ( !mPBIndexOccupied[ theIndex - mPBStartIndex ] ) {
// Index of item to be deleted still is 0, so that index position
// wasn't reused. We must delete it explicitly.
TQString id = "+cpbw=" + entry->mIndex;
mLastWriteId = id;
ATCommand *cmd = new ATCommand( id );
cmd->setAutoDelete( true );
mScheduler->execute( cmd );
ModemCommandScheduled = true;
}
// Remove entry from internal data structures
mSyncer->mMobileEntries.remove( i );
i--;
}
}
if ( ModemCommandScheduled )
emit statusMessage( i18n( "Writing mobile phonebook..." ) );
else
writePhonebookPostProcessing();
}
void MobileGui::writePhonebookPostProcessing()
{
mLastWriteId = "";
emit transientStatusMessage( i18n( "Wrote mobile phonebook." ) );
PushButton12->setEnabled( true );
setMobState( LOADED );
updateMobileBook();
if ( mComingFromToggleConnection ) {
mComingFromToggleConnection = false;
disconnectGUI();
} else
if ( mComingFromReadPhonebook ) {
mComingFromReadPhonebook = false;
TQString tmp = "";
ATCommand *cmd = new ATCommand( "+cpbr=" );
cmd->setAutoDelete( true );
cmd->addParameter( new ATParameter( tmp.setNum( mPBStartIndex ) ) );
cmd->addParameter( new ATParameter( tmp.setNum( mPBStartIndex +
mPBLength - 1 ) ) );
mScheduler->execute( cmd );
emit statusMessage( i18n( "Reading mobile phonebook..." ) );
} else
if ( mComingFromExit ) {
mComingFromExit = false;
kapp->quit();
}
}
void MobileGui::setClock()
{
char *timeStr = new char[50];
TQString id = "+cclk=";
ATCommand *cmd = new ATCommand( id );
cmd->setAutoDelete( true );
time_t tloc;
time( &tloc );
struct tm *theTime = localtime( &tloc );
strftime( timeStr, 50, "%y/%m/%d,%T+00", theTime );
TQString Time = timeStr;
cmd->addParameter( new ATParameter( quote( Time ) ) );
mScheduler->execute( cmd );
delete[] timeStr;
}
void MobileGui::readKabc()
{
if ( mKabState == LOADED )
return;
warnKabState( LOADED );
emit statusMessage( i18n( "Reading KDE address book..." ) );
mSyncer->mKabEntries.clear();
KABC::AddressBook *addressBook = KABC::StdAddressBook::self( true );
KABC::AddressBook::Iterator it;
int kabIndex = 0;
for ( it = addressBook->begin(); it != addressBook->end();
it++, kabIndex++ ) {
TQString index, name;
KABC::PhoneNumber phoneNumber;
KABC::PhoneNumber::List phoneNumbers = (*it).phoneNumbers();
KABC::PhoneNumber::List::Iterator it2;
int phoneNumberIndex = 0;
// Scan all numbers associated with a KAB entry
for ( it2 = phoneNumbers.begin(); it2 != phoneNumbers.end();
it2++, phoneNumberIndex++ ) {
bool excludeNumber = false;
phoneNumber = (*it2);
TQString phone = phoneNumber.number();
if ( (*mPrefs).excludeHome() &&
( phoneNumber.type() & KABC::PhoneNumber::Home ) )
excludeNumber = true;
if ( (*mPrefs).excludeWork() &&
( phoneNumber.type() & KABC::PhoneNumber::Work ) )
excludeNumber = true;
if ( (*mPrefs).excludeMessaging() &&
( phoneNumber.type() & KABC::PhoneNumber::Msg ) )
excludeNumber = true;
if ( (*mPrefs).excludeFax() &&
( phoneNumber.type() & KABC::PhoneNumber::Fax ) )
excludeNumber = true;
if ( (*mPrefs).excludeCell() &&
( phoneNumber.type() & KABC::PhoneNumber::Cell ) )
excludeNumber = true;
if ( (*mPrefs).excludeVideo() &&
( phoneNumber.type() & KABC::PhoneNumber::Video ) )
excludeNumber = true;
if ( (*mPrefs).excludeMailbox() &&
( phoneNumber.type() & KABC::PhoneNumber::Bbs ) )
excludeNumber = true;
if ( (*mPrefs).excludeModem() &&
( phoneNumber.type() & KABC::PhoneNumber::Modem ) )
excludeNumber = true;
if ( (*mPrefs).excludeCar() &&
( phoneNumber.type() & KABC::PhoneNumber::Car ) )
excludeNumber = true;
if ( (*mPrefs).excludeISDN() &&
( phoneNumber.type() & KABC::PhoneNumber::Isdn ) )
excludeNumber = true;
if ( (*mPrefs).excludePager() &&
( phoneNumber.type() & KABC::PhoneNumber::Pager ) )
excludeNumber = true;
if ( excludeNumber == false ) {
SyncEntryKab *kabEntry;
index = "";
name = (*it).familyName();
KABC::AddressBook::Iterator it3;
KABC::Addressee::List tmp;
bool firstCharIsUnique = true;
for ( it3 = addressBook->begin(); it3 != addressBook->end(); ++it3 )
if ( ( (*it3).familyName() == name ) && ( it3 != it ) ) {
tmp.append( (*it3) );
if ( (*it3).givenName()[0] == (*it).givenName()[0] )
firstCharIsUnique = false;
}
// There are several KAB entries with the same family name.
// So, we need to append the given name in order to
// distinguish them.
if ( ( tmp.size() > 0 ) && !(*it).givenName().isEmpty() ) {
name += ", ";
if ( firstCharIsUnique )
name += (*it).givenName()[0] + ".";
else
name += (*it).givenName();
}
// Truncate name field if it's too long for mobile phone
if ( name.length() > mPBNameLength )
name = name.remove( mPBNameLength, name.length() - mPBNameLength );
// Append Suffix to name if specified in preferences
if ( (*mPrefs).useHomeSuff() &&
( phoneNumber.type() & KABC::PhoneNumber::Home ) )
formatPBName( &name, (*mPrefs).homeSuff() );
else
if ( (*mPrefs).useWorkSuff() &&
( phoneNumber.type() & KABC::PhoneNumber::Work ) )
formatPBName( &name, (*mPrefs).workSuff() );
else
if ( (*mPrefs).useMessagingSuff() &&
( phoneNumber.type() & KABC::PhoneNumber::Msg ) )
formatPBName( &name, (*mPrefs).messagingSuff() );
else
if ( (*mPrefs).useFaxSuff() &&
( phoneNumber.type() & KABC::PhoneNumber::Fax ) )
formatPBName( &name, (*mPrefs).faxSuff() );
else
if ( (*mPrefs).useCellSuff() &&
( phoneNumber.type() & KABC::PhoneNumber::Cell ) )
formatPBName( &name, (*mPrefs).cellSuff() );
else
if ( (*mPrefs).useVideoSuff() &&
( phoneNumber.type() & KABC::PhoneNumber::Video ) )
formatPBName( &name, (*mPrefs).videoSuff() );
else
if ( (*mPrefs).useMailboxSuff() &&
( phoneNumber.type() & KABC::PhoneNumber::Bbs ) )
formatPBName( &name, (*mPrefs).mailboxSuff() );
else
if ( (*mPrefs).useModemSuff() &&
( phoneNumber.type() & KABC::PhoneNumber::Modem ) )
formatPBName( &name, (*mPrefs).modemSuff() );
else
if ( (*mPrefs).useCarSuff() &&
( phoneNumber.type() & KABC::PhoneNumber::Car ) )
formatPBName( &name, (*mPrefs).carSuff() );
else
if ( (*mPrefs).useISDNSuff() &&
( phoneNumber.type() & KABC::PhoneNumber::Isdn ) )
formatPBName( &name, (*mPrefs).iSDNSuff() );
else
if ( (*mPrefs).usePagerSuff() &&
( phoneNumber.type() & KABC::PhoneNumber::Pager ) )
formatPBName( &name, (*mPrefs).pagerSuff() );
kabEntry = new SyncEntryKab( true, index, name, phone );
kabEntry->mKABindex = kabIndex;
kabEntry->mPhoneNumberIndex = phoneNumberIndex;
kabEntry->mAddressee = (*it);
mSyncer->mKabEntries.append( kabEntry );
}
}
}
// Display KAB entries
updateKabBook();
emit transientStatusMessage( i18n( "Read KDE address book." ) );
setKabState( LOADED );
}
TQString MobileGui::decodeSuffix( const TQString &suffix )
{
TQString theSuffix = suffix;
// Check whether suffix is quoted. If so, it should be interpreted
// as Hex-Number of a special GSM character.
if ( ( theSuffix.left( 1 ) == "\"" ) && ( theSuffix.right( 1 ) == "\"" ) ) {
TQString tmp = "";
char suffixNumber = (char) dequote( suffix ).toUInt( 0, 16 );
tmp += suffixNumber;
theSuffix = GSM2String( tmp );
}
return theSuffix;
}
void MobileGui::formatPBName( TQString *name, TQString suffix )
{
TQString theSuffix = decodeSuffix( suffix );
if ( name->length() + theSuffix.length() > mPBNameLength ) {
// Truncate name field if it's too long for mobile phone
unsigned int toolong = name->length() + theSuffix.length() - mPBNameLength;
(*name) = name->remove( name->length() - toolong, toolong );
} else
if ( name->length() + theSuffix.length() < mPBNameLength )
// Add white spaces so that suffix is right justified
while ( name->length() + theSuffix.length() != mPBNameLength )
(*name) += ' ';
(*name) += theSuffix;
}
TQString MobileGui::stripWhiteSpaces( const TQString &theString )
{
int pos = 0;
int len = theString.length();
for ( unsigned int i = 0; i < theString.length(); i++ )
if ( theString[ i ].latin1() == ' ' ) {
pos++;
len--;
} else
break;
if ( len == 0 )
return "";
for ( int i = theString.length() - 1; i >= 0; i-- )
if ( theString[ i ].latin1() == ' ' )
len--;
else
break;
return theString.mid( pos, len );
}
void MobileGui::writeKabc()
{
if ( mKabState != MODIFIED )
return;
KABC::AddressBook *addressBook = KABC::StdAddressBook::self( true );
KABC::Ticket *ticket = addressBook->requestSaveTicket();
if ( !ticket ) {
kdDebug() << "Error! No ticket to save." << endl;
return;
}
for ( uint i = 0; i < mSyncer->mKabEntries.count(); i++ ) {
SyncEntryKab *kabEntry = mSyncer->mKabEntries.at( i );
TQString phoneNumber = kabEntry->mPhone;
if ( kabEntry->mToBeUpdated ) {
// Find the entry in the KAB which has to be updated
KABC::AddressBook::Iterator it = addressBook->begin();
for ( int KABindex = 0; KABindex != kabEntry->mKABindex;
it++, KABindex++ ) ;
// Find the correct phonenumber of the phonebook entry
KABC::PhoneNumber::List phoneNumbers = (*it).phoneNumbers();
KABC::PhoneNumber::List::Iterator it2 = phoneNumbers.begin();
for ( int phoneNumberIndex = 0;
phoneNumberIndex != kabEntry->mPhoneNumberIndex;
it2++, phoneNumberIndex++ ) ;
(*it2).setNumber( phoneNumber );
(*it).insertPhoneNumber( (*it2) );
} else
if ( kabEntry->mToBeInserted ) {
int phoneType = 0;
bool goon = true;
KABC::AddressBook::Iterator it;
bool equivalentEntryFound = false;
TQString name = kabEntry->mName;
//
// Identify Type of Phonenumber using possibly appended suffixes.
// If a suffix is found, remove it from the name.
//
if ( goon && (*mPrefs).useHomeSuff() ) {
TQString theSuffix = decodeSuffix( (*mPrefs).homeSuff() );
if ( name.right( theSuffix.length() ) == theSuffix ) {
phoneType = KABC::PhoneNumber::Home;
name = stripWhiteSpaces(
name.left( name.length() - theSuffix.length() ) );
goon = false;
}
}
if ( goon && (*mPrefs).useWorkSuff() ) {
TQString theSuffix = decodeSuffix( (*mPrefs).workSuff() );
if ( name.right( theSuffix.length() ) == theSuffix ) {
phoneType = KABC::PhoneNumber::Work;
name = stripWhiteSpaces(
name.left( name.length() - theSuffix.length() ) );
goon = false;
}
}
if ( goon && (*mPrefs).useMessagingSuff() ) {
TQString theSuffix = decodeSuffix( (*mPrefs).messagingSuff() );
if ( name.right( theSuffix.length() ) == theSuffix ) {
phoneType = KABC::PhoneNumber::Msg;
name = stripWhiteSpaces(
name.left( name.length() - theSuffix.length() ) );
goon = false;
}
}
if ( goon && (*mPrefs).useFaxSuff() ) {
TQString theSuffix = decodeSuffix( (*mPrefs).faxSuff() );
if ( name.right( theSuffix.length() ) == theSuffix ) {
phoneType = KABC::PhoneNumber::Fax;
name = stripWhiteSpaces(
name.left( name.length() - theSuffix.length() ) );
goon = false;
}
}
if ( goon && (*mPrefs).useCellSuff() ) {
TQString theSuffix = decodeSuffix( (*mPrefs).cellSuff() );
if ( name.right( theSuffix.length() ) == theSuffix ) {
phoneType = KABC::PhoneNumber::Cell;
name = stripWhiteSpaces(
name.left( name.length() - theSuffix.length() ) );
goon = false;
}
}
if ( goon && (*mPrefs).useVideoSuff() ) {
TQString theSuffix = decodeSuffix( (*mPrefs).videoSuff() );
if ( name.right( theSuffix.length() ) == theSuffix ) {
phoneType = KABC::PhoneNumber::Video;
name = stripWhiteSpaces(
name.left( name.length() - theSuffix.length() ) );
goon = false;
}
}
if ( goon && (*mPrefs).useMailboxSuff() ) {
TQString theSuffix = decodeSuffix( (*mPrefs).mailboxSuff() );
if ( name.right( theSuffix.length() ) == theSuffix ) {
phoneType = KABC::PhoneNumber::Bbs;
name = stripWhiteSpaces(
name.left( name.length() - theSuffix.length() ) );
goon = false;
}
}
if ( goon && (*mPrefs).useModemSuff() ) {
TQString theSuffix = decodeSuffix( (*mPrefs).modemSuff() );
if ( name.right( theSuffix.length() ) == theSuffix ) {
phoneType = KABC::PhoneNumber::Modem;
name = stripWhiteSpaces(
name.left( name.length() - theSuffix.length() ) );
goon = false;
}
}
if ( goon && (*mPrefs).useCarSuff() ) {
TQString theSuffix = decodeSuffix( (*mPrefs).carSuff() );
if ( name.right( theSuffix.length() ) == theSuffix ) {
phoneType = KABC::PhoneNumber::Car;
name = stripWhiteSpaces(
name.left( name.length() - theSuffix.length() ) );
goon = false;
}
}
if ( goon && (*mPrefs).useISDNSuff() ) {
TQString theSuffix = decodeSuffix( (*mPrefs).iSDNSuff() );
if ( name.right( theSuffix.length() ) == theSuffix ) {
phoneType = KABC::PhoneNumber::Isdn;
name = stripWhiteSpaces(
name.left( name.length() - theSuffix.length() ) );
goon = false;
}
}
if ( goon && (*mPrefs).usePagerSuff() ) {
TQString theSuffix = decodeSuffix( (*mPrefs).pagerSuff() );
if ( name.right( theSuffix.length() ) == theSuffix ) {
phoneType = KABC::PhoneNumber::Pager;
name = stripWhiteSpaces(
name.left( name.length() - theSuffix.length() ) );
goon = false;
}
}
//
// Search for a KAB entry whose name, if formatted in exactly the
// same way as was done in readKabc, is equal to the actual name.
//
for ( it = addressBook->begin(); it != addressBook->end(); it++ ) {
TQString kabName = (*it).familyName();
KABC::AddressBook::Iterator it3;
KABC::Addressee::List tmp;
bool firstCharIsUnique = true;
unsigned int minLength;
for ( it3 = addressBook->begin(); it3 != addressBook->end(); it3++ )
if ( ( (*it3).familyName() == kabName ) && ( it3 != it ) ) {
tmp.append( (*it3) );
if ( (*it3).givenName()[0] == (*it).givenName()[0] )
firstCharIsUnique = false;
}
// There are several KAB entries with the same family name.
// So, we need to append the given name in order to
// distinguish them.
if ( ( tmp.size() > 0 ) && !(*it).givenName().isEmpty() ) {
kabName += ", ";
if ( firstCharIsUnique )
kabName += (*it).givenName()[0] + ".";
else
kabName += (*it).givenName();
}
// Truncate name field if it's too long for mobile phone
if ( kabName.length() > mPBNameLength )
kabName = kabName.remove( mPBNameLength,
kabName.length() - mPBNameLength );
minLength = kabName.length();
if ( name.length() < minLength )
minLength = name.length();
if ( name.left( minLength ) == kabName.left( minLength ) ) {
(*it).insertPhoneNumber( KABC::PhoneNumber( phoneNumber,
phoneType ) );
equivalentEntryFound = true;
break;
}
}
//
// If no equivalent entry was found in KAB, we need to generate
// a complete new entry.
//
if ( !equivalentEntryFound ) {
KABC::Addressee entry;
TQStringList *fields = new TQStringList;
*fields = TQStringList::split( ',', name );
if ( fields->count() > 1 ) {
// Name string contains comma separated entry so that we
// need to build family and given names out of them.
TQString givenName = "";
entry.setFamilyName( stripWhiteSpaces( (*fields)[ 0 ] ) );
for ( unsigned int i = 1; i < fields->count(); i++ )
givenName += stripWhiteSpaces( (*fields)[ i ] ) + " ";
entry.setGivenName( stripWhiteSpaces( givenName ) );
} else
// Name string contains only one string without comma.
entry.setFamilyName( stripWhiteSpaces( name ) );
entry.insertPhoneNumber( KABC::PhoneNumber( phoneNumber, phoneType ) );
addressBook->insertAddressee( entry );
}
}
kabEntry->mToBeUpdated = false;
kabEntry->mToBeInserted = false;
}
addressBook->save( ticket );
emit transientStatusMessage( i18n( "Wrote KDE address book." ) );
setKabState( LOADED );
}
void MobileGui::refreshStatus()
{
mScheduler->executeId( "+cbc" );
mScheduler->executeId( "+csq" );
}
void MobileGui::processResult( ATCommand *command )
{
if ( command->id() == "+cbc" )
mBatteryChargeLabel->setText( command->resultField( 1 ) + " %" );
else
if ( command->id() == "+csq" )
mSignalQualityLabel->setText( command->resultField( 0 ) );
else
if ( command->id() == "+cgmi" ) {
mMobManufacturer = command->resultField( 0 );
mManufacturerLabel->setText( mMobManufacturer );
} else
if ( command->id() == "+cgmm" ) {
mMobModel = command->resultField( 0 );
mModelLabel->setText( mMobModel );
} else
if ( command->id() == "+cgmr" )
mGSMVersionLabel->setText( command->resultField( 0 ) );
else
if ( command->id() == "+cgsn" )
mSerialNumberLabel->setText( command->resultField( 0 ) );
else
if ( command->id() == "+cpbr=?" )
{
TQStringList tmpList = TQStringList::split( "-", command->resultField( 0 ) );
TQString tmpString = tmpList.first().right( tmpList.first().length() - 1 );
mPBStartIndex = tmpString.toUInt();
mPBNameLength = command->resultField( 2 ).toUInt();
} else
if ( command->id() == "+cpbs?" ) {
mPBLength = command->resultField( 2 ).toUInt();
// Allocate and initialize memory for the buckets of indices
mPBIndexOccupied.resize( mPBLength, false );
for ( unsigned int i = 0; i < mPBLength; i++ )
mPBIndexOccupied[ i ] = false;
} else
if ( command->id() == "+cpbr=" ) {
fillPhonebook( command );
if ( mComingFromSyncPhonebooks ) {
mComingFromSyncPhonebooks = false;
mergePhonebooks();
}
} else
if ( command->id() == mLastWriteId )
writePhonebookPostProcessing();
else
if ( command->id() == "+cpbs=?" ) {
TQPtrList<TQStringList> *list = command->resultFields();
TQStringList *fields = list->first();
while( fields ) {
for ( unsigned int i = 0; i < fields->count(); i++ ) {
TQString memory = dequote( (*fields)[ i ] );
if ( memory == "FD" )
mMobHasFD = true;
else
if ( memory == "LD" )
mMobHasLD = true;
else
if ( memory == "ME" )
mMobHasME = true;
else
if ( memory == "MT" )
mMobHasMT = true;
else
if ( memory == "TA" )
mMobHasTA = true;
else
if ( ( memory == "OW" ) ||
( ( memory == "ON" ) && ( mMobManufacturer == "SIEMENS" ) ) )
mMobHasOW = true;
else
if ( ( mMobManufacturer == "SIEMENS" ) && ( memory == "MC" ) )
mMobHasMC = true;
else
if ( ( mMobManufacturer == "SIEMENS" ) && ( memory == "RC" ) )
mMobHasRC = true;
}
fields = list->next();
}
}
}
TQString MobileGui::noSpaces( const TQString &theString )
{
TQString result = "";
for ( unsigned int i = 0; i < theString.length(); i++ )
if ( theString[ i ].latin1() != ' ' )
result += theString[ i ];
return result;
}
int MobileGui::firstFreeIndex()
{
unsigned int i;
if ( mPBIndexOccupied.capacity() == 0 )
return 0;
for ( i = 1; i < mPBLength; i++ )
if ( !mPBIndexOccupied[ i ] )
break;
if ( i < mPBLength )
return i;
return 0;
}
TQString MobileGui::string2GSM( const TQString &theString )
{
TQString result = "";
for ( unsigned int i = 0; i < theString.length(); i++ )
switch ( theString[ i ].latin1() ) {
case '<EFBFBD>': result += '['; break;
case '<EFBFBD>': result += '{'; break;
case '<EFBFBD>': result += 92; break;
case '<EFBFBD>': result += '|'; break;
case '<EFBFBD>': result += '^'; break;
case '<EFBFBD>': result += '~'; break;
case '<EFBFBD>': result += 30; break;
case '<EFBFBD>': result += 4; break;
case '<EFBFBD>': result += 5; break;
default: result += theString[ i ];
}
return result;
}
TQString MobileGui::GSM2String( const TQString &theString )
{
TQString result = "";
for ( unsigned int i = 0; i < theString.length(); i++ )
switch ( theString[ i ].latin1() ) {
case '[': result += '<EFBFBD>'; break;
case '{': result += '<EFBFBD>'; break;
case 92: result += '<EFBFBD>'; break;
case '|': result += '<EFBFBD>'; break;
case '^': result += '<EFBFBD>'; break;
case '~': result += '<EFBFBD>'; break;
case 30: result += '<EFBFBD>'; break;
case 4: result += '<EFBFBD>'; break;
case 5: result += '<EFBFBD>'; break;
default: result += theString[ i ];
}
return result;
}
void MobileGui::fillPhonebook( ATCommand *cmd )
{
mSyncer->mMobileEntries.clear();
TQPtrList<TQStringList> *list = cmd->resultFields();
TQStringList *fields = list->first();
while( fields ) {
if ( fields->count() != 4 )
kdDebug() << "Error! Unexpected number of address fields." << endl;
else {
TQString index = (*fields)[0];
TQString phone = (*fields)[1];
TQString type = (*fields)[2];
TQString name = GSM2String( (*fields)[3] );
SyncEntryMobile *phoneEntry = new SyncEntryMobile( true, dequote( index ),
dequote( phone ),
dequote( name ) );
mPBIndexOccupied[ index.toUInt() - mPBStartIndex ] = true;
mSyncer->mMobileEntries.append( phoneEntry );
}
fields = list->next();
}
// Display mobile entries
updateMobileBook();
emit transientStatusMessage(i18n("Read mobile phonebook."));
emit phonebookRead();
setMobState( LOADED );
}
TQString MobileGui::quote( const TQString &str )
{
if ( ( str.left(1) == "\"" ) && ( str.right(1) == "\"" ) )
return str;
return "\"" + str + "\"";
}
TQString MobileGui::dequote( const TQString &str )
{
int pos = 0;
int len = str.length();
if ( str.left(1) == "\"" ) {
pos = 1;
len --;
}
if ( str.right(1) == "\"" )
len--;
return str.mid( pos, len );
}
void MobileGui::savePhonebook()
{
if ( mMobState == UNLOADED )
return;
TQString fileName = KFileDialog::getSaveFileName( "phonebook.csv" );
TQFile outFile( fileName );
if ( outFile.open( IO_WriteOnly ) ) {
TQTextStream t( &outFile ); // use a text stream
for( uint i = 0; i < mSyncer->mMobileEntries.count(); i++) {
SyncEntryMobile *e = mSyncer->mMobileEntries.at( i );
if ( !e->mToBeDeleted )
t << e->mIndex << "," << e->mPhone << "," << e->mName << endl;
}
outFile.close();
}
}
void MobileGui::deleteMobPhonebook()
{
//
// Process all elements selected in the GUI
//
PhoneBookItem *item = (PhoneBookItem *) mMobileBook->firstChild();
while ( item ) {
if ( item->isOn() ) {
SyncEntryMobile *mobileItem = (SyncEntryMobile *) item->syncEntry();
// Deselect current item
item->setOn( false );
mobileItem->mOn = false;
// Mark current item as deleted
mobileItem->mToBeDeleted = true;
}
item = (PhoneBookItem *) item->nextSibling();
}
// Update GUI
updateMobileBook();
setMobState( MODIFIED );
}
void MobileGui::mergePhonebooks()
{
uint i;
//
// Transfer current Selection State from GUI to mSyncer
//
PhoneBookItem *item = (PhoneBookItem *) mKabBook->firstChild();
while ( item ) {
item->syncEntry()->mOn = item->isOn();
item = (PhoneBookItem *) item->nextSibling();
}
item = (PhoneBookItem *) mMobileBook->firstChild();
while ( item ) {
item->syncEntry()->mOn = item->isOn();
item = (PhoneBookItem *) item->nextSibling();
}
mSyncer->mCommonEntries.clear();
//
// Put KDE Address Book list into Common List
//
for ( i = 0; i < mSyncer->mKabEntries.count(); i++ )
if ( mSyncer->mKabEntries.at( i )->mOn ) {
mSyncer->mCommonEntries.append(
new SyncEntryCommon( true, mSyncer->mKabEntries.at( i ), 0 ) );
mSyncer->mKabEntries.at( i )->mOn = false;
}
//
// Put Mobile Address Book list into Common List; Merge equivalent entries
//
for ( i = 0; i < mSyncer->mMobileEntries.count(); i++ ) {
SyncEntryMobile *mobileEntry = mSyncer->mMobileEntries.at( i );
bool equivalentEntryFound = false;
uint j;
if( !mobileEntry->mToBeDeleted )
for ( j = 0; j < mSyncer->mCommonEntries.count(); j++ ) {
SyncEntryCommon *theCommonEntry = mSyncer->mCommonEntries.at( j );
if ( theCommonEntry->mKabEntry &&
( theCommonEntry->mKabEntry->mName == mobileEntry->mName ) ) {
theCommonEntry->mMobileEntry = mobileEntry;
equivalentEntryFound = true;
if ( noSpaces( theCommonEntry->mKabEntry->mPhone ) ==
mobileEntry->mPhone ) {
mobileEntry->mOn = false;
break;
} else {
// Conflict: 2 Entries have same name but different numbers.
// Prompt user.
TQString text = "<qt><b>" + i18n( "Kab Entry:" ) + "</b><br>";
text += " " + theCommonEntry->mKabEntry->mName + " " +
theCommonEntry->mKabEntry->mPhone + "<br>";
text += "<b>" + i18n( "Mobile Entry:" ) + "</b><br>";
text += " " + mobileEntry->mName + " " + mobileEntry->mPhone;
text += "</qt>";
TQMessageBox *msg =
new TQMessageBox( i18n( "Conflicting Entries" ), text,
TQMessageBox::Warning, 1, 2, 0, this );
msg->setButtonText( 1, i18n( "Use Kab Entry" ) );
msg->setButtonText( 2, i18n( "Use Mobile Entry" ) );
switch ( msg->exec() ) {
case 1:
// Use KDE Address Book Entry
mobileEntry->mPhone = theCommonEntry->mKabEntry->mPhone;
mobileEntry->mName = theCommonEntry->mKabEntry->mName;
mobileEntry->mOn = true;
mobileEntry->mToBeUpdated = true;
setMobState( MODIFIED );
break;
case 2:
// Use Mobile Address Book Entry
theCommonEntry->mKabEntry->mPhone = mobileEntry->mPhone;
theCommonEntry->mKabEntry->mName = mobileEntry->mName;
theCommonEntry->mKabEntry->mOn = true;
theCommonEntry->mKabEntry->mToBeUpdated = true;
mobileEntry->mOn = false;
setKabState( MODIFIED );
break;
}
}
}
}
if ( !equivalentEntryFound && mobileEntry->mOn ) {
// No equivalent entry exists; generate a new one.
mSyncer->mCommonEntries.append(
new SyncEntryCommon( true, 0, mobileEntry ) );
mobileEntry->mOn = false;
}
}
//
// Create new KAB and Mobile Entries
//
for ( i = 0; i < mSyncer->mCommonEntries.count(); i++ ) {
SyncEntryCommon *entry = mSyncer->mCommonEntries.at( i );
SyncEntryKab *kabEntry = entry->mKabEntry;
SyncEntryMobile *mobileEntry = entry->mMobileEntry;
if ( kabEntry && !mobileEntry ) {
// Create Mobile Entry
entry->mMobileEntry = new SyncEntryMobile( true, "", kabEntry->mPhone,
kabEntry->mName );
entry->mMobileEntry->mToBeInserted = true;
mSyncer->mMobileEntries.append( entry->mMobileEntry );
setMobState( MODIFIED );
} else
if ( mobileEntry && !kabEntry ) {
// Create KAB Entry
entry->mKabEntry = new SyncEntryKab( true, mobileEntry->mIndex,
mobileEntry->mName,
mobileEntry->mPhone );
entry->mKabEntry->mToBeInserted = true;
mSyncer->mKabEntries.append( entry->mKabEntry );
setKabState( MODIFIED );
}
}
//
// Update GUI
//
updateKabBook();
updateMobileBook();
emit transientStatusMessage( i18n( "Synced phonebooks." ) );
PushButton8_3->setEnabled( true );
}
void MobileGui::syncPhonebooks()
{
PushButton8_3->setEnabled( false );
if ( mKabState == UNLOADED )
readKabc();
if ( mMobState == UNLOADED ) {
mComingFromSyncPhonebooks = true;
readPhonebook();
} else
mergePhonebooks();
}
void MobileGui::updateKabBook()
{
mKabBook->clear();
for ( uint i = 0; i < mSyncer->mKabEntries.count(); i++ ) {
SyncEntryKab *kabEntry = mSyncer->mKabEntries.at( i );
PhoneBookItem *item = new PhoneBookItem( mKabBook, kabEntry,
kabEntry->mName, kabEntry->mPhone,
kabEntry->mIndex );
item->setOn( kabEntry->mOn );
}
}
void MobileGui::updateMobileBook()
{
mMobileBook->clear();
for ( uint i = 0; i < mSyncer->mMobileEntries.count(); i++ ) {
SyncEntryMobile *entry = mSyncer->mMobileEntries.at( i );
if ( !entry->mToBeDeleted ) {
PhoneBookItem *item = new PhoneBookItem( mMobileBook, entry, entry->mName,
entry->mPhone, entry->mIndex );
item->setOn( entry->mOn );
}
}
}
void MobileGui::toggleConnection()
{
if ( mConnectButton->text() == i18n( "Connect" ) ) {
emit connectModem();
readModelInformation();
refreshStatus();
mConnectButton->setText( tr2i18n( "Disconnect" ) );
PushButton1->setEnabled( true );
PushButton5_3->setEnabled( true );
mABTab->setEnabled( true );
setKabState( UNLOADED );
setMobState( UNLOADED );
((MobileMain *) mparent)->statusBar()->changeItem( i18n(" Connected "), 1 );
} else {
warnKabState( UNLOADED );
mComingFromToggleConnection = true;
if ( !warnMobState( UNLOADED ) ) {
mComingFromToggleConnection = false;
disconnectGUI();
}
}
}
void MobileGui::disconnectGUI()
{
emit disconnectModem();
mManufacturerLabel->setText( "x" );
mModelLabel->setText( "x" );
mGSMVersionLabel->setText( "x" );
mSerialNumberLabel->setText( "x" );
mBatteryChargeLabel->setText( "xx %" );
mSignalQualityLabel->setText( "x" );
mConnectButton->setText( tr2i18n( "Connect" ) );
PushButton1->setEnabled( false );
PushButton5_3->setEnabled( false );
mKabBook->clear();
mMobileBook->clear();
setKabState( UNLOADED );
setMobState( UNLOADED );
mABTab->setEnabled( false );
mMobHasFD = false;
mMobHasLD = false;
mMobHasME = false;
mMobHasMT = false;
mMobHasTA = false;
mMobHasOW = false;
mMobHasMC = false;
mMobHasRC = false;
mPBIndexOccupied.resize( 0, false );
((MobileMain *) mparent)->statusBar()->changeItem( i18n(" Disconnected "),
1 );
}
void MobileGui::termAddOutput( const char *line )
{
mTermIO->append( line );
mTermIO->setCursorPosition( mTermIO->paragraphs() - 1, 0 );
}
void MobileGui::setKabState( ABState newState )
{
switch ( mKabState ) {
case UNLOADED:
groupBox3->setTitle( tr2i18n( "KDE Address Book" ) );
mReadKabButton->setEnabled( true );
PushButton8->setEnabled( false );
break;
case LOADED:
if ( newState == MODIFIED ) {
groupBox3->setTitle( tr2i18n( "KDE Address Book (modified)" ) );
mReadKabButton->setEnabled( true );
PushButton8->setEnabled( true );
} else
if ( newState == UNLOADED ) {
groupBox3->setTitle( tr2i18n( "KDE Address Book" ) );
mReadKabButton->setEnabled( true );
PushButton8->setEnabled( false );
}
break;
case MODIFIED:
if ( newState != MODIFIED ) {
groupBox3->setTitle( tr2i18n( "KDE Address Book" ) );
mReadKabButton->setEnabled( true );
PushButton8->setEnabled( false );
}
break;
}
mKabState = newState;
}
void MobileGui::warnKabState( ABState newState )
{
if ( ( mKabState == MODIFIED ) && ( newState != MODIFIED ) ) {
TQString text = "<qt><b>" + i18n( "Warning" ) + "</b><br>";
text += i18n( "The KDE address book contains unsaved changes." ) +
"<br></qt>";
TQMessageBox *msg = new TQMessageBox( i18n( "Unsaved Changes" ), text,
TQMessageBox::Critical, 1, 2, 0, this );
msg->setButtonText( 1, i18n( "Save" ) );
msg->setButtonText( 2, i18n( "Discard" ) );
switch ( msg->exec() ) {
case 1:
// Save Changes first
writeKabc();
break;
case 2:
break;
}
}
}
void MobileGui::setMobState( ABState newState )
{
switch ( mMobState ) {
case UNLOADED:
if ( newState == UNLOADED ) {
groupBox4->setTitle( tr2i18n( "Mobile Phone Book" ) );
PushButton3->setEnabled( true );
PushButton12->setEnabled( false );
PushButton4_2->setEnabled( false );
MobDeleteButton->setEnabled( false );
} else
if ( newState == LOADED ) {
groupBox4->setTitle( tr2i18n( "Mobile Phone Book" ) );
PushButton3->setEnabled( true );
PushButton12->setEnabled( false );
PushButton4_2->setEnabled( true );
MobDeleteButton->setEnabled( true );
}
break;
case LOADED:
if ( newState == MODIFIED ) {
groupBox4->setTitle( tr2i18n( "Mobile Phone Book (modified)" ) );
PushButton3->setEnabled( true );
PushButton12->setEnabled( true );
PushButton4_2->setEnabled( true );
MobDeleteButton->setEnabled( true );
} else
if ( newState == UNLOADED ) {
groupBox4->setTitle( tr2i18n( "Mobile Phone Book" ) );
PushButton3->setEnabled( true );
PushButton12->setEnabled( false );
PushButton4_2->setEnabled( false );
MobDeleteButton->setEnabled( false );
}
break;
case MODIFIED:
if ( newState == UNLOADED ) {
groupBox4->setTitle( tr2i18n( "Mobile Phone Book" ) );
PushButton3->setEnabled( true );
PushButton12->setEnabled( false );
PushButton4_2->setEnabled( false );
MobDeleteButton->setEnabled( false );
} else
if ( newState == LOADED ) {
groupBox4->setTitle( tr2i18n( "Mobile Phone Book" ) );
PushButton3->setEnabled( true );
PushButton12->setEnabled( false );
PushButton4_2->setEnabled( true );
MobDeleteButton->setEnabled( true );
}
break;
}
mMobState = newState;
}
bool MobileGui::warnMobState( ABState newState )
{
if ( ( mMobState == MODIFIED ) && ( newState != MODIFIED ) )
{
TQString text = "<qt><b>" + i18n( "Warning" ) + "</b><br>";
text += i18n( "The mobile phone book contains unsaved changes." ) +
"<br></qt>";
TQMessageBox *msg = new TQMessageBox( i18n( "Unsaved Changes" ), text,
TQMessageBox::Critical, 1, 2, 0, this );
msg->setButtonText( 1, i18n( "Save" ) );
msg->setButtonText( 2, i18n( "Discard" ) );
switch ( msg->exec() ) {
case 1:
// Save Changes first
writePhonebook();
return true;
break;
case 2:
return false;
break;
}
}
return false;
}