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/kaddressbook/xxport/gnokii_xxport.cpp

1602 lines
54 KiB

/*
This file is part of KAddressbook.
Copyright (c) 2003-2006 Helge Deller <deller@kde.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2 as
published by the Free Software Foundation.
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 TQt, and distribute the resulting executable,
without including the source code for TQt in the source distribution.
*/
/*
Description:
This filter allows you to import and export the KDE addressbook entries
to/from a mobile phone, which is accessible via gnokii.
Gnokii homepage: http://www.gnokii.org
TODO:
- create a log file and give user possibility to see it afterwards
- handle callergroup value (Friend, VIP, Family, ...) better
*/
#include "config.h"
#ifdef HAVE_GNOKII_H
extern "C" {
#include <gnokii.h>
}
#else
#ifdef __GNUC__
# warning "Please install gnokii (http://www.gnokii.org) development headers and libraries !"
# warning "Please use at least version 0.6.13 or later of gnokii."
#endif
#endif
#include <tqcursor.h>
#include <kdebug.h>
#include <klocale.h>
#include <kmessagebox.h>
#include <kprogress.h>
#include <kguiitem.h>
#include "gnokii_xxport.h"
#define APP "GNOKII_XXPORT"
#if 1 // !defined(NDEBUG)
#define GNOKII_DEBUG(x) do { kdWarning() << (x); } while (0)
#else
#define GNOKII_DEBUG(x) do { } while (0)
#endif
#define GNOKII_CHECK_ERROR(error) \
do { \
if (error) \
kdError() << TQString("ERROR %1: %2\n").arg(error).arg(gn_error_print(error));\
} while (0)
// Locale conversion routines:
// Gnokii uses the local 8 Bit encoding (based on LC_ALL), kaddressbook uses Unicode
#define GN_FROM(x) TQString::fromLocal8Bit(x)
#define GN_TO(x) (x).local8Bit()
// static variables for GUI updates
static GNOKIIXXPort *this_filter;
static KProgressDialog *m_progressDlg;
K_EXPORT_KADDRESSBOOK_XXFILTER( libkaddrbk_gnokii_xxport, GNOKIIXXPort )
GNOKIIXXPort::GNOKIIXXPort( KABC::AddressBook *ab, TQWidget *parent, const char *name )
: KAB::XXPort( ab, parent, name )
{
this_filter = this;
m_progressDlg = NULL;
createImportAction( i18n( "Import From Mobile Phone..." ) );
createExportAction( i18n( "Export to Mobile Phone..." ) );
}
#ifdef HAVE_GNOKII_H
static TQString makeValidPhone( const TQString &number )
{
// allowed chars: 0-9, *, #, p, w, +
TQString num = number.simplifyWhiteSpace();
TQString allowed("0123456789*+#pw");
for (unsigned int i=num.length(); i>=1; i--)
if (allowed.find(num[i-1])==-1)
num.remove(i-1,1);
if (num.isEmpty())
num = "0";
return num;
}
#endif
/******************************************************************************
******************************************************************************
******************************************************************************
******************************************************************************
******************************************************************************/
#if defined(HAVE_GNOKII_H) && defined(LIBGNOKII_VERSION_MAJOR) && (LIBGNOKII_VERSION_MAJOR >= 3)
/* NEW GNOKII LIBRARIES (>= 0.6.13) */
static const char *manufacturer, *model, *revision, *imei;
static struct gn_statemachine *state;
static void busterminate(void)
{
gn_lib_phone_close(state);
gn_lib_phoneprofile_free(&state);
gn_lib_library_free();
}
static TQString businit(void)
{
GNOKII_DEBUG( "Using new gnokii version." );
GNOKII_DEBUG( TQString("Compiled with libgnokii version 0x%1\n").arg(TQString::number(LIBGNOKII_VERSION,16)) );
GNOKII_DEBUG( TQString("Using libgnokii runtime version 0x%1\n").arg(TQString::number(gn_lib_version(),16)) );
gn_error error = gn_lib_phoneprofile_load(NULL, &state);
if (error)
return i18n("Failed to initialize the gnokii library.");
error = gn_lib_phone_open( state );
GNOKII_CHECK_ERROR(error);
if (error != GN_ERR_NONE) {
busterminate();
return i18n("<qt><center>Mobile Phone interface initialization failed.<br><br>"
"The returned error message was:<br><b>%1</b><br><br>"
"You might try to run \"gnokii --identify\" on the command line to "
"check any cable/transport issues and to verify if your gnokii "
"configuration is correct.</center></qt>")
.arg(gn_error_print(error));
}
// identify phone
manufacturer = gn_lib_get_phone_manufacturer(state);
model = gn_lib_get_phone_model(state);
revision = gn_lib_get_phone_revision(state);
imei = gn_lib_get_phone_imei(state);
GNOKII_DEBUG( TQString("Found mobile phone: %1 %2, Revision: %3, IMEI: %4\n")
.arg(manufacturer, model, revision, imei) );
return TQString();
}
// get number of entries in this phone memory type (internal/SIM-card)
static gn_error read_phone_memstat( const gn_memory_type memtype, gn_memory_status *memstat )
{
gn_error error;
error = gn_lib_addressbook_memstat(state, memtype, &memstat->used, &memstat->free);
GNOKII_DEBUG( TQString("\n\nMobile phone memory status: Type: %1, used=%2, free=%3, total=%4\n\n")
.arg(memtype).arg(memstat->used).arg(memstat->free).arg(memstat->used+memstat->free) );
return error;
}
static TQString buildPhoneInfoString( const gn_memory_status &memstat )
{
TQString format = TQString::fromLatin1("<tr><td><b>%1</b></td><td>%2</td></tr>");
return TQString::fromLatin1("<b>%1</b><br><table>%2%3%4%5%6</table><br>")
.arg(i18n("Mobile Phone information:"))
.arg(format.arg(i18n("Manufacturer")).arg(GN_FROM(manufacturer)))
.arg(format.arg(i18n("Phone model")).arg(GN_FROM(model)))
.arg(format.arg(i18n("Revision")).arg(GN_FROM(revision)))
.arg(format.arg(i18n("IMEI")).arg(GN_FROM(imei)))
.arg(format.arg(i18n("Phonebook status"))
.arg(i18n("%1 out of %2 contacts used").arg(memstat.used).arg(memstat.used+memstat.free)));
}
// read and evaluate all phone entries
static gn_error read_phone_entries( const char *memtypestr, gn_memory_type memtype,
KABC::AddresseeList *addrList )
{
gn_error error;
if (m_progressDlg->wasCancelled())
return GN_ERR_NONE;
KProgress* progress = (KProgress*)m_progressDlg->progressBar();
progress->setProgress(0);
this_filter->processEvents();
// get number of entries in this phone memory type (internal/SIM-card)
gn_memory_status memstat;
error = read_phone_memstat(memtype, &memstat);
TQStringList addrlist;
KABC::Address *addr;
TQString s, country;
progress->setTotalSteps(memstat.used);
m_progressDlg->setLabel(i18n("<qt>Importing <b>%1</b> contacts from <b>%2</b> of the Mobile Phone.<br><br>%3</qt>")
.arg(memstat.used)
.arg(gn_memory_type2str(memtype))
.arg(buildPhoneInfoString(memstat)) );
int num_read = 0;
for (int i = 1; !m_progressDlg->wasCancelled() && i <= memstat.used + memstat.free; i++) {
error = gn_lib_phonebook_read_entry(state, memtype, i);
GNOKII_CHECK_ERROR(error);
progress->setProgress(num_read);
this_filter->processEvents();
if (error == GN_ERR_EMPTYLOCATION)
continue;
if (error == GN_ERR_INVALIDLOCATION)
break;
if (error == GN_ERR_INVALIDMEMORYTYPE)
break;
if (error == GN_ERR_NONE) {
const int subentries_count = gn_lib_get_pb_num_subentries(state);
const char *name = gn_lib_get_pb_name(state);
const char *number = gn_lib_get_pb_number(state);
GNOKII_DEBUG(TQString("%1: %2, num=%3, location=%4, group=%5, count=%6\n").arg(i)
.arg(GN_FROM(name)).arg(GN_FROM(number))
.arg(gn_lib_get_pb_location(state)).arg(gn_lib_get_pb_caller_group(state))
.arg(subentries_count));
KABC::Addressee *a = new KABC::Addressee();
// try to split Name into FamilyName and GivenName
s = GN_FROM(name).simplifyWhiteSpace();
a->setFormattedName(s); // set formatted name as in Phone
if (s.find(',') == -1) {
// assumed format: "givenname [... familyname]"
addrlist = TQStringList::split(' ', s);
if (addrlist.count() == 1) {
// only one string -> put it in the GivenName
a->setGivenName(s);
} else {
// multiple strings -> split them.
a->setFamilyName(addrlist.last().simplifyWhiteSpace());
addrlist.remove(addrlist.last());
a->setGivenName(addrlist.join(" ").simplifyWhiteSpace());
}
} else {
// assumed format: "familyname, ... givenname"
addrlist = TQStringList::split(',', s);
a->setFamilyName(addrlist.first().simplifyWhiteSpace());
addrlist.remove(addrlist.first());
a->setGivenName(addrlist.join(" ").simplifyWhiteSpace());
}
a->insertCustom(APP, "X_GSM_CALLERGROUP", s.setNum(gn_lib_get_pb_caller_group(state)));
a->insertCustom(APP, "X_GSM_STORE_AT", TQString("%1%2").arg(memtypestr).arg(gn_lib_get_pb_location(state)));
// set ProductId
a->setProductId(TQString("%1-%2-%3-%4").arg(APP).arg(model).arg(revision).arg(imei));
// evaluate timestamp (ignore timezone)
TQDateTime datetime;
gn_timestamp ts = gn_lib_get_pb_date(state);
if (ts.year<1998)
datetime = TQDateTime::currentDateTime();
else
datetime = TQDateTime( TQDate(ts.year, ts.month, ts.day),
TQTime(ts.hour, ts.minute, ts.second) );
GNOKII_DEBUG(TQString(" date=%1\n").arg(datetime.toString()));
a->setRevision(datetime);
if (!subentries_count)
a->insertPhoneNumber(KABC::PhoneNumber(number,
KABC::PhoneNumber::Work | KABC::PhoneNumber::Pref));
/* scan sub-entries */
if (subentries_count)
for (int n=0; n<subentries_count; n++) {
gn_phonebook_entry_type entry_type;
gn_phonebook_number_type number_type;
const char *number;
error = gn_lib_get_pb_subentry(state, n, &entry_type, &number_type, &number);
GNOKII_CHECK_ERROR(error);
TQString s = GN_FROM(number).simplifyWhiteSpace();
GNOKII_DEBUG(TQString(" Subentry#%1, entry_type=%2, number_type=%3, number=%4\n")
.arg(n).arg(entry_type).arg(number_type).arg(s));
if (s.isEmpty())
continue;
switch(entry_type) {
case GN_PHONEBOOK_ENTRY_Name:
a->setName(s);
break;
case GN_PHONEBOOK_ENTRY_Email:
a->insertEmail(s);
break;
case GN_PHONEBOOK_ENTRY_Postal:
addrlist = TQStringList::split(';', s, true);
addr = new KABC::Address(KABC::Address::Work);
if (addrlist.count() <= 1) {
addrlist = TQStringList::split(',', s, true);
if (addrlist.count() > 1 ) {
// assumed format: "Locality, ZIP, Country"
addr->setLocality(addrlist[0]);
addr->setPostalCode(addrlist[1]);
if (!addrlist[2].isEmpty())
addr->setCountry(i18n(GN_TO(addrlist[2])));
} else {
// no idea about the format, just store it.
addr->setLocality(s);
}
} else {
// assumed format: "POBox; Extended; Street; Locality; Region; ZIP [;Country]
addr->setPostOfficeBox(addrlist[0]);
addr->setExtended(addrlist[1]);
addr->setStreet(addrlist[2]);
addr->setLocality(addrlist[3]);
addr->setRegion(addrlist[4]);
addr->setPostalCode(addrlist[5]);
country = addrlist[6];
if (!country.isEmpty())
addr->setCountry(i18n(GN_TO(country)));
}
a->insertAddress(*addr);
delete addr;
break;
case GN_PHONEBOOK_ENTRY_Note:
if (!a->note().isEmpty())
s = "\n" + s;
a->setNote(a->note()+s);
break;
case GN_PHONEBOOK_ENTRY_Number:
enum KABC::PhoneNumber::Types phonetype;
switch (number_type) {
case GN_PHONEBOOK_NUMBER_Mobile: phonetype = KABC::PhoneNumber::Cell; break;
case GN_PHONEBOOK_NUMBER_Fax: phonetype = KABC::PhoneNumber::Fax; break;
case GN_PHONEBOOK_NUMBER_General:
case GN_PHONEBOOK_NUMBER_Work: phonetype = KABC::PhoneNumber::Work; break;
default:
case GN_PHONEBOOK_NUMBER_Home: phonetype = KABC::PhoneNumber::Home; break;
}
//if (s == entry.number)
// type = (KABC::PhoneNumber::Types) (phonetype | KABC::PhoneNumber::Pref);
a->insertPhoneNumber(KABC::PhoneNumber(s, phonetype));
break;
case GN_PHONEBOOK_ENTRY_URL:
a->setUrl(s);
break;
case GN_PHONEBOOK_ENTRY_Group:
a->insertCategory(s);
break;
default:
GNOKII_DEBUG(TQString(" Not handled id=%1, entry=%2\n")
.arg(entry_type).arg(s));
break;
} // switch()
} // if(subentry)
// add only if entry was valid
if (strlen(name) || strlen(number) || subentries_count)
addrList->append(*a);
// did we read all valid phonebook-entries ?
num_read++;
delete a;
if (num_read >= memstat.used)
break; // yes, all were read
else
continue; // no, we are still missing some.
}
GNOKII_CHECK_ERROR(error);
}
return GN_ERR_NONE;
}
// export to phone
static gn_error xxport_phone_write_entry( int phone_location, gn_memory_type memtype,
const KABC::Addressee *addr)
{
TQString s;
/* initialize the phonebook entry values to zero */
gn_lib_phonebook_prepare_write_entry(state);
gn_lib_set_pb_location(state, phone_location);
gn_lib_set_pb_name(state, GN_TO(addr->realName()));
s = addr->phoneNumber(KABC::PhoneNumber::Pref).number();
if (s.isEmpty())
s = addr->phoneNumber(KABC::PhoneNumber::Work).number();
if (s.isEmpty())
s = addr->phoneNumber(KABC::PhoneNumber::Home).number();
if (s.isEmpty())
s = addr->phoneNumber(KABC::PhoneNumber::Cell).number();
if (s.isEmpty() && addr->phoneNumbers().count()>0)
s = (*addr->phoneNumbers().at(0)).number();
s = makeValidPhone(s);
gn_lib_set_pb_number(state, s.ascii());
gn_lib_set_pb_memtype(state, memtype);
TQString cg = addr->custom(APP, "X_GSM_CALLERGROUP");
if (cg.isEmpty())
gn_lib_set_pb_caller_group(state, GN_PHONEBOOK_GROUP_None); // default group
else
gn_lib_set_pb_caller_group(state, (gn_phonebook_group_type) cg.toInt());
// set date/revision
TQDateTime datetime = addr->revision();
TQDate date(datetime.date());
TQTime time(datetime.time());
gn_timestamp ts;
gn_timestamp_set( &ts, date.year(), date.month(), date.day(),
time.hour(), time.minute(), time.second(), 0 );
gn_lib_set_pb_date(state, ts);
GNOKII_DEBUG(TQString("Write #%1: name=%2, number=%3\n").arg(phone_location)
.arg(GN_FROM(gn_lib_get_pb_name(state))).arg(GN_FROM(gn_lib_get_pb_number(state))));
const KABC::Address homeAddr = addr->address(KABC::Address::Home);
const KABC::Address workAddr = addr->address(KABC::Address::Work);
// add all phone numbers
const KABC::PhoneNumber::List phoneList = addr->phoneNumbers();
KABC::PhoneNumber::List::ConstIterator it;
for ( it = phoneList.begin(); it != phoneList.end(); ++it ) {
const KABC::PhoneNumber *phonenumber = &(*it);
s = phonenumber->number();
if (s.isEmpty()) continue;
gn_phonebook_number_type type;
int pn_type = phonenumber->type();
if ((pn_type & KABC::PhoneNumber::Cell))
type = GN_PHONEBOOK_NUMBER_Mobile;
else if ((pn_type & KABC::PhoneNumber::Fax))
type = GN_PHONEBOOK_NUMBER_Fax;
else if ((pn_type & KABC::PhoneNumber::Home))
type = GN_PHONEBOOK_NUMBER_Home;
else if ((pn_type & KABC::PhoneNumber::Work))
type = GN_PHONEBOOK_NUMBER_Work;
else type = GN_PHONEBOOK_NUMBER_General;
gn_lib_set_pb_subentry(state, -1 /* index to append entry */,
GN_PHONEBOOK_ENTRY_Number, type, makeValidPhone(s).ascii());
/*subentry->id = phone_location<<8+entry.subentries_count;*/
}
// add URL
s = addr->url().prettyURL();
if (!s.isEmpty()) {
gn_lib_set_pb_subentry(state, -1 /* index to append entry */,
GN_PHONEBOOK_ENTRY_URL, GN_PHONEBOOK_NUMBER_General, GN_TO(s));
}
// add E-Mails
TQStringList emails = addr->emails();
for (unsigned int n=0; n<emails.count(); n++) {
s = emails[n].simplifyWhiteSpace();
if (s.isEmpty()) continue;
// only one email allowed if we have URLS, notes, addresses (to avoid phone limitations)
if (n && !addr->url().isEmpty() && !addr->note().isEmpty() && addr->addresses().count()) {
GNOKII_DEBUG(TQString(" DROPPED email %1 in favor of URLs, notes and addresses.\n")
.arg(s));
continue;
}
gn_lib_set_pb_subentry(state, -1 /* index to append entry */,
GN_PHONEBOOK_ENTRY_Email, GN_PHONEBOOK_NUMBER_General, GN_TO(s));
}
// add Adresses
const KABC::Address::List addresses = addr->addresses();
KABC::Address::List::ConstIterator it2;
for ( it2 = addresses.begin(); it2 != addresses.end(); ++it2 ) {
const KABC::Address *Addr = &(*it2);
if (Addr->isEmpty()) continue;
TQStringList a;
TQChar sem(';');
TQString sem_repl(TQString::fromLatin1(","));
a.append( Addr->postOfficeBox().replace( sem, sem_repl ) );
a.append( Addr->extended() .replace( sem, sem_repl ) );
a.append( Addr->street() .replace( sem, sem_repl ) );
a.append( Addr->locality() .replace( sem, sem_repl ) );
a.append( Addr->region() .replace( sem, sem_repl ) );
a.append( Addr->postalCode() .replace( sem, sem_repl ) );
a.append( Addr->country() .replace( sem, sem_repl ) );
s = a.join(sem);
gn_lib_set_pb_subentry(state, -1 /* index to append entry */,
GN_PHONEBOOK_ENTRY_Postal, GN_PHONEBOOK_NUMBER_General, GN_TO(s));
}
// add Note
s = addr->note().simplifyWhiteSpace();
if (!s.isEmpty()) {
gn_lib_set_pb_subentry(state, -1 /* index to append entry */,
GN_PHONEBOOK_ENTRY_Note, GN_PHONEBOOK_NUMBER_General, GN_TO(s));
}
// debug output
for (int st=0; st<gn_lib_get_pb_num_subentries(state); st++) {
gn_phonebook_entry_type entry_type;
gn_phonebook_number_type number_type;
const char *number;
gn_lib_get_pb_subentry(state, st, &entry_type, &number_type, &number);
GNOKII_DEBUG(TQString(" SubTel #%1: entry_type=%2, number_type=%3, number=%4\n")
.arg(st).arg(entry_type)
.arg(number_type).arg(GN_FROM(number)));
}
gn_error error = gn_lib_phonebook_write_entry(state, memtype, phone_location);
GNOKII_CHECK_ERROR(error);
return error;
}
static gn_error xxport_phone_delete_entry( int phone_location, gn_memory_type memtype )
{
return gn_lib_phonebook_entry_delete(state, memtype, phone_location);
}
KABC::AddresseeList GNOKIIXXPort::importContacts( const TQString& ) const
{
KABC::AddresseeList addrList;
if (KMessageBox::Continue != KMessageBox::warningContinueCancel(parentWidget(),
i18n("<qt>Please connect your Mobile Phone to your computer and press "
"<b>Continue</b> to start importing the personal contacts.<br><br>"
"Please note that if your Mobile Phone is not properly connected "
"the following detection phase might take up to two minutes, during which "
"KAddressbook will behave unresponsively.</qt>") ))
return addrList;
m_progressDlg = new KProgressDialog( parentWidget(), "importwidget",
i18n("Mobile Phone Import"),
i18n("<qt><center>Establishing connection to the Mobile Phone.<br><br>"
"Please wait...</center></qt>") );
m_progressDlg->setAllowCancel(true);
m_progressDlg->progressBar()->setProgress(0);
m_progressDlg->progressBar()->setCenterIndicator(true);
m_progressDlg->setModal(true);
m_progressDlg->setInitialSize(TQSize(450,350));
m_progressDlg->show();
processEvents();
m_progressDlg->setCursor( TQt::BusyCursor );
TQString errStr = businit();
m_progressDlg->unsetCursor();
if (!errStr.isEmpty()) {
KMessageBox::error(parentWidget(), errStr);
delete m_progressDlg;
return addrList;
}
GNOKII_DEBUG("GNOKII import filter started.\n");
m_progressDlg->setButtonText(i18n("&Stop Import"));
read_phone_entries("ME", GN_MT_ME, &addrList); // internal phone memory
read_phone_entries("SM", GN_MT_SM, &addrList); // SIM card
GNOKII_DEBUG("GNOKII import filter finished.\n");
busterminate();
delete m_progressDlg;
return addrList;
}
bool GNOKIIXXPort::exportContacts( const KABC::AddresseeList &list, const TQString & )
{
if (KMessageBox::Continue != KMessageBox::warningContinueCancel(parentWidget(),
i18n("<qt>Please connect your Mobile Phone to your computer and press "
"<b>Continue</b> to start exporting the selected personal contacts.<br><br>"
"Please note that if your Mobile Phone is not properly connected "
"the following detection phase might take up to two minutes, during which "
"KAddressbook will behave unresponsively.</qt>") ))
return false;
m_progressDlg = new KProgressDialog( parentWidget(), "importwidget",
i18n("Mobile Phone Export"),
i18n("<qt><center>Establishing connection to the Mobile Phone.<br><br>"
"Please wait...</center></qt>") );
m_progressDlg->setAllowCancel(true);
m_progressDlg->progressBar()->setProgress(0);
m_progressDlg->progressBar()->setCenterIndicator(true);
m_progressDlg->setModal(true);
m_progressDlg->setInitialSize(TQSize(450,350));
m_progressDlg->show();
processEvents();
KProgress* progress = (KProgress*)m_progressDlg->progressBar();
KABC::AddresseeList::ConstIterator it;
TQStringList failedList;
gn_error error;
bool deleteLabelInitialized = false;
m_progressDlg->setCursor( TQt::BusyCursor );
TQString errStr = businit();
m_progressDlg->unsetCursor();
if (!errStr.isEmpty()) {
KMessageBox::error(parentWidget(), errStr);
delete m_progressDlg;
return false;
}
GNOKII_DEBUG("GNOKII export filter started.\n");
gn_memory_type memtype = GN_MT_ME; // internal phone memory
int phone_count; // num entries in phone
bool overwrite_phone_entries = false;
int phone_entry_no, entries_written;
bool entry_empty;
// get number of entries in this phone memory
gn_memory_status memstat;
error = read_phone_memstat(memtype, &memstat);
if (error == GN_ERR_NONE) {
GNOKII_DEBUG("Writing to internal phone memory.\n");
} else {
memtype = GN_MT_SM; // try SIM card instead
error = read_phone_memstat(memtype, &memstat);
if (error != GN_ERR_NONE)
goto finish;
GNOKII_DEBUG("Writing to SIM card memory.\n");
}
phone_count = memstat.used;
if (memstat.free >= (int) list.count()) {
if (KMessageBox::No == KMessageBox::questionYesNo(parentWidget(),
i18n("<qt>Do you want the selected contacts to be <b>appended</b> to "
"the current mobile phonebook or should they <b>replace</b> all "
"currently existing phonebook entries ?<br><br>"
"Please note, that in case you choose to replace the phonebook "
"entries, every contact in your phone will be deleted and only "
"the newly exported contacts will be available from inside your phone.</qt>"),
i18n("Export to Mobile Phone"),
KGuiItem(i18n("&Append to Current Phonebook")),
KGuiItem(i18n("&Replace Current Phonebook with New Contacts")) ) )
overwrite_phone_entries = true;
}
progress->setTotalSteps(list.count());
entries_written = 0;
progress->setProgress(entries_written);
m_progressDlg->setButtonText(i18n("&Stop Export"));
m_progressDlg->setLabel(i18n("<qt>Exporting <b>%1</b> contacts to the <b>%2</b> "
"of the Mobile Phone.<br><br>%3</qt>")
.arg(list.count())
.arg(gn_memory_type2str(memtype))
.arg(buildPhoneInfoString(memstat)) );
// Now run the loop...
phone_entry_no = 1;
for ( it = list.begin(); it != list.end(); ++it ) {
const KABC::Addressee *addr = &(*it);
if (addr->isEmpty())
continue;
// don't write back SIM-card entries !
if (addr->custom(APP, "X_GSM_STORE_AT").startsWith("SM"))
continue;
progress->setProgress(entries_written++);
try_next_phone_entry:
this_filter->processEvents();
if (m_progressDlg->wasCancelled())
break;
// End of phone memory reached ?
if (phone_entry_no > (memstat.used + memstat.free))
break;
GNOKII_DEBUG(TQString("Try to write entry '%1' at phone_entry_no=%2, phone_count=%3\n")
.arg(addr->realName()).arg(phone_entry_no).arg(phone_count));
error = GN_ERR_NONE;
// is this phone entry empty ?
entry_empty = gn_lib_phonebook_entry_isempty(state, memtype, phone_entry_no);
if (overwrite_phone_entries) {
// overwrite this phonebook entry ...
if (!entry_empty)
phone_count--;
error = xxport_phone_write_entry( phone_entry_no, memtype, addr);
phone_entry_no++;
} else {
// add this phonebook entry if possible ...
if (entry_empty) {
error = xxport_phone_write_entry( phone_entry_no, memtype, addr);
phone_entry_no++;
} else {
phone_entry_no++;
goto try_next_phone_entry;
}
}
if (error != GN_ERR_NONE)
failedList.append(addr->realName());
// break if we got an error on the first entry
if (error != GN_ERR_NONE && it==list.begin())
break;
} // for()
// if we wanted to overwrite all entries, make sure, that we also
// delete all remaining entries in the mobile phone.
while (overwrite_phone_entries && error==GN_ERR_NONE && phone_count>0) {
if (m_progressDlg->wasCancelled())
break;
if (!deleteLabelInitialized) {
m_progressDlg->setLabel(
i18n("<qt><center>"
"All selected contacts have been sucessfully copied to "
"the Mobile Phone.<br><br>"
"Please wait until all remaining orphaned contacts from "
"the Mobile Phone have been deleted.</center></qt>") );
m_progressDlg->setButtonText(i18n("&Stop Delete"));
deleteLabelInitialized = true;
progress->setTotalSteps(phone_count);
entries_written = 0;
progress->setProgress(entries_written);
this_filter->processEvents();
}
if (phone_entry_no > (memstat.used + memstat.free))
break;
entry_empty = gn_lib_phonebook_entry_isempty(state, memtype, phone_entry_no);
if (!entry_empty) {
error = xxport_phone_delete_entry(phone_entry_no, memtype);
phone_count--;
progress->setProgress(++entries_written);
this_filter->processEvents();
}
phone_entry_no++;
}
finish:
m_progressDlg->setLabel(i18n("Export to phone finished."));
this_filter->processEvents();
GNOKII_DEBUG("GNOKII export filter finished.\n");
busterminate();
delete m_progressDlg;
if (!failedList.isEmpty()) {
GNOKII_DEBUG(TQString("Failed to export: %1\n").arg(failedList.join(", ")));
KMessageBox::informationList(parentWidget(),
i18n("<qt>The following contacts could not be exported to the Mobile Phone. "
"Possible Reasons for this problem could be:<br><ul>"
"<li>The contacts contain more information per entry than the phone can store.</li>"
"<li>Your phone does not allow to store multiple addresses, emails, homepages, ...</li>"
"<li>other storage size related problems.</li>"
"</ul>"
"To avoid those kind of problems in the future please reduce the amount of different "
"fields in the above contacts.</qt>"),
failedList,
i18n("Mobile Phone Export") );
}
return true;
}
/******************************************************************************
******************************************************************************
******************************************************************************
******************************************************************************
******************************************************************************/
#elif defined(HAVE_GNOKII_H)
#ifdef __GNUC__
# warning "Please upgrade your gnokii installation to at least version 0.6.13"
# warning "Older gnokii versions below 0.6.13 are not binary compatible and"
# warning "prevents KDE users to upgrade gnokii to newer versions later."
#endif
/* OLD GNOKII LIBRARIES (< 0.6.13) */
/* import */
static char *lockfile = NULL;
static char manufacturer[64], model[GN_MODEL_MAX_LENGTH+1],
revision[GN_REVISION_MAX_LENGTH+1], imei[GN_IMEI_MAX_LENGTH+1];
static TQString PhoneProductId;
static struct gn_statemachine state;
static gn_data data;
static void busterminate(void)
{
gn_sm_functions(GN_OP_Terminate, NULL, &state);
if (lockfile) gn_device_unlock(lockfile);
}
static TQString businit(void)
{
gn_error error;
char *aux;
GNOKII_DEBUG( "Using old gnokii version." );
#if defined(LIBGNOKII_VERSION)
if (gn_cfg_read_default()<0)
#else
static char *BinDir;
if (gn_cfg_read(&BinDir)<0)
#endif
return i18n("Failed to initialize the gnokii library.");
if (!gn_cfg_phone_load("", &state))
return i18n("Gnokii is not yet configured.");
// uncomment to debug all gnokii communication on stderr.
// gn_log_debug_mask = GN_LOG_T_STDERR;
gn_data_clear(&data);
aux = gn_cfg_get(gn_cfg_info, "global", "use_locking");
// Defaults to 'no'
if (aux && !strcmp(aux, "yes")) {
lockfile = gn_device_lock(state.config.port_device);
if (lockfile == NULL) {
return i18n("Gnokii reports a 'Lock File Error'.\n "
"Please exit all other running instances of gnokii, check if you have "
"write permissions in the /var/lock directory and try again.");
}
}
// Initialise the code for the GSM interface.
int old_dcd = state.config.require_dcd; // work-around for older gnokii versions
state.config.require_dcd = false;
error = gn_gsm_initialise(&state);
GNOKII_CHECK_ERROR(error);
state.config.require_dcd = old_dcd;
if (error != GN_ERR_NONE) {
busterminate();
return i18n("<qt><center>Mobile Phone interface initialization failed.<br><br>"
"The returned error message was:<br><b>%1</b><br><br>"
"You might try to run \"gnokii --identify\" on the command line to "
"check any cable/transport issues and to verify if your gnokii "
"configuration is correct.</center></qt>")
.arg(gn_error_print(error));
}
// identify phone
gn_data_clear(&data);
data.manufacturer = manufacturer;
data.model = model;
data.revision = revision;
data.imei = imei;
TQCString unknown(GN_TO(i18n("Unknown")));
tqstrncpy(manufacturer, unknown, sizeof(manufacturer)-1);
tqstrncpy(model, unknown, sizeof(model)-1);
tqstrncpy(revision, unknown, sizeof(revision)-1);
tqstrncpy(imei, unknown, sizeof(imei)-1);
if (m_progressDlg->wasCancelled())
return TQString();
else
error = gn_sm_functions(GN_OP_Identify, &data, &state);
GNOKII_CHECK_ERROR(error);
GNOKII_DEBUG( TQString("Found mobile phone: %1 %2, Revision: %3, IMEI: %4\n")
.arg(manufacturer, model, revision, imei) );
PhoneProductId = TQString("%1-%2-%3-%4").arg(APP).arg(model).arg(revision).arg(imei);
return TQString();
}
// get number of entries in this phone memory type (internal/SIM-card)
static gn_error read_phone_memstat( const gn_memory_type memtype, gn_memory_status *memstat )
{
gn_error error;
gn_data_clear(&data);
memset(memstat, 0, sizeof(*memstat));
memstat->memory_type = memtype;
data.memory_status = memstat;
error = gn_sm_functions(GN_OP_GetMemoryStatus, &data, &state);
GNOKII_CHECK_ERROR(error);
if (error != GN_ERR_NONE) {
switch (memtype) {
case GN_MT_SM:
// use at least 100 entries
memstat->used = 0;
memstat->free = 100;
break;
default:
case GN_MT_ME:
// Phone doesn't support ME (5110)
memstat->used = memstat->free = 0;
break;
}
}
GNOKII_DEBUG( TQString("\n\nMobile phone memory status: Type: %1, used=%2, free=%3, total=%4\n\n")
.arg(memtype).arg(memstat->used).arg(memstat->free).arg(memstat->used+memstat->free) );
return error;
}
// read phone entry #index from memory #memtype
static gn_error read_phone_entry( const int index, const gn_memory_type memtype, gn_phonebook_entry *entry )
{
gn_error error;
entry->memory_type = memtype;
entry->location = index;
data.phonebook_entry = entry;
error = gn_sm_functions(GN_OP_ReadPhonebook, &data, &state);
GNOKII_CHECK_ERROR(error);
return error;
}
static bool phone_entry_empty( const int index, const gn_memory_type memtype )
{
gn_error error;
gn_phonebook_entry entry;
entry.memory_type = memtype;
entry.location = index;
data.phonebook_entry = &entry;
error = gn_sm_functions(GN_OP_ReadPhonebook, &data, &state);
if (error == GN_ERR_EMPTYLOCATION)
return true;
GNOKII_CHECK_ERROR(error);
if (error == GN_ERR_NONE && entry.empty)
return true;
return false;
}
static TQString buildPhoneInfoString( const gn_memory_status &memstat )
{
TQString format = TQString::fromLatin1("<tr><td><b>%1</b></td><td>%2</td></tr>");
return TQString::fromLatin1("<b>%1</b><br><table>%2%3%4%5%6</table><br>")
.arg(i18n("Mobile Phone information:"))
.arg(format.arg(i18n("Manufacturer")).arg(GN_FROM(manufacturer)))
.arg(format.arg(i18n("Phone model")).arg(GN_FROM(model)))
.arg(format.arg(i18n("Revision")).arg(GN_FROM(revision)))
.arg(format.arg(i18n("IMEI")).arg(GN_FROM(imei)))
.arg(format.arg(i18n("Phonebook status"))
.arg(i18n("%1 out of %2 contacts used").arg(memstat.used).arg(memstat.used+memstat.free)));
}
static TQString buildMemoryTypeString( gn_memory_type memtype )
{
switch (memtype) {
case GN_MT_ME: return i18n("internal memory");
case GN_MT_SM: return i18n("SIM-card memory");
default: return i18n("unknown memory");
}
}
// read and evaluate all phone entries
static gn_error read_phone_entries( const char *memtypestr, gn_memory_type memtype,
KABC::AddresseeList *addrList )
{
gn_error error;
if (m_progressDlg->wasCancelled())
return GN_ERR_NONE;
KProgress* progress = (KProgress*)m_progressDlg->progressBar();
progress->setProgress(0);
this_filter->processEvents();
// get number of entries in this phone memory type (internal/SIM-card)
gn_memory_status memstat;
error = read_phone_memstat(memtype, &memstat);
gn_phonebook_entry entry;
TQStringList addrlist;
KABC::Address *addr;
TQString s, country;
progress->setTotalSteps(memstat.used);
m_progressDlg->setLabel(i18n("<qt>Importing <b>%1</b> contacts from <b>%2</b> of the Mobile Phone.<br><br>%3</qt>")
.arg(memstat.used)
.arg(buildMemoryTypeString(memtype))
.arg(buildPhoneInfoString(memstat)) );
int num_read = 0;
for (int i = 1; !m_progressDlg->wasCancelled() && i <= memstat.used + memstat.free; i++) {
error = read_phone_entry( i, memtype, &entry );
progress->setProgress(num_read);
this_filter->processEvents();
if (error == GN_ERR_EMPTYLOCATION)
continue;
if (error == GN_ERR_INVALIDLOCATION)
break;
if (error == GN_ERR_INVALIDMEMORYTYPE)
break;
if (error == GN_ERR_NONE) {
GNOKII_DEBUG(TQString("%1: %2, num=%3, location=%4, group=%5, count=%6\n").arg(i).arg(GN_FROM(entry.name))
.arg(GN_FROM(entry.number)).arg(entry.location).arg(entry.caller_group).arg(entry.subentries_count));
KABC::Addressee *a = new KABC::Addressee();
// try to split Name into FamilyName and GivenName
s = GN_FROM(entry.name).simplifyWhiteSpace();
a->setFormattedName(s); // set formatted name as in Phone
if (s.find(',') == -1) {
// assumed format: "givenname [... familyname]"
addrlist = TQStringList::split(' ', s);
if (addrlist.count() == 1) {
// only one string -> put it in the GivenName
a->setGivenName(s);
} else {
// multiple strings -> split them.
a->setFamilyName(addrlist.last().simplifyWhiteSpace());
addrlist.remove(addrlist.last());
a->setGivenName(addrlist.join(" ").simplifyWhiteSpace());
}
} else {
// assumed format: "familyname, ... givenname"
addrlist = TQStringList::split(',', s);
a->setFamilyName(addrlist.first().simplifyWhiteSpace());
addrlist.remove(addrlist.first());
a->setGivenName(addrlist.join(" ").simplifyWhiteSpace());
}
a->insertCustom(APP, "X_GSM_CALLERGROUP", s.setNum(entry.caller_group));
a->insertCustom(APP, "X_GSM_STORE_AT", TQString("%1%2").arg(memtypestr).arg(entry.location));
// set ProductId
a->setProductId(PhoneProductId);
// evaluate timestamp (ignore timezone)
TQDateTime datetime;
if (entry.date.year<1998)
datetime = TQDateTime::currentDateTime();
else
datetime = TQDateTime( TQDate(entry.date.year, entry.date.month, entry.date.day),
TQTime(entry.date.hour, entry.date.minute, entry.date.second) );
GNOKII_DEBUG(TQString(" date=%1\n").arg(datetime.toString()));
a->setRevision(datetime);
if (!entry.subentries_count)
a->insertPhoneNumber(KABC::PhoneNumber(entry.number, KABC::PhoneNumber::Work | KABC::PhoneNumber::Pref));
/* scan sub-entries */
if (entry.subentries_count)
for (int n=0; n<entry.subentries_count; n++) {
TQString s = GN_FROM(entry.subentries[n].data.number).simplifyWhiteSpace();
GNOKII_DEBUG(TQString(" Subentry#%1, entry_type=%2, number_type=%3, number=%4\n")
.arg(n).arg(entry.subentries[n].entry_type)
.arg(entry.subentries[n].number_type).arg(s));
if (s.isEmpty())
continue;
switch(entry.subentries[n].entry_type) {
case GN_PHONEBOOK_ENTRY_Name:
a->setName(s);
break;
case GN_PHONEBOOK_ENTRY_Email:
a->insertEmail(s);
break;
case GN_PHONEBOOK_ENTRY_Postal:
addrlist = TQStringList::split(';', s, true);
addr = new KABC::Address(KABC::Address::Work);
if (addrlist.count() <= 1) {
addrlist = TQStringList::split(',', s, true);
if (addrlist.count() > 1 ) {
// assumed format: "Locality, ZIP, Country"
addr->setLocality(addrlist[0]);
addr->setPostalCode(addrlist[1]);
if (!addrlist[2].isEmpty())
addr->setCountry(i18n(GN_TO(addrlist[2])));
} else {
// no idea about the format, just store it.
addr->setLocality(s);
}
} else {
// assumed format: "POBox; Extended; Street; Locality; Region; ZIP [;Country]
addr->setPostOfficeBox(addrlist[0]);
addr->setExtended(addrlist[1]);
addr->setStreet(addrlist[2]);
addr->setLocality(addrlist[3]);
addr->setRegion(addrlist[4]);
addr->setPostalCode(addrlist[5]);
country = addrlist[6];
if (!country.isEmpty())
addr->setCountry(i18n(GN_TO(country)));
}
a->insertAddress(*addr);
delete addr;
break;
case GN_PHONEBOOK_ENTRY_Note:
if (!a->note().isEmpty())
s = "\n" + s;
a->setNote(a->note()+s);
break;
case GN_PHONEBOOK_ENTRY_Number:
enum KABC::PhoneNumber::Types phonetype;
switch (entry.subentries[n].number_type) {
case GN_PHONEBOOK_NUMBER_Mobile: phonetype = KABC::PhoneNumber::Cell; break;
case GN_PHONEBOOK_NUMBER_Fax: phonetype = KABC::PhoneNumber::Fax; break;
case GN_PHONEBOOK_NUMBER_General:
case GN_PHONEBOOK_NUMBER_Work: phonetype = KABC::PhoneNumber::Work; break;
default:
case GN_PHONEBOOK_NUMBER_Home: phonetype = KABC::PhoneNumber::Home; break;
}
//if (s == entry.number)
// type = (KABC::PhoneNumber::Types) (phonetype | KABC::PhoneNumber::Pref);
a->insertPhoneNumber(KABC::PhoneNumber(s, phonetype));
break;
case GN_PHONEBOOK_ENTRY_URL:
a->setUrl(s);
break;
case GN_PHONEBOOK_ENTRY_Group:
a->insertCategory(s);
break;
default:
GNOKII_DEBUG(TQString(" Not handled id=%1, entry=%2\n")
.arg(entry.subentries[n].entry_type).arg(s));
break;
} // switch()
} // if(subentry)
// add only if entry was valid
if (strlen(entry.name) || strlen(entry.number) || entry.subentries_count)
addrList->append(*a);
// did we read all valid phonebook-entries ?
num_read++;
delete a;
if (num_read >= memstat.used)
break; // yes, all were read
else
continue; // no, we are still missing some.
}
GNOKII_CHECK_ERROR(error);
}
return GN_ERR_NONE;
}
// export to phone
static gn_error xxport_phone_write_entry( int phone_location, gn_memory_type memtype,
const KABC::Addressee *addr)
{
gn_phonebook_entry entry;
TQString s;
memset(&entry, 0, sizeof(entry));
strncpy(entry.name, GN_TO(addr->realName()), sizeof(entry.name)-1);
s = addr->phoneNumber(KABC::PhoneNumber::Pref).number();
if (s.isEmpty())
s = addr->phoneNumber(KABC::PhoneNumber::Work).number();
if (s.isEmpty())
s = addr->phoneNumber(KABC::PhoneNumber::Home).number();
if (s.isEmpty())
s = addr->phoneNumber(KABC::PhoneNumber::Cell).number();
if (s.isEmpty() && addr->phoneNumbers().count()>0)
s = (*addr->phoneNumbers().at(0)).number();
s = makeValidPhone(s);
strncpy(entry.number, s.ascii(), sizeof(entry.number)-1);
entry.memory_type = memtype;
TQString cg = addr->custom(APP, "X_GSM_CALLERGROUP");
if (cg.isEmpty())
entry.caller_group = 5; // default group
else
entry.caller_group = cg.toInt();
entry.location = phone_location;
// set date/revision
TQDateTime datetime = addr->revision();
TQDate date(datetime.date());
TQTime time(datetime.time());
entry.date.year = date.year();
entry.date.month = date.month();
entry.date.day = date.day();
entry.date.hour = time.hour();
entry.date.minute = time.minute();
entry.date.second = time.second();
GNOKII_DEBUG(TQString("Write #%1: name=%2, number=%3\n").arg(phone_location)
.arg(GN_FROM(entry.name)).arg(GN_FROM(entry.number)));
const KABC::Address homeAddr = addr->address(KABC::Address::Home);
const KABC::Address workAddr = addr->address(KABC::Address::Work);
entry.subentries_count = 0;
gn_phonebook_subentry *subentry = &entry.subentries[0];
// add all phone numbers
const KABC::PhoneNumber::List phoneList = addr->phoneNumbers();
KABC::PhoneNumber::List::ConstIterator it;
for ( it = phoneList.begin(); it != phoneList.end(); ++it ) {
const KABC::PhoneNumber *phonenumber = &(*it);
s = phonenumber->number();
if (s.isEmpty()) continue;
subentry->entry_type = GN_PHONEBOOK_ENTRY_Number;
gn_phonebook_number_type type;
int pn_type = phonenumber->type();
if ((pn_type & KABC::PhoneNumber::Cell))
type = GN_PHONEBOOK_NUMBER_Mobile;
else if ((pn_type & KABC::PhoneNumber::Fax))
type = GN_PHONEBOOK_NUMBER_Fax;
else if ((pn_type & KABC::PhoneNumber::Home))
type = GN_PHONEBOOK_NUMBER_Home;
else if ((pn_type & KABC::PhoneNumber::Work))
type = GN_PHONEBOOK_NUMBER_Work;
else type = GN_PHONEBOOK_NUMBER_General;
subentry->number_type = type;
strncpy(subentry->data.number, makeValidPhone(s).ascii(), sizeof(subentry->data.number)-1);
subentry->id = phone_location<<8+entry.subentries_count;
entry.subentries_count++;
subentry++;
if (entry.subentries_count >= GN_PHONEBOOK_SUBENTRIES_MAX_NUMBER)
break; // Phonebook full
}
// add URL
s = addr->url().prettyURL();
if (!s.isEmpty() && (entry.subentries_count<GN_PHONEBOOK_SUBENTRIES_MAX_NUMBER)) {
subentry->entry_type = GN_PHONEBOOK_ENTRY_URL;
strncpy(subentry->data.number, GN_TO(s), sizeof(subentry->data.number)-1);
entry.subentries_count++;
subentry++;
}
// add E-Mails
TQStringList emails = addr->emails();
for (unsigned int n=0; n<emails.count(); n++) {
if (entry.subentries_count >= GN_PHONEBOOK_SUBENTRIES_MAX_NUMBER)
break; // Phonebook full
s = emails[n].simplifyWhiteSpace();
if (s.isEmpty()) continue;
// only one email allowed if we have URLS, notes, addresses (to avoid phone limitations)
if (n && !addr->url().isEmpty() && !addr->note().isEmpty() && addr->addresses().count()) {
GNOKII_DEBUG(TQString(" DROPPED email %1 in favor of URLs, notes and addresses.\n")
.arg(s));
continue;
}
subentry->entry_type = GN_PHONEBOOK_ENTRY_Email;
strncpy(subentry->data.number, GN_TO(s), sizeof(subentry->data.number)-1);
entry.subentries_count++;
subentry++;
}
// add Adresses
const KABC::Address::List addresses = addr->addresses();
KABC::Address::List::ConstIterator it2;
for ( it2 = addresses.begin(); it2 != addresses.end(); ++it2 ) {
if (entry.subentries_count >= GN_PHONEBOOK_SUBENTRIES_MAX_NUMBER)
break; // Phonebook full
const KABC::Address *Addr = &(*it2);
if (Addr->isEmpty()) continue;
subentry->entry_type = GN_PHONEBOOK_ENTRY_Postal;
TQStringList a;
TQChar sem(';');
TQString sem_repl(TQString::fromLatin1(","));
a.append( Addr->postOfficeBox().replace( sem, sem_repl ) );
a.append( Addr->extended() .replace( sem, sem_repl ) );
a.append( Addr->street() .replace( sem, sem_repl ) );
a.append( Addr->locality() .replace( sem, sem_repl ) );
a.append( Addr->region() .replace( sem, sem_repl ) );
a.append( Addr->postalCode() .replace( sem, sem_repl ) );
a.append( Addr->country() .replace( sem, sem_repl ) );
s = a.join(sem);
strncpy(subentry->data.number, GN_TO(s), sizeof(subentry->data.number)-1);
entry.subentries_count++;
subentry++;
}
// add Note
s = addr->note().simplifyWhiteSpace();
if (!s.isEmpty() && (entry.subentries_count<GN_PHONEBOOK_SUBENTRIES_MAX_NUMBER)) {
subentry->entry_type = GN_PHONEBOOK_ENTRY_Note;
strncpy(subentry->data.number, GN_TO(s), sizeof(subentry->data.number)-1);
entry.subentries_count++;
subentry++;
}
// debug output
for (int st=0; st<entry.subentries_count; st++) {
gn_phonebook_subentry *subentry = &entry.subentries[st];
GNOKII_DEBUG(TQString(" SubTel #%1: entry_type=%2, number_type=%3, number=%4\n")
.arg(st).arg(subentry->entry_type)
.arg(subentry->number_type).arg(GN_FROM(subentry->data.number)));
}
data.phonebook_entry = &entry;
gn_error error = gn_sm_functions(GN_OP_WritePhonebook, &data, &state);
GNOKII_CHECK_ERROR(error);
return error;
}
static gn_error xxport_phone_delete_entry( int phone_location, gn_memory_type memtype )
{
gn_phonebook_entry entry;
memset(&entry, 0, sizeof(entry));
entry.empty = 1;
entry.memory_type = memtype;
entry.location = phone_location;
data.phonebook_entry = &entry;
GNOKII_DEBUG(TQString("Deleting entry %1\n").arg(phone_location));
gn_error error = gn_sm_functions(GN_OP_WritePhonebook, &data, &state);
GNOKII_CHECK_ERROR(error);
return error;
}
KABC::AddresseeList GNOKIIXXPort::importContacts( const TQString& ) const
{
KABC::AddresseeList addrList;
if (KMessageBox::Continue != KMessageBox::warningContinueCancel(parentWidget(),
i18n("<qt>Please connect your Mobile Phone to your computer and press "
"<b>Continue</b> to start importing the personal contacts.<br><br>"
"Please note that if your Mobile Phone is not properly connected "
"the following detection phase might take up to two minutes, during which "
"KAddressbook will behave unresponsively.</qt>") ))
return addrList;
m_progressDlg = new KProgressDialog( parentWidget(), "importwidget",
i18n("Mobile Phone Import"),
i18n("<qt><center>Establishing connection to the Mobile Phone.<br><br>"
"Please wait...</center></qt>") );
m_progressDlg->setAllowCancel(true);
m_progressDlg->progressBar()->setProgress(0);
m_progressDlg->progressBar()->setCenterIndicator(true);
m_progressDlg->setModal(true);
m_progressDlg->setInitialSize(TQSize(450,350));
m_progressDlg->show();
processEvents();
m_progressDlg->setCursor( TQt::BusyCursor );
TQString errStr = businit();
m_progressDlg->unsetCursor();
if (!errStr.isEmpty()) {
KMessageBox::error(parentWidget(), errStr);
delete m_progressDlg;
return addrList;
}
GNOKII_DEBUG("GNOKII import filter started.\n");
m_progressDlg->setButtonText(i18n("&Stop Import"));
read_phone_entries("ME", GN_MT_ME, &addrList); // internal phone memory
read_phone_entries("SM", GN_MT_SM, &addrList); // SIM card
GNOKII_DEBUG("GNOKII import filter finished.\n");
busterminate();
delete m_progressDlg;
return addrList;
}
bool GNOKIIXXPort::exportContacts( const KABC::AddresseeList &list, const TQString & )
{
if (KMessageBox::Continue != KMessageBox::warningContinueCancel(parentWidget(),
i18n("<qt>Please connect your Mobile Phone to your computer and press "
"<b>Continue</b> to start exporting the selected personal contacts.<br><br>"
"Please note that if your Mobile Phone is not properly connected "
"the following detection phase might take up to two minutes, during which "
"KAddressbook will behave unresponsively.</qt>") ))
return false;
m_progressDlg = new KProgressDialog( parentWidget(), "importwidget",
i18n("Mobile Phone Export"),
i18n("<qt><center>Establishing connection to the Mobile Phone.<br><br>"
"Please wait...</center></qt>") );
m_progressDlg->setAllowCancel(true);
m_progressDlg->progressBar()->setProgress(0);
m_progressDlg->progressBar()->setCenterIndicator(true);
m_progressDlg->setModal(true);
m_progressDlg->setInitialSize(TQSize(450,350));
m_progressDlg->show();
processEvents();
KProgress* progress = (KProgress*)m_progressDlg->progressBar();
KABC::AddresseeList::ConstIterator it;
TQStringList failedList;
gn_error error;
bool deleteLabelInitialized = false;
m_progressDlg->setCursor( TQt::BusyCursor );
TQString errStr = businit();
m_progressDlg->unsetCursor();
if (!errStr.isEmpty()) {
KMessageBox::error(parentWidget(), errStr);
delete m_progressDlg;
return false;
}
GNOKII_DEBUG("GNOKII export filter started.\n");
gn_memory_type memtype = GN_MT_ME; // internal phone memory
int phone_count; // num entries in phone
bool overwrite_phone_entries = false;
int phone_entry_no, entries_written;
bool entry_empty;
// get number of entries in this phone memory
gn_memory_status memstat;
error = read_phone_memstat(memtype, &memstat);
if (error == GN_ERR_NONE) {
GNOKII_DEBUG("Writing to internal phone memory.\n");
} else {
memtype = GN_MT_SM; // try SIM card instead
error = read_phone_memstat(memtype, &memstat);
if (error != GN_ERR_NONE)
goto finish;
GNOKII_DEBUG("Writing to SIM card memory.\n");
}
phone_count = memstat.used;
if (memstat.free >= (int) list.count()) {
if (KMessageBox::No == KMessageBox::questionYesNo(parentWidget(),
i18n("<qt>Do you want the selected contacts to be <b>appended</b> to "
"the current mobile phonebook or should they <b>replace</b> all "
"currently existing phonebook entries ?<br><br>"
"Please note, that in case you choose to replace the phonebook "
"entries, every contact in your phone will be deleted and only "
"the newly exported contacts will be available from inside your phone.</qt>"),
i18n("Export to Mobile Phone"),
KGuiItem(i18n("&Append to Current Phonebook")),
KGuiItem(i18n("&Replace Current Phonebook with New Contacts")) ) )
overwrite_phone_entries = true;
}
progress->setTotalSteps(list.count());
entries_written = 0;
progress->setProgress(entries_written);
m_progressDlg->setButtonText(i18n("&Stop Export"));
m_progressDlg->setLabel(i18n("<qt>Exporting <b>%1</b> contacts to the <b>%2</b> "
"of the Mobile Phone.<br><br>%3</qt>")
.arg(list.count())
.arg(buildMemoryTypeString(memtype))
.arg(buildPhoneInfoString(memstat)) );
// Now run the loop...
phone_entry_no = 1;
for ( it = list.begin(); it != list.end(); ++it ) {
const KABC::Addressee *addr = &(*it);
if (addr->isEmpty())
continue;
// don't write back SIM-card entries !
if (addr->custom(APP, "X_GSM_STORE_AT").startsWith("SM"))
continue;
progress->setProgress(entries_written++);
try_next_phone_entry:
this_filter->processEvents();
if (m_progressDlg->wasCancelled())
break;
// End of phone memory reached ?
if (phone_entry_no > (memstat.used + memstat.free))
break;
GNOKII_DEBUG(TQString("Try to write entry '%1' at phone_entry_no=%2, phone_count=%3\n")
.arg(addr->realName()).arg(phone_entry_no).arg(phone_count));
error = GN_ERR_NONE;
// is this phone entry empty ?
entry_empty = phone_entry_empty(phone_entry_no, memtype);
if (overwrite_phone_entries) {
// overwrite this phonebook entry ...
if (!entry_empty)
phone_count--;
error = xxport_phone_write_entry( phone_entry_no, memtype, addr);
phone_entry_no++;
} else {
// add this phonebook entry if possible ...
if (entry_empty) {
error = xxport_phone_write_entry( phone_entry_no, memtype, addr);
phone_entry_no++;
} else {
phone_entry_no++;
goto try_next_phone_entry;
}
}
if (error != GN_ERR_NONE)
failedList.append(addr->realName());
// break if we got an error on the first entry
if (error != GN_ERR_NONE && it==list.begin())
break;
} // for()
// if we wanted to overwrite all entries, make sure, that we also
// delete all remaining entries in the mobile phone.
while (overwrite_phone_entries && error==GN_ERR_NONE && phone_count>0) {
if (m_progressDlg->wasCancelled())
break;
if (!deleteLabelInitialized) {
m_progressDlg->setLabel(
i18n("<qt><center>"
"All selected contacts have been sucessfully copied to "
"the Mobile Phone.<br><br>"
"Please wait until all remaining orphaned contacts from "
"the Mobile Phone have been deleted.</center></qt>") );
m_progressDlg->setButtonText(i18n("&Stop Delete"));
deleteLabelInitialized = true;
progress->setTotalSteps(phone_count);
entries_written = 0;
progress->setProgress(entries_written);
this_filter->processEvents();
}
if (phone_entry_no > (memstat.used + memstat.free))
break;
entry_empty = phone_entry_empty(phone_entry_no, memtype);
if (!entry_empty) {
error = xxport_phone_delete_entry(phone_entry_no, memtype);
phone_count--;
progress->setProgress(++entries_written);
this_filter->processEvents();
}
phone_entry_no++;
}
finish:
m_progressDlg->setLabel(i18n("Export to phone finished."));
this_filter->processEvents();
GNOKII_DEBUG("GNOKII export filter finished.\n");
busterminate();
delete m_progressDlg;
if (!failedList.isEmpty()) {
GNOKII_DEBUG(TQString("Failed to export: %1\n").arg(failedList.join(", ")));
KMessageBox::informationList(parentWidget(),
i18n("<qt>The following contacts could not be exported to the Mobile Phone. "
"Possible Reasons for this problem could be:<br><ul>"
"<li>The contacts contain more information per entry than the phone can store.</li>"
"<li>Your phone does not allow to store multiple addresses, emails, homepages, ...</li>"
"<li>other storage size related problems.</li>"
"</ul>"
"To avoid those kind of problems in the future please reduce the amount of different "
"fields in the above contacts.</qt>"),
failedList,
i18n("Mobile Phone Export") );
}
return true;
}
/******************************************************************************
******************************************************************************
******************************************************************************
******************************************************************************
******************************************************************************/
#else /* no gnokii installed */
KABC::AddresseeList GNOKIIXXPort::importContacts( const TQString& ) const
{
KABC::AddresseeList addrList;
KMessageBox::error(parentWidget(), i18n("Gnokii interface is not available.\n"
"Please ask your distributor to add gnokii at compile time."));
return addrList;
}
bool GNOKIIXXPort::exportContacts( const KABC::AddresseeList &list, const TQString & )
{
Q_UNUSED(list);
KMessageBox::error(parentWidget(), i18n("Gnokii interface is not available.\n"
"Please ask your distributor to add gnokii at compile time."));
return true;
}
#endif /* END OF GNOKII LIB SWITCH */
/******************************************************************************
******************************************************************************
******************************************************************************
******************************************************************************
******************************************************************************/
#include "gnokii_xxport.moc"
/* vim: set sts=4 ts=4 sw=4: */